From 41d24e497a37a0e5d2f8077ed3e4cffaa946b3b4 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sat, 30 Mar 2024 01:24:11 +0100 Subject: Fix typo in help. --- tools/dcpdecryptmxf.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/dcpdecryptmxf.cc b/tools/dcpdecryptmxf.cc index 1cdb58ec..a375093c 100644 --- a/tools/dcpdecryptmxf.cc +++ b/tools/dcpdecryptmxf.cc @@ -62,7 +62,7 @@ static void help (string n) { cerr << "Re-write a MXF (decrypting it if required)\n" - << "Syntax: " << n << " [OPTION] ]\n" + << "Syntax: " << n << " [OPTION] \n" << " --version show libdcp version\n" << " -v, --verbose be verbose\n" << " -h, --help show this help\n" -- cgit v1.2.3 From 0eff1f460e187c5d0e3f3829a266d8dc9ee000db Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sat, 30 Mar 2024 23:06:05 +0000 Subject: Add hack decrypt of sound assets by dcpdecryptmxf. --- tools/dcpdecryptmxf.cc | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/tools/dcpdecryptmxf.cc b/tools/dcpdecryptmxf.cc index a375093c..451a4d34 100644 --- a/tools/dcpdecryptmxf.cc +++ b/tools/dcpdecryptmxf.cc @@ -43,6 +43,8 @@ #include "key.h" #include "mono_picture_asset.h" #include "mono_picture_asset_writer.h" +#include "sound_asset.h" +#include "sound_asset_writer.h" #include "util.h" #include "version.h" #include @@ -69,7 +71,7 @@ help (string n) << " -o, --output output filename\n" << " -k, --kdm KDM file\n" << " -p, --private-key private key file\n" - << " -t, --type MXF type: picture or atmos\n" + << " -t, --type MXF type: picture, sound or atmos\n" << " -i, --ignore-hmac don't raise an error if HMACs don't agree\n"; } @@ -99,6 +101,7 @@ main (int argc, char* argv[]) enum class Type { PICTURE, + SOUND, ATMOS, }; @@ -146,6 +149,8 @@ main (int argc, char* argv[]) case 't': if (strcmp(optarg, "picture") == 0) { type = Type::PICTURE; + } else if (strcmp(optarg, "sound") == 0) { + type = Type::SOUND; } else if (strcmp(optarg, "atmos") == 0) { type = Type::ATMOS; } else { @@ -234,6 +239,32 @@ main (int argc, char* argv[]) copy (in, writer, ignore_hmac); break; } + case Type::SOUND: + { + dcp::SoundAsset in(input_file); + add_key(in, decrypted_kdm); + /* XXX: this is all a bit of a hack */ + dcp::SoundAsset out(in.edit_rate(), in.sampling_rate(), in.channels(), dcp::LanguageTag(in.language().get_value_or("en-GB")), dcp::Standard::SMPTE); + auto writer = out.start_write(output_file.get(), {}, dcp::SoundAsset::AtmosSync::DISABLED, dcp::SoundAsset::MCASubDescriptors::DISABLED); + auto reader = in.start_read(); + reader->set_check_hmac(!ignore_hmac); + for (int64_t i = 0; i < in.intrinsic_duration(); ++i) { + auto frame = reader->get_frame(i); + std::vector pointers(frame->channels()); + for (auto channel = 0; channel < frame->channels(); ++channel) { + pointers[channel] = new int32_t[frame->samples()]; + for (auto sample = 0; sample < frame->samples(); ++sample) { + pointers[channel][sample] = frame->get(channel, sample); + } + } + writer->write(pointers.data(), frame->channels(), frame->samples()); + for (auto channel = 0; channel < frame->channels(); ++channel) { + delete[] pointers[channel]; + } + } + writer->finalize(); + break; + } } } catch (dcp::ReadError& e) { cerr << "Read error: " << e.what() << "\n"; -- cgit v1.2.3 From f22433bfab1cae79a9f4cab7286a27ca09d11715 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 15 Apr 2024 23:29:13 +0200 Subject: Generalise sign language video tag handling and add test. --- src/cpl.cc | 26 +++++++++++----- test/cpl_metadata_test.cc | 17 +++++++++++ test/ref/cpl_metadata_test4.xml | 68 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+), 8 deletions(-) create mode 100644 test/ref/cpl_metadata_test4.xml diff --git a/src/cpl.cc b/src/cpl.cc index 5467fef3..da4e0563 100644 --- a/src/cpl.cc +++ b/src/cpl.cc @@ -345,21 +345,31 @@ CPL::read_composition_metadata_asset (cxml::ConstNodePtr node) } auto eml = node->optional_node_child ("ExtensionMetadataList"); - if (eml) { + + auto extension_metadata = [eml](string scope, string name, string property) -> boost::optional { + if (!eml) { + return {}; + } + for (auto i: eml->node_children("ExtensionMetadata")) { - auto name = i->optional_string_child("Name"); - if (name && *name == "Sign Language Video") { + auto xml_scope = i->optional_string_attribute("scope"); + auto xml_name = i->optional_string_child("Name"); + if (xml_scope && *xml_scope == scope && xml_name && *xml_name == name) { auto property_list = i->node_child("PropertyList"); for (auto j: property_list->node_children("Property")) { - auto name = j->optional_string_child("Name"); - auto value = j->optional_string_child("Value"); - if (name && value && *name == "Language Tag") { - _sign_language_video_language = *value; + auto property_name = j->optional_string_child("Name"); + auto property_value = j->optional_string_child("Value"); + if (property_name && property_value && *property_name == property) { + return property_value; } } } } - } + + return {}; + }; + + _sign_language_video_language = extension_metadata("http://isdcf.com/2017/10/SignLanguageVideo", "Sign Language Video", "Language Tag"); } diff --git a/test/cpl_metadata_test.cc b/test/cpl_metadata_test.cc index 0ebf9078..f704fc9a 100644 --- a/test/cpl_metadata_test.cc +++ b/test/cpl_metadata_test.cc @@ -450,3 +450,20 @@ BOOST_AUTO_TEST_CASE(check_that_missing_full_content_title_text_is_tolerated) { dcp::CPL cpl("test/ref/cpl_metadata_test3.xml"); } + + +BOOST_AUTO_TEST_CASE(check_sign_language_video_language) +{ + dcp::CPL cpl("test/ref/cpl_metadata_test3.xml"); + cpl.set_sign_language_video_language(dcp::LanguageTag("es-PT")); + cpl.write_xml("build/test/check_sign_language_video_language.xml", {}); + check_xml( + dcp::file_to_string("test/ref/cpl_metadata_test4.xml"), + dcp::file_to_string("build/test/check_sign_language_video_language.xml"), + {"Id"} + ); + + dcp::CPL check("build/test/check_sign_language_video_language.xml"); + BOOST_CHECK_EQUAL(check.sign_language_video_language().get_value_or(""), "es-PT"); + +} diff --git a/test/ref/cpl_metadata_test4.xml b/test/ref/cpl_metadata_test4.xml new file mode 100644 index 00000000..e4459375 --- /dev/null +++ b/test/ref/cpl_metadata_test4.xml @@ -0,0 +1,68 @@ + + + urn:uuid:81fb54df-e1bf-4647-8788-ea7ba154375b + + 2020-08-28T13:35:06+02:00 + libdcp1.6.4devel + libdcp1.6.4devel + + feature + + id + version + + + + + urn:uuid:46c3eb45-15e5-47d6-8684-d8641e4dc516 + + + urn:uuid:e98d059d-645f-4343-a30f-edc61d58b8e0 + 24 1 + 24 + 0 + 24 + JtPL3uT3jyKMLysaqgdBWQb/n2E= + 24 1 + 1998 1080 + + + urn:uuid:d36f4bb3-c4fa-4a95-9915-6fec3110cd71 + 24 1 + 24 + + 71/L,R,C,LFE,-,-,-,-,-,-,-,-,-,FSKSync,-,- + 48000 1 + + 1998 + 1080 + + + 1440 + 1080 + + + + Application + + + DCP Constraints Profile + SMPTE-RDD-52:2020-Bv2.1 + + + + + Sign Language Video + + + Language Tag + es-PT + + + + + + + + + -- cgit v1.2.3 From 0a8f2a1a2058f0461a7f978295e31af34a03bb40 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 15 Apr 2024 23:29:36 +0200 Subject: Add Dolby EDR metadata support (GH #12). --- src/cpl.cc | 5 +++ src/cpl.h | 9 ++++++ test/cpl_metadata_test.cc | 17 +++++++++++ test/ref/cpl_metadata_test5.xml | 68 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+) create mode 100644 test/ref/cpl_metadata_test5.xml diff --git a/src/cpl.cc b/src/cpl.cc index da4e0563..5ff86fda 100644 --- a/src/cpl.cc +++ b/src/cpl.cc @@ -370,6 +370,7 @@ CPL::read_composition_metadata_asset (cxml::ConstNodePtr node) }; _sign_language_video_language = extension_metadata("http://isdcf.com/2017/10/SignLanguageVideo", "Sign Language Video", "Language Tag"); + _dolby_edr_image_transfer_function = extension_metadata("http://www.dolby.com/schemas/2014/EDR-Metadata", "Dolby EDR", "image transfer function"); } @@ -568,6 +569,10 @@ CPL::maybe_write_composition_metadata_asset(xmlpp::Element* node, bool include_m add_extension_metadata ("http://isdcf.com/2017/10/SignLanguageVideo", "Sign Language Video", "Language Tag", *_sign_language_video_language); } + if (_dolby_edr_image_transfer_function) { + add_extension_metadata("http://www.dolby.com/schemas/2014/EDR-Metadata", "Dolby EDR", "image transfer function", *_dolby_edr_image_transfer_function); + } + if (_reels.front()->main_sound()) { auto asset = _reels.front()->main_sound()->asset(); if (asset && include_mca_subdescriptors) { diff --git a/src/cpl.h b/src/cpl.h index 25c294eb..fb4f3376 100644 --- a/src/cpl.h +++ b/src/cpl.h @@ -326,6 +326,14 @@ public: return _sign_language_video_language; } + void set_dolby_edr_image_transfer_function(std::string function) { + _dolby_edr_image_transfer_function = function; + } + + boost::optional dolby_edr_image_transfer_function() const { + return _dolby_edr_image_transfer_function; + } + Standard standard () const { return _standard; } @@ -383,6 +391,7 @@ private: /* See note for _release_territory above */ std::vector _additional_subtitle_languages; boost::optional _sign_language_video_language; + boost::optional _dolby_edr_image_transfer_function; bool _read_composition_metadata = false; std::vector> _reels; diff --git a/test/cpl_metadata_test.cc b/test/cpl_metadata_test.cc index f704fc9a..a811e56f 100644 --- a/test/cpl_metadata_test.cc +++ b/test/cpl_metadata_test.cc @@ -467,3 +467,20 @@ BOOST_AUTO_TEST_CASE(check_sign_language_video_language) BOOST_CHECK_EQUAL(check.sign_language_video_language().get_value_or(""), "es-PT"); } + + +BOOST_AUTO_TEST_CASE(check_dolby_edr_metadata) +{ + dcp::CPL cpl("test/ref/cpl_metadata_test3.xml"); + cpl.set_dolby_edr_image_transfer_function("PQ10K"); + cpl.write_xml("build/test/check_dolby_edr_metadata.xml", {}); + check_xml( + dcp::file_to_string("test/ref/cpl_metadata_test5.xml"), + dcp::file_to_string("build/test/check_dolby_edr_metadata.xml"), + {"Id"} + ); + + dcp::CPL check("build/test/check_dolby_edr_metadata.xml"); + BOOST_CHECK_EQUAL(check.dolby_edr_image_transfer_function().get_value_or(""), "PQ10K"); +} + diff --git a/test/ref/cpl_metadata_test5.xml b/test/ref/cpl_metadata_test5.xml new file mode 100644 index 00000000..55209e53 --- /dev/null +++ b/test/ref/cpl_metadata_test5.xml @@ -0,0 +1,68 @@ + + + urn:uuid:81fb54df-e1bf-4647-8788-ea7ba154375b + + 2020-08-28T13:35:06+02:00 + libdcp1.6.4devel + libdcp1.6.4devel + + feature + + id + version + + + + + urn:uuid:46c3eb45-15e5-47d6-8684-d8641e4dc516 + + + urn:uuid:e98d059d-645f-4343-a30f-edc61d58b8e0 + 24 1 + 24 + 0 + 24 + JtPL3uT3jyKMLysaqgdBWQb/n2E= + 24 1 + 1998 1080 + + + urn:uuid:d36f4bb3-c4fa-4a95-9915-6fec3110cd71 + 24 1 + 24 + + 71/L,R,C,LFE,-,-,-,-,-,-,-,-,-,FSKSync,-,- + 48000 1 + + 1998 + 1080 + + + 1440 + 1080 + + + + Application + + + DCP Constraints Profile + SMPTE-RDD-52:2020-Bv2.1 + + + + + Dolby EDR + + + image transfer function + PQ10K + + + + + + + + + -- cgit v1.2.3 From 869462070671b273ac528e075ac1c00a417cc8a0 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 17 Apr 2024 22:19:02 +0200 Subject: Make some not-so-important CPL read errors non-fatal (DoM #2797). --- src/cpl.cc | 25 ++++++++++++++++++++++--- src/cpl.h | 8 ++++++-- src/dcp.cc | 2 +- src/verify.cc | 4 ++++ src/verify.h | 10 ++++++++++ 5 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/cpl.cc b/src/cpl.cc index 5ff86fda..6a25863a 100644 --- a/src/cpl.cc +++ b/src/cpl.cc @@ -104,7 +104,7 @@ CPL::CPL (string annotation_text, ContentKind content_kind, Standard standard) } -CPL::CPL (boost::filesystem::path file) +CPL::CPL (boost::filesystem::path file, vector* notes) : Asset (file) , _content_kind (ContentKind::FEATURE) { @@ -116,7 +116,17 @@ CPL::CPL (boost::filesystem::path file) } else if (f.namespace_uri() == cpl_smpte_ns) { _standard = Standard::SMPTE; } else { - boost::throw_exception (XMLError ("Unrecognised CPL namespace " + f.namespace_uri())); + if (notes) { + notes->push_back( + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, + dcp::VerificationNote::Code::INVALID_CPL_NAMESPACE, + f.namespace_uri(), + file + ) + ); + } + _standard = Standard::INTEROP; } _id = remove_urn_uuid (f.string_child ("Id")); @@ -139,7 +149,16 @@ CPL::CPL (boost::filesystem::path file) content_version->done (); } else if (_standard == Standard::SMPTE) { /* ContentVersion is required in SMPTE */ - throw XMLError ("Missing ContentVersion tag in CPL"); + if (notes) { + notes->push_back( + dcp::VerificationNote( + dcp::VerificationNote::Type::ERROR, + dcp::VerificationNote::Code::MISSING_CPL_CONTENT_VERSION, + _id, + file + ) + ); + } } auto rating_list = f.node_child ("RatingList"); for (auto i: rating_list->node_children("Rating")) { diff --git a/src/cpl.h b/src/cpl.h index fb4f3376..824faaa1 100644 --- a/src/cpl.h +++ b/src/cpl.h @@ -47,6 +47,7 @@ #include "key.h" #include "language_tag.h" #include "rating.h" +#include "verify.h" #include #include #include @@ -82,8 +83,11 @@ class CPL : public Asset public: CPL (std::string annotation_text, ContentKind content_kind, Standard standard); - /** Construct a CPL object from a XML file */ - explicit CPL (boost::filesystem::path file); + /** Construct a CPL object from a XML file. + * If notes is not null, non-fatal errors will be added. + * Exceptions will be thrown on non-recoverable errors. + */ + explicit CPL(boost::filesystem::path file, std::vector* notes = nullptr); bool equals ( std::shared_ptr other, diff --git a/src/dcp.cc b/src/dcp.cc index d603cfae..eb21b47d 100644 --- a/src/dcp.cc +++ b/src/dcp.cc @@ -234,7 +234,7 @@ DCP::read (vector* notes, bool ignore_incorrect_picture_m delete p; if (root == "CompositionPlaylist") { - auto cpl = make_shared(path); + auto cpl = make_shared(path, notes); if (cpl->standard() != standard && notes) { notes->push_back ({VerificationNote::Type::ERROR, VerificationNote::Code::MISMATCHED_STANDARD}); } diff --git a/src/verify.cc b/src/verify.cc index 9715c020..112a5bb5 100644 --- a/src/verify.cc +++ b/src/verify.cc @@ -2178,6 +2178,10 @@ dcp::note_to_string (VerificationNote note) return String::compose("The asset with ID %1 in the asset map actually has an id of %2", note.id().get(), note.other_id().get()); case VerificationNote::Code::EMPTY_CONTENT_VERSION_LABEL_TEXT: return String::compose("The in a in CPL %1 is empty", note.id().get()); + case VerificationNote::Code::INVALID_CPL_NAMESPACE: + return String::compose("The namespace %1 in CPL %2 is invalid", note.note().get(), note.file()->filename()); + case VerificationNote::Code::MISSING_CPL_CONTENT_VERSION: + return String::compose("The CPL %1 has no tag", note.note().get()); } return ""; diff --git a/src/verify.h b/src/verify.h index 4ca3297a..b5d913bd 100644 --- a/src/verify.h +++ b/src/verify.h @@ -475,6 +475,16 @@ public: * file contains the CPL filename */ EMPTY_CONTENT_VERSION_LABEL_TEXT, + /** The CPL namespace is not valid. + * note contains the invalid namespace + * file contains the CPL filename + */ + INVALID_CPL_NAMESPACE, + /** A SMPTE CPL does not contain a __ tag + * note contains the CPL ID + * file contains the CPL filename + */ + MISSING_CPL_CONTENT_VERSION }; VerificationNote (Type type, Code code) -- cgit v1.2.3