Bv2.1 7.2.2: Check that subtitle languages are the same for all reels.
authorCarl Hetherington <cth@carlh.net>
Mon, 14 Dec 2020 23:51:34 +0000 (00:51 +0100)
committerCarl Hetherington <cth@carlh.net>
Sun, 17 Jan 2021 19:13:22 +0000 (20:13 +0100)
BRANCH
src/verify.cc
src/verify.h
test/test.h
test/verify_test.cc

diff --git a/BRANCH b/BRANCH
index 09e77d128e4be07bbb3c38bf0ef1e923ccc469c9..7b9aab02117709038a1de596361480a4c4d2c86b 100644 (file)
--- a/BRANCH
+++ b/BRANCH
@@ -24,6 +24,6 @@ Mark things with [Bv2.1_paragraph]
     - Timed text XML files for closed captions must be <= 256kB [/]
     - Timed text total track asset must be <= 115MB [/]
     - Font resource <= 10MB [/]
-7.2.2 Language Element shall be present [/] and contiguous across all MainSubtitles.
+7.2.2 Language Element shall be present [/] and contiguous across all MainSubtitles [/]
 
        
index 1b476ef2c3be6be58a9f7b2ee092ed933318c41c..0b7def3c7cb06ff987df15947c7392a84d68456f 100644 (file)
@@ -640,12 +640,19 @@ verify_closed_caption_reel (shared_ptr<const ReelClosedCaptionAsset> reel_asset,
 }
 
 
+struct State
+{
+       boost::optional<string> subtitle_language;
+};
+
+
 static void
 verify_subtitle_asset (
        shared_ptr<const SubtitleAsset> asset,
        function<void (string, optional<boost::filesystem::path>)> stage,
        boost::filesystem::path xsd_dtd_directory,
-       list<VerificationNote>& notes
+       list<VerificationNote>& notes,
+       State& state
        )
 {
        stage ("Checking subtitle XML", asset->file());
@@ -657,7 +664,17 @@ verify_subtitle_asset (
        shared_ptr<const SMPTESubtitleAsset> smpte = dynamic_pointer_cast<const SMPTESubtitleAsset>(asset);
        if (smpte) {
                if (smpte->language()) {
-                       verify_language_tag (*smpte->language(), notes);
+                       string const language = *smpte->language();
+                       verify_language_tag (language, notes);
+                       if (!state.subtitle_language) {
+                               state.subtitle_language = language;
+                       } else if (state.subtitle_language != language) {
+                               notes.push_back (
+                                       VerificationNote(
+                                               VerificationNote::VERIFY_BV21_ERROR, VerificationNote::SUBTITLE_LANGUAGES_DIFFER, *asset->file()
+                                               )
+                                       );
+                       }
                } else {
                        notes.push_back (
                                VerificationNote(
@@ -696,10 +713,11 @@ verify_closed_caption_asset (
        shared_ptr<const SubtitleAsset> asset,
        function<void (string, optional<boost::filesystem::path>)> stage,
        boost::filesystem::path xsd_dtd_directory,
-       list<VerificationNote>& notes
+       list<VerificationNote>& notes,
+       State& state
        )
 {
-       verify_subtitle_asset (asset, stage, xsd_dtd_directory, notes);
+       verify_subtitle_asset (asset, stage, xsd_dtd_directory, notes, state);
 
        if (asset->raw_xml().size() > 256 * 1024) {
                notes.push_back (
@@ -722,6 +740,7 @@ dcp::verify (
        xsd_dtd_directory = boost::filesystem::canonical (xsd_dtd_directory);
 
        list<VerificationNote> notes;
+       State state;
 
        list<shared_ptr<DCP> > dcps;
        BOOST_FOREACH (boost::filesystem::path i, directories) {
@@ -804,14 +823,14 @@ dcp::verify (
                                if (reel->main_subtitle()) {
                                        verify_main_subtitle_reel (reel->main_subtitle(), notes);
                                        if (reel->main_subtitle()->asset_ref().resolved()) {
-                                               verify_subtitle_asset (reel->main_subtitle()->asset(), stage, xsd_dtd_directory, notes);
+                                               verify_subtitle_asset (reel->main_subtitle()->asset(), stage, xsd_dtd_directory, notes, state);
                                        }
                                }
 
                                BOOST_FOREACH (shared_ptr<dcp::ReelClosedCaptionAsset> i, reel->closed_captions()) {
                                        verify_closed_caption_reel (i, notes);
                                        if (i->asset_ref().resolved()) {
-                                               verify_closed_caption_asset (i->asset(), stage, xsd_dtd_directory, notes);
+                                               verify_closed_caption_asset (i->asset(), stage, xsd_dtd_directory, notes, state);
                                        }
                                }
                        }
@@ -891,6 +910,8 @@ dcp::note_to_string (dcp::VerificationNote note)
                return String::compose("The total size of the fonts in timed text asset %1 is larger than the 10MB maximum required by Bv2.1", note.file()->filename());
        case dcp::VerificationNote::MISSING_SUBTITLE_LANGUAGE:
                return String::compose("The XML for a SMPTE subtitle asset has no <Language> tag, which is required by Bv2.1", note.file()->filename());
+       case dcp::VerificationNote::SUBTITLE_LANGUAGES_DIFFER:
+               return String::compose("Some subtitle assets have different <Language> tags than others", note.file()->filename());
        }
 
        return "";
index 8a049dd5ec16771ae5e554549371e9f41b6a5708..170aeb8b6386d6f426c1089705a356c196e05656 100644 (file)
@@ -110,6 +110,8 @@ public:
                TIMED_TEXT_FONTS_TOO_LARGE_IN_BYTES,
                /** Some SMPTE subtitle XML has no <Language> tag [Bv2.1_7.2.2] */
                MISSING_SUBTITLE_LANGUAGE,
+               /** Not all subtitle assets specify the same <Language> tag [Bv2.1_7.2.2] */
+               SUBTITLE_LANGUAGES_DIFFER,
        };
 
        VerificationNote (Type type, Code code)
index 1d9cd9215f6ac77a5b6dd8204bc2d821ca1088d2..10f99ce1f30785f2d77fee9b5ab05662c445c426 100644 (file)
@@ -45,6 +45,7 @@ extern void check_xml (std::string ref, std::string test, std::list<std::string>
 extern void check_file (boost::filesystem::path ref, boost::filesystem::path check);
 extern std::shared_ptr<dcp::MonoPictureAsset> simple_picture (boost::filesystem::path path, std::string suffix);
 extern std::shared_ptr<dcp::SoundAsset> simple_sound (boost::filesystem::path path, std::string suffix, dcp::MXFMetadata mxf_meta, std::string language);
+extern std::shared_ptr<dcp::Subtitle> simple_subtitle ();
 extern std::shared_ptr<dcp::DCP> make_simple (boost::filesystem::path path, int reels = 1);
 extern std::shared_ptr<dcp::DCP> make_simple_with_interop_subs (boost::filesystem::path path);
 extern std::shared_ptr<dcp::DCP> make_simple_with_smpte_subs (boost::filesystem::path path);
index 24d583b6d7c633ded7d9e238bdd45ff14806657c..9bb3859abab01e2948c38efb9306f8c10cd2ca5e 100644 (file)
@@ -1335,3 +1335,39 @@ BOOST_AUTO_TEST_CASE (verify_missing_language_tag_in_subtitle_xml)
        BOOST_CHECK_EQUAL (notes.front().type(), dcp::VerificationNote::VERIFY_BV21_ERROR);
        BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::MISSING_SUBTITLE_LANGUAGE);
 }
+
+
+BOOST_AUTO_TEST_CASE (verify_inconsistent_subtitle_languages)
+{
+       boost::filesystem::path path ("build/test/verify_inconsistent_subtitle_languages");
+       shared_ptr<dcp::DCP> dcp = make_simple (path, 2);
+       shared_ptr<dcp::CPL> cpl = dcp->cpls().front();
+
+       {
+               shared_ptr<dcp::SMPTESubtitleAsset> subs(new dcp::SMPTESubtitleAsset());
+               subs->set_language (dcp::LanguageTag("de-DE"));
+               subs->add (simple_subtitle());
+               subs->write (path / "subs1.mxf");
+               shared_ptr<dcp::ReelSubtitleAsset> reel_subs(new dcp::ReelSubtitleAsset(subs, dcp::Fraction(24, 1), 240, 0));
+               cpl->reels().front()->add (reel_subs);
+       }
+
+       {
+               shared_ptr<dcp::SMPTESubtitleAsset> subs(new dcp::SMPTESubtitleAsset());
+               subs->set_language (dcp::LanguageTag("en-US"));
+               subs->add (simple_subtitle());
+               subs->write (path / "subs2.mxf");
+               shared_ptr<dcp::ReelSubtitleAsset> reel_subs(new dcp::ReelSubtitleAsset(subs, dcp::Fraction(24, 1), 240, 0));
+               cpl->reels().back()->add (reel_subs);
+       }
+
+       dcp->write_xml (dcp::SMPTE);
+
+       vector<boost::filesystem::path> dirs;
+       dirs.push_back (path);
+       list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
+       BOOST_REQUIRE_EQUAL (notes.size(), 1U);
+       BOOST_CHECK_EQUAL (notes.front().type(), dcp::VerificationNote::VERIFY_BV21_ERROR);
+       BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::SUBTITLE_LANGUAGES_DIFFER);
+}
+