X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Fverify.cc;h=ec8925f2ffba6a5a6c2713d0f7d6a4dd8cb39a16;hb=4b2a91af4331c1c7bc540fb352b1099292b5f753;hp=1fc9e851839ede47f977a7456bed794b919789d3;hpb=056e3a4a7b41d4f78b73d46bba1973c5f1ffa139;p=libdcp.git diff --git a/src/verify.cc b/src/verify.cc index 1fc9e851..ec8925f2 100644 --- a/src/verify.cc +++ b/src/verify.cc @@ -41,6 +41,7 @@ #include "cpl.h" #include "dcp.h" #include "exceptions.h" +#include "filesystem.h" #include "interop_subtitle_asset.h" #include "mono_picture_asset.h" #include "mono_picture_frame.h" @@ -80,6 +81,7 @@ #include #include #include +#include #include #include #include @@ -384,9 +386,26 @@ enum class VerifyAssetResult { static VerifyAssetResult -verify_asset (shared_ptr dcp, shared_ptr reel_file_asset, function progress) +verify_asset( + shared_ptr dcp, + shared_ptr reel_file_asset, + function progress, + string* reference_hash, + string* calculated_hash + ) { - auto const actual_hash = reel_file_asset->asset_ref()->hash(progress); + DCP_ASSERT(reference_hash); + DCP_ASSERT(calculated_hash); + + /* 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(); + *calculated_hash = reel_file_asset->asset_ref()->hash([progress](int64_t done, int64_t total) { + progress(float(done) / total); + }); auto pkls = dcp->pkls(); /* We've read this DCP in so it must have at least one PKL */ @@ -394,22 +413,23 @@ verify_asset (shared_ptr dcp, shared_ptr reel_fi auto asset = reel_file_asset->asset_ref().asset(); - optional pkl_hash; + optional maybe_pkl_hash; for (auto i: pkls) { - pkl_hash = i->hash (reel_file_asset->asset_ref()->id()); - if (pkl_hash) { + maybe_pkl_hash = i->hash (reel_file_asset->asset_ref()->id()); + if (maybe_pkl_hash) { break; } } - DCP_ASSERT (pkl_hash); + DCP_ASSERT(maybe_pkl_hash); + *reference_hash = *maybe_pkl_hash; auto cpl_hash = reel_file_asset->hash(); - if (cpl_hash && *cpl_hash != *pkl_hash) { + if (cpl_hash && *cpl_hash != *reference_hash) { return VerifyAssetResult::CPL_PKL_DIFFER; } - if (actual_hash != *pkl_hash) { + if (*calculated_hash != *reference_hash) { return VerifyAssetResult::BAD; } @@ -429,9 +449,8 @@ verify_language_tag (string tag, vector& notes) static void -verify_picture_asset (shared_ptr reel_file_asset, boost::filesystem::path file, vector& notes, function progress) +verify_picture_asset(shared_ptr reel_file_asset, boost::filesystem::path file, int64_t start_frame, vector& notes, function progress) { - int biggest_frame = 0; auto asset = dynamic_pointer_cast(reel_file_asset->asset_ref().asset()); auto const duration = asset->intrinsic_duration (); @@ -443,14 +462,33 @@ verify_picture_asset (shared_ptr reel_file_asset, boost::fi } }; + int const max_frame = rint(250 * 1000000 / (8 * asset->edit_rate().as_float())); + int const risky_frame = rint(230 * 1000000 / (8 * asset->edit_rate().as_float())); + + auto check_frame_size = [max_frame, risky_frame, file, start_frame](int index, int size, int frame_rate, vector& notes) { + if (size > max_frame) { + notes.push_back( + VerificationNote( + VerificationNote::Type::ERROR, VerificationNote::Code::INVALID_PICTURE_FRAME_SIZE_IN_BYTES, file + ).set_frame(start_frame + index).set_frame_rate(frame_rate) + ); + } else if (size > risky_frame) { + notes.push_back( + VerificationNote( + VerificationNote::Type::WARNING, VerificationNote::Code::NEARLY_INVALID_PICTURE_FRAME_SIZE_IN_BYTES, file + ).set_frame(start_frame + index).set_frame_rate(frame_rate) + ); + } + }; + if (auto mono_asset = dynamic_pointer_cast(reel_file_asset->asset_ref().asset())) { auto reader = mono_asset->start_read (); for (int64_t i = 0; i < duration; ++i) { auto frame = reader->get_frame (i); - biggest_frame = max(biggest_frame, frame->size()); + check_frame_size(i, frame->size(), mono_asset->frame_rate().numerator, notes); if (!mono_asset->encrypted() || mono_asset->key()) { vector j2k_notes; - verify_j2k(frame, i, mono_asset->frame_rate().numerator, j2k_notes); + verify_j2k(frame, start_frame, i, mono_asset->frame_rate().numerator, j2k_notes); check_and_add (j2k_notes); } progress (float(i) / duration); @@ -459,29 +497,18 @@ verify_picture_asset (shared_ptr reel_file_asset, boost::fi auto reader = stereo_asset->start_read (); for (int64_t i = 0; i < duration; ++i) { auto frame = reader->get_frame (i); - biggest_frame = max(biggest_frame, max(frame->left()->size(), frame->right()->size())); + check_frame_size(i, frame->left()->size(), stereo_asset->frame_rate().numerator, notes); + check_frame_size(i, frame->right()->size(), stereo_asset->frame_rate().numerator, notes); if (!stereo_asset->encrypted() || stereo_asset->key()) { vector 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); + verify_j2k(frame->left(), start_frame, i, stereo_asset->frame_rate().numerator, j2k_notes); + verify_j2k(frame->right(), start_frame, i, stereo_asset->frame_rate().numerator, j2k_notes); check_and_add (j2k_notes); } progress (float(i) / duration); } } - - static const int max_frame = rint(250 * 1000000 / (8 * asset->edit_rate().as_float())); - static const int risky_frame = rint(230 * 1000000 / (8 * asset->edit_rate().as_float())); - if (biggest_frame > max_frame) { - notes.push_back ({ - VerificationNote::Type::ERROR, VerificationNote::Code::INVALID_PICTURE_FRAME_SIZE_IN_BYTES, file - }); - } else if (biggest_frame > risky_frame) { - notes.push_back ({ - VerificationNote::Type::WARNING, VerificationNote::Code::NEARLY_INVALID_PICTURE_FRAME_SIZE_IN_BYTES, file - }); - } } @@ -489,6 +516,7 @@ static void verify_main_picture_asset ( shared_ptr dcp, shared_ptr reel_asset, + int64_t start_frame, function)> stage, function progress, VerificationOptions options, @@ -498,14 +526,20 @@ verify_main_picture_asset ( auto asset = reel_asset->asset(); auto const file = *asset->file(); - if (options.check_asset_hashes && (!options.maximum_asset_size_for_hash_check || boost::filesystem::file_size(file) < *options.maximum_asset_size_for_hash_check)) { + if (options.check_asset_hashes && (!options.maximum_asset_size_for_hash_check || 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); + string reference_hash; + string calculated_hash; + auto const r = verify_asset(dcp, reel_asset, progress, &reference_hash, &calculated_hash); switch (r) { case VerifyAssetResult::BAD: - notes.push_back ({ - VerificationNote::Type::ERROR, VerificationNote::Code::INCORRECT_PICTURE_HASH, file - }); + notes.push_back( + dcp::VerificationNote( + VerificationNote::Type::ERROR, + VerificationNote::Code::INCORRECT_PICTURE_HASH, + file + ).set_reference_hash(reference_hash).set_calculated_hash(calculated_hash) + ); break; case VerifyAssetResult::CPL_PKL_DIFFER: notes.push_back ({ @@ -518,7 +552,7 @@ verify_main_picture_asset ( } stage ("Checking picture frame sizes", asset->file()); - verify_picture_asset (reel_asset, file, notes, progress); + verify_picture_asset(reel_asset, file, start_frame, notes, progress); /* Only flat/scope allowed by Bv2.1 */ if ( @@ -594,12 +628,20 @@ verify_main_sound_asset ( auto asset = reel_asset->asset(); auto const file = *asset->file(); - if (options.check_asset_hashes && (!options.maximum_asset_size_for_hash_check || boost::filesystem::file_size(file) < *options.maximum_asset_size_for_hash_check)) { + if (options.check_asset_hashes && (!options.maximum_asset_size_for_hash_check || 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); + string reference_hash; + string calculated_hash; + auto const r = verify_asset(dcp, reel_asset, progress, &reference_hash, &calculated_hash); switch (r) { case VerifyAssetResult::BAD: - notes.push_back({VerificationNote::Type::ERROR, VerificationNote::Code::INCORRECT_SOUND_HASH, file}); + notes.push_back( + dcp::VerificationNote( + VerificationNote::Type::ERROR, + VerificationNote::Code::INCORRECT_SOUND_HASH, + file + ).set_reference_hash(reference_hash).set_calculated_hash(calculated_hash) + ); break; case VerifyAssetResult::CPL_PKL_DIFFER: notes.push_back({VerificationNote::Type::ERROR, VerificationNote::Code::MISMATCHED_SOUND_HASHES, file}); @@ -672,7 +714,7 @@ verify_smpte_timed_text_asset ( notes.push_back ({ VerificationNote::Type::BV21_ERROR, VerificationNote::Code::MISSING_SUBTITLE_LANGUAGE, *asset->file() }); } - auto const size = boost::filesystem::file_size(asset->file().get()); + auto const size = filesystem::file_size(asset->file().get()); if (size > 115 * 1024 * 1024) { notes.push_back ( { VerificationNote::Type::BV21_ERROR, VerificationNote::Code::INVALID_TIMED_TEXT_SIZE_IN_BYTES, raw_convert(size), *asset->file() } @@ -709,9 +751,9 @@ verify_smpte_timed_text_asset ( } -/** Verify Interop subtitle-only stuff */ +/** Verify Interop subtitle / CCAP stuff */ void -verify_interop_subtitle_asset(shared_ptr asset, vector& notes) +verify_interop_text_asset(shared_ptr asset, vector& notes) { if (asset->subtitles().empty()) { notes.push_back({VerificationNote::Type::ERROR, VerificationNote::Code::MISSING_SUBTITLE, asset->id(), asset->file().get() }); @@ -800,7 +842,7 @@ verify_subtitle_asset ( auto interop = dynamic_pointer_cast(asset); if (interop) { - verify_interop_subtitle_asset(interop, notes); + verify_interop_text_asset(interop, notes); if (namespace_count(asset, "DCSubtitle") > 1) { notes.push_back({ VerificationNote::Type::WARNING, VerificationNote::Code::INCORRECT_SUBTITLE_NAMESPACE_COUNT, asset->id() }); } @@ -842,6 +884,11 @@ verify_closed_caption_asset ( notes.push_back ({VerificationNote::Type::WARNING, VerificationNote::Code::MISSED_CHECK_OF_ENCRYPTED}); } + auto interop = dynamic_pointer_cast(asset); + if (interop) { + verify_interop_text_asset(interop, notes); + } + auto smpte = dynamic_pointer_cast(asset); if (smpte) { verify_smpte_timed_text_asset (smpte, reel_asset_duration, notes); @@ -859,7 +906,8 @@ verify_text_details ( 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) */ @@ -871,16 +919,18 @@ verify_text_details ( auto empty_text = false; /* current reel start time (in editable units) */ int64_t reel_offset = 0; - vector font_ids; optional missing_load_font_id; - std::function, optional