Debug.
[libdcp.git] / src / sound_asset_writer.cc
1 /*
2     Copyright (C) 2012-2020 Carl Hetherington <cth@carlh.net>
3
4     This file is part of libdcp.
5
6     libdcp is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     libdcp is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with libdcp.  If not, see <http://www.gnu.org/licenses/>.
18
19     In addition, as a special exception, the copyright holders give
20     permission to link the code of portions of this program with the
21     OpenSSL library under certain conditions as described in each
22     individual source file, and distribute linked combinations
23     including the two.
24
25     You must obey the GNU General Public License in all respects
26     for all of the code used other than OpenSSL.  If you modify
27     file(s) with this exception, you may extend this exception to your
28     version of the file(s), but you are not obligated to do so.  If you
29     do not wish to do so, delete this exception statement from your
30     version.  If you delete this exception statement from all source
31     files in the program, then also delete it here.
32 */
33
34 #include "bitstream.h"
35 #include "sound_asset_writer.h"
36 #include "sound_asset.h"
37 #include "exceptions.h"
38 #include "dcp_assert.h"
39 #include "compose.hpp"
40 #include "crypto_context.h"
41 #include <asdcp/AS_DCP.h>
42 #include <asdcp/Metadata.h>
43 #include <boost/foreach.hpp>
44 #include <iostream>
45
46 using std::min;
47 using std::max;
48 using std::cout;
49 using std::string;
50 using std::vector;
51 using namespace dcp;
52
53
54 struct SoundAssetWriter::ASDCPState
55 {
56         ASDCP::PCM::MXFWriter mxf_writer;
57         ASDCP::PCM::FrameBuffer frame_buffer;
58         ASDCP::WriterInfo writer_info;
59         ASDCP::PCM::AudioDescriptor desc;
60 };
61
62 SoundAssetWriter::SoundAssetWriter (SoundAsset* asset, boost::filesystem::path file, vector<Channel> active_channels, bool sync)
63         : AssetWriter (asset, file)
64         , _state (new SoundAssetWriter::ASDCPState)
65         , _asset (asset)
66         , _frame_buffer_offset (0)
67         , _sync (sync)
68         , _sync_packet (0)
69         , _active_channels (active_channels)
70 {
71         DCP_ASSERT (!_sync || _asset->channels() >= 14);
72         DCP_ASSERT (!_sync || _asset->standard() == SMPTE);
73
74         /* Derived from ASDCP::Wav::SimpleWaveHeader::FillADesc */
75         _state->desc.EditRate = ASDCP::Rational (_asset->edit_rate().numerator, _asset->edit_rate().denominator);
76         _state->desc.AudioSamplingRate = ASDCP::Rational (_asset->sampling_rate(), 1);
77         _state->desc.Locked = 0;
78         _state->desc.ChannelCount = _asset->channels ();
79         _state->desc.QuantizationBits = 24;
80         _state->desc.BlockAlign = 3 * _asset->channels();
81         _state->desc.AvgBps = _asset->sampling_rate() * _state->desc.BlockAlign;
82         _state->desc.LinkedTrackID = 0;
83         if (asset->standard() == INTEROP) {
84                 _state->desc.ChannelFormat = ASDCP::PCM::CF_NONE;
85         } else {
86                 /* Just use WTF ("wild track format") for SMPTE for now; searches suggest that this
87                    uses the same assignment as Interop.
88                 */
89                 _state->desc.ChannelFormat = ASDCP::PCM::CF_CFG_4;
90         }
91
92         /* I'm fairly sure this is not necessary, as ContainerDuration is written
93            in ASDCP's WriteMXFFooter, but it stops a valgrind warning.
94         */
95         _state->desc.ContainerDuration = 0;
96
97         _state->frame_buffer.Capacity (ASDCP::PCM::CalcFrameBufferSize (_state->desc));
98         _state->frame_buffer.Size (ASDCP::PCM::CalcFrameBufferSize (_state->desc));
99         memset (_state->frame_buffer.Data(), 0, _state->frame_buffer.Capacity());
100
101         _asset->fill_writer_info (&_state->writer_info, _asset->id());
102
103         if (_sync) {
104                 _fsk.set_data (create_sync_packets());
105         }
106 }
107
108
109 void
110 SoundAssetWriter::start ()
111 {
112         Kumu::Result_t r = _state->mxf_writer.OpenWrite (_file.string().c_str(), _state->writer_info, _state->desc);
113         if (ASDCP_FAILURE (r)) {
114                 boost::throw_exception (FileError ("could not open audio MXF for writing", _file.string(), r));
115         }
116
117         if (_asset->standard() == dcp::SMPTE && !_active_channels.empty()) {
118
119                 ASDCP::MXF::WaveAudioDescriptor* essence_descriptor = 0;
120                 _state->mxf_writer.OP1aHeader().GetMDObjectByType(
121                         asdcp_smpte_dict->ul(ASDCP::MDD_WaveAudioDescriptor), reinterpret_cast<ASDCP::MXF::InterchangeObject**>(&essence_descriptor)
122                         );
123                 DCP_ASSERT (essence_descriptor);
124                 essence_descriptor->ChannelAssignment = asdcp_smpte_dict->ul(ASDCP::MDD_DCAudioChannelCfg_MCA);
125
126                 ASDCP::MXF::SoundfieldGroupLabelSubDescriptor* soundfield = new ASDCP::MXF::SoundfieldGroupLabelSubDescriptor(asdcp_smpte_dict);
127                 GenRandomValue (soundfield->MCALinkID);
128                 soundfield->RFC5646SpokenLanguage = _asset->language().to_string();
129
130                 const MCASoundField field = _asset->channels() > 10 ? SEVEN_POINT_ONE : FIVE_POINT_ONE;
131
132                 if (field == SEVEN_POINT_ONE) {
133                         soundfield->MCATagSymbol = "sg71";
134                         soundfield->MCATagName = "7.1DS";
135                         soundfield->MCALabelDictionaryID = asdcp_smpte_dict->ul(ASDCP::MDD_DCAudioSoundfield_71);
136                 } else {
137                         soundfield->MCATagSymbol = "sg51";
138                         soundfield->MCATagName = "5.1";
139                         soundfield->MCALabelDictionaryID = asdcp_smpte_dict->ul(ASDCP::MDD_DCAudioSoundfield_51);
140                 }
141
142                 _state->mxf_writer.OP1aHeader().AddChildObject(soundfield);
143                 essence_descriptor->SubDescriptors.push_back(soundfield->InstanceUID);
144
145                 BOOST_FOREACH (Channel i, _active_channels) {
146                         ASDCP::MXF::AudioChannelLabelSubDescriptor* channel = new ASDCP::MXF::AudioChannelLabelSubDescriptor(asdcp_smpte_dict);
147                         GenRandomValue (channel->MCALinkID);
148                         channel->SoundfieldGroupLinkID = soundfield->MCALinkID;
149                         channel->MCAChannelID = static_cast<int>(i) + 1;
150                         channel->MCATagSymbol = "ch" + channel_to_mca_id(i, field);
151                         channel->MCATagName = channel_to_mca_name(i, field);
152                         channel->RFC5646SpokenLanguage = _asset->language().to_string();
153                         channel->MCALabelDictionaryID = channel_to_mca_universal_label(i, field, asdcp_smpte_dict);
154                         _state->mxf_writer.OP1aHeader().AddChildObject(channel);
155                         essence_descriptor->SubDescriptors.push_back(channel->InstanceUID);
156                 }
157         }
158
159         _asset->set_file (_file);
160         _started = true;
161 }
162
163
164 void
165 SoundAssetWriter::write (float const * const * data, int frames)
166 {
167         DCP_ASSERT (!_finalized);
168         DCP_ASSERT (frames > 0);
169
170         static float const clip = 1.0f - (1.0f / pow (2, 23));
171
172         if (!_started) {
173                 start ();
174         }
175
176         int const ch = _asset->channels ();
177
178         for (int i = 0; i < frames; ++i) {
179
180                 byte_t* out = _state->frame_buffer.Data() + _frame_buffer_offset;
181
182                 /* Write one sample per channel */
183                 for (int j = 0; j < ch; ++j) {
184                         int32_t s = 0;
185                         if (j == 13 && _sync) {
186                                 s = _fsk.get();
187                         } else {
188                                 /* Convert sample to 24-bit int, clipping if necessary. */
189                                 float x = data[j][i];
190                                 if (x > clip) {
191                                         x = clip;
192                                 } else if (x < -clip) {
193                                         x = -clip;
194                                 }
195                                 s = x * (1 << 23);
196                         }
197                         *out++ = (s & 0xff);
198                         *out++ = (s & 0xff00) >> 8;
199                         *out++ = (s & 0xff0000) >> 16;
200                 }
201                 _frame_buffer_offset += 3 * ch;
202
203                 DCP_ASSERT (_frame_buffer_offset <= int (_state->frame_buffer.Capacity()));
204
205                 /* Finish the MXF frame if required */
206                 if (_frame_buffer_offset == int (_state->frame_buffer.Capacity())) {
207                         write_current_frame ();
208                         _frame_buffer_offset = 0;
209                         memset (_state->frame_buffer.Data(), 0, _state->frame_buffer.Capacity());
210                 }
211         }
212 }
213
214 void
215 SoundAssetWriter::write_current_frame ()
216 {
217         ASDCP::Result_t const r = _state->mxf_writer.WriteFrame (_state->frame_buffer, _crypto_context->context(), _crypto_context->hmac());
218         if (ASDCP_FAILURE (r)) {
219                 boost::throw_exception (MiscError (String::compose ("could not write audio MXF frame (%1)", int (r))));
220         }
221
222         ++_frames_written;
223
224         if (_sync) {
225                 /* We need a new set of sync packets for this frame */
226                 _fsk.set_data (create_sync_packets());
227         }
228 }
229
230 bool
231 SoundAssetWriter::finalize ()
232 {
233         if (_frame_buffer_offset > 0) {
234                 write_current_frame ();
235         }
236
237         if (_started) {
238                 ASDCP::Result_t const r = _state->mxf_writer.Finalize();
239                 if (ASDCP_FAILURE(r)) {
240                         boost::throw_exception (MiscError (String::compose ("could not finalise audio MXF (%1)", int(r))));
241                 }
242         }
243
244         _asset->_intrinsic_duration = _frames_written;
245         return AssetWriter::finalize ();
246 }
247
248
249 /** Calculate and return the sync packets required for this edit unit (aka "frame") */
250 vector<bool>
251 SoundAssetWriter::create_sync_packets ()
252 {
253         /* Parts of this code assumes 48kHz */
254         DCP_ASSERT (_asset->sampling_rate() == 48000);
255
256         /* Encoding of edit rate */
257         int edit_rate_code = 0;
258         /* How many 0 bits are used to pad the end of the packet */
259         int remaining_bits = 0;
260         /* How many packets in this edit unit (i.e. "frame") */
261         int packets = 0;
262         Fraction const edit_rate = _asset->edit_rate ();
263         if (edit_rate == Fraction(24, 1)) {
264                 edit_rate_code = 0;
265                 remaining_bits = 25;
266                 packets = 4;
267         } else if (edit_rate == Fraction(25, 1)) {
268                 edit_rate_code = 1;
269                 remaining_bits = 20;
270                 packets = 4;
271         } else if (edit_rate == Fraction(30, 1)) {
272                 edit_rate_code = 2;
273                 remaining_bits = 0;
274                 packets = 4;
275         } else if (edit_rate == Fraction(48, 1)) {
276                 edit_rate_code = 3;
277                 remaining_bits = 25;
278                 packets = 2;
279         } else if (edit_rate == Fraction(50, 1)) {
280                 edit_rate_code = 4;
281                 remaining_bits = 20;
282                 packets = 2;
283         } else if (edit_rate == Fraction(60, 1)) {
284                 edit_rate_code = 5;
285                 remaining_bits = 0;
286                 packets = 2;
287         } else if (edit_rate == Fraction(96, 1)) {
288                 edit_rate_code = 6;
289                 remaining_bits = 25;
290                 packets = 1;
291         } else if (edit_rate == Fraction(100, 1)) {
292                 edit_rate_code = 7;
293                 remaining_bits = 20;
294                 packets = 1;
295         } else if (edit_rate == Fraction(120, 1)) {
296                 edit_rate_code = 8;
297                 remaining_bits = 0;
298                 packets = 1;
299         }
300
301         Bitstream bs;
302
303         Kumu::UUID id;
304         DCP_ASSERT (id.DecodeHex(_asset->id().c_str()));
305
306         for (int i = 0; i < packets; ++i) {
307                 bs.write_from_byte (0x4d);
308                 bs.write_from_byte (0x56);
309                 bs.start_crc (0x1021);
310                 bs.write_from_byte (edit_rate_code, 4);
311                 bs.write_from_byte (0, 2);
312                 bs.write_from_byte (_sync_packet, 2);
313                 bs.write_from_byte (id.Value()[i * 4 + 0]);
314                 bs.write_from_byte (id.Value()[i * 4 + 1]);
315                 bs.write_from_byte (id.Value()[i * 4 + 2]);
316                 bs.write_from_byte (id.Value()[i * 4 + 3]);
317                 bs.write_from_word (_frames_written, 24);
318                 bs.write_crc ();
319                 bs.write_from_byte (0, 4);
320                 bs.write_from_word (0, remaining_bits);
321
322                 ++_sync_packet;
323                 if (_sync_packet == 4) {
324                         _sync_packet = 0;
325                 }
326         }
327
328         return bs.get();
329 }
330