summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/asset_reader.h4
-rw-r--r--src/cpl.cc75
-rw-r--r--src/exceptions.cc7
-rw-r--r--src/exceptions.h7
-rw-r--r--src/sound_asset.cc31
-rw-r--r--src/sound_asset.h12
-rw-r--r--src/sound_asset_writer.cc76
-rw-r--r--src/sound_asset_writer.h5
-rw-r--r--src/types.cc238
-rw-r--r--src/types.h26
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;
diff --git a/src/cpl.cc b/src/cpl.cc
index 494f53be..711c9e1b 100644
--- a/src/cpl.cc
+++ b/src/cpl.cc
@@ -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;
};