Bv2.1 8.6.{1.2}: CompositionMetadataAsset must exist and it must have some <VersionNu...
authorCarl Hetherington <cth@carlh.net>
Mon, 18 Jan 2021 12:05:11 +0000 (13:05 +0100)
committerCarl Hetherington <cth@carlh.net>
Mon, 18 Jan 2021 12:05:11 +0000 (13:05 +0100)
14 files changed:
src/verify.cc
src/verify.h
test/combine_test.cc
test/ref/DCP/dcp_test1/ASSETMAP.xml
test/ref/DCP/dcp_test1/audio.mxf
test/ref/DCP/dcp_test1/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml
test/ref/DCP/dcp_test1/pkl_2b9b857f-ab4a-440e-a313-1ace0f1cfc95.xml [new file with mode: 0644]
test/ref/DCP/dcp_test1/pkl_63c3aece-c581-4603-b612-75e43f0c0430.xml [deleted file]
test/ref/DCP/dcp_test7/ASSETMAP
test/ref/DCP/dcp_test7/audio.mxf
test/ref/DCP/dcp_test7/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml
test/ref/DCP/dcp_test7/pkl_63c3aece-c581-4603-b612-75e43f0c0430.xml
test/test.cc
test/verify_test.cc

index 1cea1a0c40ca0a6d1b387210acae5f52c5ba78dc..d5b80b9fc3c6a739e5e974225de54ed1cfe52521 100644 (file)
@@ -1231,6 +1231,15 @@ dcp::verify (
                                if (result.error_length_exceeded) {
                                        notes.push_back (VerificationNote(VerificationNote::VERIFY_BV21_ERROR, VerificationNote::CLOSED_CAPTION_LINE_TOO_LONG));
                                }
+
+                               if (!cpl->full_content_title_text()) {
+                                       /* Since FullContentTitleText is assumed always to exist if there's a CompositionMetadataAsset we
+                                        * can use it as a proxy for CompositionMetadataAsset's existence.
+                                        */
+                                       notes.push_back ({VerificationNote::VERIFY_BV21_ERROR, VerificationNote::MISSING_CPL_METADATA});
+                               } else if (!cpl->version_number()) {
+                                       notes.push_back ({VerificationNote::VERIFY_BV21_ERROR, VerificationNote::MISSING_CPL_METADATA_VERSION_NUMBER});
+                               }
                        }
                }
 
@@ -1364,6 +1373,10 @@ dcp::note_to_string (dcp::VerificationNote note)
                return "The FFOC marker should bet set to 1";
        case dcp::VerificationNote::INCORRECT_LFOC:
                return "The LFOC marker should be set to 1 less than the duration of the last reel";
+       case dcp::VerificationNote::MISSING_CPL_METADATA:
+               return "There should be a <CompositionMetadataAsset> tag";
+       case dcp::VerificationNote::MISSING_CPL_METADATA_VERSION_NUMBER:
+               return "The CPL metadata must contain a <VersionNumber>";
        }
 
        return "";
index 05a494172b65c1383132a5ec66cdbb78455901c4..65095a8f795801227b6c36c13bdd1ce4530d79c8 100644 (file)
@@ -165,6 +165,10 @@ public:
                INCORRECT_FFOC,
                /** The LFOC should be the last frame in the reel */
                INCORRECT_LFOC,
+               /** There must be a <CompositionMetadataAsset> */
+               MISSING_CPL_METADATA,
+               /** CPL metadata should contain <VersionNumber> of 1, at least */
+               MISSING_CPL_METADATA_VERSION_NUMBER,
        };
 
        VerificationNote (Type type, Code code)
index 92949cf26ca867f15a4999e6f92cb6e36222a5e4..050978c7eb903368efca2bd8d0ffd2f5a69ab062 100644 (file)
@@ -318,6 +318,11 @@ BOOST_AUTO_TEST_CASE (combine_two_dcps_with_shared_asset)
        cpl->set_content_version (
                dcp::ContentVersion("urn:uuid:75ac29aa-42ac-1234-ecae-49251abefd11","content-version-label-text")
                );
+       cpl->set_main_sound_configuration ("L,C,R,Lfe,-,-");
+       cpl->set_main_sound_sample_rate (48000);
+       cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
+       cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
+       cpl->set_version_number(1);
 
        shared_ptr<dcp::ReelMonoPictureAsset> pic(new dcp::ReelMonoPictureAsset(simple_picture("build/test/combine_input2", ""), 0));
        shared_ptr<dcp::ReelSoundAsset> sound(new dcp::ReelSoundAsset(first->cpls().front()->reels().front()->main_sound()->asset(), 0));
index fcb38592f6899288184eea40bbdfe429daef5250..72096d956ba04dd481c1abdc69c1e7e7d3228b77 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <AssetMap xmlns="http://www.smpte-ra.org/schemas/429-9/2007/AM">
-  <Id>urn:uuid:2b9b857f-ab4a-440e-a313-1ace0f1cfc95</Id>
+  <Id>urn:uuid:07e9f5a0-83ab-4791-8c6b-7df5d11f76f9</Id>
   <AnnotationText>Created by libdcp</AnnotationText>
   <Creator>OpenDCP 0.0.25</Creator>
   <VolumeCount>1</VolumeCount>
@@ -8,11 +8,11 @@
   <Issuer>OpenDCP 0.0.25</Issuer>
   <AssetList>
     <Asset>
-      <Id>urn:uuid:63c3aece-c581-4603-b612-75e43f0c0430</Id>
+      <Id>urn:uuid:2b9b857f-ab4a-440e-a313-1ace0f1cfc95</Id>
       <PackingList>true</PackingList>
       <ChunkList>
         <Chunk>
-          <Path>pkl_63c3aece-c581-4603-b612-75e43f0c0430.xml</Path>
+          <Path>pkl_2b9b857f-ab4a-440e-a313-1ace0f1cfc95.xml</Path>
           <VolumeIndex>1</VolumeIndex>
           <Offset>0</Offset>
           <Length>1186</Length>
@@ -26,7 +26,7 @@
           <Path>cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml</Path>
           <VolumeIndex>1</VolumeIndex>
           <Offset>0</Offset>
-          <Length>2170</Length>
+          <Length>5082</Length>
         </Chunk>
       </ChunkList>
     </Asset>
@@ -48,7 +48,7 @@
           <Path>audio.mxf</Path>
           <VolumeIndex>1</VolumeIndex>
           <Offset>0</Offset>
-          <Length>161326</Length>
+          <Length>881326</Length>
         </Chunk>
       </ChunkList>
     </Asset>
index b58ff4363322a83b00a121952d1b4517804ab0b7..0b5a4459d90c37cd6f23cbc64c383d62a6f4e05a 100644 (file)
Binary files a/test/ref/DCP/dcp_test1/audio.mxf and b/test/ref/DCP/dcp_test1/audio.mxf differ
index 9f626dd60daf982d2de4d0e791af62836d824824..2ee11df5dea1a38be25823f4c7f2a64b87971d11 100644 (file)
           <IntrinsicDuration>24</IntrinsicDuration>
           <EntryPoint>0</EntryPoint>
           <Duration>24</Duration>
-          <Hash>cb1OLhgHG9svy7G8hoTSPpltzhw=</Hash>
+          <Hash>qtXbkcwhUj/yqquVLmV+wbzbxQ8=</Hash>
         </MainSound>
+        <meta:CompositionMetadataAsset xmlns:meta="http://www.smpte-ra.org/schemas/429-16/2014/CPL-Metadata">
+          <Id>urn:uuid:63c3aece-c581-4603-b612-75e43f0c0430</Id>
+          <EditRate>24 1</EditRate>
+          <IntrinsicDuration>24</IntrinsicDuration>
+          <meta:FullContentTitleText/>
+          <meta:VersionNumber>1</meta:VersionNumber>
+          <meta:MainSoundConfiguration>51/L,R,C,LFE,Ls,Rs</meta:MainSoundConfiguration>
+          <meta:MainSoundSampleRate>48000 1</meta:MainSoundSampleRate>
+          <meta:MainPictureStoredArea>
+            <meta:Width>1998</meta:Width>
+            <meta:Height>1080</meta:Height>
+          </meta:MainPictureStoredArea>
+          <meta:MainPictureActiveArea>
+            <meta:Width>1998</meta:Width>
+            <meta:Height>1080</meta:Height>
+          </meta:MainPictureActiveArea>
+          <meta:ExtensionMetadataList>
+            <meta:ExtensionMetadata scope="http://isdcf.com/ns/cplmd/app">
+              <meta:Name>Application</meta:Name>
+              <meta:PropertyList>
+                <meta:Property>
+                  <meta:Name>DCP Constraints Profile</meta:Name>
+                  <meta:Value>SMPTE-RDD-52:2020-Bv2.1</meta:Value>
+                </meta:Property>
+              </meta:PropertyList>
+            </meta:ExtensionMetadata>
+          </meta:ExtensionMetadataList>
+          <mca:MCASubDescriptors xmlns:mca="http://isdcf.com/ns/cplmd/mca" xmlns:r0="http://www.smpte-ra.org/reg/395/2014/13/1/aaf" xmlns:r1="http://www.smpte-ra.org/reg/335/2012">
+            <r0:SoundfieldGroupLabelSubDescriptor>
+              <r1:InstanceID>urn:uuid:18be072e-5a0f-44e1-b2eb-c8a52ae12789</r1:InstanceID>
+              <r1:MCALabelDictionaryID>urn:smpte:ul:060e2b34.0401010d.03020201.00000000</r1:MCALabelDictionaryID>
+              <r1:MCALinkID>urn:uuid:8e293965-f8ad-48c6-971d-261b01f65cdb</r1:MCALinkID>
+              <r1:MCATagSymbol>sg51</r1:MCATagSymbol>
+              <r1:MCATagName>5.1</r1:MCATagName>
+              <r1:RFC5646SpokenLanguage>en-US</r1:RFC5646SpokenLanguage>
+            </r0:SoundfieldGroupLabelSubDescriptor>
+            <r0:AudioChannelLabelSubDescriptor>
+              <r1:InstanceID>urn:uuid:74e205d0-d145-42d2-8c49-7b55d058ca55</r1:InstanceID>
+              <r1:MCALabelDictionaryID>urn:smpte:ul:060e2b34.0401010d.03020101.00000000</r1:MCALabelDictionaryID>
+              <r1:MCALinkID>urn:uuid:ae8a9818-872a-4f86-8493-11dfdea03e09</r1:MCALinkID>
+              <r1:MCATagSymbol>chL</r1:MCATagSymbol>
+              <r1:MCATagName>Left</r1:MCATagName>
+              <r1:MCAChannelID>1</r1:MCAChannelID>
+              <r1:RFC5646SpokenLanguage>en-US</r1:RFC5646SpokenLanguage>
+              <r1:SoundfieldGroupLinkID>urn:uuid:8e293965-f8ad-48c6-971d-261b01f65cdb</r1:SoundfieldGroupLinkID>
+            </r0:AudioChannelLabelSubDescriptor>
+          </mca:MCASubDescriptors>
+        </meta:CompositionMetadataAsset>
       </AssetList>
     </Reel>
   </ReelList>
diff --git a/test/ref/DCP/dcp_test1/pkl_2b9b857f-ab4a-440e-a313-1ace0f1cfc95.xml b/test/ref/DCP/dcp_test1/pkl_2b9b857f-ab4a-440e-a313-1ace0f1cfc95.xml
new file mode 100644 (file)
index 0000000..ea99d11
--- /dev/null
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<PackingList xmlns="http://www.smpte-ra.org/schemas/429-8/2007/PKL">
+  <Id>urn:uuid:2b9b857f-ab4a-440e-a313-1ace0f1cfc95</Id>
+  <AnnotationText>Created by libdcp</AnnotationText>
+  <IssueDate>2012-07-17T04:45:18+00:00</IssueDate>
+  <Issuer>OpenDCP 0.0.25</Issuer>
+  <Creator>OpenDCP 0.0.25</Creator>
+  <AssetList>
+    <Asset>
+      <Id>urn:uuid:81fb54df-e1bf-4647-8788-ea7ba154375b</Id>
+      <AnnotationText>81fb54df-e1bf-4647-8788-ea7ba154375b</AnnotationText>
+      <Hash>xz+gUPoPMdbFlAewvWIq8BRhBmA=</Hash>
+      <Size>5082</Size>
+      <Type>text/xml</Type>
+    </Asset>
+    <Asset>
+      <Id>urn:uuid:1fab8bb0-cfaf-4225-ad6d-01768bc10470</Id>
+      <AnnotationText>1fab8bb0-cfaf-4225-ad6d-01768bc10470</AnnotationText>
+      <Hash>XGhFVrqZqapOJx5Fh2SLjj48Yjg=</Hash>
+      <Size>40144</Size>
+      <Type>application/mxf</Type>
+    </Asset>
+    <Asset>
+      <Id>urn:uuid:9482e87d-292d-4e0e-a98d-c61822b60fe9</Id>
+      <AnnotationText>9482e87d-292d-4e0e-a98d-c61822b60fe9</AnnotationText>
+      <Hash>qtXbkcwhUj/yqquVLmV+wbzbxQ8=</Hash>
+      <Size>881326</Size>
+      <Type>application/mxf</Type>
+    </Asset>
+  </AssetList>
+</PackingList>
diff --git a/test/ref/DCP/dcp_test1/pkl_63c3aece-c581-4603-b612-75e43f0c0430.xml b/test/ref/DCP/dcp_test1/pkl_63c3aece-c581-4603-b612-75e43f0c0430.xml
deleted file mode 100644 (file)
index 1280ed9..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<PackingList xmlns="http://www.smpte-ra.org/schemas/429-8/2007/PKL">
-  <Id>urn:uuid:63c3aece-c581-4603-b612-75e43f0c0430</Id>
-  <AnnotationText>Created by libdcp</AnnotationText>
-  <IssueDate>2012-07-17T04:45:18+00:00</IssueDate>
-  <Issuer>OpenDCP 0.0.25</Issuer>
-  <Creator>OpenDCP 0.0.25</Creator>
-  <AssetList>
-    <Asset>
-      <Id>urn:uuid:81fb54df-e1bf-4647-8788-ea7ba154375b</Id>
-      <AnnotationText>81fb54df-e1bf-4647-8788-ea7ba154375b</AnnotationText>
-      <Hash>jWh8hMgamta5Q9sW88wHfI7TS/I=</Hash>
-      <Size>2170</Size>
-      <Type>text/xml</Type>
-    </Asset>
-    <Asset>
-      <Id>urn:uuid:1fab8bb0-cfaf-4225-ad6d-01768bc10470</Id>
-      <AnnotationText>1fab8bb0-cfaf-4225-ad6d-01768bc10470</AnnotationText>
-      <Hash>XGhFVrqZqapOJx5Fh2SLjj48Yjg=</Hash>
-      <Size>40144</Size>
-      <Type>application/mxf</Type>
-    </Asset>
-    <Asset>
-      <Id>urn:uuid:9482e87d-292d-4e0e-a98d-c61822b60fe9</Id>
-      <AnnotationText>9482e87d-292d-4e0e-a98d-c61822b60fe9</AnnotationText>
-      <Hash>cb1OLhgHG9svy7G8hoTSPpltzhw=</Hash>
-      <Size>161326</Size>
-      <Type>application/mxf</Type>
-    </Asset>
-  </AssetList>
-</PackingList>
index 85222f75422a45a26a9dbecaa81a32c9bddc3e37..a0a42801aaa04e81c0bcc16f5cbbbf373fd387ab 100644 (file)
@@ -48,7 +48,7 @@
           <Path>audio.mxf</Path>
           <VolumeIndex>1</VolumeIndex>
           <Offset>0</Offset>
-          <Length>161326</Length>
+          <Length>881326</Length>
         </Chunk>
       </ChunkList>
     </Asset>
index b58ff4363322a83b00a121952d1b4517804ab0b7..0b5a4459d90c37cd6f23cbc64c383d62a6f4e05a 100644 (file)
Binary files a/test/ref/DCP/dcp_test7/audio.mxf and b/test/ref/DCP/dcp_test7/audio.mxf differ
index f78c3711022490ed1a6a4a24c8d9b137d8d72bbd..a9ff202bd1a6f053051932b77515a7b496565bce 100644 (file)
@@ -52,7 +52,7 @@
           <IntrinsicDuration>24</IntrinsicDuration>
           <EntryPoint>0</EntryPoint>
           <Duration>24</Duration>
-          <Hash>cb1OLhgHG9svy7G8hoTSPpltzhw=</Hash>
+          <Hash>qtXbkcwhUj/yqquVLmV+wbzbxQ8=</Hash>
         </MainSound>
       </AssetList>
     </Reel>
index ca2c865db410dac3529a5b55e53823596a95a526..919fe206bccd12b28fb17426e74b7c606f1f76d0 100644 (file)
@@ -9,7 +9,7 @@
     <Asset>
       <Id>urn:uuid:81fb54df-e1bf-4647-8788-ea7ba154375b</Id>
       <AnnotationText>81fb54df-e1bf-4647-8788-ea7ba154375b</AnnotationText>
-      <Hash>tc+MzIDj0cjUXzAGaE5mmse4DVM=</Hash>
+      <Hash>JxqfjtwuLuimdPydOWGY/Vgrzek=</Hash>
       <Size>2168</Size>
       <Type>text/xml;asdcpKind=CPL</Type>
     </Asset>
@@ -23,8 +23,8 @@
     <Asset>
       <Id>urn:uuid:9482e87d-292d-4e0e-a98d-c61822b60fe9</Id>
       <AnnotationText>9482e87d-292d-4e0e-a98d-c61822b60fe9</AnnotationText>
-      <Hash>cb1OLhgHG9svy7G8hoTSPpltzhw=</Hash>
-      <Size>161326</Size>
+      <Hash>qtXbkcwhUj/yqquVLmV+wbzbxQ8=</Hash>
+      <Size>881326</Size>
       <Type>application/x-smpte-mxf;asdcpKind=Sound</Type>
     </Asset>
   </AssetList>
index 38ff565edb8e46ca99fe8885f23b70be021be187..91ecfcf71592c11b0ec5a13b20b2c7ffde01a899 100644 (file)
@@ -280,7 +280,7 @@ simple_picture (boost::filesystem::path path, string suffix, int frames)
 shared_ptr<dcp::SoundAsset>
 simple_sound (boost::filesystem::path path, string suffix, dcp::MXFMetadata mxf_meta, string language, int frames, int sample_rate)
 {
-       int const channels = 1;
+       int const channels = 6;
 
        /* Set a valid language, then overwrite it, so that the language parameter can be badly formed */
        shared_ptr<dcp::SoundAsset> ms (new dcp::SoundAsset(dcp::Fraction(24, 1), sample_rate, channels, dcp::LanguageTag("en-US"), dcp::SMPTE));
@@ -332,6 +332,11 @@ make_simple (boost::filesystem::path path, int reels, int frames)
        cpl->set_content_version (
                dcp::ContentVersion("urn:uuid:75ac29aa-42ac-1234-ecae-49251abefd11", "content-version-label-text")
                );
+       cpl->set_main_sound_configuration("51/L,R,C,LFE,Ls,Rs");
+       cpl->set_main_sound_sample_rate(48000);
+       cpl->set_main_picture_stored_area(dcp::Size(1998, 1080));
+       cpl->set_main_picture_active_area(dcp::Size(1998, 1080));
+       cpl->set_version_number(1);
 
        for (int i = 0; i < reels; ++i) {
                string suffix = reels == 1 ? "" : dcp::String::compose("%1", i);
index 777339723de776c670c59018351b24ae8ebef057..fd76209bc2ee177e72fff245d895863ce8bb58b9 100644 (file)
@@ -67,7 +67,9 @@ using boost::optional;
 using std::shared_ptr;
 
 
-static list<pair<string, optional<boost::filesystem::path> > > stages;
+static list<pair<string, optional<boost::filesystem::path>>> stages;
+static string const dcp_test1_pkl = "pkl_2b9b857f-ab4a-440e-a313-1ace0f1cfc95.xml";
+static string const dcp_test1_cpl = "cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml";
 
 static void
 stage (string s, optional<boost::filesystem::path> p)
@@ -167,7 +169,6 @@ void
 check_verify_result (vector<boost::filesystem::path> dir, vector<std::pair<dcp::VerificationNote::Type, dcp::VerificationNote::Code>> types_and_codes)
 {
        auto notes = dcp::verify ({dir}, &stage, &progress, xsd_test);
-       dump_notes (notes);
        BOOST_REQUIRE_EQUAL (notes.size(), types_and_codes.size());
        auto i = notes.begin();
        auto j = types_and_codes.begin();
@@ -211,8 +212,8 @@ BOOST_AUTO_TEST_CASE (verify_test1)
        auto directories = setup (1, 1);
        auto notes = dcp::verify (directories, &stage, &progress, xsd_test);
 
-       boost::filesystem::path const cpl_file = "build/test/verify_test1/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml";
-       boost::filesystem::path const pkl_file = "build/test/verify_test1/pkl_63c3aece-c581-4603-b612-75e43f0c0430.xml";
+       boost::filesystem::path const cpl_file = boost::filesystem::path("build") / "test" / "verify_test1" / dcp_test1_cpl;
+       boost::filesystem::path const pkl_file = boost::filesystem::path("build") / "test" / "verify_test1" / dcp_test1_pkl;
        boost::filesystem::path const assetmap_file = "build/test/verify_test1/ASSETMAP.xml";
 
        auto st = stages.begin();
@@ -289,7 +290,7 @@ BOOST_AUTO_TEST_CASE (verify_test3)
        auto directories = setup (1, 3);
 
        {
-               Editor e ("build/test/verify_test3/pkl_63c3aece-c581-4603-b612-75e43f0c0430.xml");
+               Editor e (boost::filesystem::path("build") / "test" / "verify_test3" / dcp_test1_pkl);
                e.replace ("<Hash>", "<Hash>x");
        }
 
@@ -311,7 +312,7 @@ BOOST_AUTO_TEST_CASE (verify_test4)
        auto directories = setup (1, 4);
 
        {
-               Editor e ("build/test/verify_test4/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml");
+               Editor e (boost::filesystem::path("build") / "test" / "verify_test4" / dcp_test1_cpl);
                e.replace ("<ContentKind>", "<ContentKind>x");
        }
 
@@ -326,14 +327,14 @@ static
 boost::filesystem::path
 cpl (int n)
 {
-       return dcp::String::compose("build/test/verify_test%1/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml", n);
+       return dcp::String::compose("build/test/verify_test%1/%2", n, dcp_test1_cpl);
 }
 
 static
 boost::filesystem::path
 pkl (int n)
 {
-       return dcp::String::compose("build/test/verify_test%1/pkl_63c3aece-c581-4603-b612-75e43f0c0430.xml", n);
+       return dcp::String::compose("build/test/verify_test%1/%2", n, dcp_test1_pkl);
 }
 
 static
@@ -388,6 +389,10 @@ BOOST_AUTO_TEST_CASE (verify_test8)
                        8, &cpl,
                        "http://www.smpte-ra.org/schemas/429-7/2006/CPL", "http://www.digicine.com/PROTO-ASDCP-CPL-20040511#",
                        { dcp::VerificationNote::MISMATCHED_STANDARD,
+                         dcp::VerificationNote::XML_VALIDATION_ERROR,
+                         dcp::VerificationNote::XML_VALIDATION_ERROR,
+                         dcp::VerificationNote::XML_VALIDATION_ERROR,
+                         dcp::VerificationNote::XML_VALIDATION_ERROR,
                          dcp::VerificationNote::XML_VALIDATION_ERROR,
                          dcp::VerificationNote::CPL_HASH_INCORRECT }
                        );
@@ -420,7 +425,7 @@ BOOST_AUTO_TEST_CASE (verify_test11)
 {
        check_verify_result_after_replace (
                11, &pkl,
-               "<Id>urn:uuid:63c", "<Id>urn:uuid:x3c",
+               "<Id>urn:uuid:2b9", "<Id>urn:uuid:xb9",
                { dcp::VerificationNote::XML_VALIDATION_ERROR }
                );
 }
@@ -430,7 +435,7 @@ BOOST_AUTO_TEST_CASE (verify_test12)
 {
        check_verify_result_after_replace (
                12, &asset_map,
-               "<Id>urn:uuid:63c", "<Id>urn:uuid:x3c",
+               "<Id>urn:uuid:07e", "<Id>urn:uuid:x7e",
                { dcp::VerificationNote::XML_VALIDATION_ERROR }
                );
 }
@@ -442,8 +447,8 @@ BOOST_AUTO_TEST_CASE (verify_test13)
        auto directories = setup (3, 13);
        auto notes = dcp::verify (directories, &stage, &progress, xsd_test);
 
-       boost::filesystem::path const cpl_file = "build/test/verify_test13/cpl_cbfd2bc0-21cf-4a8f-95d8-9cddcbe51296.xml";
-       boost::filesystem::path const pkl_file = "build/test/verify_test13/pkl_d87a950c-bd6f-41f6-90cc-56ccd673e131.xml";
+       boost::filesystem::path const cpl_file = boost::filesystem::path("build") / "test" / "verify_test13" / "cpl_cbfd2bc0-21cf-4a8f-95d8-9cddcbe51296.xml";
+       boost::filesystem::path const pkl_file = boost::filesystem::path("build") / "test" / "verify_test13" / "pkl_d87a950c-bd6f-41f6-90cc-56ccd673e131.xml";
        boost::filesystem::path const assetmap_file = "build/test/verify_test13/ASSETMAP";
 
        auto st = stages.begin();
@@ -544,8 +549,10 @@ BOOST_AUTO_TEST_CASE (verify_test15)
 
        check_verify_result (
                { dir },
-               {{ dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::PICTURE_FRAME_TOO_LARGE_IN_BYTES }}
-               );
+               {
+                       { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::PICTURE_FRAME_TOO_LARGE_IN_BYTES },
+                       { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
+               });
 }
 
 
@@ -570,8 +577,10 @@ BOOST_AUTO_TEST_CASE (verify_test16)
 
        check_verify_result (
                { dir },
-               {{ dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::PICTURE_FRAME_NEARLY_TOO_LARGE_IN_BYTES }}
-               );
+               {
+                       { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::PICTURE_FRAME_NEARLY_TOO_LARGE_IN_BYTES },
+                       { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
+               });
 }
 
 
@@ -587,8 +596,7 @@ BOOST_AUTO_TEST_CASE (verify_test17)
        boost::filesystem::remove_all (dir);
        dcp_from_frame (frame, dir);
 
-       auto notes = dcp::verify ({dir}, &stage, &progress, xsd_test);
-       BOOST_REQUIRE_EQUAL (notes.size(), 0);
+       check_verify_result ({ dir }, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }});
 }
 
 
@@ -641,7 +649,7 @@ BOOST_AUTO_TEST_CASE (verify_test20)
        auto reel_asset = make_shared<dcp::ReelSubtitleAsset>(asset, dcp::Fraction(24, 1), 16 * 24, 0);
        write_dcp_with_single_asset (dir, reel_asset);
 
-       check_verify_result ({dir}, {});
+       check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }});
 }
 
 
@@ -660,7 +668,8 @@ BOOST_AUTO_TEST_CASE (verify_test21)
                {
                        { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::XML_VALIDATION_ERROR },
                        { dcp::VerificationNote::VERIFY_ERROR, dcp::VerificationNote::XML_VALIDATION_ERROR },
-                       { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_SUBTITLE_START_TIME }
+                       { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_SUBTITLE_START_TIME },
+                       { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
                });
 }
 
@@ -686,7 +695,10 @@ BOOST_AUTO_TEST_CASE (verify_test22)
 
        check_verify_result (
                { vf_dir },
-               {{ dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::EXTERNAL_ASSET }});
+               {
+                       { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::EXTERNAL_ASSET },
+                       { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
+               });
 }
 
 
@@ -716,7 +728,7 @@ BOOST_AUTO_TEST_CASE (verify_test23)
        dcp.add (cpl);
        dcp.write_xml (dcp::SMPTE);
 
-       check_verify_result ({dir}, {});
+       check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }});
 }
 
 
@@ -747,6 +759,7 @@ BOOST_AUTO_TEST_CASE (verify_test24)
        cpl->set_main_sound_sample_rate (48000);
        cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
        cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
+       cpl->set_version_number (1);
 
        reel->add (simple_markers());
 
@@ -815,7 +828,7 @@ BOOST_AUTO_TEST_CASE (verify_test26)
        write_dcp_with_single_asset (dir, reel_asset);
 
        auto notes = dcp::verify ({dir}, &stage, &progress, xsd_test);
-       BOOST_REQUIRE_EQUAL (notes.size(), 2U);
+       BOOST_REQUIRE_EQUAL (notes.size(), 3U);
        auto i = notes.begin();
        BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::BAD_LANGUAGE);
        BOOST_REQUIRE (i->note());
@@ -824,6 +837,8 @@ BOOST_AUTO_TEST_CASE (verify_test26)
        BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::BAD_LANGUAGE);
        BOOST_REQUIRE (i->note());
        BOOST_CHECK_EQUAL (*i->note(), "wrong-andbad");
+       i++;
+       BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::MISSING_CPL_METADATA);
 }
 
 
@@ -841,7 +856,7 @@ BOOST_AUTO_TEST_CASE (verify_invalid_closed_caption_languages)
        write_dcp_with_single_asset (dir, reel_asset);
 
        auto notes = dcp::verify ({dir}, &stage, &progress, xsd_test);
-       BOOST_REQUIRE_EQUAL (notes.size(), 2U);
+       BOOST_REQUIRE_EQUAL (notes.size(), 3U);
        auto i = notes.begin ();
        BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::BAD_LANGUAGE);
        BOOST_REQUIRE (i->note());
@@ -850,6 +865,8 @@ BOOST_AUTO_TEST_CASE (verify_invalid_closed_caption_languages)
        BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::BAD_LANGUAGE);
        BOOST_REQUIRE (i->note());
        BOOST_CHECK_EQUAL (*i->note(), "wrong-andbad");
+       i++;
+       BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::MISSING_CPL_METADATA);
 }
 
 
@@ -878,6 +895,7 @@ BOOST_AUTO_TEST_CASE (verify_various_invalid_languages)
        cpl->set_main_sound_sample_rate (48000);
        cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
        cpl->set_main_picture_active_area (dcp::Size(1440, 1080));
+       cpl->set_version_number (1);
        cpl->_release_territory = "fred-jim";
        auto dcp = make_shared<dcp::DCP>(dir);
        dcp->add (cpl);
@@ -901,7 +919,6 @@ BOOST_AUTO_TEST_CASE (verify_various_invalid_languages)
        BOOST_CHECK_EQUAL (i->code(), dcp::VerificationNote::BAD_LANGUAGE);
        BOOST_REQUIRE (i->note());
        BOOST_CHECK_EQUAL (*i->note(), "frobozz");
-       ++i;
 }
 
 
@@ -935,6 +952,11 @@ check_picture_size (int width, int height, int frame_rate, bool three_d)
        auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::TRAILER);
        cpl->set_annotation_text ("A Test DCP");
        cpl->set_issue_date ("2012-07-17T04:45:18+00:00");
+       cpl->set_main_sound_configuration ("L,C,R,Lfe,-,-");
+       cpl->set_main_sound_sample_rate (48000);
+       cpl->set_main_picture_stored_area (dcp::Size(1998, 1080));
+       cpl->set_main_picture_active_area (dcp::Size(1998, 1080));
+       cpl->set_version_number (1);
 
        auto reel = make_shared<dcp::Reel>();
 
@@ -1096,7 +1118,8 @@ BOOST_AUTO_TEST_CASE (verify_closed_caption_xml_too_large)
                {
                        { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_SUBTITLE_START_TIME },
                        { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::CLOSED_CAPTION_XML_TOO_LARGE_IN_BYTES },
-                       { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::FIRST_TEXT_TOO_EARLY }
+                       { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::FIRST_TEXT_TOO_EARLY },
+                       { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA },
                });
 }
 
@@ -1135,7 +1158,8 @@ verify_timed_text_asset_too_large (string name)
                        { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::TIMED_TEXT_ASSET_TOO_LARGE_IN_BYTES },
                        { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::TIMED_TEXT_FONTS_TOO_LARGE_IN_BYTES },
                        { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_SUBTITLE_START_TIME },
-                       { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::FIRST_TEXT_TOO_EARLY }
+                       { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::FIRST_TEXT_TOO_EARLY },
+                       { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA },
                });
 }
 
@@ -1367,7 +1391,11 @@ BOOST_AUTO_TEST_CASE (verify_text_too_early)
        dcp_with_text<dcp::ReelSubtitleAsset> (dir, {{ 4 * 24 - 1, 5 * 24 }});
        check_verify_result (
                { dir },
-               {{ dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::FIRST_TEXT_TOO_EARLY }});
+               {
+                       { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::FIRST_TEXT_TOO_EARLY },
+                       { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
+               });
+
 }
 
 
@@ -1376,8 +1404,7 @@ BOOST_AUTO_TEST_CASE (verify_text_not_too_early)
        auto const dir = boost::filesystem::path("build/test/verify_text_not_too_early");
        /* Just late enough */
        dcp_with_text<dcp::ReelSubtitleAsset> (dir, {{ 4 * 24, 5 * 24 }});
-       auto notes = dcp::verify ({dir}, &stage, &progress, xsd_test);
-       BOOST_REQUIRE (notes.empty());
+       check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }});
 }
 
 
@@ -1419,8 +1446,7 @@ BOOST_AUTO_TEST_CASE (verify_text_early_on_second_reel)
        dcp->add (cpl);
        dcp->write_xml (dcp::SMPTE);
 
-       auto notes = dcp::verify ({dir}, &stage, &progress, xsd_test);
-       BOOST_REQUIRE (notes.empty());
+       check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }});
 }
 
 
@@ -1433,7 +1459,12 @@ BOOST_AUTO_TEST_CASE (verify_text_too_close)
                        { 4 * 24,     5 * 24 },
                        { 5 * 24 + 1, 6 * 24 },
                });
-       check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::SUBTITLE_TOO_CLOSE }});
+       check_verify_result (
+               {dir},
+               {
+                       { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::SUBTITLE_TOO_CLOSE },
+                       { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
+               });
 }
 
 
@@ -1446,8 +1477,7 @@ BOOST_AUTO_TEST_CASE (verify_text_not_too_close)
                        { 4 * 24,      5 * 24 },
                        { 5 * 24 + 16, 8 * 24 },
                });
-       auto notes = dcp::verify ({dir}, &stage, &progress, xsd_test);
-       BOOST_REQUIRE (notes.empty());
+       check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }});
 }
 
 
@@ -1455,7 +1485,12 @@ BOOST_AUTO_TEST_CASE (verify_text_too_short)
 {
        auto const dir = boost::filesystem::path("build/test/verify_text_too_short");
        dcp_with_text<dcp::ReelSubtitleAsset> (dir, {{ 4 * 24, 4 * 24 + 1 }});
-       check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::SUBTITLE_TOO_SHORT }});
+       check_verify_result (
+               {dir},
+               {
+                       { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::SUBTITLE_TOO_SHORT },
+                       { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
+               });
 }
 
 
@@ -1463,8 +1498,7 @@ BOOST_AUTO_TEST_CASE (verify_text_not_too_short)
 {
        auto const dir = boost::filesystem::path("build/test/verify_text_not_too_short");
        dcp_with_text<dcp::ReelSubtitleAsset> (dir, {{ 4 * 24, 4 * 24 + 17 }});
-       auto notes = dcp::verify ({dir}, &stage, &progress, xsd_test);
-       BOOST_REQUIRE (notes.empty());
+       check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }});
 }
 
 
@@ -1479,7 +1513,12 @@ BOOST_AUTO_TEST_CASE (verify_too_many_subtitle_lines1)
                        { 96, 200, 0.2, "four" },
                        { 96, 200, 0.3, "lines" }
                });
-       check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::TOO_MANY_SUBTITLE_LINES}});
+       check_verify_result (
+               {dir},
+               {
+                       { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::TOO_MANY_SUBTITLE_LINES },
+                       { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
+               });
 }
 
 
@@ -1493,8 +1532,7 @@ BOOST_AUTO_TEST_CASE (verify_not_too_many_subtitle_lines1)
                        { 96, 200, 0.1, "have" },
                        { 96, 200, 0.2, "four" },
                });
-       auto notes = dcp::verify ({dir}, &stage, &progress, xsd_test);
-       BOOST_REQUIRE (notes.empty());
+       check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }});
 }
 
 
@@ -1509,7 +1547,12 @@ BOOST_AUTO_TEST_CASE (verify_too_many_subtitle_lines2)
                        { 150, 180, 0.2, "four" },
                        { 150, 180, 0.3, "lines" }
                });
-       check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::TOO_MANY_SUBTITLE_LINES}});
+       check_verify_result (
+               {dir},
+               {
+                       { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::TOO_MANY_SUBTITLE_LINES },
+                       { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
+               });
 }
 
 
@@ -1524,8 +1567,7 @@ BOOST_AUTO_TEST_CASE (verify_not_too_many_subtitle_lines2)
                        { 150, 180, 0.2, "four" },
                        { 190, 250, 0.3, "lines" }
                });
-       auto notes = dcp::verify ({dir}, &stage, &progress, xsd_test);
-       BOOST_REQUIRE (notes.empty());
+       check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }});
 }
 
 
@@ -1537,7 +1579,12 @@ BOOST_AUTO_TEST_CASE (verify_subtitle_lines_too_long1)
                {
                        { 96, 300, 0.0, "012345678901234567890123456789012345678901234567890123" }
                });
-       check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::SUBTITLE_LINE_LONGER_THAN_RECOMMENDED }});
+       check_verify_result (
+               {dir},
+               {
+                       { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::SUBTITLE_LINE_LONGER_THAN_RECOMMENDED },
+                       { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
+               });
 }
 
 
@@ -1549,7 +1596,12 @@ BOOST_AUTO_TEST_CASE (verify_subtitle_lines_too_long2)
                {
                        { 96, 300, 0.0, "012345678901234567890123456789012345678901234567890123456789012345678901234567890" }
                });
-       check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::SUBTITLE_LINE_TOO_LONG }});
+       check_verify_result (
+               {dir},
+               {
+                       { dcp::VerificationNote::VERIFY_WARNING, dcp::VerificationNote::SUBTITLE_LINE_TOO_LONG },
+                       { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
+               });
 }
 
 
@@ -1564,7 +1616,12 @@ BOOST_AUTO_TEST_CASE (verify_too_many_closed_caption_lines1)
                        { 96, 200, 0.2, "four" },
                        { 96, 200, 0.3, "lines" }
                });
-       check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::TOO_MANY_CLOSED_CAPTION_LINES}});
+       check_verify_result (
+               {dir},
+               {
+                       { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::TOO_MANY_CLOSED_CAPTION_LINES},
+                       { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
+               });
 }
 
 
@@ -1578,8 +1635,7 @@ BOOST_AUTO_TEST_CASE (verify_not_too_many_closed_caption_lines1)
                        { 96, 200, 0.1, "have" },
                        { 96, 200, 0.2, "four" },
                });
-       auto notes = dcp::verify ({dir}, &stage, &progress, xsd_test);
-       BOOST_REQUIRE (notes.empty());
+       check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }});
 }
 
 
@@ -1594,7 +1650,12 @@ BOOST_AUTO_TEST_CASE (verify_too_many_closed_caption_lines2)
                        { 150, 180, 0.2, "four" },
                        { 150, 180, 0.3, "lines" }
                });
-       check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::TOO_MANY_CLOSED_CAPTION_LINES}});
+       check_verify_result (
+               {dir},
+               {
+                       { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::TOO_MANY_CLOSED_CAPTION_LINES},
+                       { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
+               });
 }
 
 
@@ -1609,8 +1670,7 @@ BOOST_AUTO_TEST_CASE (verify_not_too_many_closed_caption_lines2)
                        { 150, 180, 0.2, "four" },
                        { 190, 250, 0.3, "lines" }
                });
-       auto notes = dcp::verify ({dir}, &stage, &progress, xsd_test);
-       BOOST_REQUIRE (notes.empty());
+       check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }});
 }
 
 
@@ -1622,7 +1682,12 @@ BOOST_AUTO_TEST_CASE (verify_closed_caption_lines_too_long1)
                {
                        { 96, 300, 0.0, "0123456789012345678901234567890123" }
                });
-       check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::CLOSED_CAPTION_LINE_TOO_LONG }});
+       check_verify_result (
+               {dir},
+               {
+                       { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::CLOSED_CAPTION_LINE_TOO_LONG },
+                       { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
+               });
 }
 
 
@@ -1645,7 +1710,12 @@ BOOST_AUTO_TEST_CASE (verify_sound_sampling_rate_must_be_48k)
        dcp->add (cpl);
        dcp->write_xml (dcp::SMPTE);
 
-       check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::INVALID_SOUND_FRAME_RATE }});
+       check_verify_result (
+               {dir},
+               {
+                       { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::INVALID_SOUND_FRAME_RATE },
+                       { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
+               });
 }
 
 
@@ -1715,7 +1785,12 @@ BOOST_AUTO_TEST_CASE (verify_reel_assets_durations_must_match)
        dcp->add (cpl);
        dcp->write_xml (dcp::SMPTE);
 
-       check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISMATCHED_ASSET_DURATION }});
+       check_verify_result (
+               {dir},
+               {
+                       { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISMATCHED_ASSET_DURATION },
+                       { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
+               });
 }
 
 
@@ -1776,21 +1851,25 @@ 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}});
+               check_verify_result (
+                       { dir },
+                       {
+                               { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MAIN_SUBTITLE_NOT_IN_ALL_REELS },
+                               { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
+                       });
+
        }
 
        {
                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());
+               check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }});
        }
 
        {
                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());
+               check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }});
        }
 }
 
@@ -1851,21 +1930,24 @@ 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 }});
+               check_verify_result (
+                       {dir},
+                       {
+                               { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::CLOSED_CAPTION_ASSET_COUNTS_DIFFER },
+                               { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
+                       });
        }
 
        {
                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());
+               check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }});
        }
 
        {
                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());
+               check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }});
        }
 }
 
@@ -1901,7 +1983,12 @@ verify_text_entry_point_check (boost::filesystem::path dir, dcp::VerificationNot
        dcp->add (cpl);
        dcp->write_xml (dcp::SMPTE);
 
-       check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, code }});
+       check_verify_result (
+               {dir},
+               {
+                       { dcp::VerificationNote::VERIFY_BV21_ERROR, code },
+                       { dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA }
+               });
 }
 
 
@@ -1953,7 +2040,7 @@ BOOST_AUTO_TEST_CASE (verify_assets_must_have_hashes)
        {
                BOOST_REQUIRE (dcp->cpls()[0]->file());
                Editor e(dcp->cpls()[0]->file().get());
-               e.replace("<Hash>cb1OLhgHG9svy7G8hoTSPpltzhw=</Hash>", "");
+               e.replace("<Hash>XGhFVrqZqapOJx5Fh2SLjj48Yjg=</Hash>", "");
        }
 
        check_verify_result (
@@ -2067,3 +2154,14 @@ BOOST_AUTO_TEST_CASE (verify_markers)
                });
 }
 
+
+BOOST_AUTO_TEST_CASE (verify_cpl_metadata_version)
+{
+       boost::filesystem::path dir = "build/test/verify_cpl_metadata_version";
+       prepare_directory (dir);
+       auto dcp = make_simple (dir);
+       dcp->cpls()[0]->unset_version_number();
+       dcp->write_xml (dcp::SMPTE);
+       check_verify_result ({dir}, {{ dcp::VerificationNote::VERIFY_BV21_ERROR, dcp::VerificationNote::MISSING_CPL_METADATA_VERSION_NUMBER }});
+}
+