Bv2.1 7.2.3: Check that subtitle <StartTime> exists and is 0.
authorCarl Hetherington <cth@carlh.net>
Sat, 2 Jan 2021 23:31:40 +0000 (00:31 +0100)
committerCarl Hetherington <cth@carlh.net>
Sun, 17 Jan 2021 19:13:22 +0000 (20:13 +0100)
12 files changed:
BRANCH
src/verify.cc
src/verify.h
test/data/822bd341-c751-45b1-94d2-410e4ffcff1b.png
test/data/sub.png
test/data/subs.mxf
test/ref/write_interop_subtitle_test3/ASSETMAP
test/ref/write_interop_subtitle_test3/d36f4bb3-c4fa-4a95-9915-6fec3110cd71.png
test/ref/write_interop_subtitle_test3/pkl.xml [changed from symlink to file mode: 0644]
test/ref/write_interop_subtitle_test3/pkl_6a9e31a6-50a4-4ecb-8683-fa667848470a.xml [deleted file]
test/test.cc
test/verify_test.cc

diff --git a/BRANCH b/BRANCH
index 7b9aab02117709038a1de596361480a4c4d2c86b..103b734ba1d76a6d7defce864415ae138a7907cc 100644 (file)
--- a/BRANCH
+++ b/BRANCH
@@ -25,5 +25,5 @@ Mark things with [Bv2.1_paragraph]
     - 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.3 StartTime element shall be present and equal to 00:00:00:00 [/]
        
index 0b7def3c7cb06ff987df15947c7392a84d68456f..bbae1ba4e76de1cdb3c5182aefd9d30bbefc2ffd 100644 (file)
@@ -704,6 +704,18 @@ verify_subtitle_asset (
                                        )
                                );
                }
+
+               if (!smpte->start_time()) {
+                       notes.push_back (
+                               VerificationNote(
+                                       VerificationNote::VERIFY_BV21_ERROR, VerificationNote::MISSING_SUBTITLE_START_TIME, *asset->file())
+                               );
+               } else if (smpte->start_time() != dcp::Time()) {
+                       notes.push_back (
+                               VerificationNote(
+                                       VerificationNote::VERIFY_BV21_ERROR, VerificationNote::SUBTITLE_START_TIME_NON_ZERO, *asset->file())
+                               );
+               }
        }
 }
 
@@ -912,6 +924,10 @@ dcp::note_to_string (dcp::VerificationNote note)
                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());
+       case dcp::VerificationNote::MISSING_SUBTITLE_START_TIME:
+               return String::compose("The XML for a SMPTE subtitle asset has no <StartTime> tag, which is required by Bv2.1", note.file()->filename());
+       case dcp::VerificationNote::SUBTITLE_START_TIME_NON_ZERO:
+               return String::compose("The XML for a SMPTE subtitle asset has a non-zero <StartTime> tag, which is disallowed by Bv2.1", note.file()->filename());
        }
 
        return "";
index 170aeb8b6386d6f426c1089705a356c196e05656..2957654fc3a917a3043f9990d0193fe3f1cbcfb6 100644 (file)
@@ -112,6 +112,10 @@ public:
                MISSING_SUBTITLE_LANGUAGE,
                /** Not all subtitle assets specify the same <Language> tag [Bv2.1_7.2.2] */
                SUBTITLE_LANGUAGES_DIFFER,
+               /** Some SMPTE subtitle XML has no <StartTime> tag [Bv2.1_7.2.3] */
+               MISSING_SUBTITLE_START_TIME,
+               /** Some SMPTE subtitle XML has a non-zero <StartTime> tag [Bv2.1_7.2.3] */
+               SUBTITLE_START_TIME_NON_ZERO,
        };
 
        VerificationNote (Type type, Code code)
index 89b53cf2ce9074c1e908c8b7a2473eaccfa61c5a..9d8f298892fe8de21b515c65c63f5fc6f25ebab6 100644 (file)
Binary files a/test/data/822bd341-c751-45b1-94d2-410e4ffcff1b.png and b/test/data/822bd341-c751-45b1-94d2-410e4ffcff1b.png differ
index 89b53cf2ce9074c1e908c8b7a2473eaccfa61c5a..9d8f298892fe8de21b515c65c63f5fc6f25ebab6 100644 (file)
Binary files a/test/data/sub.png and b/test/data/sub.png differ
index ec208dcede9321075951ed5330ad3ca08f842e38..d321e5c620d09cfd02454a31d5709432bb8b8006 100644 (file)
Binary files a/test/data/subs.mxf and b/test/data/subs.mxf differ
index dfcc1bc9a4e2510647c06eab2ebc01b63e91ea6d..0b704a41c0d05dff5a6640ca3a29ba08c7712e5f 100644 (file)
@@ -48,7 +48,7 @@
           <Path>d36f4bb3-c4fa-4a95-9915-6fec3110cd71.png</Path>
           <VolumeIndex>1</VolumeIndex>
           <Offset>0</Offset>
-          <Length>44935</Length>
+          <Length>44861</Length>
         </Chunk>
       </ChunkList>
     </Asset>
index 89b53cf2ce9074c1e908c8b7a2473eaccfa61c5a..9d8f298892fe8de21b515c65c63f5fc6f25ebab6 100644 (file)
Binary files a/test/ref/write_interop_subtitle_test3/d36f4bb3-c4fa-4a95-9915-6fec3110cd71.png and b/test/ref/write_interop_subtitle_test3/d36f4bb3-c4fa-4a95-9915-6fec3110cd71.png differ
deleted file mode 120000 (symlink)
index 23d28034d93599194647b80978d4d1303c44a3f8..0000000000000000000000000000000000000000
+++ /dev/null
@@ -1 +0,0 @@
-pkl_6a9e31a6-50a4-4ecb-8683-fa667848470a.xml
\ No newline at end of file
new file mode 100644 (file)
index 0000000000000000000000000000000000000000..f82e98c4a3d153b41deb920b2276e606e52f9185
--- /dev/null
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<PackingList xmlns="http://www.digicine.com/PROTO-ASDCP-PKL-20040311#">
+  <Id>urn:uuid:6a9e31a6-50a4-4ecb-8683-fa667848470a</Id>
+  <AnnotationText>Created by libdcp</AnnotationText>
+  <IssueDate>2018-09-02T04:45:18+00:00</IssueDate>
+  <Issuer>libdcp</Issuer>
+  <Creator>libdcp</Creator>
+  <AssetList>
+    <Asset>
+      <Id>urn:uuid:46c3eb45-15e5-47d6-8684-d8641e4dc516</Id>
+      <AnnotationText>46c3eb45-15e5-47d6-8684-d8641e4dc516</AnnotationText>
+      <Hash>hu0RaV4ZgrcqQQtgOW4r/YznVo0=</Hash>
+      <Size>1105</Size>
+      <Type>text/xml;asdcpKind=CPL</Type>
+    </Asset>
+    <Asset>
+      <Id>urn:uuid:a6c58cff-3e1e-4b38-acec-a42224475ef6</Id>
+      <AnnotationText>a6c58cff-3e1e-4b38-acec-a42224475ef6</AnnotationText>
+      <Hash>cVnFjMLTQnSIAlIzJpNB/p7B230=</Hash>
+      <Size>414</Size>
+      <Type>text/xml;asdcpKind=Subtitle</Type>
+    </Asset>
+    <Asset>
+      <Id>urn:uuid:d36f4bb3-c4fa-4a95-9915-6fec3110cd71</Id>
+      <Hash>2vTylSKQ5MCQHbKPT4X+rlwfHk4=</Hash>
+      <Size>44861</Size>
+      <Type>image/png</Type>
+    </Asset>
+  </AssetList>
+</PackingList>
diff --git a/test/ref/write_interop_subtitle_test3/pkl_6a9e31a6-50a4-4ecb-8683-fa667848470a.xml b/test/ref/write_interop_subtitle_test3/pkl_6a9e31a6-50a4-4ecb-8683-fa667848470a.xml
deleted file mode 100644 (file)
index 5e72118..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<PackingList xmlns="http://www.digicine.com/PROTO-ASDCP-PKL-20040311#">
-  <Id>urn:uuid:6a9e31a6-50a4-4ecb-8683-fa667848470a</Id>
-  <AnnotationText>Created by libdcp</AnnotationText>
-  <IssueDate>2018-09-02T04:45:18+00:00</IssueDate>
-  <Issuer>libdcp</Issuer>
-  <Creator>libdcp</Creator>
-  <AssetList>
-    <Asset>
-      <Id>urn:uuid:46c3eb45-15e5-47d6-8684-d8641e4dc516</Id>
-      <AnnotationText>46c3eb45-15e5-47d6-8684-d8641e4dc516</AnnotationText>
-      <Hash>hu0RaV4ZgrcqQQtgOW4r/YznVo0=</Hash>
-      <Size>1105</Size>
-      <Type>text/xml;asdcpKind=CPL</Type>
-    </Asset>
-    <Asset>
-      <Id>urn:uuid:a6c58cff-3e1e-4b38-acec-a42224475ef6</Id>
-      <AnnotationText>a6c58cff-3e1e-4b38-acec-a42224475ef6</AnnotationText>
-      <Hash>cVnFjMLTQnSIAlIzJpNB/p7B230=</Hash>
-      <Size>414</Size>
-      <Type>text/xml;asdcpKind=Subtitle</Type>
-    </Asset>
-    <Asset>
-      <Id>urn:uuid:d36f4bb3-c4fa-4a95-9915-6fec3110cd71</Id>
-      <Hash>w0Xc4TUYpao08I0yPSDfFkaEwdg=</Hash>
-      <Size>44935</Size>
-      <Type>image/png</Type>
-    </Asset>
-  </AssetList>
-</PackingList>
index 7a08cfc3e5bc777226df04cfd9a2d48a09efd120..1d3368063ddd2bf5e462d89be262621fd11f3f94 100644 (file)
@@ -404,6 +404,7 @@ make_simple_with_smpte_subs (boost::filesystem::path path)
 
        shared_ptr<dcp::SMPTESubtitleAsset> subs(new dcp::SMPTESubtitleAsset());
        subs->set_language (dcp::LanguageTag("de-DE"));
+       subs->set_start_time (dcp::Time());
        subs->add (simple_subtitle());
 
        subs->write (path / "subs.mxf");
@@ -438,6 +439,7 @@ make_simple_with_smpte_ccaps (boost::filesystem::path path)
 
        shared_ptr<dcp::SMPTESubtitleAsset> subs(new dcp::SMPTESubtitleAsset());
        subs->set_language (dcp::LanguageTag("de-DE"));
+       subs->set_start_time (dcp::Time());
        subs->add (simple_subtitle());
        subs->write (path / "ccap.mxf");
 
index 9bb3859abab01e2948c38efb9306f8c10cd2ca5e..4cde39668d66f2ff563c376f0314206eb31a9144 100644 (file)
@@ -729,9 +729,13 @@ BOOST_AUTO_TEST_CASE (verify_test21)
        vector<boost::filesystem::path> dirs;
        dirs.push_back (dir);
        list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
-       BOOST_REQUIRE_EQUAL (notes.size(), 2);
-       BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
-       BOOST_CHECK_EQUAL (notes.back().code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
+       BOOST_REQUIRE_EQUAL (notes.size(), 3);
+       list<dcp::VerificationNote>::const_iterator i = notes.begin();
+       BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
+       ++i;
+       BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::XML_VALIDATION_ERROR);
+       ++i;
+       BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::MISSING_SUBTITLE_START_TIME);
 }
 
 
@@ -1206,9 +1210,12 @@ BOOST_AUTO_TEST_CASE (verify_closed_caption_xml_too_large)
        vector<boost::filesystem::path> dirs;
        dirs.push_back (dir);
        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::CLOSED_CAPTION_XML_TOO_LARGE_IN_BYTES);
+       BOOST_REQUIRE_EQUAL (notes.size(), 2U);
+       list<dcp::VerificationNote>::const_iterator i = notes.begin();
+       BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::MISSING_SUBTITLE_START_TIME);
+       ++i;
+       BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_BV21_ERROR);
+       BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::CLOSED_CAPTION_XML_TOO_LARGE_IN_BYTES);
 }
 
 
@@ -1273,13 +1280,15 @@ verify_timed_text_asset_too_large (string name)
        vector<boost::filesystem::path> dirs;
        dirs.push_back (dir);
        list<dcp::VerificationNote> notes = dcp::verify (dirs, &stage, &progress, xsd_test);
-       BOOST_REQUIRE_EQUAL (notes.size(), 2U);
+       BOOST_REQUIRE_EQUAL (notes.size(), 3U);
        list<dcp::VerificationNote>::const_iterator i = notes.begin();
        BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_BV21_ERROR);
        BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::TIMED_TEXT_ASSET_TOO_LARGE_IN_BYTES);
        ++i;
        BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_BV21_ERROR);
        BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::TIMED_TEXT_FONTS_TOO_LARGE_IN_BYTES);
+       ++i;
+       BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::MISSING_SUBTITLE_START_TIME);
 }
 
 
@@ -1366,8 +1375,106 @@ BOOST_AUTO_TEST_CASE (verify_inconsistent_subtitle_languages)
        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(), 3U);
+       list<dcp::VerificationNote>::const_iterator i = notes.begin();
+       BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::MISSING_SUBTITLE_START_TIME);
+       ++i;
+       BOOST_CHECK_EQUAL (i->type(), dcp::VerificationNote::VERIFY_BV21_ERROR);
+       ++i;
+       BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::MISSING_SUBTITLE_START_TIME);
+}
+
+
+BOOST_AUTO_TEST_CASE (verify_missing_start_time_tag_in_subtitle_xml)
+{
+       boost::filesystem::path dir = "build/test/verify_missing_start_time_tag_in_subtitle_xml";
+       prepare_directory (dir);
+       shared_ptr<dcp::DCP> dcp = make_simple (dir, 1);
+
+       string const xml =
+               "<?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:e6a8ae03-ebbf-41ed-9def-913a87d1493a</Id>"
+               "<ContentTitleText>Content</ContentTitleText>"
+               "<AnnotationText>Annotation</AnnotationText>"
+               "<IssueDate>2018-10-02T12:25:14+02:00</IssueDate>"
+               "<ReelNumber>1</ReelNumber>"
+               "<Language>de-DE</Language>"
+               "<EditRate>25 1</EditRate>"
+               "<TimeCodeRate>25</TimeCodeRate>"
+               "<LoadFont ID=\"arial\">urn:uuid:e4f0ff0a-9eba-49e0-92ee-d89a88a575f6</LoadFont>"
+               "<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>";
+
+       FILE* xml_file = dcp::fopen_boost (dir / "subs.xml", "w");
+       BOOST_REQUIRE (xml_file);
+       fwrite (xml.c_str(), xml.size(), 1, xml_file);
+       fclose (xml_file);
+       shared_ptr<dcp::SMPTESubtitleAsset> subs (new dcp::SMPTESubtitleAsset(dir / "subs.xml"));
+       subs->write (dir / "subs.mxf");
+
+       shared_ptr<dcp::ReelSubtitleAsset> reel_subs (new dcp::ReelSubtitleAsset(subs, dcp::Fraction(24, 1), 100, 0));
+       dcp->cpls().front()->reels().front()->add (reel_subs);
+       dcp->write_xml (dcp::SMPTE);
+
+       vector<boost::filesystem::path> dirs;
+       dirs.push_back (dir);
+       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);
+       BOOST_CHECK_EQUAL (notes.front().code(), dcp::VerificationNote::MISSING_SUBTITLE_START_TIME);
 }
 
+
+BOOST_AUTO_TEST_CASE (verify_non_zero_start_time_tag_in_subtitle_xml)
+{
+       boost::filesystem::path dir = "build/test/verify_non_zero_start_time_tag_in_subtitle_xml";
+       prepare_directory (dir);
+       shared_ptr<dcp::DCP> dcp = make_simple (dir, 1);
+
+       string const xml =
+               "<?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:e6a8ae03-ebbf-41ed-9def-913a87d1493a</Id>"
+               "<ContentTitleText>Content</ContentTitleText>"
+               "<AnnotationText>Annotation</AnnotationText>"
+               "<IssueDate>2018-10-02T12:25:14+02:00</IssueDate>"
+               "<ReelNumber>1</ReelNumber>"
+               "<Language>de-DE</Language>"
+               "<EditRate>25 1</EditRate>"
+               "<TimeCodeRate>25</TimeCodeRate>"
+               "<StartTime>00:00:02:00</StartTime>"
+               "<LoadFont ID=\"arial\">urn:uuid:e4f0ff0a-9eba-49e0-92ee-d89a88a575f6</LoadFont>"
+               "<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>";
+
+       FILE* xml_file = dcp::fopen_boost (dir / "subs.xml", "w");
+       BOOST_REQUIRE (xml_file);
+       fwrite (xml.c_str(), xml.size(), 1, xml_file);
+       fclose (xml_file);
+       shared_ptr<dcp::SMPTESubtitleAsset> subs (new dcp::SMPTESubtitleAsset(dir / "subs.xml"));
+       subs->write (dir / "subs.mxf");
+
+       shared_ptr<dcp::ReelSubtitleAsset> reel_subs (new dcp::ReelSubtitleAsset(subs, dcp::Fraction(24, 1), 100, 0));
+       dcp->cpls().front()->reels().front()->add (reel_subs);
+       dcp->write_xml (dcp::SMPTE);
+
+       vector<boost::filesystem::path> dirs;
+       dirs.push_back (dir);
+       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_START_TIME_NON_ZERO);
+}