Verify that SMPTE subtitle IDs are handled properly (DoM #1962).
authorCarl Hetherington <cth@carlh.net>
Thu, 8 Apr 2021 00:07:05 +0000 (02:07 +0200)
committerCarl Hetherington <cth@carlh.net>
Thu, 8 Apr 2021 00:07:05 +0000 (02:07 +0200)
src/verify.cc
src/verify.h
test/verify_test.cc

index 382a67ba9e71a9517e480a9c6b234e1f1984143c..35ec69f83e9341014c6c1d523d6210b405c6be6c 100644 (file)
@@ -686,6 +686,15 @@ verify_smpte_subtitle_asset (
                        notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::MISMATCHED_SUBTITLE_LANGUAGES });
                }
        }
+
+       DCP_ASSERT (asset->resource_id());
+       if (asset->resource_id().get() != asset->xml_id()) {
+               notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::MISMATCHED_TIMED_TEXT_RESOURCE_ID });
+       }
+
+       if (asset->id() == asset->resource_id().get() || asset->id() == asset->xml_id()) {
+               notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INCORRECT_TIMED_TEXT_ASSET_ID });
+       }
 }
 
 
@@ -1565,6 +1574,10 @@ dcp::note_to_string (VerificationNote note)
                return String::compose("The JPEG2000 codestream has %1 tile parts in a 4K image instead of 6.", note.note().get());
        case VerificationNote::Code::MISSING_JPEG200_TLM_MARKER:
                return "No TLM marker was found in a JPEG2000 codestream.";
+       case VerificationNote::Code::MISMATCHED_TIMED_TEXT_RESOURCE_ID:
+               return "The Resource ID in a timed text MXF did not match the ID of the contained XML.";
+       case VerificationNote::Code::INCORRECT_TIMED_TEXT_ASSET_ID:
+               return "The Asset ID in a timed text MXF is the same as the Resource ID or that of the contained XML.";
        }
 
        return "";
index f14382c53dcd55f4dcf37c095397bcbeeb5f370a..0a4228012f94aed3734101aef70de1eefc1f7180 100644 (file)
@@ -366,6 +366,10 @@ public:
                INVALID_JPEG2000_TILE_PARTS_FOR_4K,
                /** No TLM marker was found [Bv2.1_10.2.1] */
                MISSING_JPEG200_TLM_MARKER,
+               /** The MXF ResourceID of a timed text resource was not the same as that of the contained XML essence [Bv2.1_10.4.3] */
+               MISMATCHED_TIMED_TEXT_RESOURCE_ID,
+               /** The AssetID of a timed text MXF is the same as its ResourceID or that of the contained XML essence [Bv2.1_10.4.2] */
+               INCORRECT_TIMED_TEXT_ASSET_ID,
        };
 
        VerificationNote (Type type, Code code)
index b4cbc5aa2f7342fbef883f94b7f86388bc89011e..801b142eceddbcce82e64cfa240a576e0d9ffb83 100644 (file)
@@ -2843,3 +2843,128 @@ BOOST_AUTO_TEST_CASE (verify_jpeg2000_codestream_libdcp)
        BOOST_REQUIRE_EQUAL (notes.size(), 0U);
 }
 
+
+/** Check that ResourceID and the XML ID being different is spotted */
+BOOST_AUTO_TEST_CASE (verify_mismatched_subtitle_resource_id)
+{
+       boost::filesystem::path const dir = "build/test/verify_mismatched_subtitle_resource_id";
+       prepare_directory (dir);
+
+       ASDCP::WriterInfo writer_info;
+       writer_info.LabelSetType = ASDCP::LS_MXF_SMPTE;
+
+       unsigned int c;
+       auto mxf_id = dcp::make_uuid ();
+       Kumu::hex2bin (mxf_id.c_str(), writer_info.AssetUUID, Kumu::UUID_Length, &c);
+       BOOST_REQUIRE (c == Kumu::UUID_Length);
+
+       auto resource_id = dcp::make_uuid ();
+       ASDCP::TimedText::TimedTextDescriptor descriptor;
+       Kumu::hex2bin (resource_id.c_str(), descriptor.AssetID, Kumu::UUID_Length, &c);
+       DCP_ASSERT (c == Kumu::UUID_Length);
+
+       auto xml_id = dcp::make_uuid ();
+       ASDCP::TimedText::MXFWriter writer;
+       auto subs_mxf = dir / "subs.mxf";
+       auto r = writer.OpenWrite(subs_mxf.c_str(), writer_info, descriptor, 4096);
+       BOOST_REQUIRE (ASDCP_SUCCESS(r));
+       writer.WriteTimedTextResource (dcp::String::compose(
+               "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+               "<SubtitleReel xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\" xmlns:xs=\"http://www.w3.org/2001/schema\">"
+               "<Id>urn:uuid:%1</Id>"
+               "<ContentTitleText>Content</ContentTitleText>"
+               "<AnnotationText>Annotation</AnnotationText>"
+               "<IssueDate>2018-10-02T12:25:14+02:00</IssueDate>"
+               "<ReelNumber>1</ReelNumber>"
+               "<Language>en-US</Language>"
+               "<EditRate>25 1</EditRate>"
+               "<TimeCodeRate>25</TimeCodeRate>"
+               "<StartTime>00:00:00:00</StartTime>"
+               "<SubtitleList>"
+               "<Font ID=\"arial\" Color=\"FFFEFEFE\" Weight=\"normal\" Size=\"42\" Effect=\"border\" EffectColor=\"FF181818\" AspectAdjust=\"1.00\">"
+               "<Subtitle SpotNumber=\"1\" TimeIn=\"00:00:03:00\" TimeOut=\"00:00:04:10\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">"
+               "<Text Hposition=\"0.0\" Halign=\"center\" Valign=\"bottom\" Vposition=\"13.5\" Direction=\"ltr\">Hello world</Text>"
+               "</Subtitle>"
+               "</Font>"
+               "</SubtitleList>"
+               "</SubtitleReel>",
+               xml_id).c_str());
+
+       writer.Finalize();
+
+       auto subs_asset = make_shared<dcp::SMPTESubtitleAsset>(subs_mxf);
+       auto subs_reel = make_shared<dcp::ReelSubtitleAsset>(subs_asset, dcp::Fraction(24, 1), 240, 0);
+
+       auto cpl = write_dcp_with_single_asset (dir, subs_reel);
+
+       check_verify_result (
+               { dir },
+               {
+                       { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISMATCHED_TIMED_TEXT_RESOURCE_ID },
+                       { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME },
+                       { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() }
+               });
+}
+
+
+/** Check that ResourceID and the MXF ID being the same is spotted */
+BOOST_AUTO_TEST_CASE (verify_incorrect_timed_text_id)
+{
+       boost::filesystem::path const dir = "build/test/verify_incorrect_timed_text_id";
+       prepare_directory (dir);
+
+       ASDCP::WriterInfo writer_info;
+       writer_info.LabelSetType = ASDCP::LS_MXF_SMPTE;
+
+       unsigned int c;
+       auto mxf_id = dcp::make_uuid ();
+       Kumu::hex2bin (mxf_id.c_str(), writer_info.AssetUUID, Kumu::UUID_Length, &c);
+       BOOST_REQUIRE (c == Kumu::UUID_Length);
+
+       auto resource_id = mxf_id;
+       ASDCP::TimedText::TimedTextDescriptor descriptor;
+       Kumu::hex2bin (resource_id.c_str(), descriptor.AssetID, Kumu::UUID_Length, &c);
+       DCP_ASSERT (c == Kumu::UUID_Length);
+
+       auto xml_id = resource_id;
+       ASDCP::TimedText::MXFWriter writer;
+       auto subs_mxf = dir / "subs.mxf";
+       auto r = writer.OpenWrite(subs_mxf.c_str(), writer_info, descriptor, 4096);
+       BOOST_REQUIRE (ASDCP_SUCCESS(r));
+       writer.WriteTimedTextResource (dcp::String::compose(
+               "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+               "<SubtitleReel xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\" xmlns:xs=\"http://www.w3.org/2001/schema\">"
+               "<Id>urn:uuid:%1</Id>"
+               "<ContentTitleText>Content</ContentTitleText>"
+               "<AnnotationText>Annotation</AnnotationText>"
+               "<IssueDate>2018-10-02T12:25:14+02:00</IssueDate>"
+               "<ReelNumber>1</ReelNumber>"
+               "<Language>en-US</Language>"
+               "<EditRate>25 1</EditRate>"
+               "<TimeCodeRate>25</TimeCodeRate>"
+               "<StartTime>00:00:00:00</StartTime>"
+               "<SubtitleList>"
+               "<Font ID=\"arial\" Color=\"FFFEFEFE\" Weight=\"normal\" Size=\"42\" Effect=\"border\" EffectColor=\"FF181818\" AspectAdjust=\"1.00\">"
+               "<Subtitle SpotNumber=\"1\" TimeIn=\"00:00:03:00\" TimeOut=\"00:00:04:10\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">"
+               "<Text Hposition=\"0.0\" Halign=\"center\" Valign=\"bottom\" Vposition=\"13.5\" Direction=\"ltr\">Hello world</Text>"
+               "</Subtitle>"
+               "</Font>"
+               "</SubtitleList>"
+               "</SubtitleReel>",
+               xml_id).c_str());
+
+       writer.Finalize();
+
+       auto subs_asset = make_shared<dcp::SMPTESubtitleAsset>(subs_mxf);
+       auto subs_reel = make_shared<dcp::ReelSubtitleAsset>(subs_asset, dcp::Fraction(24, 1), 240, 0);
+
+       auto cpl = write_dcp_with_single_asset (dir, subs_reel);
+
+       check_verify_result (
+               { dir },
+               {
+                       { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::INCORRECT_TIMED_TEXT_ASSET_ID },
+                       { dcp::VerificationNote::Type::WARNING, dcp::VerificationNote::Code::INVALID_SUBTITLE_FIRST_TEXT_TIME },
+                       { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() }
+               });
+}