From 1dc40e9c0e2758619ce5bda802cd32371aee5829 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 15 Jan 2021 00:17:09 +0100 Subject: Bv2.1 8.3.1: MainSubtitles must be in all reels (if they are there at all) and ClosedCaptions must have the same count on all reels. --- src/verify.cc | 28 +++++++++++ src/verify.h | 4 ++ test/verify_test.cc | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 168 insertions(+) diff --git a/src/verify.cc b/src/verify.cc index a7f3f1da..f8ab3d44 100644 --- a/src/verify.cc +++ b/src/verify.cc @@ -1053,6 +1053,15 @@ dcp::verify ( } } + /* set to true if any reel has a MainSubtitle */ + auto have_main_subtitle = false; + /* set to true if any reel has no MainSubtitle */ + auto have_no_main_subtitle = false; + /* fewest number of closed caption assets seen in a reel */ + size_t fewest_closed_captions = SIZE_MAX; + /* most number of closed caption assets seen in a reel */ + size_t most_closed_captions = 0; + for (auto reel: cpl->reels()) { stage ("Checking reel", optional()); @@ -1105,6 +1114,9 @@ dcp::verify ( if (reel->main_subtitle()->asset_ref().resolved()) { verify_subtitle_asset (reel->main_subtitle()->asset(), stage, xsd_dtd_directory, notes, state); } + have_main_subtitle = true; + } else { + have_no_main_subtitle = true; } for (auto i: reel->closed_captions()) { @@ -1113,9 +1125,21 @@ dcp::verify ( verify_closed_caption_asset (i->asset(), stage, xsd_dtd_directory, notes, state); } } + + fewest_closed_captions = std::min (fewest_closed_captions, reel->closed_captions().size()); + most_closed_captions = std::max (most_closed_captions, reel->closed_captions().size()); } if (dcp->standard() == dcp::SMPTE) { + + if (have_main_subtitle && have_no_main_subtitle) { + notes.push_back ({VerificationNote::VERIFY_BV21_ERROR, VerificationNote::MAIN_SUBTITLE_NOT_IN_ALL_REELS}); + } + + if (fewest_closed_captions != most_closed_captions) { + notes.push_back ({VerificationNote::VERIFY_BV21_ERROR, VerificationNote::CLOSED_CAPTION_ASSET_COUNTS_DIFFER}); + } + check_text_timing (cpl->reels(), notes); LinesCharactersResult result; @@ -1256,6 +1280,10 @@ dcp::note_to_string (dcp::VerificationNote note) return "The CPL's differs from its , which Bv2.1 advises against."; case dcp::VerificationNote::MISMATCHED_ASSET_DURATION: return "All assets in a reel do not have the same duration, which is required by Bv2.1"; + case dcp::VerificationNote::MAIN_SUBTITLE_NOT_IN_ALL_REELS: + return "At least one reel contains a subtitle asset, but some reel(s) do not"; + case dcp::VerificationNote::CLOSED_CAPTION_ASSET_COUNTS_DIFFER: + return "At least one reel has closed captions, but reels have different numbers of closed caption assets."; } return ""; diff --git a/src/verify.h b/src/verify.h index 3b2629f9..64232a43 100644 --- a/src/verify.h +++ b/src/verify.h @@ -139,6 +139,10 @@ public: CPL_ANNOTATION_TEXT_DIFFERS_FROM_CONTENT_TITLE_TEXT, /** At least one asset in a reel does not have the same duration as the others */ MISMATCHED_ASSET_DURATION, + /** If one reel has a MainSubtitle, all must have them */ + MAIN_SUBTITLE_NOT_IN_ALL_REELS, + /** If one reel has at least one ClosedCaption, all reels must have the same number of ClosedCaptions */ + CLOSED_CAPTION_ASSET_COUNTS_DIFFER, }; VerificationNote (Type type, Code code) diff --git a/test/verify_test.cc b/test/verify_test.cc index 86b98d2b..246b4462 100644 --- a/test/verify_test.cc +++ b/test/verify_test.cc @@ -1698,3 +1698,139 @@ BOOST_AUTO_TEST_CASE (verify_reel_assets_durations_must_match) check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISMATCHED_ASSET_DURATION }}); } + + +static +void +verify_subtitles_must_be_in_all_reels_check (boost::filesystem::path dir, bool add_to_reel1, bool add_to_reel2) +{ + boost::filesystem::remove_all (dir); + boost::filesystem::create_directories (dir); + auto dcp = make_shared(dir); + auto cpl = make_shared("A Test DCP", dcp::FEATURE); + + auto subs = make_shared(); + subs->set_language (dcp::LanguageTag("de-DE")); + subs->set_start_time (dcp::Time()); + subs->add (simple_subtitle()); + subs->write (dir / "subs.mxf"); + auto reel_subs = make_shared(subs, dcp::Fraction(24, 1), 240, 0); + + auto reel1 = make_shared( + make_shared(simple_picture(dir, "", 240), 0), + make_shared(simple_sound(dir, "", dcp::MXFMetadata(), "en-US", 240), 0) + ); + + if (add_to_reel1) { + reel1->add (make_shared(subs, dcp::Fraction(24, 1), 240, 0)); + } + + cpl->add (reel1); + + + auto reel2 = make_shared( + make_shared(simple_picture(dir, "", 240), 0), + make_shared(simple_sound(dir, "", dcp::MXFMetadata(), "en-US", 240), 0) + ); + + if (add_to_reel2) { + reel2->add (make_shared(subs, dcp::Fraction(24, 1), 240, 0)); + } + + cpl->add (reel2); + + dcp->add (cpl); + dcp->write_xml (dcp::SMPTE); +} + + +BOOST_AUTO_TEST_CASE (verify_subtitles_must_be_in_all_reels) +{ + { + boost::filesystem::path dir ("build/test/verify_subtitles_must_be_in_all_reels1"); + verify_subtitles_must_be_in_all_reels_check (dir, true, false); + check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MAIN_SUBTITLE_NOT_IN_ALL_REELS}}); + } + + { + boost::filesystem::path dir ("build/test/verify_subtitles_must_be_in_all_reels2"); + verify_subtitles_must_be_in_all_reels_check (dir, true, true); + auto notes = dcp::verify ({dir}, &stage, &progress, xsd_test); + BOOST_REQUIRE (notes.empty()); + } + + { + boost::filesystem::path dir ("build/test/verify_subtitles_must_be_in_all_reels1"); + verify_subtitles_must_be_in_all_reels_check (dir, false, false); + auto notes = dcp::verify ({dir}, &stage, &progress, xsd_test); + BOOST_REQUIRE (notes.empty()); + } +} + + +static +void +verify_closed_captions_must_be_in_all_reels_check (boost::filesystem::path dir, int caps_in_reel1, int caps_in_reel2) +{ + boost::filesystem::remove_all (dir); + boost::filesystem::create_directories (dir); + auto dcp = make_shared(dir); + auto cpl = make_shared("A Test DCP", dcp::FEATURE); + + auto subs = make_shared(); + subs->set_language (dcp::LanguageTag("de-DE")); + subs->set_start_time (dcp::Time()); + subs->add (simple_subtitle()); + subs->write (dir / "subs.mxf"); + + auto reel1 = make_shared( + make_shared(simple_picture(dir, "", 240), 0), + make_shared(simple_sound(dir, "", dcp::MXFMetadata(), "en-US", 240), 0) + ); + + for (int i = 0; i < caps_in_reel1; ++i) { + reel1->add (make_shared(subs, dcp::Fraction(24, 1), 240, 0)); + } + + cpl->add (reel1); + + auto reel2 = make_shared( + make_shared(simple_picture(dir, "", 240), 0), + make_shared(simple_sound(dir, "", dcp::MXFMetadata(), "en-US", 240), 0) + ); + + for (int i = 0; i < caps_in_reel2; ++i) { + reel2->add (make_shared(subs, dcp::Fraction(24, 1), 240, 0)); + } + + cpl->add (reel2); + + dcp->add (cpl); + dcp->write_xml (dcp::SMPTE); + +} + + +BOOST_AUTO_TEST_CASE (verify_closed_captions_must_be_in_all_reels) +{ + { + boost::filesystem::path dir ("build/test/verify_closed_captions_must_be_in_all_reels1"); + verify_closed_captions_must_be_in_all_reels_check (dir, 3, 4); + check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::CLOSED_CAPTION_ASSET_COUNTS_DIFFER }}); + } + + { + boost::filesystem::path dir ("build/test/verify_closed_captions_must_be_in_all_reels2"); + verify_closed_captions_must_be_in_all_reels_check (dir, 4, 4); + auto notes = dcp::verify ({dir}, &stage, &progress, xsd_test); + BOOST_REQUIRE (notes.empty()); + } + + { + boost::filesystem::path dir ("build/test/verify_closed_captions_must_be_in_all_reels3"); + verify_closed_captions_must_be_in_all_reels_check (dir, 0, 0); + auto notes = dcp::verify ({dir}, &stage, &progress, xsd_test); + BOOST_REQUIRE (notes.empty()); + } +} + -- cgit v1.2.3