diff options
| author | Carl Hetherington <cth@carlh.net> | 2020-09-06 20:10:13 +0200 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2020-09-21 21:57:18 +0200 |
| commit | cdc8bc6a7da0b4f8c3dbfcf560fea61473cf1ca3 (patch) | |
| tree | 6f6fc0c6b7897e6d3bd48fcc27e0e5eb08fc92b9 /src | |
| parent | 445f2495fbb0885132d3a6c8e7a1e135cbac3cce (diff) | |
Support MCA sound channel tags in MXF/CPL.
Diffstat (limited to 'src')
| -rw-r--r-- | src/asset_reader.h | 4 | ||||
| -rw-r--r-- | src/cpl.cc | 75 | ||||
| -rw-r--r-- | src/exceptions.cc | 7 | ||||
| -rw-r--r-- | src/exceptions.h | 7 | ||||
| -rw-r--r-- | src/sound_asset.cc | 31 | ||||
| -rw-r--r-- | src/sound_asset.h | 12 | ||||
| -rw-r--r-- | src/sound_asset_writer.cc | 76 | ||||
| -rw-r--r-- | src/sound_asset_writer.h | 5 | ||||
| -rw-r--r-- | src/types.cc | 238 | ||||
| -rw-r--r-- | src/types.h | 26 |
10 files changed, 377 insertions, 104 deletions
diff --git a/src/asset_reader.h b/src/asset_reader.h index dbd2761b..714d960c 100644 --- a/src/asset_reader.h +++ b/src/asset_reader.h @@ -69,6 +69,10 @@ public: return boost::shared_ptr<const F> (new F (_reader, n, _crypto_context)); } + R* reader () const { + return _reader; + } + protected: R* _reader; boost::shared_ptr<DecryptionContext> _crypto_context; @@ -46,6 +46,7 @@ #include "dcp_assert.h" #include "compose.hpp" #include "raw_convert.h" +#include <asdcp/Metadata.h> #include <libxml/parser.h> #include <libxml++/libxml++.h> #include <boost/algorithm/string.hpp> @@ -67,7 +68,9 @@ using namespace dcp; static string const cpl_interop_ns = "http://www.digicine.com/PROTO-ASDCP-CPL-20040511#"; static string const cpl_smpte_ns = "http://www.smpte-ra.org/schemas/429-7/2006/CPL"; static string const cpl_metadata_ns = "http://www.smpte-ra.org/schemas/429-16/2014/CPL-Metadata"; - +static string const mca_sub_descriptors_ns = "http://isdcf.com/ns/cplmd/mca"; +static string const smpte_395_ns = "http://www.smpte-ra.org/reg/395/2014/13/1/aaf"; +static string const smpte_335_ns = "http://www.smpte-ra.org/reg/335/2012"; CPL::CPL (string annotation_text, ContentKind content_kind) /* default _content_title_text to annotation_text */ @@ -395,6 +398,76 @@ CPL::maybe_write_composition_metadata_asset (xmlpp::Element* node) const } meta->add_child("MainSubtitleLanguageList")->add_child_text(lang); } + + if (_reels.front()->main_sound()) { + shared_ptr<const SoundAsset> asset = _reels.front()->main_sound()->asset(); + if (asset) { + shared_ptr<SoundAssetReader> reader = asset->start_read (); + ASDCP::MXF::SoundfieldGroupLabelSubDescriptor* soundfield; + ASDCP::Result_t r = reader->reader()->OP1aHeader().GetMDObjectByType( + ASDCP::DefaultSMPTEDict().ul(ASDCP::MDD_SoundfieldGroupLabelSubDescriptor), + reinterpret_cast<ASDCP::MXF::InterchangeObject**>(&soundfield) + ); + if (KM_SUCCESS(r)) { + xmlpp::Element* mca_subs = meta->add_child("mca:MCASubDescriptors"); + mca_subs->set_namespace_declaration (mca_sub_descriptors_ns, "mca"); + mca_subs->set_namespace_declaration (smpte_395_ns, "r0"); + mca_subs->set_namespace_declaration (smpte_335_ns, "r1"); + xmlpp::Element* sf = mca_subs->add_child("SoundfieldGroupLabelSubDescriptor", "r0"); + char buffer[64]; + soundfield->InstanceUID.EncodeString(buffer, sizeof(buffer)); + sf->add_child("InstanceID", "r1")->add_child_text("urn:uuid:" + string(buffer)); + soundfield->MCALabelDictionaryID.EncodeString(buffer, sizeof(buffer)); + sf->add_child("MCALabelDictionaryID", "r1")->add_child_text("urn:smpte:ul:" + string(buffer)); + soundfield->MCALinkID.EncodeString(buffer, sizeof(buffer)); + sf->add_child("MCALinkID", "r1")->add_child_text("urn:uuid:" + string(buffer)); + soundfield->MCATagSymbol.EncodeString(buffer, sizeof(buffer)); + sf->add_child("MCATagSymbol", "r1")->add_child_text(buffer); + if (!soundfield->MCATagName.empty()) { + soundfield->MCATagName.get().EncodeString(buffer, sizeof(buffer)); + sf->add_child("MCATagName", "r1")->add_child_text(buffer); + } + if (!soundfield->RFC5646SpokenLanguage.empty()) { + soundfield->RFC5646SpokenLanguage.get().EncodeString(buffer, sizeof(buffer)); + sf->add_child("RFC5646SpokenLanguage", "r1")->add_child_text(buffer); + } + + list<ASDCP::MXF::InterchangeObject*> channels; + ASDCP::Result_t r = reader->reader()->OP1aHeader().GetMDObjectsByType( + ASDCP::DefaultSMPTEDict().ul(ASDCP::MDD_AudioChannelLabelSubDescriptor), + channels + ); + + BOOST_FOREACH (ASDCP::MXF::InterchangeObject* i, channels) { + ASDCP::MXF::AudioChannelLabelSubDescriptor* channel = reinterpret_cast<ASDCP::MXF::AudioChannelLabelSubDescriptor*>(i); + xmlpp::Element* ch = mca_subs->add_child("AudioChannelLabelSubDescriptor", "r0"); + channel->InstanceUID.EncodeString(buffer, sizeof(buffer)); + ch->add_child("InstanceID", "r1")->add_child_text("urn:uuid:" + string(buffer)); + channel->MCALabelDictionaryID.EncodeString(buffer, sizeof(buffer)); + ch->add_child("MCALabelDictionaryID", "r1")->add_child_text("urn:smpte:ul:" + string(buffer)); + channel->MCALinkID.EncodeString(buffer, sizeof(buffer)); + ch->add_child("MCALinkID", "r1")->add_child_text("urn:uuid:" + string(buffer)); + channel->MCATagSymbol.EncodeString(buffer, sizeof(buffer)); + ch->add_child("MCATagSymbol", "r1")->add_child_text(buffer); + if (!channel->MCATagName.empty()) { + channel->MCATagName.get().EncodeString(buffer, sizeof(buffer)); + ch->add_child("MCATagName", "r1")->add_child_text(buffer); + } + if (!channel->MCAChannelID.empty()) { + ch->add_child("MCAChannelID", "r1")->add_child_text(raw_convert<string>(channel->MCAChannelID.get())); + } + if (!channel->RFC5646SpokenLanguage.empty()) { + channel->RFC5646SpokenLanguage.get().EncodeString(buffer, sizeof(buffer)); + ch->add_child("RFC5646SpokenLanguage", "r1")->add_child_text(buffer); + } + if (!channel->SoundfieldGroupLinkID.empty()) { + channel->SoundfieldGroupLinkID.get().EncodeString(buffer, sizeof(buffer)); + ch->add_child("SoundfieldGroupLinkID", "r1")->add_child_text("urn:uuid:" + string(buffer)); + } + } + } + } + } } diff --git a/src/exceptions.cc b/src/exceptions.cc index 16676e20..ebe8609a 100644 --- a/src/exceptions.cc +++ b/src/exceptions.cc @@ -163,4 +163,9 @@ MainSoundConfigurationError::MainSoundConfigurationError (std::string s) } ->>>>>>> Support CPL metadata. + +UnknownChannelIdError::UnknownChannelIdError (std::string id) + : runtime_error (String::compose("Unrecognised channel id '%1'", id)) +{ + +} diff --git a/src/exceptions.h b/src/exceptions.h index 12624175..b9bcfd37 100644 --- a/src/exceptions.h +++ b/src/exceptions.h @@ -276,6 +276,13 @@ public: }; +class UnknownChannelIdError : public std::runtime_error +{ +public: + UnknownChannelIdError (std::string s); +}; + + } #endif diff --git a/src/sound_asset.cc b/src/sound_asset.cc index 7f2bf5e3..15626b9a 100644 --- a/src/sound_asset.cc +++ b/src/sound_asset.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net> + Copyright (C) 2012-2020 Carl Hetherington <cth@carlh.net> This file is part of libdcp. @@ -43,8 +43,9 @@ #include "sound_asset_reader.h" #include "compose.hpp" #include "dcp_assert.h" -#include <asdcp/KM_fileio.h> #include <asdcp/AS_DCP.h> +#include <asdcp/KM_fileio.h> +#include <asdcp/Metadata.h> #include <libxml++/nodes/element.h> #include <boost/filesystem.hpp> #include <stdexcept> @@ -58,6 +59,11 @@ using namespace dcp; SoundAsset::SoundAsset (boost::filesystem::path file) : Asset (file) + /* XXX: this is a fallback language, which will be used if we can't find the RFC5646SpokenLanguage + * in the MXF header. Perhaps RFC5646SpokenLanguage is optional and we should just not write it + * if we don't know it. + */ + , _language ("en-US") { ASDCP::PCM::MXFReader reader; Kumu::Result_t r = reader.OpenRead (file.string().c_str()); @@ -81,15 +87,30 @@ SoundAsset::SoundAsset (boost::filesystem::path file) boost::throw_exception (ReadError ("could not read audio MXF information")); } + ASDCP::MXF::SoundfieldGroupLabelSubDescriptor* soundfield; + ASDCP::Result_t rr = reader.OP1aHeader().GetMDObjectByType( + ASDCP::DefaultSMPTEDict().ul(ASDCP::MDD_SoundfieldGroupLabelSubDescriptor), + reinterpret_cast<ASDCP::MXF::InterchangeObject**>(&soundfield) + ); + + if (KM_SUCCESS(rr)) { + if (!soundfield->RFC5646SpokenLanguage.empty()) { + char buffer[64]; + soundfield->RFC5646SpokenLanguage.get().EncodeString(buffer, sizeof(buffer)); + _language = dcp::LanguageTag (buffer); + } + } + _id = read_writer_info (info); } -SoundAsset::SoundAsset (Fraction edit_rate, int sampling_rate, int channels, Standard standard) +SoundAsset::SoundAsset (Fraction edit_rate, int sampling_rate, int channels, LanguageTag language, Standard standard) : MXF (standard) , _edit_rate (edit_rate) , _intrinsic_duration (0) , _channels (channels) , _sampling_rate (sampling_rate) + , _language (language) { } @@ -193,13 +214,13 @@ SoundAsset::equals (shared_ptr<const Asset> other, EqualityOptions opt, NoteHand } shared_ptr<SoundAssetWriter> -SoundAsset::start_write (boost::filesystem::path file, bool atmos_sync) +SoundAsset::start_write (boost::filesystem::path file, vector<Channel> active_channels, bool atmos_sync) { if (atmos_sync && _channels < 14) { throw MiscError ("Insufficient channels to write ATMOS sync (there must be at least 14)"); } - return shared_ptr<SoundAssetWriter> (new SoundAssetWriter(this, file, atmos_sync)); + return shared_ptr<SoundAssetWriter> (new SoundAssetWriter(this, file, active_channels, atmos_sync)); } shared_ptr<SoundAssetReader> diff --git a/src/sound_asset.h b/src/sound_asset.h index 9656cf90..80f1cfb6 100644 --- a/src/sound_asset.h +++ b/src/sound_asset.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net> + Copyright (C) 2012-2020 Carl Hetherington <cth@carlh.net> This file is part of libdcp. @@ -40,6 +40,7 @@ #include "mxf.h" #include "types.h" +#include "language_tag.h" #include "metadata.h" #include "sound_frame.h" #include "sound_asset_reader.h" @@ -56,9 +57,9 @@ class SoundAsset : public Asset, public MXF { public: explicit SoundAsset (boost::filesystem::path file); - SoundAsset (Fraction edit_rate, int sampling_rate, int channels, Standard standard); + SoundAsset (Fraction edit_rate, int sampling_rate, int channels, LanguageTag language, Standard standard); - boost::shared_ptr<SoundAssetWriter> start_write (boost::filesystem::path file, bool atmos_sync = false); + boost::shared_ptr<SoundAssetWriter> start_write (boost::filesystem::path file, std::vector<Channel> active_channels, bool atmos_sync = false); boost::shared_ptr<SoundAssetReader> start_read () const; bool equals ( @@ -85,6 +86,10 @@ public: return _intrinsic_duration; } + LanguageTag language () const { + return _language; + } + static bool valid_mxf (boost::filesystem::path); static std::string static_pkl_type (Standard standard); @@ -102,6 +107,7 @@ private: int64_t _intrinsic_duration; int _channels; ///< number of channels int _sampling_rate; ///< sampling rate in Hz + LanguageTag _language; }; } diff --git a/src/sound_asset_writer.cc b/src/sound_asset_writer.cc index ff1d02c2..3980dc62 100644 --- a/src/sound_asset_writer.cc +++ b/src/sound_asset_writer.cc @@ -39,6 +39,8 @@ #include "compose.hpp" #include "crypto_context.h" #include <asdcp/AS_DCP.h> +#include <asdcp/Metadata.h> +#include <boost/foreach.hpp> #include <iostream> using std::min; @@ -48,6 +50,13 @@ using std::string; using std::vector; using namespace dcp; + +/* Some ASDCP objects store this as a *&, for reasons which are not + * at all clear, so we have to keep this around forever. + */ +static ASDCP::Dictionary const* smpte_dict = &ASDCP::DefaultSMPTEDict(); + + struct SoundAssetWriter::ASDCPState { ASDCP::PCM::MXFWriter mxf_writer; @@ -56,13 +65,14 @@ struct SoundAssetWriter::ASDCPState ASDCP::PCM::AudioDescriptor desc; }; -SoundAssetWriter::SoundAssetWriter (SoundAsset* asset, boost::filesystem::path file, bool sync) +SoundAssetWriter::SoundAssetWriter (SoundAsset* asset, boost::filesystem::path file, vector<Channel> active_channels, bool sync) : AssetWriter (asset, file) , _state (new SoundAssetWriter::ASDCPState) , _asset (asset) , _frame_buffer_offset (0) , _sync (sync) , _sync_packet (0) + , _active_channels (active_channels) { DCP_ASSERT (!_sync || _asset->channels() >= 14); DCP_ASSERT (!_sync || _asset->standard() == SMPTE); @@ -101,6 +111,62 @@ SoundAssetWriter::SoundAssetWriter (SoundAsset* asset, boost::filesystem::path f } } + +void +SoundAssetWriter::start () +{ + Kumu::Result_t r = _state->mxf_writer.OpenWrite (_file.string().c_str(), _state->writer_info, _state->desc); + if (ASDCP_FAILURE (r)) { + boost::throw_exception (FileError ("could not open audio MXF for writing", _file.string(), r)); + } + + if (_asset->standard() == dcp::SMPTE && !_active_channels.empty()) { + + ASDCP::MXF::WaveAudioDescriptor* essence_descriptor = 0; + _state->mxf_writer.OP1aHeader().GetMDObjectByType( + smpte_dict->ul(ASDCP::MDD_WaveAudioDescriptor), reinterpret_cast<ASDCP::MXF::InterchangeObject**>(&essence_descriptor) + ); + DCP_ASSERT (essence_descriptor); + essence_descriptor->ChannelAssignment = smpte_dict->ul(ASDCP::MDD_DCAudioChannelCfg_MCA); + + ASDCP::MXF::SoundfieldGroupLabelSubDescriptor* soundfield = new ASDCP::MXF::SoundfieldGroupLabelSubDescriptor(smpte_dict); + GenRandomValue (soundfield->MCALinkID); + soundfield->RFC5646SpokenLanguage = _asset->language().to_string(); + + const MCASoundField field = _asset->channels() > 10 ? SEVEN_POINT_ONE : FIVE_POINT_ONE; + + if (field == SEVEN_POINT_ONE) { + soundfield->MCATagSymbol = "sg71"; + soundfield->MCATagName = "7.1DS"; + soundfield->MCALabelDictionaryID = smpte_dict->ul(ASDCP::MDD_DCAudioSoundfield_71); + } else { + soundfield->MCATagSymbol = "sg51"; + soundfield->MCATagName = "5.1"; + soundfield->MCALabelDictionaryID = smpte_dict->ul(ASDCP::MDD_DCAudioSoundfield_51); + } + + _state->mxf_writer.OP1aHeader().AddChildObject(soundfield); + essence_descriptor->SubDescriptors.push_back(soundfield->InstanceUID); + + BOOST_FOREACH (Channel i, _active_channels) { + ASDCP::MXF::AudioChannelLabelSubDescriptor* channel = new ASDCP::MXF::AudioChannelLabelSubDescriptor(smpte_dict); + GenRandomValue (channel->MCALinkID); + channel->SoundfieldGroupLinkID = soundfield->MCALinkID; + channel->MCAChannelID = static_cast<int>(i) + 1; + channel->MCATagSymbol = "ch" + channel_to_mca_id(i, field); + channel->MCATagName = channel_to_mca_name(i, field); + channel->RFC5646SpokenLanguage = _asset->language().to_string(); + channel->MCALabelDictionaryID = channel_to_mca_universal_label(i, field, smpte_dict); + _state->mxf_writer.OP1aHeader().AddChildObject(channel); + essence_descriptor->SubDescriptors.push_back(channel->InstanceUID); + } + } + + _asset->set_file (_file); + _started = true; +} + + void SoundAssetWriter::write (float const * const * data, int frames) { @@ -110,13 +176,7 @@ SoundAssetWriter::write (float const * const * data, int frames) static float const clip = 1.0f - (1.0f / pow (2, 23)); if (!_started) { - Kumu::Result_t r = _state->mxf_writer.OpenWrite (_file.string().c_str(), _state->writer_info, _state->desc); - if (ASDCP_FAILURE (r)) { - boost::throw_exception (FileError ("could not open audio MXF for writing", _file.string(), r)); - } - - _asset->set_file (_file); - _started = true; + start (); } int const ch = _asset->channels (); diff --git a/src/sound_asset_writer.h b/src/sound_asset_writer.h index f1b1514d..d3b260e6 100644 --- a/src/sound_asset_writer.h +++ b/src/sound_asset_writer.h @@ -70,8 +70,9 @@ private: friend class SoundAsset; friend struct ::sync_test1; - SoundAssetWriter (SoundAsset *, boost::filesystem::path, bool sync); + SoundAssetWriter (SoundAsset *, boost::filesystem::path, std::vector<Channel> active_channels, bool sync); + void start (); void write_current_frame (); std::vector<bool> create_sync_packets (); @@ -90,6 +91,8 @@ private: /** index of the sync packet (0-3) which starts the next edit unit */ int _sync_packet; FSK _fsk; + + std::vector<Channel> _active_channels; }; } diff --git a/src/types.cc b/src/types.cc index 9d67ee67..669d4fca 100644 --- a/src/types.cc +++ b/src/types.cc @@ -596,40 +596,14 @@ MainSoundConfiguration::MainSoundConfiguration (string s) BOOST_FOREACH (string i, channels) { if (i == "-") { _channels.push_back(optional<Channel>()); - } else if (i == "L") { - _channels.push_back(LEFT); - } else if (i == "R") { - _channels.push_back(RIGHT); - } else if (i == "C") { - _channels.push_back(CENTRE); - } else if (i == "LFE") { - _channels.push_back(LFE); - } else if (i == "Ls" || i == "Lss") { - _channels.push_back(LS); - } else if (i == "Rs" || i == "Rss") { - _channels.push_back(RS); - } else if (i == "HI") { - _channels.push_back(HI); - } else if (i == "VIN") { - _channels.push_back(VI); - } else if (i == "Lrs") { - _channels.push_back(BSL); - } else if (i == "Rrs") { - _channels.push_back(BSR); - } else if (i == "DBOX") { - _channels.push_back(MOTION_DATA); - } else if (i == "Sync") { - _channels.push_back(SYNC_SIGNAL); - } else if (i == "Sign") { - _channels.push_back(SIGN_LANGUAGE); } else { - throw MainSoundConfigurationError (s); + _channels.push_back(mca_id_to_channel(i)); } } } -MainSoundConfiguration::MainSoundConfiguration (Field field, int channels) +MainSoundConfiguration::MainSoundConfiguration (MCASoundField field, int channels) : _field (field) { _channels.resize (channels); @@ -650,55 +624,7 @@ MainSoundConfiguration::to_string () const if (!i) { c += "-,"; } else { - switch (*i) { - case LEFT: - c += "L,"; - break; - case RIGHT: - c += "R,"; - break; - case CENTRE: - c += "C,"; - break; - case LFE: - c += "LFE,"; - break; - case LS: - c += (_field == FIVE_POINT_ONE ? "Ls," : "Lss,"); - break; - case RS: - c += (_field == FIVE_POINT_ONE ? "Rs," : "Rss,"); - break; - case HI: - c += "HI,"; - break; - case VI: - c += "VIN,"; - break; - case LC: - case RC: - c += "-,"; - break; - case BSL: - c += "Lrs,"; - break; - case BSR: - c += "Rrs,"; - break; - case MOTION_DATA: - c += "DBOX,"; - break; - case SYNC_SIGNAL: - c += "Sync,"; - break; - case SIGN_LANGUAGE: - /* XXX: not sure what this should be */ - c += "Sign,"; - break; - default: - c += "-,"; - break; - } + c += channel_to_mca_id(*i, _field) + ","; } } @@ -757,3 +683,161 @@ dcp::string_to_status (string s) DCP_ASSERT (false); } + +Channel +dcp::mca_id_to_channel (string id) +{ + if (id == "L") { + return LEFT; + } else if (id == "R") { + return RIGHT; + } else if (id == "C") { + return CENTRE; + } else if (id == "LFE") { + return LFE; + } else if (id == "Ls" || id == "Lss") { + return LS; + } else if (id == "Rs" || id == "Rss") { + return RS; + } else if (id == "HI") { + return HI; + } else if (id == "VIN") { + return VI; + } else if (id == "Lrs") { + return BSL; + } else if (id == "Rrs") { + return BSR; + } else if (id == "DBOX") { + return MOTION_DATA; + } else if (id == "FSKSync") { + return SYNC_SIGNAL; + } else if (id == "SLVS") { + return SIGN_LANGUAGE; + } + + throw UnknownChannelIdError (id); +} + + +string +dcp::channel_to_mca_id (Channel c, MCASoundField field) +{ + switch (c) { + case LEFT: + return "L"; + case RIGHT: + return "R"; + case CENTRE: + return "C"; + case LFE: + return "LFE"; + case LS: + return field == FIVE_POINT_ONE ? "Ls" : "Lss"; + case RS: + return field == FIVE_POINT_ONE ? "Rs" : "Rss"; + case HI: + return "HI"; + case VI: + return "VIN"; + case BSL: + return "Lrs"; + case BSR: + return "Rrs"; + case MOTION_DATA: + return "DBOX"; + case SYNC_SIGNAL: + return "FSKSync"; + case SIGN_LANGUAGE: + return "SLVS"; + default: + break; + } + + DCP_ASSERT (false); +} + + +string +dcp::channel_to_mca_name (Channel c, MCASoundField field) +{ + switch (c) { + case LEFT: + return "Left"; + case RIGHT: + return "Right"; + case CENTRE: + return "Center"; + case LFE: + return "LFE"; + case LS: + return field == FIVE_POINT_ONE ? "Left Surround" : "Left Side Surround"; + case RS: + return field == FIVE_POINT_ONE ? "Right Surround" : "Right Side Surround"; + case HI: + return "Hearing Impaired"; + case VI: + return "Visually Impaired-Narrative"; + case BSL: + return "Left Rear Surround"; + case BSR: + return "Right Rear Surround"; + case MOTION_DATA: + return "D-BOX Motion Code Primary Stream"; + case SYNC_SIGNAL: + return "FSK Sync"; + case SIGN_LANGUAGE: + return "Sign Language Video Stream"; + default: + break; + } + + DCP_ASSERT (false); +} + + +ASDCP::UL +dcp::channel_to_mca_universal_label (Channel c, MCASoundField field, ASDCP::Dictionary const* dict) +{ + static byte_t sync_signal[] = { + 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, 0x03, 0x02, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00 + }; + + static byte_t sign_language[] = { + 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, 0x0d, 0x0f, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00 + }; + + switch (c) { + case LEFT: + return dict->ul(ASDCP::MDD_DCAudioChannel_L); + case RIGHT: + return dict->ul(ASDCP::MDD_DCAudioChannel_R); + case CENTRE: + return dict->ul(ASDCP::MDD_DCAudioChannel_C); + case LFE: + return dict->ul(ASDCP::MDD_DCAudioChannel_LFE); + case LS: + return dict->ul(field == FIVE_POINT_ONE ? ASDCP::MDD_DCAudioChannel_Ls : ASDCP::MDD_DCAudioChannel_Lss); + case RS: + return dict->ul(field == FIVE_POINT_ONE ? ASDCP::MDD_DCAudioChannel_Rs : ASDCP::MDD_DCAudioChannel_Rss); + case HI: + return dict->ul(ASDCP::MDD_DCAudioChannel_HI); + case VI: + return dict->ul(ASDCP::MDD_DCAudioChannel_VIN); + case BSL: + return dict->ul(ASDCP::MDD_DCAudioChannel_Lrs); + case BSR: + return dict->ul(ASDCP::MDD_DCAudioChannel_Rrs); + case MOTION_DATA: + return dict->ul(ASDCP::MDD_DBOXMotionCodePrimaryStream); + case SYNC_SIGNAL: + return ASDCP::UL(sync_signal); + case SIGN_LANGUAGE: + return ASDCP::UL(sign_language); + default: + break; + } + + DCP_ASSERT (false); +} + + diff --git a/src/types.h b/src/types.h index 9a4b3e13..ed0b7b84 100644 --- a/src/types.h +++ b/src/types.h @@ -39,6 +39,7 @@ #define LIBDCP_TYPES_H #include <libcxml/cxml.h> +#include <asdcp/KLV.h> #include <boost/shared_ptr.hpp> #include <boost/function.hpp> #include <string> @@ -98,6 +99,20 @@ enum Channel { CHANNEL_COUNT = 16 }; + +enum MCASoundField +{ + FIVE_POINT_ONE, + SEVEN_POINT_ONE +}; + + +extern std::string channel_to_mca_id (Channel c, MCASoundField field); +extern Channel mca_id_to_channel (std::string); +extern std::string channel_to_mca_name (Channel c, MCASoundField field); +extern ASDCP::UL channel_to_mca_universal_label (Channel c, MCASoundField field, ASDCP::Dictionary const* dict); + + enum ContentKind { FEATURE, @@ -402,15 +417,10 @@ bool operator== (Luminance const& a, Luminance const& b); class MainSoundConfiguration { public: - enum Field { - FIVE_POINT_ONE, - SEVEN_POINT_ONE, - }; - MainSoundConfiguration (std::string); - MainSoundConfiguration (Field field_, int channels); + MainSoundConfiguration (MCASoundField field_, int channels); - Field field () const { + MCASoundField field () const { return _field; } @@ -424,7 +434,7 @@ public: std::string to_string () const; private: - Field _field; + MCASoundField _field; std::vector<boost::optional<Channel> > _channels; }; |
