Reduce test flakyness a bit.
[libdcp.git] / test / verify_test.cc
index 78e264a73c09c2ac99ff05c9cfc7f0fa8f9fb388..dd95ef6ecf1c5890d3c310c303fa0e1c301fd53e 100644 (file)
 #include "openjpeg_image.h"
 #include "raw_convert.h"
 #include "reel.h"
-#include "reel_closed_caption_asset.h"
+#include "reel_interop_closed_caption_asset.h"
 #include "reel_interop_subtitle_asset.h"
 #include "reel_markers_asset.h"
 #include "reel_mono_picture_asset.h"
 #include "reel_sound_asset.h"
 #include "reel_stereo_picture_asset.h"
+#include "reel_smpte_closed_caption_asset.h"
 #include "reel_smpte_subtitle_asset.h"
 #include "smpte_subtitle_asset.h"
 #include "stereo_picture_asset.h"
@@ -60,6 +61,7 @@
 #include <cstdio>
 #include <iostream>
 
+
 using std::list;
 using std::pair;
 using std::string;
@@ -72,13 +74,25 @@ using std::shared_ptr;
 
 
 static list<pair<string, optional<path>>> stages;
-static string const dcp_test1_pkl_id = "6af1e0c1-c441-47f8-a502-3efd46b1fa4f";
-static string const dcp_test1_pkl = "pkl_" + dcp_test1_pkl_id + ".xml";
-static string const dcp_test1_cpl_id = "81fb54df-e1bf-4647-8788-ea7ba154375b";
-static string const dcp_test1_cpl = "cpl_" + dcp_test1_cpl_id + ".xml";
+
+static string filename_to_id(boost::filesystem::path path)
+{
+       return path.string().substr(4, path.string().length() - 8);
+}
+
+static boost::filesystem::path const dcp_test1_pkl = find_file("test/ref/DCP/dcp_test1", "pkl_").filename();
+static string const dcp_test1_pkl_id = filename_to_id(dcp_test1_pkl);
+
+static boost::filesystem::path const dcp_test1_cpl = find_file("test/ref/DCP/dcp_test1", "cpl_").filename();
+static string const dcp_test1_cpl_id = filename_to_id(dcp_test1_cpl);
+
 static string const dcp_test1_asset_map_id = "5d51e8a1-b2a5-4da6-9b66-4615c3609440";
-static string const encryption_test_cpl_id = "81fb54df-e1bf-4647-8788-ea7ba154375b";
-static string const encryption_test_pkl_id = "627ad740-ae36-4c49-92bb-553a9f09c4f8";
+
+static boost::filesystem::path const encryption_test_cpl = find_file("test/ref/DCP/encryption_test", "cpl_").filename();
+static string const encryption_test_cpl_id = filename_to_id(encryption_test_cpl);
+
+static boost::filesystem::path const encryption_test_pkl = find_file("test/ref/DCP/encryption_test", "pkl_").filename();
+static string const encryption_test_pkl_id = filename_to_id(encryption_test_pkl);
 
 static void
 stage (string s, optional<path> p)
@@ -122,12 +136,11 @@ write_dcp_with_single_asset (path dir, shared_ptr<dcp::ReelAsset> reel_asset, dc
        reel->add (reel_asset);
        reel->add (simple_markers());
 
-       auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER);
+       auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, standard);
        cpl->add (reel);
        auto dcp = make_shared<dcp::DCP>(dir);
        dcp->add (cpl);
        dcp->write_xml (
-               standard,
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::LocalTime().as_string(),
@@ -165,6 +178,23 @@ public:
                BOOST_REQUIRE (_content != old_content);
        }
 
+       void delete_first_line_containing (string s)
+       {
+               vector<string> lines;
+               boost::algorithm::split (lines, _content, boost::is_any_of("\r\n"), boost::token_compress_on);
+               auto old_content = _content;
+               _content = "";
+               bool done = false;
+               for (auto i: lines) {
+                       if (i.find(s) == string::npos || done) {
+                               _content += i + "\n";
+                       } else {
+                               done = true;
+                       }
+               }
+               BOOST_REQUIRE (_content != old_content);
+       }
+
        void delete_lines (string from, string to)
        {
                vector<string> lines;
@@ -192,7 +222,7 @@ private:
 };
 
 
-#if 0
+LIBDCP_DISABLE_WARNINGS
 static
 void
 dump_notes (vector<dcp::VerificationNote> const & notes)
@@ -201,7 +231,7 @@ dump_notes (vector<dcp::VerificationNote> const & notes)
                std::cout << dcp::note_to_string(i) << "\n";
        }
 }
-#endif
+LIBDCP_ENABLE_WARNINGS
 
 
 static
@@ -210,6 +240,8 @@ check_verify_result (vector<path> dir, vector<dcp::VerificationNote> test_notes)
 {
        auto notes = dcp::verify ({dir}, &stage, &progress, xsd_test);
        BOOST_REQUIRE_EQUAL (notes.size(), test_notes.size());
+       std::sort (notes.begin(), notes.end());
+       std::sort (test_notes.begin(), test_notes.end());
        for (auto i = 0U; i < notes.size(); ++i) {
                BOOST_REQUIRE_EQUAL (notes[i], test_notes[i]);
        }
@@ -340,9 +372,9 @@ BOOST_AUTO_TEST_CASE (verify_mismatched_picture_sound_hashes)
                        { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, dcp_test1_cpl_id, canonical(dir / dcp_test1_cpl) },
                        { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_PICTURE_HASHES, canonical(dir / "video.mxf") },
                        { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_SOUND_HASHES, canonical(dir / "audio.mxf") },
-                       { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, "value 'xSEEi70vx1WQs67bmu2zKvzIkXvY=' is invalid Base64-encoded binary", canonical(dir / dcp_test1_pkl), 12 },
-                       { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, "value 'xaddO7je2lZSNQp55qjCWo5DLKFQ=' is invalid Base64-encoded binary", canonical(dir / dcp_test1_pkl), 19 },
-                       { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, "value 'xWU0/u1wM17y7Kriq06+65/ViX1o=' is invalid Base64-encoded binary", canonical(dir / dcp_test1_pkl), 26 }
+                       { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, "value 'xD9HpNAjKsECGtJEWtwV2/T5ndG8=' is invalid Base64-encoded binary", canonical(dir / dcp_test1_pkl), 26 },
+                       { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, "value 'xgVKhC9IkWyzQbgzpFcJ1bpqbtwk=' is invalid Base64-encoded binary", canonical(dir / dcp_test1_pkl), 19 },
+                       { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::INVALID_XML, "value 'xz/y4fI+ocWzVB7cr8pVt2OYpOHA=' is invalid Base64-encoded binary", canonical(dir / dcp_test1_pkl), 12 }
                });
 }
 
@@ -705,6 +737,7 @@ BOOST_AUTO_TEST_CASE (verify_invalid_smpte_subtitles)
 
        path const dir("build/test/verify_invalid_smpte_subtitles");
        prepare_directory (dir);
+       /* This broken_smpte.mxf does not use urn:uuid: for its subtitle ID, which we tolerate (rightly or wrongly) */
        copy_file ("test/data/broken_smpte.mxf", dir / "subs.mxf");
        auto asset = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.mxf");
        auto reel_asset = make_shared<dcp::ReelSMPTESubtitleAsset>(asset, dcp::Fraction(24, 1), 6046, 0);
@@ -770,7 +803,7 @@ BOOST_AUTO_TEST_CASE (verify_valid_cpl_metadata)
        reel->add (make_shared<dcp::ReelMonoPictureAsset>(simple_picture(dir, "", 16 * 24), 0));
        reel->add (simple_markers(16 * 24));
 
-       auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER);
+       auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
        cpl->add (reel);
        cpl->set_main_sound_configuration ("L,C,R,Lfe,-,-");
        cpl->set_main_sound_sample_rate (48000);
@@ -781,7 +814,6 @@ BOOST_AUTO_TEST_CASE (verify_valid_cpl_metadata)
        dcp::DCP dcp (dir);
        dcp.add (cpl);
        dcp.write_xml (
-               dcp::Standard::SMPTE,
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::LocalTime().as_string(),
@@ -813,7 +845,7 @@ BOOST_AUTO_TEST_CASE (verify_invalid_cpl_metadata_bad_tag)
 
        auto reel = make_shared<dcp::Reel>();
        reel->add (black_picture_asset(dir));
-       auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER);
+       auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
        cpl->add (reel);
        cpl->set_main_sound_configuration ("L,C,R,Lfe,-,-");
        cpl->set_main_sound_sample_rate (48000);
@@ -826,7 +858,6 @@ BOOST_AUTO_TEST_CASE (verify_invalid_cpl_metadata_bad_tag)
        dcp::DCP dcp (dir);
        dcp.add (cpl);
        dcp.write_xml (
-               dcp::Standard::SMPTE,
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::LocalTime().as_string(),
@@ -868,7 +899,7 @@ BOOST_AUTO_TEST_CASE (verify_invalid_cpl_metadata_missing_tag)
 
        auto reel = make_shared<dcp::Reel>();
        reel->add (black_picture_asset(dir));
-       auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER);
+       auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
        cpl->add (reel);
        cpl->set_main_sound_configuration ("L,C,R,Lfe,-,-");
        cpl->set_main_sound_sample_rate (48000);
@@ -878,7 +909,6 @@ BOOST_AUTO_TEST_CASE (verify_invalid_cpl_metadata_missing_tag)
        dcp::DCP dcp (dir);
        dcp.add (cpl);
        dcp.write_xml (
-               dcp::Standard::SMPTE,
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::LocalTime().as_string(),
@@ -928,7 +958,7 @@ BOOST_AUTO_TEST_CASE (verify_invalid_language2)
        auto asset = make_shared<dcp::SMPTESubtitleAsset>(dir / "subs.mxf");
        asset->_language = "wrong-andbad";
        asset->write (dir / "subs.mxf");
-       auto reel_asset = make_shared<dcp::ReelClosedCaptionAsset>(asset, dcp::Fraction(24, 1), 6046, 0);
+       auto reel_asset = make_shared<dcp::ReelSMPTEClosedCaptionAsset>(asset, dcp::Fraction(24, 1), 6046, 0);
        reel_asset->_language = "badlang";
        auto cpl = write_dcp_with_single_asset (dir, reel_asset);
 
@@ -959,7 +989,7 @@ BOOST_AUTO_TEST_CASE (verify_invalid_language3)
        reel->add (reel_sound);
        reel->add (simple_markers());
 
-       auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER);
+       auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
        cpl->add (reel);
        cpl->_additional_subtitle_languages.push_back("this-is-wrong");
        cpl->_additional_subtitle_languages.push_back("andso-is-this");
@@ -972,7 +1002,6 @@ BOOST_AUTO_TEST_CASE (verify_invalid_language3)
        auto dcp = make_shared<dcp::DCP>(dir);
        dcp->add (cpl);
        dcp->write_xml (
-               dcp::Standard::SMPTE,
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::LocalTime().as_string(),
@@ -1016,7 +1045,7 @@ check_picture_size (int width, int height, int frame_rate, bool three_d)
        picture_writer->finalize ();
 
        auto d = make_shared<dcp::DCP>(dcp_path);
-       auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER);
+       auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
        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,-,-");
@@ -1039,7 +1068,6 @@ check_picture_size (int width, int height, int frame_rate, bool three_d)
 
        d->add (cpl);
        d->write_xml (
-               dcp::Standard::SMPTE,
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::LocalTime().as_string(),
@@ -1182,7 +1210,7 @@ BOOST_AUTO_TEST_CASE (verify_invalid_closed_caption_xml_size_in_bytes)
        }
        asset->set_language (dcp::LanguageTag("de-DE"));
        asset->write (dir / "subs.mxf");
-       auto reel_asset = make_shared<dcp::ReelClosedCaptionAsset>(asset, dcp::Fraction(24, 1), 49148, 0);
+       auto reel_asset = make_shared<dcp::ReelSMPTEClosedCaptionAsset>(asset, dcp::Fraction(24, 1), 49148, 0);
        auto cpl = write_dcp_with_single_asset (dir, reel_asset);
 
        check_verify_result (
@@ -1244,7 +1272,7 @@ verify_timed_text_asset_too_large (string name)
 BOOST_AUTO_TEST_CASE (verify_subtitle_asset_too_large)
 {
        verify_timed_text_asset_too_large<dcp::ReelSMPTESubtitleAsset>("verify_subtitle_asset_too_large");
-       verify_timed_text_asset_too_large<dcp::ReelClosedCaptionAsset>("verify_closed_caption_asset_too_large");
+       verify_timed_text_asset_too_large<dcp::ReelSMPTEClosedCaptionAsset>("verify_closed_caption_asset_too_large");
 }
 
 
@@ -1283,9 +1311,8 @@ BOOST_AUTO_TEST_CASE (verify_missing_subtitle_language)
        subs->write (dir / "subs.mxf");
 
        auto reel_subs = make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), 106, 0);
-       dcp->cpls().front()->reels().front()->add(reel_subs);
+       dcp->cpls()[0]->reels()[0]->add(reel_subs);
        dcp->write_xml (
-               dcp::Standard::SMPTE,
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::LocalTime().as_string(),
@@ -1327,7 +1354,6 @@ BOOST_AUTO_TEST_CASE (verify_mismatched_subtitle_languages)
        }
 
        dcp->write_xml (
-               dcp::Standard::SMPTE,
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::LocalTime().as_string(),
@@ -1356,7 +1382,7 @@ BOOST_AUTO_TEST_CASE (verify_multiple_closed_caption_languages_allowed)
                ccaps->set_language (dcp::LanguageTag("de-DE"));
                ccaps->add (simple_subtitle());
                ccaps->write (path / "subs1.mxf");
-               auto reel_ccaps = make_shared<dcp::ReelClosedCaptionAsset>(ccaps, dcp::Fraction(24, 1), reel_length, 0);
+               auto reel_ccaps = make_shared<dcp::ReelSMPTEClosedCaptionAsset>(ccaps, dcp::Fraction(24, 1), reel_length, 0);
                cpl->reels()[0]->add(reel_ccaps);
        }
 
@@ -1365,12 +1391,11 @@ BOOST_AUTO_TEST_CASE (verify_multiple_closed_caption_languages_allowed)
                ccaps->set_language (dcp::LanguageTag("en-US"));
                ccaps->add (simple_subtitle());
                ccaps->write (path / "subs2.mxf");
-               auto reel_ccaps = make_shared<dcp::ReelClosedCaptionAsset>(ccaps, dcp::Fraction(24, 1), reel_length, 0);
+               auto reel_ccaps = make_shared<dcp::ReelSMPTEClosedCaptionAsset>(ccaps, dcp::Fraction(24, 1), reel_length, 0);
                cpl->reels()[1]->add(reel_ccaps);
        }
 
        dcp->write_xml (
-               dcp::Standard::SMPTE,
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::LocalTime().as_string(),
@@ -1421,9 +1446,8 @@ BOOST_AUTO_TEST_CASE (verify_missing_subtitle_start_time)
        subs->write (dir / "subs.mxf");
 
        auto reel_subs = make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), 106, 0);
-       dcp->cpls().front()->reels().front()->add(reel_subs);
+       dcp->cpls()[0]->reels()[0]->add(reel_subs);
        dcp->write_xml (
-               dcp::Standard::SMPTE,
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::LocalTime().as_string(),
@@ -1477,7 +1501,6 @@ BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_start_time)
        auto reel_subs = make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), 106, 0);
        dcp->cpls().front()->reels().front()->add(reel_subs);
        dcp->write_xml (
-               dcp::Standard::SMPTE,
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::LocalTime().as_string(),
@@ -1583,13 +1606,12 @@ BOOST_AUTO_TEST_CASE (verify_valid_subtitle_first_text_time_on_second_reel)
        markers2->set (dcp::Marker::LFOC, dcp::Time(4 * 24 - 1, 24, 24));
        reel2->add (markers2);
 
-       auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER);
+       auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
        cpl->add (reel1);
        cpl->add (reel2);
        auto dcp = make_shared<dcp::DCP>(dir);
        dcp->add (cpl);
        dcp->write_xml (
-               dcp::Standard::SMPTE,
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::LocalTime().as_string(),
@@ -1783,7 +1805,7 @@ BOOST_AUTO_TEST_CASE (verify_invalid_subtitle_line_length2)
 BOOST_AUTO_TEST_CASE (verify_valid_closed_caption_line_count1)
 {
        auto const dir = path ("build/test/verify_valid_closed_caption_line_count1");
-       auto cpl = dcp_with_text<dcp::ReelClosedCaptionAsset> (
+       auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
                dir,
                {
                        { 96, 200, 0.0, "We" },
@@ -1803,7 +1825,7 @@ BOOST_AUTO_TEST_CASE (verify_valid_closed_caption_line_count1)
 BOOST_AUTO_TEST_CASE (verify_valid_closed_caption_line_count2)
 {
        auto const dir = path ("build/test/verify_valid_closed_caption_line_count2");
-       auto cpl = dcp_with_text<dcp::ReelClosedCaptionAsset> (
+       auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
                dir,
                {
                        { 96, 200, 0.0, "We" },
@@ -1817,7 +1839,7 @@ BOOST_AUTO_TEST_CASE (verify_valid_closed_caption_line_count2)
 BOOST_AUTO_TEST_CASE (verify_invalid_closed_caption_line_count3)
 {
        auto const dir = path ("build/test/verify_invalid_closed_caption_line_count3");
-       auto cpl = dcp_with_text<dcp::ReelClosedCaptionAsset> (
+       auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
                dir,
                {
                        { 96, 300, 0.0, "We" },
@@ -1837,7 +1859,7 @@ BOOST_AUTO_TEST_CASE (verify_invalid_closed_caption_line_count3)
 BOOST_AUTO_TEST_CASE (verify_valid_closed_caption_line_count4)
 {
        auto const dir = path ("build/test/verify_valid_closed_caption_line_count4");
-       auto cpl = dcp_with_text<dcp::ReelClosedCaptionAsset> (
+       auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
                dir,
                {
                        { 96, 300, 0.0, "We" },
@@ -1852,7 +1874,7 @@ BOOST_AUTO_TEST_CASE (verify_valid_closed_caption_line_count4)
 BOOST_AUTO_TEST_CASE (verify_invalid_closed_caption_line_length)
 {
        auto const dir = path ("build/test/verify_invalid_closed_caption_line_length");
-       auto cpl = dcp_with_text<dcp::ReelClosedCaptionAsset> (
+       auto cpl = dcp_with_text<dcp::ReelSMPTEClosedCaptionAsset> (
                dir,
                {
                        { 96, 300, 0.0, "0123456789012345678901234567890123" }
@@ -1879,12 +1901,11 @@ BOOST_AUTO_TEST_CASE (verify_invalid_sound_frame_rate)
        auto reel_sound = make_shared<dcp::ReelSoundAsset>(sound, 0);
        reel->add (reel_sound);
        reel->add (simple_markers());
-       auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER);
+       auto cpl = make_shared<dcp::CPL>("hello", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
        cpl->add (reel);
        auto dcp = make_shared<dcp::DCP>(dir);
        dcp->add (cpl);
        dcp->write_xml (
-               dcp::Standard::SMPTE,
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::LocalTime().as_string(),
@@ -1905,7 +1926,6 @@ BOOST_AUTO_TEST_CASE (verify_missing_cpl_annotation_text)
        path const dir("build/test/verify_missing_cpl_annotation_text");
        auto dcp = make_simple (dir);
        dcp->write_xml (
-               dcp::Standard::SMPTE,
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::LocalTime().as_string(),
@@ -1936,7 +1956,6 @@ BOOST_AUTO_TEST_CASE (verify_mismatched_cpl_annotation_text)
        path const dir("build/test/verify_mismatched_cpl_annotation_text");
        auto dcp = make_simple (dir);
        dcp->write_xml (
-               dcp::Standard::SMPTE,
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::LocalTime().as_string(),
@@ -1966,7 +1985,7 @@ BOOST_AUTO_TEST_CASE (verify_mismatched_asset_duration)
        path const dir("build/test/verify_mismatched_asset_duration");
        prepare_directory (dir);
        shared_ptr<dcp::DCP> dcp (new dcp::DCP(dir));
-       shared_ptr<dcp::CPL> cpl (new dcp::CPL("A Test DCP", dcp::ContentKind::TRAILER));
+       auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
 
        shared_ptr<dcp::MonoPictureAsset> mp = simple_picture (dir, "", 24);
        shared_ptr<dcp::SoundAsset> ms = simple_sound (dir, "", dcp::MXFMetadata(), "en-US", 25);
@@ -1981,7 +2000,6 @@ BOOST_AUTO_TEST_CASE (verify_mismatched_asset_duration)
 
        dcp->add (cpl);
        dcp->write_xml (
-               dcp::Standard::SMPTE,
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::LocalTime().as_string(),
@@ -2004,7 +2022,7 @@ verify_subtitles_must_be_in_all_reels_check (path dir, bool add_to_reel1, bool a
 {
        prepare_directory (dir);
        auto dcp = make_shared<dcp::DCP>(dir);
-       auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER);
+       auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
 
        auto constexpr reel_length = 192;
 
@@ -2047,7 +2065,6 @@ verify_subtitles_must_be_in_all_reels_check (path dir, bool add_to_reel1, bool a
 
        dcp->add (cpl);
        dcp->write_xml (
-               dcp::Standard::SMPTE,
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::LocalTime().as_string(),
@@ -2092,7 +2109,7 @@ verify_closed_captions_must_be_in_all_reels_check (path dir, int caps_in_reel1,
 {
        prepare_directory (dir);
        auto dcp = make_shared<dcp::DCP>(dir);
-       auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER);
+       auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
 
        auto constexpr reel_length = 192;
 
@@ -2108,7 +2125,7 @@ verify_closed_captions_must_be_in_all_reels_check (path dir, int caps_in_reel1,
                );
 
        for (int i = 0; i < caps_in_reel1; ++i) {
-               reel1->add (make_shared<dcp::ReelClosedCaptionAsset>(subs, dcp::Fraction(24, 1), reel_length, 0));
+               reel1->add (make_shared<dcp::ReelSMPTEClosedCaptionAsset>(subs, dcp::Fraction(24, 1), reel_length, 0));
        }
 
        auto markers1 = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), reel_length, 0);
@@ -2123,7 +2140,7 @@ verify_closed_captions_must_be_in_all_reels_check (path dir, int caps_in_reel1,
                );
 
        for (int i = 0; i < caps_in_reel2; ++i) {
-               reel2->add (make_shared<dcp::ReelClosedCaptionAsset>(subs, dcp::Fraction(24, 1), reel_length, 0));
+               reel2->add (make_shared<dcp::ReelSMPTEClosedCaptionAsset>(subs, dcp::Fraction(24, 1), reel_length, 0));
        }
 
        auto markers2 = make_shared<dcp::ReelMarkersAsset>(dcp::Fraction(24, 1), reel_length, 0);
@@ -2134,7 +2151,6 @@ verify_closed_captions_must_be_in_all_reels_check (path dir, int caps_in_reel1,
 
        dcp->add (cpl);
        dcp->write_xml (
-               dcp::Standard::SMPTE,
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::LocalTime().as_string(),
@@ -2178,7 +2194,7 @@ verify_text_entry_point_check (path dir, dcp::VerificationNote::Code code, boost
 {
        prepare_directory (dir);
        auto dcp = make_shared<dcp::DCP>(dir);
-       auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER);
+       auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
 
        auto constexpr reel_length = 192;
 
@@ -2203,7 +2219,6 @@ verify_text_entry_point_check (path dir, dcp::VerificationNote::Code code, boost
 
        dcp->add (cpl);
        dcp->write_xml (
-               dcp::Standard::SMPTE,
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::LocalTime().as_string(),
@@ -2237,18 +2252,18 @@ BOOST_AUTO_TEST_CASE (verify_text_entry_point)
                        }
                );
 
-       verify_text_entry_point_check<dcp::ReelClosedCaptionAsset> (
+       verify_text_entry_point_check<dcp::ReelSMPTEClosedCaptionAsset> (
                "build/test/verify_closed_caption_entry_point_must_be_present",
                dcp::VerificationNote::Code::MISSING_CLOSED_CAPTION_ENTRY_POINT,
-               [](shared_ptr<dcp::ReelClosedCaptionAsset> asset) {
+               [](shared_ptr<dcp::ReelSMPTEClosedCaptionAsset> asset) {
                        asset->unset_entry_point ();
                        }
                );
 
-       verify_text_entry_point_check<dcp::ReelClosedCaptionAsset> (
+       verify_text_entry_point_check<dcp::ReelSMPTEClosedCaptionAsset> (
                "build/test/verify_closed_caption_entry_point_must_be_zero",
                dcp::VerificationNote::Code::INCORRECT_CLOSED_CAPTION_ENTRY_POINT,
-               [](shared_ptr<dcp::ReelClosedCaptionAsset> asset) {
+               [](shared_ptr<dcp::ReelSMPTEClosedCaptionAsset> asset) {
                        asset->set_entry_point (9);
                        }
                );
@@ -2262,7 +2277,6 @@ BOOST_AUTO_TEST_CASE (verify_missing_hash)
        path const dir("build/test/verify_missing_hash");
        auto dcp = make_simple (dir);
        dcp->write_xml (
-               dcp::Standard::SMPTE,
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::LocalTime().as_string(),
@@ -2271,18 +2285,21 @@ BOOST_AUTO_TEST_CASE (verify_missing_hash)
 
        BOOST_REQUIRE_EQUAL (dcp->cpls().size(), 1U);
        auto const cpl = dcp->cpls()[0];
+       BOOST_REQUIRE_EQUAL (cpl->reels().size(), 1U);
+       BOOST_REQUIRE (cpl->reels()[0]->main_picture());
+       auto asset_id = cpl->reels()[0]->main_picture()->id();
 
        {
                BOOST_REQUIRE (cpl->file());
                Editor e(cpl->file().get());
-               e.replace("<Hash>addO7je2lZSNQp55qjCWo5DLKFQ=</Hash>", "");
+               e.delete_first_line_containing("<Hash>");
        }
 
        check_verify_result (
                {dir},
                {
                        { dcp::VerificationNote::Type::ERROR, dcp::VerificationNote::Code::MISMATCHED_CPL_HASHES, cpl->id(), cpl->file().get() },
-                       { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_HASH, string("1fab8bb0-cfaf-4225-ad6d-01768bc10470") }
+                       { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_HASH, asset_id }
                });
 }
 
@@ -2303,7 +2320,6 @@ verify_markers_test (
        }
        dcp->cpls()[0]->reels()[0]->add(markers_asset);
        dcp->write_xml (
-               dcp::Standard::SMPTE,
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::LocalTime().as_string(),
@@ -2405,7 +2421,6 @@ BOOST_AUTO_TEST_CASE (verify_missing_cpl_metadata_version_number)
        auto cpl = dcp->cpls()[0];
        cpl->unset_version_number();
        dcp->write_xml (
-               dcp::Standard::SMPTE,
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::LocalTime().as_string(),
@@ -2421,7 +2436,6 @@ BOOST_AUTO_TEST_CASE (verify_missing_extension_metadata1)
        path dir = "build/test/verify_missing_extension_metadata1";
        auto dcp = make_simple (dir);
        dcp->write_xml (
-               dcp::Standard::SMPTE,
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::LocalTime().as_string(),
@@ -2449,7 +2463,6 @@ BOOST_AUTO_TEST_CASE (verify_missing_extension_metadata2)
        path dir = "build/test/verify_missing_extension_metadata2";
        auto dcp = make_simple (dir);
        dcp->write_xml (
-               dcp::Standard::SMPTE,
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::LocalTime().as_string(),
@@ -2477,7 +2490,6 @@ BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata3)
        path dir = "build/test/verify_invalid_xml_cpl_extension_metadata3";
        auto dcp = make_simple (dir);
        dcp->write_xml (
-               dcp::Standard::SMPTE,
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::LocalTime().as_string(),
@@ -2507,7 +2519,6 @@ BOOST_AUTO_TEST_CASE (verify_invalid_extension_metadata1)
        path dir = "build/test/verify_invalid_extension_metadata1";
        auto dcp = make_simple (dir);
        dcp->write_xml (
-               dcp::Standard::SMPTE,
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::LocalTime().as_string(),
@@ -2535,7 +2546,6 @@ BOOST_AUTO_TEST_CASE (verify_invalid_extension_metadata2)
        path dir = "build/test/verify_invalid_extension_metadata2";
        auto dcp = make_simple (dir);
        dcp->write_xml (
-               dcp::Standard::SMPTE,
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::LocalTime().as_string(),
@@ -2563,7 +2573,6 @@ BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata6)
        path dir = "build/test/verify_invalid_xml_cpl_extension_metadata6";
        auto dcp = make_simple (dir);
        dcp->write_xml (
-               dcp::Standard::SMPTE,
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::LocalTime().as_string(),
@@ -2593,7 +2602,6 @@ BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata7)
        path dir = "build/test/verify_invalid_xml_cpl_extension_metadata7";
        auto dcp = make_simple (dir);
        dcp->write_xml (
-               dcp::Standard::SMPTE,
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::LocalTime().as_string(),
@@ -2621,7 +2629,6 @@ BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata8)
        path dir = "build/test/verify_invalid_xml_cpl_extension_metadata8";
        auto dcp = make_simple (dir);
        dcp->write_xml (
-               dcp::Standard::SMPTE,
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::LocalTime().as_string(),
@@ -2651,7 +2658,6 @@ BOOST_AUTO_TEST_CASE (verify_invalid_xml_cpl_extension_metadata9)
        path dir = "build/test/verify_invalid_xml_cpl_extension_metadata9";
        auto dcp = make_simple (dir);
        dcp->write_xml (
-               dcp::Standard::SMPTE,
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::String::compose("libdcp %1", dcp::version),
                dcp::LocalTime().as_string(),
@@ -2767,7 +2773,7 @@ BOOST_AUTO_TEST_CASE (verify_partially_encrypted)
        signer->add (dcp::Certificate(dcp::file_to_string("test/ref/crypt/leaf.signed.pem")));
        signer->set_key (dcp::file_to_string("test/ref/crypt/leaf.key"));
 
-       auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER);
+       auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
 
        dcp::Key key;
 
@@ -2807,7 +2813,7 @@ BOOST_AUTO_TEST_CASE (verify_partially_encrypted)
 
        d.add (cpl);
 
-       d.write_xml (dcp::Standard::SMPTE, "OpenDCP 0.0.25", "OpenDCP 0.0.25", "2012-07-17T04:45:18+00:00", "A Test DCP", signer);
+       d.write_xml ("OpenDCP 0.0.25", "OpenDCP 0.0.25", "2012-07-17T04:45:18+00:00", "A Test DCP", signer);
 
        check_verify_result (
                {dir},
@@ -2844,7 +2850,7 @@ BOOST_AUTO_TEST_CASE (verify_jpeg2000_codestream_libdcp)
        boost::filesystem::path dir = "build/test/verify_jpeg2000_codestream_libdcp";
        prepare_directory (dir);
        auto dcp = make_simple (dir);
-       dcp->write_xml (dcp::Standard::SMPTE);
+       dcp->write_xml ();
        vector<dcp::VerificationNote> notes;
        dcp::MonoPictureAsset picture (find_file(dir, "video"));
        auto reader = picture.start_read ();
@@ -2980,3 +2986,23 @@ BOOST_AUTO_TEST_CASE (verify_incorrect_timed_text_id)
                        { dcp::VerificationNote::Type::BV21_ERROR, dcp::VerificationNote::Code::MISSING_CPL_METADATA, cpl->id(), cpl->file().get() }
                });
 }
+
+
+/** Check a DCP with a 3D asset marked as 2D */
+BOOST_AUTO_TEST_CASE (verify_threed_marked_as_twod)
+{
+       check_verify_result (
+               { private_test / "data" / "xm" },
+               {
+                       {
+                               dcp::VerificationNote::Type::WARNING,
+                               dcp::VerificationNote::Code::THREED_ASSET_MARKED_AS_TWOD, boost::filesystem::canonical(find_file(private_test / "data" / "xm", "j2c"))
+                       },
+                       {
+                               dcp::VerificationNote::Type::BV21_ERROR,
+                               dcp::VerificationNote::Code::INVALID_STANDARD
+                       },
+               });
+
+}
+