2 Copyright (C) 2018-2019 Carl Hetherington <cth@carlh.net>
4 This file is part of libdcp.
6 libdcp is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 libdcp is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with libdcp. If not, see <http://www.gnu.org/licenses/>.
19 In addition, as a special exception, the copyright holders give
20 permission to link the code of portions of this program with the
21 OpenSSL library under certain conditions as described in each
22 individual source file, and distribute linked combinations
25 You must obey the GNU General Public License in all respects
26 for all of the code used other than OpenSSL. If you modify
27 file(s) with this exception, you may extend this exception to your
28 version of the file(s), but you are not obligated to do so. If you
29 do not wish to do so, delete this exception statement from your
30 version. If you delete this exception statement from all source
31 files in the program, then also delete it here.
38 #include "reel_picture_asset.h"
39 #include "reel_sound_asset.h"
40 #include "exceptions.h"
41 #include "compose.hpp"
42 #include <boost/foreach.hpp>
51 using boost::shared_ptr;
52 using boost::optional;
53 using boost::function;
59 RESULT_CPL_PKL_DIFFER,
64 verify_asset (shared_ptr<DCP> dcp, shared_ptr<ReelMXF> reel_mxf, function<void (float)> progress)
66 string const actual_hash = reel_mxf->asset_ref()->hash(progress);
68 list<shared_ptr<PKL> > pkls = dcp->pkls();
69 /* We've read this DCP in so it must have at least one PKL */
70 DCP_ASSERT (!pkls.empty());
72 shared_ptr<Asset> asset = reel_mxf->asset_ref().asset();
74 optional<string> pkl_hash;
75 BOOST_FOREACH (shared_ptr<PKL> i, pkls) {
76 pkl_hash = i->hash (reel_mxf->asset_ref()->id());
82 DCP_ASSERT (pkl_hash);
84 optional<string> cpl_hash = reel_mxf->hash();
85 if (cpl_hash && *cpl_hash != *pkl_hash) {
86 return RESULT_CPL_PKL_DIFFER;
89 if (actual_hash != *pkl_hash) {
96 list<VerificationNote>
97 dcp::verify (vector<boost::filesystem::path> directories, function<void (string, optional<boost::filesystem::path>)> stage, function<void (float)> progress)
99 list<VerificationNote> notes;
101 list<shared_ptr<DCP> > dcps;
102 BOOST_FOREACH (boost::filesystem::path i, directories) {
103 dcps.push_back (shared_ptr<DCP> (new DCP (i)));
106 BOOST_FOREACH (shared_ptr<DCP> dcp, dcps) {
107 stage ("Checking DCP", dcp->directory());
110 } catch (DCPReadError& e) {
111 notes.push_back (VerificationNote(VerificationNote::VERIFY_ERROR, VerificationNote::GENERAL_READ, string(e.what())));
112 } catch (XMLError& e) {
113 notes.push_back (VerificationNote(VerificationNote::VERIFY_ERROR, VerificationNote::GENERAL_READ, string(e.what())));
116 BOOST_FOREACH (shared_ptr<CPL> cpl, dcp->cpls()) {
117 stage ("Checking CPL", cpl->file());
119 /* Check that the CPL's hash corresponds to the PKL */
120 BOOST_FOREACH (shared_ptr<PKL> i, dcp->pkls()) {
121 optional<string> h = i->hash(cpl->id());
122 if (h && make_digest(Data(*cpl->file())) != *h) {
123 notes.push_back (VerificationNote(VerificationNote::VERIFY_ERROR, VerificationNote::CPL_HASH_INCORRECT));
127 BOOST_FOREACH (shared_ptr<Reel> reel, cpl->reels()) {
128 stage ("Checking reel", optional<boost::filesystem::path>());
129 if (reel->main_picture()) {
130 /* Check reel stuff */
131 Fraction const frame_rate = reel->main_picture()->frame_rate();
132 if (frame_rate.denominator != 1 ||
133 (frame_rate.numerator != 24 &&
134 frame_rate.numerator != 25 &&
135 frame_rate.numerator != 30 &&
136 frame_rate.numerator != 48 &&
137 frame_rate.numerator != 50 &&
138 frame_rate.numerator != 60 &&
139 frame_rate.numerator != 96)) {
140 notes.push_back (VerificationNote(VerificationNote::VERIFY_ERROR, VerificationNote::INVALID_PICTURE_FRAME_RATE));
143 if (reel->main_picture()->asset_ref().resolved()) {
144 stage ("Checking picture asset hash", reel->main_picture()->asset()->file());
145 Result const r = verify_asset (dcp, reel->main_picture(), progress);
150 VerificationNote::VERIFY_ERROR, VerificationNote::PICTURE_HASH_INCORRECT, *reel->main_picture()->asset()->file()
154 case RESULT_CPL_PKL_DIFFER:
155 notes.push_back (VerificationNote(VerificationNote::VERIFY_ERROR, VerificationNote::PKL_CPL_PICTURE_HASHES_DISAGREE));
162 if (reel->main_sound() && reel->main_sound()->asset_ref().resolved()) {
163 stage ("Checking sound asset hash", reel->main_sound()->asset()->file());
164 Result const r = verify_asset (dcp, reel->main_sound(), progress);
169 VerificationNote::VERIFY_ERROR, VerificationNote::SOUND_HASH_INCORRECT, *reel->main_sound()->asset()->file()
173 case RESULT_CPL_PKL_DIFFER:
174 notes.push_back (VerificationNote (VerificationNote::VERIFY_ERROR, VerificationNote::PKL_CPL_SOUND_HASHES_DISAGREE));
188 dcp::note_to_string (dcp::VerificationNote note)
190 switch (note.code()) {
191 case dcp::VerificationNote::GENERAL_READ:
193 case dcp::VerificationNote::CPL_HASH_INCORRECT:
194 return "The hash of the CPL in the PKL does not agree with the CPL file";
195 case dcp::VerificationNote::INVALID_PICTURE_FRAME_RATE:
196 return "The picture in a reel has an invalid frame rate";
197 case dcp::VerificationNote::PICTURE_HASH_INCORRECT:
198 return dcp::String::compose("The hash of the picture asset %1 does not agree with the PKL file", note.file()->filename());
199 case dcp::VerificationNote::PKL_CPL_PICTURE_HASHES_DISAGREE:
200 return "The PKL and CPL hashes disagree for a picture asset.";
201 case dcp::VerificationNote::SOUND_HASH_INCORRECT:
202 return dcp::String::compose("The hash of the sound asset %1 does not agree with the PKL file", note.file()->filename());
203 case dcp::VerificationNote::PKL_CPL_SOUND_HASHES_DISAGREE:
204 return "The PKL and CPL hashes disagree for a sound asset.";
205 case dcp::VerificationNote::EMPTY_ASSET_PATH:
206 return "The asset map contains an empty asset path.";
207 case dcp::VerificationNote::MISSING_ASSET:
208 return "The file for an asset in the asset map cannot be found.";
209 case dcp::VerificationNote::MISMATCHED_STANDARD:
210 return "The DCP contains both SMPTE and Interop parts.";