Allow specification of channels that need a MCASubDescriptor.
[libdcp.git] / src / sound_asset_writer.cc
1 /*
2     Copyright (C) 2012-2021 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
35 /** @file  src/sound_asset_writer.cc
36  *  @brief SoundAssetWriter class
37  */
38
39
40 #include "bitstream.h"
41 #include "compose.hpp"
42 #include "crypto_context.h"
43 #include "dcp_assert.h"
44 #include "exceptions.h"
45 #include "sound_asset.h"
46 #include "sound_asset_writer.h"
47 #include "warnings.h"
48 LIBDCP_DISABLE_WARNINGS
49 #include <asdcp/AS_DCP.h>
50 #include <asdcp/Metadata.h>
51 LIBDCP_ENABLE_WARNINGS
52 #include <iostream>
53
54
55 using std::min;
56 using std::max;
57 using std::cout;
58 using std::string;
59 using std::vector;
60 using namespace dcp;
61
62
63 struct SoundAssetWriter::ASDCPState
64 {
65         ASDCP::PCM::MXFWriter mxf_writer;
66         ASDCP::PCM::FrameBuffer frame_buffer;
67         ASDCP::WriterInfo writer_info;
68         ASDCP::PCM::AudioDescriptor desc;
69 };
70
71
72 SoundAssetWriter::SoundAssetWriter(SoundAsset* asset, boost::filesystem::path file, vector<dcp::Channel> extra_active_channels, bool sync, bool include_mca_subdescriptors)
73         : AssetWriter (asset, file)
74         , _state (new SoundAssetWriter::ASDCPState)
75         , _asset (asset)
76         , _extra_active_channels(extra_active_channels)
77         , _sync (sync)
78         , _include_mca_subdescriptors(include_mca_subdescriptors)
79 {
80         DCP_ASSERT (!_sync || _asset->channels() >= 14);
81         DCP_ASSERT (!_sync || _asset->standard() == Standard::SMPTE);
82
83         /* None of these are allowed in extra_active_channels; some are implicit, and (it seems) should never have a descriptor
84          * written for them.
85          */
86         vector<Channel> disallowed_extra = {
87                 Channel::LEFT,
88                 Channel::RIGHT,
89                 Channel::CENTRE,
90                 Channel::LFE,
91                 Channel::LS,
92                 Channel::RS,
93                 Channel::MOTION_DATA,
94                 Channel::SYNC_SIGNAL,
95                 Channel::SIGN_LANGUAGE,
96                 Channel::CHANNEL_COUNT
97         };
98         for (auto disallowed: disallowed_extra) {
99                 DCP_ASSERT(std::find(extra_active_channels.begin(), extra_active_channels.end(), disallowed) == extra_active_channels.end());
100         }
101
102         /* Derived from ASDCP::Wav::SimpleWaveHeader::FillADesc */
103         _state->desc.EditRate = ASDCP::Rational (_asset->edit_rate().numerator, _asset->edit_rate().denominator);
104         _state->desc.AudioSamplingRate = ASDCP::Rational (_asset->sampling_rate(), 1);
105         _state->desc.Locked = 0;
106         _state->desc.ChannelCount = _asset->channels();
107         _state->desc.QuantizationBits = 24;
108         _state->desc.BlockAlign = 3 * _asset->channels();
109         _state->desc.AvgBps = _asset->sampling_rate() * _state->desc.BlockAlign;
110         _state->desc.LinkedTrackID = 0;
111         if (asset->standard() == Standard::INTEROP) {
112                 _state->desc.ChannelFormat = ASDCP::PCM::CF_NONE;
113         } else {
114                 /* As required by Bv2.1 */
115                 _state->desc.ChannelFormat = ASDCP::PCM::CF_CFG_4;
116         }
117
118         /* I'm fairly sure this is not necessary, as ContainerDuration is written
119            in ASDCP's WriteMXFFooter, but it stops a valgrind warning.
120         */
121         _state->desc.ContainerDuration = 0;
122
123         _state->frame_buffer.Capacity (ASDCP::PCM::CalcFrameBufferSize (_state->desc));
124         _state->frame_buffer.Size (ASDCP::PCM::CalcFrameBufferSize (_state->desc));
125         memset (_state->frame_buffer.Data(), 0, _state->frame_buffer.Capacity());
126
127         _asset->fill_writer_info (&_state->writer_info, _asset->id());
128
129         if (_sync) {
130                 _fsk.set_data (create_sync_packets());
131         }
132 }
133
134
135 SoundAssetWriter::~SoundAssetWriter()
136 {
137         try {
138                 /* Last-resort finalization to close the file, at least */
139                 if (!_finalized) {
140                         _state->mxf_writer.Finalize();
141                 }
142         } catch (...) {}
143 }
144
145
146 void
147 SoundAssetWriter::start ()
148 {
149         auto r = _state->mxf_writer.OpenWrite (_file.string().c_str(), _state->writer_info, _state->desc);
150         if (ASDCP_FAILURE(r)) {
151                 boost::throw_exception (FileError("could not open audio MXF for writing", _file.string(), r));
152         }
153
154         if (_asset->standard() == Standard::SMPTE && _include_mca_subdescriptors) {
155
156                 ASDCP::MXF::WaveAudioDescriptor* essence_descriptor = nullptr;
157                 _state->mxf_writer.OP1aHeader().GetMDObjectByType(
158                         asdcp_smpte_dict->ul(ASDCP::MDD_WaveAudioDescriptor), reinterpret_cast<ASDCP::MXF::InterchangeObject**>(&essence_descriptor)
159                         );
160                 DCP_ASSERT (essence_descriptor);
161                 essence_descriptor->ChannelAssignment = asdcp_smpte_dict->ul(ASDCP::MDD_DCAudioChannelCfg_4_WTF);
162
163                 auto soundfield = new ASDCP::MXF::SoundfieldGroupLabelSubDescriptor(asdcp_smpte_dict);
164                 GenRandomValue (soundfield->MCALinkID);
165                 if (auto lang = _asset->language()) {
166                         soundfield->RFC5646SpokenLanguage = *lang;
167                 }
168
169                 MCASoundField const field =
170                         (
171                                 find(_extra_active_channels.begin(), _extra_active_channels.end(), dcp::Channel::BSL) != _extra_active_channels.end() ||
172                                 find(_extra_active_channels.begin(), _extra_active_channels.end(), dcp::Channel::BSR) != _extra_active_channels.end()
173                         ) ? MCASoundField::SEVEN_POINT_ONE : MCASoundField::FIVE_POINT_ONE;
174
175                 if (field == MCASoundField::SEVEN_POINT_ONE) {
176                         soundfield->MCATagSymbol = "sg71";
177                         soundfield->MCATagName = "7.1DS";
178 LIBDCP_DISABLE_WARNINGS
179                         soundfield->MCALabelDictionaryID = asdcp_smpte_dict->ul(ASDCP::MDD_DCAudioSoundfield_71);
180 LIBDCP_ENABLE_WARNINGS
181                 } else {
182                         soundfield->MCATagSymbol = "sg51";
183                         soundfield->MCATagName = "5.1";
184 LIBDCP_DISABLE_WARNINGS
185                         soundfield->MCALabelDictionaryID = asdcp_smpte_dict->ul(ASDCP::MDD_DCAudioSoundfield_51);
186 LIBDCP_ENABLE_WARNINGS
187                 }
188
189                 _state->mxf_writer.OP1aHeader().AddChildObject(soundfield);
190                 essence_descriptor->SubDescriptors.push_back(soundfield->InstanceUID);
191
192                 std::vector<dcp::Channel> dcp_channels = {
193                         Channel::LEFT,
194                         Channel::RIGHT,
195                         Channel::CENTRE,
196                         Channel::LFE,
197                         Channel::LS,
198                         Channel::RS
199                 };
200
201                 std::copy(_extra_active_channels.begin(), _extra_active_channels.end(), back_inserter(dcp_channels));
202                 std::sort(dcp_channels.begin(), dcp_channels.end());
203                 auto last = std::unique(dcp_channels.begin(), dcp_channels.end());
204                 dcp_channels.erase(last, dcp_channels.end());
205
206                 for (auto dcp_channel: dcp_channels) {
207                         auto channel = new ASDCP::MXF::AudioChannelLabelSubDescriptor(asdcp_smpte_dict);
208                         GenRandomValue (channel->MCALinkID);
209                         channel->SoundfieldGroupLinkID = soundfield->MCALinkID;
210                         channel->MCAChannelID = static_cast<int>(dcp_channel) + 1;
211                         channel->MCATagSymbol = "ch" + channel_to_mca_id(dcp_channel, field);
212                         channel->MCATagName = channel_to_mca_name(dcp_channel, field);
213                         if (auto lang = _asset->language()) {
214                                 channel->RFC5646SpokenLanguage = *lang;
215                         }
216 LIBDCP_DISABLE_WARNINGS
217                         channel->MCALabelDictionaryID = channel_to_mca_universal_label(dcp_channel, field, asdcp_smpte_dict);
218 LIBDCP_ENABLE_WARNINGS
219                         _state->mxf_writer.OP1aHeader().AddChildObject(channel);
220                         essence_descriptor->SubDescriptors.push_back(channel->InstanceUID);
221                 }
222         }
223
224         _asset->set_file (_file);
225         _started = true;
226 }
227
228
229 void
230 SoundAssetWriter::write(float const * const * data, int data_channels, int frames)
231 {
232         do_write(data, data_channels, frames);
233 }
234
235
236 void
237 SoundAssetWriter::write(int32_t const * const * data, int data_channels, int frames)
238 {
239         do_write(data, data_channels, frames);
240 }
241
242
243 void
244 SoundAssetWriter::write_current_frame ()
245 {
246         auto const r = _state->mxf_writer.WriteFrame (_state->frame_buffer, _crypto_context->context(), _crypto_context->hmac());
247         if (ASDCP_FAILURE(r)) {
248                 boost::throw_exception (MiscError(String::compose("could not write audio MXF frame (%1)", static_cast<int>(r))));
249         }
250
251         ++_frames_written;
252
253         if (_sync) {
254                 /* We need a new set of sync packets for this frame */
255                 _fsk.set_data (create_sync_packets());
256         }
257 }
258
259 bool
260 SoundAssetWriter::finalize ()
261 {
262         if (_frame_buffer_offset > 0) {
263                 write_current_frame ();
264         }
265
266         if (_started) {
267                 auto const r = _state->mxf_writer.Finalize();
268                 if (ASDCP_FAILURE(r)) {
269                         boost::throw_exception (MiscError(String::compose ("could not finalise audio MXF (%1)", static_cast<int>(r))));
270                 }
271         }
272
273         _asset->_intrinsic_duration = _frames_written;
274         return AssetWriter::finalize ();
275 }
276
277
278 /** Calculate and return the sync packets required for this edit unit (aka "frame") */
279 vector<bool>
280 SoundAssetWriter::create_sync_packets ()
281 {
282         /* Parts of this code assumes 48kHz */
283         DCP_ASSERT (_asset->sampling_rate() == 48000);
284
285         /* Encoding of edit rate */
286         int edit_rate_code = 0;
287         /* How many 0 bits are used to pad the end of the packet */
288         int remaining_bits = 0;
289         /* How many packets in this edit unit (i.e. "frame") */
290         int packets = 0;
291         auto const edit_rate = _asset->edit_rate ();
292         if (edit_rate == Fraction(24, 1)) {
293                 edit_rate_code = 0;
294                 remaining_bits = 25;
295                 packets = 4;
296         } else if (edit_rate == Fraction(25, 1)) {
297                 edit_rate_code = 1;
298                 remaining_bits = 20;
299                 packets = 4;
300         } else if (edit_rate == Fraction(30, 1)) {
301                 edit_rate_code = 2;
302                 remaining_bits = 0;
303                 packets = 4;
304         } else if (edit_rate == Fraction(48, 1)) {
305                 edit_rate_code = 3;
306                 remaining_bits = 25;
307                 packets = 2;
308         } else if (edit_rate == Fraction(50, 1)) {
309                 edit_rate_code = 4;
310                 remaining_bits = 20;
311                 packets = 2;
312         } else if (edit_rate == Fraction(60, 1)) {
313                 edit_rate_code = 5;
314                 remaining_bits = 0;
315                 packets = 2;
316         } else if (edit_rate == Fraction(96, 1)) {
317                 edit_rate_code = 6;
318                 remaining_bits = 25;
319                 packets = 1;
320         } else if (edit_rate == Fraction(100, 1)) {
321                 edit_rate_code = 7;
322                 remaining_bits = 20;
323                 packets = 1;
324         } else if (edit_rate == Fraction(120, 1)) {
325                 edit_rate_code = 8;
326                 remaining_bits = 0;
327                 packets = 1;
328         }
329
330         Bitstream bs;
331
332         Kumu::UUID id;
333         DCP_ASSERT (id.DecodeHex(_asset->id().c_str()));
334
335         for (int i = 0; i < packets; ++i) {
336                 bs.write_from_byte (0x4d);
337                 bs.write_from_byte (0x56);
338                 bs.start_crc (0x1021);
339                 bs.write_from_byte (edit_rate_code, 4);
340                 bs.write_from_byte (0, 2);
341                 bs.write_from_byte (_sync_packet, 2);
342                 bs.write_from_byte (id.Value()[i * 4 + 0]);
343                 bs.write_from_byte (id.Value()[i * 4 + 1]);
344                 bs.write_from_byte (id.Value()[i * 4 + 2]);
345                 bs.write_from_byte (id.Value()[i * 4 + 3]);
346                 bs.write_from_word (_frames_written, 24);
347                 bs.write_crc ();
348                 bs.write_from_byte (0, 4);
349                 bs.write_from_word (0, remaining_bits);
350
351                 ++_sync_packet;
352                 if (_sync_packet == 4) {
353                         _sync_packet = 0;
354                 }
355         }
356
357         return bs.get();
358 }
359
360
361 byte_t*
362 SoundAssetWriter::frame_buffer_data() const
363 {
364         return _state->frame_buffer.Data();
365 }
366
367
368 int
369 SoundAssetWriter::frame_buffer_capacity() const
370 {
371         return _state->frame_buffer.Capacity();
372 }
373