X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Fverify.cc;h=42ee192119b85280ada83512167a01aaa2a4805d;hb=4dca630057509164494b65c2deeb748a51928c73;hp=2f8f0a535b3eb1d895d9add26d5134689aa8d649;hpb=c88d7a66e3751cac223704c68aa4278a9c0de638;p=libdcp.git diff --git a/src/verify.cc b/src/verify.cc index 2f8f0a53..42ee1921 100644 --- a/src/verify.cc +++ b/src/verify.cc @@ -58,6 +58,7 @@ #include "stereo_picture_frame.h" #include "verify.h" #include "verify_j2k.h" +#include #include #include #include @@ -242,7 +243,8 @@ public: add("http://www.digicine.com/PROTO-ASDCP-AM-20040311.xsd", "PROTO-ASDCP-AM-20040311.xsd"); add("http://www.digicine.com/PROTO-ASDCP-CC-CPL-20070926#", "PROTO-ASDCP-CC-CPL-20070926.xsd"); add("interop-subs", "DCSubtitle.v1.mattsson.xsd"); - add("http://www.smpte-ra.org/schemas/428-7/2010/DCST.xsd", "SMPTE-428-7-2010-DCST.xsd"); + add("http://www.smpte-ra.org/schemas/428-7/2010/DCST.xsd", "DCDMSubtitle-2010.xsd"); + add("http://www.smpte-ra.org/schemas/428-7/2014/DCST.xsd", "DCDMSubtitle-2014.xsd"); add("http://www.smpte-ra.org/schemas/429-16/2014/CPL-Metadata", "SMPTE-429-16.xsd"); add("http://www.dolby.com/schemas/2012/AD", "Dolby-2012-AD.xsd"); add("http://www.smpte-ra.org/schemas/429-10/2008/Main-Stereo-Picture-CPL", "SMPTE-429-10-2008.xsd"); @@ -278,7 +280,7 @@ private: static void parse (XercesDOMParser& parser, boost::filesystem::path xml) { - parser.parse(xml.string().c_str()); + parser.parse(xml.c_str()); } @@ -321,6 +323,7 @@ validate_xml (T xml, boost::filesystem::path xsd_dtd_directory, vector dcp, shared_ptr reel_file_asset, function progress) { + /* When reading the DCP the hash will have been set to the one from the PKL/CPL. + * We want to calculate the hash of the actual file contents here, so that we + * can check it. unset_hash() means that this calculation will happen on the + * call to hash(). + */ + reel_file_asset->asset_ref()->unset_hash(); auto const actual_hash = reel_file_asset->asset_ref()->hash(progress); auto pkls = dcp->pkls(); @@ -447,7 +456,7 @@ verify_picture_asset (shared_ptr reel_file_asset, boost::fi biggest_frame = max(biggest_frame, frame->size()); if (!mono_asset->encrypted() || mono_asset->key()) { vector j2k_notes; - verify_j2k (frame, j2k_notes); + verify_j2k(frame, i, mono_asset->frame_rate().numerator, j2k_notes); check_and_add (j2k_notes); } progress (float(i) / duration); @@ -459,8 +468,8 @@ verify_picture_asset (shared_ptr reel_file_asset, boost::fi biggest_frame = max(biggest_frame, max(frame->left()->size(), frame->right()->size())); if (!stereo_asset->encrypted() || stereo_asset->key()) { vector j2k_notes; - verify_j2k (frame->left(), j2k_notes); - verify_j2k (frame->right(), j2k_notes); + verify_j2k(frame->left(), i, stereo_asset->frame_rate().numerator, j2k_notes); + verify_j2k(frame->right(), i, stereo_asset->frame_rate().numerator, j2k_notes); check_and_add (j2k_notes); } progress (float(i) / duration); @@ -488,27 +497,32 @@ verify_main_picture_asset ( shared_ptr reel_asset, function)> stage, function progress, + VerificationOptions options, vector& notes ) { auto asset = reel_asset->asset(); auto const file = *asset->file(); - stage ("Checking picture asset hash", file); - auto const r = verify_asset (dcp, reel_asset, progress); - switch (r) { - case VerifyAssetResult::BAD: - notes.push_back ({ - VerificationNote::Type::ERROR, VerificationNote::Code::INCORRECT_PICTURE_HASH, file - }); - break; - case VerifyAssetResult::CPL_PKL_DIFFER: - notes.push_back ({ - VerificationNote::Type::ERROR, VerificationNote::Code::MISMATCHED_PICTURE_HASHES, file - }); - break; - default: - break; + + if (options.check_asset_hashes && (!options.maximum_asset_size_for_hash_check || boost::filesystem::file_size(file) < *options.maximum_asset_size_for_hash_check)) { + stage ("Checking picture asset hash", file); + auto const r = verify_asset (dcp, reel_asset, progress); + switch (r) { + case VerifyAssetResult::BAD: + notes.push_back ({ + VerificationNote::Type::ERROR, VerificationNote::Code::INCORRECT_PICTURE_HASH, file + }); + break; + case VerifyAssetResult::CPL_PKL_DIFFER: + notes.push_back ({ + VerificationNote::Type::ERROR, VerificationNote::Code::MISMATCHED_PICTURE_HASHES, file + }); + break; + default: + break; + } } + stage ("Checking picture frame sizes", asset->file()); verify_picture_asset (reel_asset, file, notes, progress); @@ -565,29 +579,46 @@ verify_main_picture_asset ( } +struct State +{ + boost::optional subtitle_language; + boost::optional audio_channels; +}; + + static void verify_main_sound_asset ( shared_ptr dcp, shared_ptr reel_asset, function)> stage, function progress, - vector& notes + VerificationOptions options, + vector& notes, + State& state ) { auto asset = reel_asset->asset(); auto const file = *asset->file(); - stage("Checking sound asset hash", file); - auto const r = verify_asset (dcp, reel_asset, progress); - switch (r) { - case VerifyAssetResult::BAD: - notes.push_back({VerificationNote::Type::ERROR, VerificationNote::Code::INCORRECT_SOUND_HASH, file}); - break; - case VerifyAssetResult::CPL_PKL_DIFFER: - notes.push_back({VerificationNote::Type::ERROR, VerificationNote::Code::MISMATCHED_SOUND_HASHES, file}); - break; - default: - break; + if (options.check_asset_hashes && (!options.maximum_asset_size_for_hash_check || boost::filesystem::file_size(file) < *options.maximum_asset_size_for_hash_check)) { + stage("Checking sound asset hash", file); + auto const r = verify_asset (dcp, reel_asset, progress); + switch (r) { + case VerifyAssetResult::BAD: + notes.push_back({VerificationNote::Type::ERROR, VerificationNote::Code::INCORRECT_SOUND_HASH, file}); + break; + case VerifyAssetResult::CPL_PKL_DIFFER: + notes.push_back({VerificationNote::Type::ERROR, VerificationNote::Code::MISMATCHED_SOUND_HASHES, file}); + break; + default: + break; + } + } + + if (!state.audio_channels) { + state.audio_channels = asset->channels(); + } else if (*state.audio_channels != asset->channels()) { + notes.push_back({ VerificationNote::Type::ERROR, VerificationNote::Code::MISMATCHED_SOUND_CHANNEL_COUNTS, file }); } stage ("Checking sound asset metadata", file); @@ -633,12 +664,6 @@ verify_closed_caption_reel (shared_ptr reel_asset, } -struct State -{ - boost::optional subtitle_language; -}; - - /** Verify stuff that is common to both subtitles and closed captions */ void verify_smpte_timed_text_asset ( @@ -697,6 +722,10 @@ verify_interop_subtitle_asset(shared_ptr asset, vect if (asset->subtitles().empty()) { notes.push_back({VerificationNote::Type::ERROR, VerificationNote::Code::MISSING_SUBTITLE, asset->id(), asset->file().get() }); } + auto const unresolved = asset->unresolved_fonts(); + if (!unresolved.empty()) { + notes.push_back({VerificationNote::Type::ERROR, VerificationNote::Code::MISSING_FONT, unresolved.front() }); + } } @@ -764,15 +793,33 @@ verify_subtitle_asset ( notes.push_back ({VerificationNote::Type::WARNING, VerificationNote::Code::MISSED_CHECK_OF_ENCRYPTED}); } + auto namespace_count = [](shared_ptr asset, string root_node) { + cxml::Document doc(root_node); + doc.read_string(asset->raw_xml().get()); + auto root = dynamic_cast(doc.node())->cobj(); + int count = 0; + for (auto ns = root->nsDef; ns != nullptr; ns = ns->next) { + ++count; + } + return count; + }; + auto interop = dynamic_pointer_cast(asset); if (interop) { verify_interop_subtitle_asset(interop, notes); + if (namespace_count(asset, "DCSubtitle") > 1) { + notes.push_back({ VerificationNote::Type::WARNING, VerificationNote::Code::INCORRECT_SUBTITLE_NAMESPACE_COUNT, asset->id() }); + } } auto smpte = dynamic_pointer_cast(asset); if (smpte) { verify_smpte_timed_text_asset (smpte, reel_asset_duration, notes); verify_smpte_subtitle_asset (smpte, notes, state); + /* This asset may be encrypted and in that case we'll have no raw_xml() */ + if (asset->raw_xml() && namespace_count(asset, "SubtitleReel") > 1) { + notes.push_back({ VerificationNote::Type::WARNING, VerificationNote::Code::INCORRECT_SUBTITLE_NAMESPACE_COUNT, asset->id()}); + } } } @@ -808,16 +855,18 @@ verify_closed_caption_asset ( } -/** Check the timing of the individual subtitles and make sure there are no empty nodes */ +/** Check the timing of the individual subtitles and make sure there are no empty nodes etc. */ static void verify_text_details ( + dcp::Standard standard, vector> reels, int edit_rate, vector& notes, std::function)> check, std::function (shared_ptr)> xml, - std::function)> duration + std::function)> duration, + std::function)> id ) { /* end of last subtitle (in editable units) */ @@ -829,9 +878,19 @@ verify_text_details ( auto empty_text = false; /* current reel start time (in editable units) */ int64_t reel_offset = 0; - - std::function, optional