#define LIBDCP_VERIFY_H
+#include "decrypted_kdm.h"
+#include <boost/any.hpp>
#include <boost/filesystem.hpp>
#include <boost/function.hpp>
#include <boost/optional.hpp>
+#include <map>
#include <string>
#include <vector>
-/* Something in windows.h defines this */
+/* windows.h defines this but we want to use it */
#undef ERROR
class VerificationNote
{
public:
- /* I've been unable to make mingw happy with ERROR as a symbol, so
- I'm using a VERIFY_ prefix here.
- */
enum class Type {
ERROR,
BV21_ERROR, ///< may not always be considered an error, but violates a "shall" requirement of Bv2.1
* - MISMATCHED: two things, which should be the same, are not.
* - EMPTY: something, which should have a value, has no value.
* - MISSING: something, which should be present, is not.
+ * - UNEXPECTED: something, which is present, should not be.
* - FAILED: some part of the verification failed in some serious way.
*
* Comments should clarify meaning and also say which of the optional fields (e.g. file)
* are filled in when this code is used.
*/
+
+ // If you change the next line, also look in doc/manual/verifier.py in DCP-o-matic
+ // as it looks for it when compiling the manual. Also, in this enum:
+ // [...] will be taken as a reference to a section of Bv2.1
+ // _foo_ means foo should be written as a piece of code
enum class Code {
- /** An error when reading the DCP
+ /** A general error when reading the DCP
* note contains (probably technical) details
*/
FAILED_READ,
* file contains CPL filename
*/
MISMATCHED_CPL_HASHES,
- /** Frame rate given in a reel for the main picture is not 24, 25, 30, 48, 50 or 60
+ /** The frame rate given in a reel for the main picture is not 24, 25, 30, 48, 50 or 60
* note contains the invalid frame rate as "<numerator>/<denominator>"
*/
INVALID_PICTURE_FRAME_RATE,
* file contains the sound asset filename
*/
MISMATCHED_SOUND_HASHES,
- /** An assetmap's <Path> entry is empty. */
+ /** An assetmap's _<Path>_ entry is empty */
EMPTY_ASSET_PATH,
/** A file mentioned in an asset map cannot be found
* file contains the filename that is missing
MISSING_ASSET,
/** The DCP contains both SMPTE and Interop-standard components */
MISMATCHED_STANDARD,
- /** Some XML fails to validate against the XSD/DTD
+ /** Some XML fails to validate against its XSD/DTD
* note contains the (probably technical) details
* file contains the invalid filename
* line contains the line number
*/
INVALID_XML,
- /** No ASSETMAP{.xml} was found */
+ /** No _ASSETMAP_ or _ASSETMAP.xml_ was found */
MISSING_ASSETMAP,
- /** An asset's IntrinsicDuration is less than 1 second
+ /** An asset's _IntrinsicDuration_ is less than 1 second
* note contains asset ID
*/
INVALID_INTRINSIC_DURATION,
- /** An asset's Duration is less than 1 second
+ /** An asset's _Duration_ is less than 1 second
* note contains asset ID
*/
INVALID_DURATION,
* note contains the asset ID
*/
EXTERNAL_ASSET,
+ /** A stereoscopic asset has an MXF which is marked as being monoscopic
+ * file contains the asset filename
+ */
+ THREED_ASSET_MARKED_AS_TWOD,
/** DCP is Interop, not SMPTE [Bv2.1_6.1] */
INVALID_STANDARD,
- /** A language or territory does not conform to RFC 5646 [Bv2.1_6.2.1].
+ /** A language or territory does not conform to RFC 5646 [Bv2.1_6.2.1]
* note contains the invalid language
*/
INVALID_LANGUAGE,
- /** A picture asset does not have one of the required Bv2.1 sizes (in pixels) [Bv2.1_7.1].
+ /** A picture asset does not have one of the required Bv2.1 sizes (in pixels) [Bv2.1_7.1]
* note contains the incorrect size as "<width>x<height>"
* file contains the asset filename
*/
INVALID_PICTURE_SIZE_IN_PIXELS,
- /** A picture asset is 2K but is not at 24, 25 or 48 fps as required by Bv2.1 [Bv2.1_7.1].
+ /** A picture asset is 2K but is not at 24, 25 or 48 fps as required by Bv2.1 [Bv2.1_7.1]
* note contains the invalid frame rate as "<numerator>/<denominator>"
* file contains the asset filename
*/
* file contains the asset filename
*/
INVALID_PICTURE_ASSET_RESOLUTION_FOR_3D,
- /** A closed caption's XML file is larger than 256KB [Bv2.1_7.2.1].
+ /** A closed caption's XML file is larger than 256KB [Bv2.1_7.2.1]
* note contains the invalid size in bytes
* file contains the asset filename
*/
* file contains the asset filename
*/
INVALID_TIMED_TEXT_FONT_SIZE_IN_BYTES,
- /** Some SMPTE subtitle XML has no <Language> tag [Bv2.1_7.2.2]
+ /** Some SMPTE subtitle XML has no _<Language>_ tag [Bv2.1_7.2.2]
* file contains the asset filename
*/
MISSING_SUBTITLE_LANGUAGE,
- /** Not all subtitle assets specify the same <Language> tag [Bv2.1_7.2.2] */
+ /** Not all subtitle assets specify the same _<Language>_ tag [Bv2.1_7.2.2] */
MISMATCHED_SUBTITLE_LANGUAGES,
- /** Some SMPTE subtitle XML has no <StartTime> tag [Bv2.1_7.2.3]
+ /** Some SMPTE subtitle XML has no _<StartTime>_ tag [Bv2.1_7.2.3]
* file contains the asset filename
*/
MISSING_SUBTITLE_START_TIME,
- /** Some SMPTE subtitle XML has a non-zero <StartTime> tag [Bv2.1_7.2.3]
+ /** Some SMPTE subtitle XML has a non-zero _<StartTime>_ tag [Bv2.1_7.2.3]
* file contains the asset filename
*/
INVALID_SUBTITLE_START_TIME,
INVALID_SUBTITLE_DURATION,
/** At least one pair of subtitles are separated by less than the the minimum of 2 frames suggested by [Bv2.1_7.2.5] */
INVALID_SUBTITLE_SPACING,
+ /** A subtitle lasts for longer than the reel which contains it */
+ SUBTITLE_OVERLAPS_REEL_BOUNDARY,
/** There are more than 3 subtitle lines in at least one place [Bv2.1_7.2.7] */
INVALID_SUBTITLE_LINE_COUNT,
/** There are more than 52 characters in at least one subtitle line [Bv2.1_7.2.7] */
INVALID_CLOSED_CAPTION_LINE_COUNT,
/** There are more than 32 characters in at least one closed caption line [Bv2.1_7.2.6] */
INVALID_CLOSED_CAPTION_LINE_LENGTH,
- /** The audio sampling rate must be 48kHz [Bv2.1_7.3].
+ /** The audio sampling rate must be 48kHz [Bv2.1_7.3]
* note contains the invalid frame rate
* file contains the asset filename
*/
INVALID_SOUND_FRAME_RATE,
- /** The CPL has no <AnnotationText> tag [Bv2.1_8.1]
+ /** The CPL has no _<AnnotationText>_ tag [Bv2.1_8.1]
* note contains the CPL ID
* file contains the CPL filename
*/
MISSING_CPL_ANNOTATION_TEXT,
- /** The <AnnotationText> is not the same as the <ContentTitleText> [Bv2.1_8.1]
+ /** The _<AnnotationText>_ is not the same as the _<ContentTitleText>_ [Bv2.1_8.1]
* note contains the CPL ID
* file contains the CPL filename
*/
MISMATCHED_CPL_ANNOTATION_TEXT,
/** At least one asset in a reel does not have the same duration as the others */
MISMATCHED_ASSET_DURATION,
- /** If one reel has a MainSubtitle, all must have them */
+ /** If one reel has a _MainSubtitle_, all must have them */
MISSING_MAIN_SUBTITLE_FROM_SOME_REELS,
- /** If one reel has at least one ClosedCaption, all reels must have the same number of ClosedCaptions */
+ /** If one reel has at least one _ClosedCaption_, all reels must have the same number of _ClosedCaptions_ */
MISMATCHED_CLOSED_CAPTION_ASSET_COUNTS,
- /** MainSubtitle in reels must have <EntryPoint> [Bv2.1_8.3.2]
+ /** MainSubtitle in reels must have _<EntryPoint>_ [Bv2.1_8.3.2]
* note contains the asset ID
*/
MISSING_SUBTITLE_ENTRY_POINT,
- /** MainSubtitle <EntryPoint> must be zero [Bv2.1_8.3.2]
+ /** MainSubtitle _<EntryPoint>_ must be zero [Bv2.1_8.3.2]
* note contains the asset ID
*/
INCORRECT_SUBTITLE_ENTRY_POINT,
- /** Closed caption in reels must have <EntryPoint> [Bv2.1_8.3.2]
+ /** Closed caption in reels must have _<EntryPoint>_ [Bv2.1_8.3.2]
* note contains the asset ID
*/
MISSING_CLOSED_CAPTION_ENTRY_POINT,
- /** Closed caption MainSubtitle <EntryPoint> must be zero [Bv2.1_8.3.2]
+ /** Closed caption _MainSubtitle_ _<EntryPoint>_ must be zero [Bv2.1_8.3.2]
* note contains the asset ID
*/
INCORRECT_CLOSED_CAPTION_ENTRY_POINT,
- /** <Hash> must be present for assets in CPLs
+ /** _<Hash>_ must be present for assets in CPLs
* note contains the asset ID
*/
MISSING_HASH,
- /** If ContentKind is Feature there must be a FFEC marker */
+ /** If _ContentKind_ is Feature there must be a FFEC marker */
MISSING_FFEC_IN_FEATURE,
- /** If ContentKind is Feature there must be a FFMC marker */
+ /** If _ContentKind_ is Feature there must be a FFMC marker */
MISSING_FFMC_IN_FEATURE,
- /** There should be a FFOC */
+ /** There should be a FFOC marker */
MISSING_FFOC,
- /** There should be a LFOC */
+ /** There should be a LFOC marker */
MISSING_LFOC,
- /** The FFOC should be 1
+ /** The FFOC marker should be 1
* note contains the incorrect value.
*/
INCORRECT_FFOC,
- /** The LFOC should be the last frame in the reel
+ /** The LFOC marker should be the last frame in the reel
* note contains the incorrect value
*/
INCORRECT_LFOC,
- /** There must be a <CompositionMetadataAsset>
+ /** There must be a _<CompositionMetadataAsset>_
* note contains the CPL ID
* file contains the CPL filename
*/
MISSING_CPL_METADATA,
- /** CPL metadata should contain <VersionNumber> of 1, at least
+ /** CPL metadata should contain _<VersionNumber>_ of 1, at least
* note contains the CPL ID
* file contains the CPL filename
*/
MISSING_CPL_METADATA_VERSION_NUMBER,
- /** There must be an <ExtensionMetadata> in <CompositionMetadataAsset> [Bv2.1_8.6.3]
+ /** There must be an _<ExtensionMetadata>_ in _<CompositionMetadataAsset>_ [Bv2.1_8.6.3]
* note contains the CPL ID
* file contains the CPL filename
*/
MISSING_EXTENSION_METADATA,
- /** <ExtensionMetadata> must have a particular form [Bv2.1_8.6.3]
+ /** _<ExtensionMetadata>_ does not have the correct form [Bv2.1_8.6.3]
* note contains details of what's wrong
* file contains the CPL filename
*/
INVALID_EXTENSION_METADATA,
- /** CPLs containing encrypted content must be signed [Bv2.1_8.7]
+ /** A CPL containing encrypted content is not signed [Bv2.1_8.7]
* note contains the CPL ID
* file contains the CPL filename
*/
UNSIGNED_CPL_WITH_ENCRYPTED_CONTENT,
- /** PKLs containing encrypted content must be signed [Bv2.1_8.7]
+ /** A PKL containing encrypted content is not signed [Bv2.1_8.7]
* note contains the PKL ID
* file contains the PKL filename
*/
UNSIGNED_PKL_WITH_ENCRYPTED_CONTENT,
- /** If a PKL has one CPL its <ContentTitleText> must be the same as the PKL's <AnnotationText>.
+ /** If a PKL has one CPL its _<ContentTitleText>_ must be the same as the PKL's _<AnnotationText>_
* note contains the PKL ID
* file contains the PKL filename
*/
MISMATCHED_PKL_ANNOTATION_TEXT_WITH_CPL,
- /** If any content is encrypted, everything must be encrypted */
+ /** Some, but not all content, is encrypted */
PARTIALLY_ENCRYPTED,
- /** General error from our JPEG2000 codestream verification
+ /** General error during JPEG2000 codestream verification
+ * frame contains the frame index (counted from 0)
* note contains details
*/
INVALID_JPEG2000_CODESTREAM,
INVALID_JPEG2000_TILE_PARTS_FOR_4K,
/** No TLM marker was found [Bv2.1_10.2.1] */
MISSING_JPEG200_TLM_MARKER,
+ /** The MXF _ResourceID_ of a timed text resource was not the same as that of the contained XML essence [Bv2.1_10.4.3] */
+ MISMATCHED_TIMED_TEXT_RESOURCE_ID,
+ /** The AssetID of a timed text MXF is the same as its _ResourceID_ or that of the contained XML essence [Bv2.1_10.4.2] */
+ INCORRECT_TIMED_TEXT_ASSET_ID,
+ /** The ContainerDuration of a timed text MXF is not the same as the _Duration_ in its reel [Bv2.1_10.4.3]
+ * note contains the reel duration, followed by a space, followed by the MXF duration
+ * file contains the asset filename
+ */
+ MISMATCHED_TIMED_TEXT_DURATION,
+ /** Something could not be verified because content is encrypted and no key is available */
+ MISSED_CHECK_OF_ENCRYPTED,
+ /** Some timed-text XML has an empty <_Text_> node */
+ EMPTY_TEXT,
+ /** Some closed captions do not have the same vertical alignment within a <_Subtitle_> node */
+ MISMATCHED_CLOSED_CAPTION_VALIGN,
+ /** Some closed captions are not listed in the XML in the order of their vertical position */
+ INCORRECT_CLOSED_CAPTION_ORDERING,
+ /** Some <MainMarkers> asset has an <EntryPoint> that should not be there */
+ UNEXPECTED_ENTRY_POINT,
+ /** Some <MainMarkers> asset has an <Duration> that should not be there */
+ UNEXPECTED_DURATION,
+ /** A <ContentKind> has been specified with either no scope or the SMPTE 429-7 scope, but which is not one of those allowed */
+ INVALID_CONTENT_KIND,
+ /** Either the width or height of a <MainPictureActiveArea> in a CPL is either not an even number, or bigger than the corresponding asset dimension.
+ * note contains details of what is wrong
+ * file contains the CPL filename
+ */
+ INVALID_MAIN_PICTURE_ACTIVE_AREA,
+ /** A PKL has more than one asset with the same ID
+ * note contains the PKL ID
+ * file contains the PKL filename
+ */
+ DUPLICATE_ASSET_ID_IN_PKL,
+ /** An ASSETMAP has more than one asset with the same ID
+ * note contains the ASSETMAP ID
+ * file contains the ASSETMAP filename
+ */
+ DUPLICATE_ASSET_ID_IN_ASSETMAP,
+ /** An Interop subtitle asset has no subtitles
+ * note contains the asset ID
+ * file contains the asset filename
+ */
+ MISSING_SUBTITLE,
+ /** A SMPTE subtitle asset as an <IssueDate> which is not of the form yyyy-mm-ddThh:mm:ss
+ * I can find no reference in a standard to this being required, but the Deluxe delivery
+ * specifications require it and their QC will fail DCPs that don't have it.
+ * note contains the incorrect <IssueDate>
+ */
+ INVALID_SUBTITLE_ISSUE_DATE,
+ /** The sound assets in the CPL do not have the same audio channel count.
+ * file contains the filename of the first asset to differ
+ */
+ MISMATCHED_SOUND_CHANNEL_COUNTS,
+ /** The CPL contains a MainSoundConfiguration tag which does not describe the number of
+ * channels in the audio assets.
+ * note contains details of what is wrong
+ * file contains the CPL filename
+ */
+ INVALID_MAIN_SOUND_CONFIGURATION,
+ /** An interop subtitle file has a <LoadFont> node which refers to a font file that is not found.
+ * note contains the <LoadFont> ID
+ */
+ MISSING_FONT,
+ /** A tile part in a JPEG2000 frame is too big.
+ * frame contains the frame index (counted from 0)
+ * component contains the component index (0, 1 or 2)
+ * size contains the invalid size in bytes.
+ */
+ INVALID_JPEG2000_TILE_PART_SIZE,
+ /** A subtitle XML root node has more than one namespace (xmlns) declaration.
+ * note contains the asset ID
+ */
+ INCORRECT_SUBTITLE_NAMESPACE_COUNT,
+ /** A subtitle or closed caption file has a <Font> tag which refers to a font that is not
+ * first introduced with a <LoadFont>.
+ * id contains the ID of the <Font> tag.
+ */
+ MISSING_LOAD_FONT_FOR_FONT,
+ /** A SMPTE subtitle asset has at least one <Text> element but no <LoadFont>
+ * id contains the ID of the subtitle asset.
+ */
+ MISSING_LOAD_FONT,
+ /** An ID in an asset map does not match the ID obtained from reading the actual file.
+ * id contains the ID from the asset map.
+ * other_id contains the ID from the file.
+ */
+ MISMATCHED_ASSET_MAP_ID,
+ /** The <LabelText> inside a <ContentVersion> is empty
+ * note contains the CPL ID
+ * file contains the CPL filename
+ */
+ EMPTY_CONTENT_VERSION_LABEL_TEXT,
};
VerificationNote (Type type, Code code)
VerificationNote (Type type, Code code, std::string note)
: _type (type)
, _code (code)
- , _note (note)
- {}
+ {
+ _data[Data::NOTE] = note;
+ }
VerificationNote (Type type, Code code, boost::filesystem::path file)
: _type (type)
, _code (code)
- , _file (file)
- {}
+ {
+ _data[Data::FILE] = file;
+ }
VerificationNote (Type type, Code code, std::string note, boost::filesystem::path file)
: _type (type)
, _code (code)
- , _note (note)
- , _file (file)
- {}
+ {
+ _data[Data::NOTE] = note;
+ _data[Data::FILE] = file;
+ }
VerificationNote (Type type, Code code, std::string note, boost::filesystem::path file, uint64_t line)
: _type (type)
, _code (code)
- , _note (note)
- , _file (file)
- , _line (line)
- {}
+ {
+ _data[Data::NOTE] = note;
+ _data[Data::FILE] = file;
+ _data[Data::LINE] = line;
+ }
Type type () const {
return _type;
return _code;
}
+private:
+ enum class Data {
+ NOTE, ///< further information about the error
+ FILE, ///< path of file containing the error
+ LINE, ///< error line number within the FILE
+ FRAME,
+ COMPONENT,
+ SIZE,
+ ID,
+ OTHER_ID,
+ FRAME_RATE
+ };
+
+ template <class T>
+ boost::optional<T> data(Data key) const
+ {
+ auto iter = _data.find(key);
+ if (iter == _data.end()) {
+ return {};
+ }
+ return boost::any_cast<T>(iter->second);
+ }
+
+public:
boost::optional<std::string> note () const {
- return _note;
+ return data<std::string>(Data::NOTE);
}
boost::optional<boost::filesystem::path> file () const {
- return _file;
+ return data<boost::filesystem::path>(Data::FILE);
}
boost::optional<uint64_t> line () const {
- return _line;
+ return data<uint64_t>(Data::LINE);
+ }
+
+ VerificationNote& set_frame(int frame) {
+ _data[Data::FRAME] = frame;
+ return *this;
+ }
+
+ boost::optional<int> frame() const {
+ return data<int>(Data::FRAME);
+ }
+
+ VerificationNote& set_component(int component) {
+ _data[Data::COMPONENT] = component;
+ return *this;
+ }
+
+ boost::optional<int> component() const {
+ return data<int>(Data::COMPONENT);
+ }
+
+ VerificationNote& set_size(int size) {
+ _data[Data::SIZE] = size;
+ return *this;
+ }
+
+ boost::optional<int> size() const {
+ return data<int>(Data::SIZE);
+ }
+
+ VerificationNote& set_id(std::string id) {
+ _data[Data::ID] = id;
+ return *this;
+ }
+
+ boost::optional<std::string> id() const {
+ return data<std::string>(Data::ID);
+ }
+
+ VerificationNote& set_other_id(std::string other_id) {
+ _data[Data::OTHER_ID] = other_id;
+ return *this;
+ }
+
+ boost::optional<std::string> other_id() const {
+ return data<std::string>(Data::OTHER_ID);
+ }
+
+ VerificationNote& set_frame_rate(int frame_rate) {
+ _data[Data::FRAME_RATE] = frame_rate;
+ return *this;
+ }
+
+ boost::optional<int> frame_rate() const {
+ return data<int>(Data::FRAME_RATE);
}
private:
Type _type;
Code _code;
- /** Further information about the error, if applicable */
- boost::optional<std::string> _note;
- /** Path of file containing the error, if applicable */
- boost::optional<boost::filesystem::path> _file;
- /** Error line number within _file, if applicable */
- boost::optional<uint64_t> _line;
+ std::map<Data, boost::any> _data;
+};
+
+
+struct VerificationOptions
+{
+ ///< If set, any assets larger than this number of bytes will not have their hashes checked
+ boost::optional<boost::uintmax_t> maximum_asset_size_for_hash_check;
+ ///< true to check asset hashes (except those which match maximum_asset_size_for_hash_check)
+ ///< false to check no asset hashes.
+ bool check_asset_hashes = true;
};
std::vector<VerificationNote> verify (
std::vector<boost::filesystem::path> directories,
+ std::vector<dcp::DecryptedKDM> kdms,
boost::function<void (std::string, boost::optional<boost::filesystem::path>)> stage,
boost::function<void (float)> progress,
- boost::filesystem::path xsd_dtd_directory
+ VerificationOptions options = {},
+ boost::optional<boost::filesystem::path> xsd_dtd_directory = boost::optional<boost::filesystem::path>()
);
std::string note_to_string (dcp::VerificationNote note);
bool operator== (dcp::VerificationNote const& a, dcp::VerificationNote const& b);
+bool operator< (dcp::VerificationNote const& a, dcp::VerificationNote const& b);
std::ostream& operator<<(std::ostream& s, dcp::VerificationNote const& note);