diff options
33 files changed, 606 insertions, 155 deletions
@@ -175,10 +175,10 @@ CPL::write_xml (boost::filesystem::path file, Standard standard, shared_ptr<cons set_file (file); } -list<shared_ptr<ReelAsset> > -CPL::reel_assets () +list<shared_ptr<ReelMXF> > +CPL::reel_mxfs () { - list<shared_ptr<ReelAsset> > c; + list<shared_ptr<ReelMXF> > c; BOOST_FOREACH (shared_ptr<Reel> i, _reels) { if (i->main_picture ()) { @@ -201,10 +201,10 @@ CPL::reel_assets () return c; } -list<shared_ptr<const ReelAsset> > -CPL::reel_assets () const +list<shared_ptr<const ReelMXF> > +CPL::reel_mxfs () const { - list<shared_ptr<const ReelAsset> > c; + list<shared_ptr<const ReelMXF> > c; BOOST_FOREACH (shared_ptr<Reel> i, _reels) { if (i->main_picture ()) { @@ -1,5 +1,5 @@ /* - Copyright (C) 2014 Carl Hetherington <cth@carlh.net> + Copyright (C) 2014-2019 Carl Hetherington <cth@carlh.net> This file is part of libdcp. @@ -51,7 +51,7 @@ namespace dcp { -class ReelAsset; +class ReelMXF; class Reel; class XMLMetadata; class MXFMetadata; @@ -116,10 +116,10 @@ public: return _reels; } - /** @return the ReelAssets in this CPL in all reels. + /** @return the ReelMXFs in this CPL in all reels. */ - std::list<boost::shared_ptr<const ReelAsset> > reel_assets () const; - std::list<boost::shared_ptr<ReelAsset> > reel_assets (); + std::list<boost::shared_ptr<const ReelMXF> > reel_mxfs () const; + std::list<boost::shared_ptr<ReelMXF> > reel_mxfs (); bool encrypted () const; @@ -476,7 +476,7 @@ DCP::assets (bool ignore_unresolved) const list<shared_ptr<Asset> > assets; BOOST_FOREACH (shared_ptr<CPL> i, cpls ()) { assets.push_back (i); - BOOST_FOREACH (shared_ptr<const ReelAsset> j, i->reel_assets ()) { + BOOST_FOREACH (shared_ptr<const ReelMXF> j, i->reel_mxfs()) { if (ignore_unresolved && !j->asset_ref().resolved()) { continue; } diff --git a/src/decrypted_kdm.cc b/src/decrypted_kdm.cc index 756028d1..4bd9a9d5 100644 --- a/src/decrypted_kdm.cc +++ b/src/decrypted_kdm.cc @@ -271,10 +271,9 @@ DecryptedKDM::DecryptedKDM ( { /* Create DecryptedKDMKey objects for each encryptable asset */ bool did_one = false; - BOOST_FOREACH(shared_ptr<const ReelAsset> i, cpl->reel_assets ()) { - shared_ptr<const ReelMXF> mxf = boost::dynamic_pointer_cast<const ReelMXF> (i); - if (mxf && mxf->key_id ()) { - add_key (mxf->key_type(), mxf->key_id().get(), key, cpl->id(), SMPTE); + BOOST_FOREACH(shared_ptr<const ReelMXF> i, cpl->reel_mxfs()) { + if (i->key_id()) { + add_key (i->key_type(), i->key_id().get(), key, cpl->id(), SMPTE); did_one = true; } } diff --git a/src/reel.cc b/src/reel.cc index 4b42ec0e..bda83531 100644 --- a/src/reel.cc +++ b/src/reel.cc @@ -42,6 +42,7 @@ #include "reel_stereo_picture_asset.h" #include "reel_sound_asset.h" #include "reel_subtitle_asset.h" +#include "reel_markers_asset.h" #include "decrypted_kdm_key.h" #include "decrypted_kdm.h" #include "interop_subtitle_asset.h" @@ -84,6 +85,11 @@ Reel::Reel (boost::shared_ptr<const cxml::Node> node) _main_subtitle.reset (new ReelSubtitleAsset (main_subtitle)); } + shared_ptr<cxml::Node> main_markers = asset_list->optional_node_child ("MainMarkers"); + if (main_markers) { + _main_markers.reset (new ReelMarkersAsset (main_markers)); + } + /* XXX: it's not ideal that we silently tolerate Interop or SMPTE nodes here */ /* XXX: not sure if Interop supports multiple closed captions */ list<shared_ptr<cxml::Node> > closed_captions = asset_list->node_children ("MainClosedCaption"); @@ -110,6 +116,10 @@ Reel::write_to_cpl (xmlpp::Element* node, Standard standard) const reel->add_child("Id")->add_child_text ("urn:uuid:" + make_uuid()); xmlpp::Element* asset_list = reel->add_child ("AssetList"); + if (_main_markers) { + _main_markers->write_to_cpl (asset_list, standard); + } + if (_main_picture && dynamic_pointer_cast<ReelMonoPictureAsset> (_main_picture)) { /* Mono pictures come before other stuff... */ _main_picture->write_to_cpl (asset_list, standard); @@ -167,6 +177,10 @@ Reel::equals (boost::shared_ptr<const Reel> other, EqualityOptions opt, NoteHand return false; } + if (_main_markers && !_main_markers->equals (other->_main_markers, opt, note)) { + return false; + } + if (_closed_captions.size() != other->_closed_captions.size()) { return false; } @@ -250,6 +264,7 @@ Reel::add (shared_ptr<ReelAsset> asset) shared_ptr<ReelPictureAsset> p = dynamic_pointer_cast<ReelPictureAsset> (asset); shared_ptr<ReelSoundAsset> so = dynamic_pointer_cast<ReelSoundAsset> (asset); shared_ptr<ReelSubtitleAsset> su = dynamic_pointer_cast<ReelSubtitleAsset> (asset); + shared_ptr<ReelMarkersAsset> m = dynamic_pointer_cast<ReelMarkersAsset> (asset); shared_ptr<ReelClosedCaptionAsset> c = dynamic_pointer_cast<ReelClosedCaptionAsset> (asset); shared_ptr<ReelAtmosAsset> a = dynamic_pointer_cast<ReelAtmosAsset> (asset); if (p) { @@ -258,6 +273,8 @@ Reel::add (shared_ptr<ReelAsset> asset) _main_sound = so; } else if (su) { _main_subtitle = su; + } else if (m) { + _main_markers = m; } else if (c) { _closed_captions.push_back (c); } else if (a) { @@ -319,6 +336,9 @@ Reel::duration () const if (_main_subtitle) { d = max (d, _main_subtitle->duration ()); } + if (_main_markers) { + d = max (d, _main_markers->duration ()); + } BOOST_FOREACH (shared_ptr<ReelClosedCaptionAsset> i, _closed_captions) { d = max (d, i->duration()); } @@ -56,11 +56,12 @@ class ReelAsset; class ReelPictureAsset; class ReelSoundAsset; class ReelSubtitleAsset; +class ReelMarkersAsset; class ReelClosedCaptionAsset; class ReelAtmosAsset; class Content; -/** @brief A reel within a DCP; the part which actually refers to picture, sound and subtitle data */ +/** @brief A reel within a DCP; the part which actually refers to picture, sound, subtitle, marker and Atmos data */ class Reel : public Object { public: @@ -70,11 +71,13 @@ public: boost::shared_ptr<ReelPictureAsset> picture, boost::shared_ptr<ReelSoundAsset> sound = boost::shared_ptr<ReelSoundAsset> (), boost::shared_ptr<ReelSubtitleAsset> subtitle = boost::shared_ptr<ReelSubtitleAsset> (), + boost::shared_ptr<ReelMarkersAsset> markers = boost::shared_ptr<ReelMarkersAsset> (), boost::shared_ptr<ReelAtmosAsset> atmos = boost::shared_ptr<ReelAtmosAsset> () ) : _main_picture (picture) , _main_sound (sound) , _main_subtitle (subtitle) + , _main_markers (markers) , _atmos (atmos) {} @@ -92,6 +95,10 @@ public: return _main_subtitle; } + boost::shared_ptr<ReelMarkersAsset> main_markers () const { + return _main_markers; + } + std::list<boost::shared_ptr<ReelClosedCaptionAsset> > closed_captions () const { return _closed_captions; } @@ -118,6 +125,7 @@ private: boost::shared_ptr<ReelPictureAsset> _main_picture; boost::shared_ptr<ReelSoundAsset> _main_sound; boost::shared_ptr<ReelSubtitleAsset> _main_subtitle; + boost::shared_ptr<ReelMarkersAsset> _main_markers; std::list<boost::shared_ptr<ReelClosedCaptionAsset> > _closed_captions; boost::shared_ptr<ReelAtmosAsset> _atmos; }; diff --git a/src/reel_asset.cc b/src/reel_asset.cc index 72a1937c..caaf3eee 100644 --- a/src/reel_asset.cc +++ b/src/reel_asset.cc @@ -46,54 +46,38 @@ using std::pair; using std::string; using std::make_pair; using boost::shared_ptr; +using boost::optional; using namespace dcp; -ReelAsset::ReelAsset () - : _asset_ref (_id) - , _edit_rate (Fraction (24, 1)) - , _intrinsic_duration (0) - , _entry_point (0) - , _duration (0) -{ - -} - /** Construct a ReelAsset. - * @param asset Asset that this ReelAsset refers to. + * @param id ID of this ReelAsset (which is that of the MXF, if there is one) * @param edit_rate Edit rate for the asset. * @param intrinsic_duration Intrinsic duration of this asset. * @param entry_point Entry point to use in that asset. */ -ReelAsset::ReelAsset (shared_ptr<Asset> asset, Fraction edit_rate, int64_t intrinsic_duration, int64_t entry_point) - : Object (asset->id ()) - , _asset_ref (asset) - , _edit_rate (edit_rate) +ReelAsset::ReelAsset (string id, Fraction edit_rate, int64_t intrinsic_duration, int64_t entry_point) + : Object (id) , _intrinsic_duration (intrinsic_duration) - , _entry_point (entry_point) , _duration (intrinsic_duration - entry_point) - , _hash (asset->hash ()) + , _edit_rate (edit_rate) + , _entry_point (entry_point) { - /* default _annotation_text to the leaf name of our file */ - if (asset->file ()) { - _annotation_text = asset->file()->leaf().string (); - } + } ReelAsset::ReelAsset (shared_ptr<const cxml::Node> node) : Object (remove_urn_uuid (node->string_child ("Id"))) - , _asset_ref (_id) + , _intrinsic_duration (node->number_child<int64_t> ("IntrinsicDuration")) + , _duration (node->number_child<int64_t> ("Duration")) , _annotation_text (node->optional_string_child ("AnnotationText").get_value_or ("")) , _edit_rate (Fraction (node->string_child ("EditRate"))) - , _intrinsic_duration (node->number_child<int64_t> ("IntrinsicDuration")) , _entry_point (node->number_child<int64_t> ("EntryPoint")) - , _duration (node->number_child<int64_t> ("Duration")) - , _hash (node->optional_string_child ("Hash")) { } xmlpp::Node* -ReelAsset::write_to_cpl (xmlpp::Node* node, Standard standard) const +ReelAsset::write_to_cpl_base (xmlpp::Node* node, Standard standard, optional<string> hash) const { xmlpp::Element* a = node->add_child (cpl_node_name (standard)); pair<string, string> const attr = cpl_node_attribute (standard); @@ -110,8 +94,8 @@ ReelAsset::write_to_cpl (xmlpp::Node* node, Standard standard) const a->add_child("IntrinsicDuration")->add_child_text (raw_convert<string> (_intrinsic_duration)); a->add_child("EntryPoint")->add_child_text (raw_convert<string> (_entry_point)); a->add_child("Duration")->add_child_text (raw_convert<string> (_duration)); - if (_hash) { - a->add_child("Hash")->add_child_text (_hash.get()); + if (hash) { + a->add_child("Hash")->add_child_text (hash.get()); } return a; } @@ -129,7 +113,7 @@ ReelAsset::cpl_node_namespace (Standard) const } bool -ReelAsset::equals (shared_ptr<const ReelAsset> other, EqualityOptions opt, NoteHandler note) const +ReelAsset::asset_equals (shared_ptr<const ReelAsset> other, EqualityOptions opt, NoteHandler note) const { if (_annotation_text != other->_annotation_text) { string const s = "Reel: annotation texts differ (" + _annotation_text + " vs " + other->_annotation_text + ")\n"; @@ -161,18 +145,5 @@ ReelAsset::equals (shared_ptr<const ReelAsset> other, EqualityOptions opt, NoteH return false; } - if (_hash != other->_hash) { - if (!opt.reel_hashes_can_differ) { - note (DCP_ERROR, "Reel: hashes differ"); - return false; - } else { - note (DCP_NOTE, "Reel: hashes differ"); - } - } - - if (_asset_ref.resolved () && other->_asset_ref.resolved ()) { - return _asset_ref->equals (other->_asset_ref.asset(), opt, note); - } - return true; } diff --git a/src/reel_asset.h b/src/reel_asset.h index 42409ab9..4092a97a 100644 --- a/src/reel_asset.h +++ b/src/reel_asset.h @@ -65,22 +65,10 @@ class Asset; class ReelAsset : public Object { public: - ReelAsset (); - ReelAsset (boost::shared_ptr<Asset> asset, Fraction edit_rate, int64_t intrinsic_duration, int64_t entry_point); + ReelAsset (std::string id, Fraction edit_rate, int64_t intrinsic_duration, int64_t entry_point); explicit ReelAsset (boost::shared_ptr<const cxml::Node>); - virtual xmlpp::Node* write_to_cpl (xmlpp::Node* node, Standard standard) const; - virtual bool equals (boost::shared_ptr<const ReelAsset>, EqualityOptions, NoteHandler) const; - - /** @return a Ref to our actual asset */ - Ref const & asset_ref () const { - return _asset_ref; - } - - /** @return a Ref to our actual asset */ - Ref & asset_ref () { - return _asset_ref; - } + virtual xmlpp::Node* write_to_cpl (xmlpp::Node* node, Standard standard) const = 0; Fraction edit_rate () const { return _edit_rate; @@ -106,13 +94,6 @@ public: return _duration; } - /** @return the asset's hash, if this ReelAsset has been created from one, - * otherwise the hash written to the CPL for this asset (if present). - */ - boost::optional<std::string> hash () const { - return _hash; - } - std::string annotation_text () const { return _annotation_text; } @@ -121,17 +102,9 @@ public: _annotation_text = at; } -protected: - - template <class T> - boost::shared_ptr<T> asset_of_type () const { - return boost::dynamic_pointer_cast<T> (_asset_ref.asset ()); - } + bool asset_equals (boost::shared_ptr<const ReelAsset>, EqualityOptions, NoteHandler) const; - template <class T> - boost::shared_ptr<T> asset_of_type () { - return boost::dynamic_pointer_cast<T> (_asset_ref.asset ()); - } +protected: /** @return the node name that this asset uses in the CPL's <Reel> node * e.g. MainPicture, MainSound etc. @@ -144,19 +117,15 @@ protected: /** @return Any namespace that should be used on the asset's node in the CPL */ virtual std::pair<std::string, std::string> cpl_node_namespace (Standard) const; - /** Reference to the asset (MXF or XML file) that this reel entry - * applies to. - */ - Ref _asset_ref; + xmlpp::Node* write_to_cpl_base (xmlpp::Node* node, Standard standard, boost::optional<std::string> hash) const; + + int64_t _intrinsic_duration; ///< The <IntrinsicDuration> from the reel's entry for this asset + int64_t _duration; ///< The <Duration> from the reel's entry for this asset private: std::string _annotation_text; ///< The <AnnotationText> from the reel's entry for this asset Fraction _edit_rate; ///< The <EditRate> from the reel's entry for this asset - int64_t _intrinsic_duration; ///< The <IntrinsicDuration> from the reel's entry for this asset int64_t _entry_point; ///< The <EntryPoint> from the reel's entry for this asset - int64_t _duration; ///< The <Duration> from the reel's entry for this asset - /** Either our asset's computed hash or the hash read in from the CPL, if it's present */ - boost::optional<std::string> _hash; }; } diff --git a/src/reel_atmos_asset.cc b/src/reel_atmos_asset.cc index 636a7a79..1ce8b6ea 100644 --- a/src/reel_atmos_asset.cc +++ b/src/reel_atmos_asset.cc @@ -47,7 +47,8 @@ using boost::shared_ptr; using namespace dcp; ReelAtmosAsset::ReelAtmosAsset (boost::shared_ptr<AtmosAsset> asset, int64_t entry_point) - : ReelAsset (asset, asset->edit_rate(), asset->intrinsic_duration(), entry_point) + : ReelAsset (asset->id(), asset->edit_rate(), asset->intrinsic_duration(), entry_point) + , ReelMXF (asset, asset->key_id()) { } @@ -81,7 +82,20 @@ ReelAtmosAsset::key_type () const xmlpp::Node * ReelAtmosAsset::write_to_cpl (xmlpp::Node* node, Standard standard) const { - xmlpp::Node* asset = ReelAsset::write_to_cpl (node, standard); + xmlpp::Node* asset = write_to_cpl_base (node, standard, hash()); asset->add_child("axd:DataType")->add_child_text("urn:smpte:ul:060e2b34.04010105.0e090604.00000000"); return asset; } + +bool +ReelAtmosAsset::equals (shared_ptr<const ReelAtmosAsset> other, EqualityOptions opt, NoteHandler note) const +{ + if (!asset_equals (other, opt, note)) { + return false; + } + if (!mxf_equals (other, opt, note)) { + return false; + } + + return true; +} diff --git a/src/reel_atmos_asset.h b/src/reel_atmos_asset.h index e93a5414..6fb4bf51 100644 --- a/src/reel_atmos_asset.h +++ b/src/reel_atmos_asset.h @@ -60,6 +60,7 @@ public: } xmlpp::Node* write_to_cpl (xmlpp::Node* node, Standard standard) const; + bool equals (boost::shared_ptr<const ReelAtmosAsset>, EqualityOptions, NoteHandler) const; private: std::string key_type () const; diff --git a/src/reel_closed_caption_asset.cc b/src/reel_closed_caption_asset.cc index b7629011..435c3438 100644 --- a/src/reel_closed_caption_asset.cc +++ b/src/reel_closed_caption_asset.cc @@ -50,8 +50,8 @@ using boost::optional; using namespace dcp; ReelClosedCaptionAsset::ReelClosedCaptionAsset (boost::shared_ptr<SubtitleAsset> asset, Fraction edit_rate, int64_t intrinsic_duration, int64_t entry_point) - : ReelAsset (asset, edit_rate, intrinsic_duration, entry_point) - , ReelMXF (dynamic_pointer_cast<SMPTESubtitleAsset>(asset) ? dynamic_pointer_cast<SMPTESubtitleAsset>(asset)->key_id() : optional<string>()) + : ReelAsset (asset->id(), edit_rate, intrinsic_duration, entry_point) + , ReelMXF (asset, dynamic_pointer_cast<SMPTESubtitleAsset>(asset) ? dynamic_pointer_cast<SMPTESubtitleAsset>(asset)->key_id() : optional<string>()) { } @@ -99,7 +99,7 @@ ReelClosedCaptionAsset::key_type () const xmlpp::Node * ReelClosedCaptionAsset::write_to_cpl (xmlpp::Node* node, Standard standard) const { - xmlpp::Node* asset = ReelAsset::write_to_cpl (node, standard); + xmlpp::Node* asset = write_to_cpl_base (node, standard, hash()); if (key_id()) { /* Find <Hash> */ @@ -113,3 +113,16 @@ ReelClosedCaptionAsset::write_to_cpl (xmlpp::Node* node, Standard standard) cons return asset; } + +bool +ReelClosedCaptionAsset::equals (shared_ptr<const ReelClosedCaptionAsset> other, EqualityOptions opt, NoteHandler note) const +{ + if (!asset_equals (other, opt, note)) { + return false; + } + if (!mxf_equals (other, opt, note)) { + return false; + } + + return true; +} diff --git a/src/reel_closed_caption_asset.h b/src/reel_closed_caption_asset.h index 80e444d9..6ed50ae0 100644 --- a/src/reel_closed_caption_asset.h +++ b/src/reel_closed_caption_asset.h @@ -56,6 +56,7 @@ public: explicit ReelClosedCaptionAsset (boost::shared_ptr<const cxml::Node>); xmlpp::Node* write_to_cpl (xmlpp::Node* node, Standard standard) const; + bool equals (boost::shared_ptr<const ReelClosedCaptionAsset>, EqualityOptions, NoteHandler) const; boost::shared_ptr<SubtitleAsset> asset () const { return asset_of_type<SubtitleAsset> (); diff --git a/src/reel_markers_asset.cc b/src/reel_markers_asset.cc new file mode 100644 index 00000000..8c5f66dd --- /dev/null +++ b/src/reel_markers_asset.cc @@ -0,0 +1,140 @@ +/* + Copyright (C) 2019 Carl Hetherington <cth@carlh.net> + + This file is part of libdcp. + + libdcp is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + libdcp is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libdcp. If not, see <http://www.gnu.org/licenses/>. + + In addition, as a special exception, the copyright holders give + permission to link the code of portions of this program with the + OpenSSL library under certain conditions as described in each + individual source file, and distribute linked combinations + including the two. + + You must obey the GNU General Public License in all respects + for all of the code used other than OpenSSL. If you modify + file(s) with this exception, you may extend this exception to your + version of the file(s), but you are not obligated to do so. If you + do not wish to do so, delete this exception statement from your + version. If you delete this exception statement from all source + files in the program, then also delete it here. +*/ + +#include "reel_markers_asset.h" +#include "raw_convert.h" +#include "dcp_assert.h" +#include <libxml++/libxml++.h> +#include <boost/foreach.hpp> + +using std::string; +using std::map; +using std::max; +using boost::optional; +using boost::shared_ptr; +using namespace dcp; + +ReelMarkersAsset::ReelMarkersAsset (Fraction edit_rate, int64_t entry_point) + : ReelAsset (make_uuid(), edit_rate, 0, entry_point) +{ + +} + +ReelMarkersAsset::ReelMarkersAsset (cxml::ConstNodePtr node) + : ReelAsset (node) +{ + cxml::ConstNodePtr list = node->node_child ("MarkerList"); + DCP_ASSERT (list); + BOOST_FOREACH (cxml::ConstNodePtr i, list->node_children("Marker")) { + set (marker_from_string(i->string_child("Label")), dcp::Time(i->number_child<int64_t>("Offset"), edit_rate().as_float(), edit_rate().numerator)); + } +} + +string +ReelMarkersAsset::cpl_node_name (Standard) const +{ + return "MainMarkers"; +} + +void +ReelMarkersAsset::set (Marker m, Time t) +{ + _markers[m] = t; + update_duration (); +} + +void +ReelMarkersAsset::unset (Marker m) +{ + _markers.erase (m); + update_duration (); +} + +optional<Time> +ReelMarkersAsset::get (Marker m) const +{ + map<Marker, Time>::const_iterator i = _markers.find (m); + if (i == _markers.end ()) { + return optional<Time>(); + } + return i->second; +} + +void +ReelMarkersAsset::update_duration () +{ + int const tcr = edit_rate().numerator / edit_rate().denominator; + _intrinsic_duration = 0; + for (map<Marker, Time>::const_iterator i = _markers.begin(); i != _markers.end(); ++i) { + _intrinsic_duration = max(_intrinsic_duration, i->second.as_editable_units(tcr)); + } + _duration = _intrinsic_duration; +} + +xmlpp::Node* +ReelMarkersAsset::write_to_cpl (xmlpp::Node* node, Standard standard) const +{ + int const tcr = edit_rate().numerator / edit_rate().denominator; + xmlpp::Node* asset = write_to_cpl_base (node, standard, optional<string>()); + xmlpp::Node* ml = asset->add_child("MarkerList"); + for (map<Marker, Time>::const_iterator i = _markers.begin(); i != _markers.end(); ++i) { + xmlpp::Node* m = ml->add_child("Marker"); + m->add_child("Label")->add_child_text (marker_to_string(i->first)); + m->add_child("Offset")->add_child_text (raw_convert<string>(i->second.as_editable_units(tcr))); + } + + return asset; +} + +bool +ReelMarkersAsset::equals (shared_ptr<const ReelMarkersAsset> other, EqualityOptions opt, NoteHandler note) const +{ + if (!asset_equals(other, opt, note)) { + return false; + } + + if (get(FFOC) != other->get(FFOC) || + get(LFOC) != other->get(LFOC) || + get(FFTC) != other->get(FFTC) || + get(LFTC) != other->get(LFTC) || + get(FFOI) != other->get(FFOI) || + get(LFOI) != other->get(LFOI) || + get(FFEC) != other->get(FFEC) || + get(LFEC) != other->get(LFEC) || + get(FFMC) != other->get(FFMC) || + get(LFMC) != other->get(LFMC)) { + return false; + } + + return true; +} diff --git a/src/reel_markers_asset.h b/src/reel_markers_asset.h new file mode 100644 index 00000000..4077fbbe --- /dev/null +++ b/src/reel_markers_asset.h @@ -0,0 +1,61 @@ +/* + Copyright (C) 2019 Carl Hetherington <cth@carlh.net> + + This file is part of libdcp. + + libdcp is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + libdcp is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libdcp. If not, see <http://www.gnu.org/licenses/>. + + In addition, as a special exception, the copyright holders give + permission to link the code of portions of this program with the + OpenSSL library under certain conditions as described in each + individual source file, and distribute linked combinations + including the two. + + You must obey the GNU General Public License in all respects + for all of the code used other than OpenSSL. If you modify + file(s) with this exception, you may extend this exception to your + version of the file(s), but you are not obligated to do so. If you + do not wish to do so, delete this exception statement from your + version. If you delete this exception statement from all source + files in the program, then also delete it here. +*/ + +#include "reel_asset.h" +#include "dcp_time.h" + +namespace dcp { + +class ReelMarkersAsset : public ReelAsset +{ +public: + ReelMarkersAsset (Fraction edit_rate, int64_t entry_point); + explicit ReelMarkersAsset (boost::shared_ptr<const cxml::Node>); + + xmlpp::Node* write_to_cpl (xmlpp::Node* node, Standard standard) const; + bool equals (boost::shared_ptr<const ReelMarkersAsset>, EqualityOptions, NoteHandler) const; + + void set (Marker, Time); + void unset (Marker); + boost::optional<Time> get (Marker m) const; + +protected: + std::string cpl_node_name (Standard) const; + +private: + void update_duration (); + + std::map<Marker, Time> _markers; +}; + +} diff --git a/src/reel_mono_picture_asset.cc b/src/reel_mono_picture_asset.cc index e894764e..36abb55e 100644 --- a/src/reel_mono_picture_asset.cc +++ b/src/reel_mono_picture_asset.cc @@ -43,11 +43,6 @@ using std::string; using boost::shared_ptr; using namespace dcp; -ReelMonoPictureAsset::ReelMonoPictureAsset () -{ - -} - ReelMonoPictureAsset::ReelMonoPictureAsset (boost::shared_ptr<MonoPictureAsset> asset, int64_t entry_point) : ReelPictureAsset (asset, entry_point) { diff --git a/src/reel_mono_picture_asset.h b/src/reel_mono_picture_asset.h index 4c5eaa08..099feafd 100644 --- a/src/reel_mono_picture_asset.h +++ b/src/reel_mono_picture_asset.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2017 Carl Hetherington <cth@carlh.net> + Copyright (C) 2014-2019 Carl Hetherington <cth@carlh.net> This file is part of libdcp. @@ -51,7 +51,6 @@ class MonoPictureAsset; class ReelMonoPictureAsset : public ReelPictureAsset { public: - ReelMonoPictureAsset (); ReelMonoPictureAsset (boost::shared_ptr<MonoPictureAsset> asset, int64_t entry_point); explicit ReelMonoPictureAsset (boost::shared_ptr<const cxml::Node>); diff --git a/src/reel_mxf.cc b/src/reel_mxf.cc index 9c2d3b60..f170157e 100644 --- a/src/reel_mxf.cc +++ b/src/reel_mxf.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2015 Carl Hetherington <cth@carlh.net> + Copyright (C) 2012-2019 Carl Hetherington <cth@carlh.net> This file is part of libdcp. @@ -43,16 +43,39 @@ using boost::shared_ptr; using boost::optional; using namespace dcp; -ReelMXF::ReelMXF (optional<string> key_id) - : _key_id (key_id) +ReelMXF::ReelMXF (shared_ptr<Asset> asset, optional<string> key_id) + : _asset_ref (asset) + , _key_id (key_id) + , _hash (asset->hash()) { } ReelMXF::ReelMXF (shared_ptr<const cxml::Node> node) - : _key_id (node->optional_string_child ("KeyId")) + : _asset_ref (remove_urn_uuid(node->string_child("Id"))) + , _key_id (node->optional_string_child ("KeyId")) + , _hash (node->optional_string_child ("Hash")) { if (_key_id) { _key_id = remove_urn_uuid (*_key_id); } } + +bool +ReelMXF::mxf_equals (shared_ptr<const ReelMXF> other, EqualityOptions opt, NoteHandler note) const +{ + if (_hash != other->_hash) { + if (!opt.reel_hashes_can_differ) { + note (DCP_ERROR, "Reel: hashes differ"); + return false; + } else { + note (DCP_NOTE, "Reel: hashes differ"); + } + } + + if (_asset_ref.resolved() && other->_asset_ref.resolved()) { + return _asset_ref->equals (other->_asset_ref.asset(), opt, note); + } + + return true; +} diff --git a/src/reel_mxf.h b/src/reel_mxf.h index 91625579..7bc8f75b 100644 --- a/src/reel_mxf.h +++ b/src/reel_mxf.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2015 Carl Hetherington <cth@carlh.net> + Copyright (C) 2012-2019 Carl Hetherington <cth@carlh.net> This file is part of libdcp. @@ -35,9 +35,10 @@ * @brief ReelMXF */ -#ifndef LIBDCP_REEL_ENCRYPTABLE_ASSET_H -#define LIBDCP_REEL_ENCRYPTABLE_ASSET_H +#ifndef LIBDCP_REEL_MXF_H +#define LIBDCP_REEL_MXF_H +#include "ref.h" #include <boost/optional.hpp> #include <boost/shared_ptr.hpp> #include <string> @@ -54,14 +55,30 @@ namespace dcp { class ReelMXF { public: - ReelMXF () {} - explicit ReelMXF (boost::optional<std::string> key_id); + explicit ReelMXF (boost::shared_ptr<Asset> asset, boost::optional<std::string> key_id); explicit ReelMXF (boost::shared_ptr<const cxml::Node>); virtual ~ReelMXF () {} /** @return the 4-character key type for this MXF (MDIK, MDAK, etc.) */ virtual std::string key_type () const = 0; + /** @return a Ref to our actual asset */ + Ref const & asset_ref () const { + return _asset_ref; + } + + /** @return a Ref to our actual asset */ + Ref & asset_ref () { + return _asset_ref; + } + + /** @return the asset's hash, if this ReelMXF has been created from one, + * otherwise the hash written to the CPL for this asset (if present). + */ + boost::optional<std::string> hash () const { + return _hash; + } + /** @return true if a KeyId is specified for this asset, implying * that its content is encrypted. */ @@ -76,8 +93,29 @@ public: return _key_id; } + bool mxf_equals (boost::shared_ptr<const ReelMXF> other, EqualityOptions opt, NoteHandler note) const; + +protected: + + template <class T> + boost::shared_ptr<T> asset_of_type () const { + return boost::dynamic_pointer_cast<T> (_asset_ref.asset ()); + } + + template <class T> + boost::shared_ptr<T> asset_of_type () { + return boost::dynamic_pointer_cast<T> (_asset_ref.asset ()); + } + + /** Reference to the asset (MXF or XML file) that this reel entry + * applies to. + */ + Ref _asset_ref; + private: boost::optional<std::string> _key_id; ///< The <KeyId> from the reel's entry for this asset, if there is one + /** Either our asset's computed hash or the hash read in from the CPL, if it's present */ + boost::optional<std::string> _hash; }; } diff --git a/src/reel_picture_asset.cc b/src/reel_picture_asset.cc index 1933c769..5b4ced67 100644 --- a/src/reel_picture_asset.cc +++ b/src/reel_picture_asset.cc @@ -52,16 +52,9 @@ using boost::dynamic_pointer_cast; using boost::optional; using namespace dcp; -ReelPictureAsset::ReelPictureAsset () - : _frame_rate (Fraction (24, 1)) - , _screen_aspect_ratio (Fraction (1998, 1080)) -{ - -} - ReelPictureAsset::ReelPictureAsset (shared_ptr<PictureAsset> asset, int64_t entry_point) - : ReelAsset (asset, asset->edit_rate(), asset->intrinsic_duration(), entry_point) - , ReelMXF (asset->key_id()) + : ReelAsset (asset->id(), asset->edit_rate(), asset->intrinsic_duration(), entry_point) + , ReelMXF (asset, asset->key_id()) , _frame_rate (asset->frame_rate ()) , _screen_aspect_ratio (asset->screen_aspect_ratio ()) { @@ -89,7 +82,7 @@ ReelPictureAsset::ReelPictureAsset (shared_ptr<const cxml::Node> node) xmlpp::Node* ReelPictureAsset::write_to_cpl (xmlpp::Node* node, Standard standard) const { - xmlpp::Node* asset = ReelAsset::write_to_cpl (node, standard); + xmlpp::Node* asset = write_to_cpl_base (node, standard, hash()); asset->add_child("FrameRate")->add_child_text(String::compose("%1 %2", _frame_rate.numerator, _frame_rate.denominator)); if (standard == INTEROP) { @@ -135,9 +128,12 @@ ReelPictureAsset::key_type () const } bool -ReelPictureAsset::equals (shared_ptr<const ReelAsset> other, EqualityOptions opt, NoteHandler note) const +ReelPictureAsset::equals (shared_ptr<const ReelPictureAsset> other, EqualityOptions opt, NoteHandler note) const { - if (!ReelAsset::equals (other, opt, note)) { + if (!asset_equals (other, opt, note)) { + return false; + } + if (!mxf_equals (other, opt, note)) { return false; } diff --git a/src/reel_picture_asset.h b/src/reel_picture_asset.h index a20c216f..88729148 100644 --- a/src/reel_picture_asset.h +++ b/src/reel_picture_asset.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2015 Carl Hetherington <cth@carlh.net> + Copyright (C) 2014-2019 Carl Hetherington <cth@carlh.net> This file is part of libdcp. @@ -50,12 +50,11 @@ namespace dcp { class ReelPictureAsset : public ReelAsset, public ReelMXF { public: - ReelPictureAsset (); ReelPictureAsset (boost::shared_ptr<PictureAsset> asset, int64_t entry_point); explicit ReelPictureAsset (boost::shared_ptr<const cxml::Node>); virtual xmlpp::Node* write_to_cpl (xmlpp::Node* node, Standard standard) const; - virtual bool equals (boost::shared_ptr<const ReelAsset>, EqualityOptions, NoteHandler) const; + bool equals (boost::shared_ptr<const ReelPictureAsset>, EqualityOptions, NoteHandler) const; /** @return the PictureAsset that this object refers to */ boost::shared_ptr<const PictureAsset> asset () const { diff --git a/src/reel_sound_asset.cc b/src/reel_sound_asset.cc index baacfe72..25259f42 100644 --- a/src/reel_sound_asset.cc +++ b/src/reel_sound_asset.cc @@ -45,8 +45,8 @@ using boost::shared_ptr; using namespace dcp; ReelSoundAsset::ReelSoundAsset (shared_ptr<SoundAsset> asset, int64_t entry_point) - : ReelAsset (asset, asset->edit_rate(), asset->intrinsic_duration(), entry_point) - , ReelMXF (asset->key_id()) + : ReelAsset (asset->id(), asset->edit_rate(), asset->intrinsic_duration(), entry_point) + , ReelMXF (asset, asset->key_id()) { } @@ -74,7 +74,7 @@ ReelSoundAsset::key_type () const xmlpp::Node * ReelSoundAsset::write_to_cpl (xmlpp::Node* node, Standard standard) const { - xmlpp::Node* asset = ReelAsset::write_to_cpl (node, standard); + xmlpp::Node* asset = write_to_cpl_base (node, standard, hash()); if (key_id ()) { /* Find <Hash> */ @@ -84,3 +84,16 @@ ReelSoundAsset::write_to_cpl (xmlpp::Node* node, Standard standard) const return asset; } + +bool +ReelSoundAsset::equals (shared_ptr<const ReelSoundAsset> other, EqualityOptions opt, NoteHandler note) const +{ + if (!asset_equals (other, opt, note)) { + return false; + } + if (!mxf_equals (other, opt, note)) { + return false; + } + + return true; +} diff --git a/src/reel_sound_asset.h b/src/reel_sound_asset.h index 2fb01c8d..57d14bc6 100644 --- a/src/reel_sound_asset.h +++ b/src/reel_sound_asset.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2015 Carl Hetherington <cth@carlh.net> + Copyright (C) 2014-2019 Carl Hetherington <cth@carlh.net> This file is part of libdcp. @@ -53,6 +53,7 @@ public: explicit ReelSoundAsset (boost::shared_ptr<const cxml::Node>); xmlpp::Node* write_to_cpl (xmlpp::Node* node, Standard standard) const; + bool equals (boost::shared_ptr<const ReelSoundAsset>, EqualityOptions, NoteHandler) const; /** @return the SoundAsset that this object refers to */ boost::shared_ptr<SoundAsset> asset () { diff --git a/src/reel_stereo_picture_asset.cc b/src/reel_stereo_picture_asset.cc index f194cca0..8a169df2 100644 --- a/src/reel_stereo_picture_asset.cc +++ b/src/reel_stereo_picture_asset.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2014 Carl Hetherington <cth@carlh.net> + Copyright (C) 2014-2019 Carl Hetherington <cth@carlh.net> This file is part of libdcp. @@ -45,11 +45,6 @@ using std::make_pair; using boost::shared_ptr; using namespace dcp; -ReelStereoPictureAsset::ReelStereoPictureAsset () -{ - -} - ReelStereoPictureAsset::ReelStereoPictureAsset (boost::shared_ptr<StereoPictureAsset> mxf, int64_t entry_point) : ReelPictureAsset (mxf, entry_point) { diff --git a/src/reel_stereo_picture_asset.h b/src/reel_stereo_picture_asset.h index c7223495..80353b77 100644 --- a/src/reel_stereo_picture_asset.h +++ b/src/reel_stereo_picture_asset.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2015 Carl Hetherington <cth@carlh.net> + Copyright (C) 2014-2019 Carl Hetherington <cth@carlh.net> This file is part of libdcp. @@ -51,7 +51,6 @@ class StereoPictureAsset; class ReelStereoPictureAsset : public ReelPictureAsset { public: - ReelStereoPictureAsset (); ReelStereoPictureAsset (boost::shared_ptr<StereoPictureAsset> content, int64_t entry_point); explicit ReelStereoPictureAsset (boost::shared_ptr<const cxml::Node>); diff --git a/src/reel_subtitle_asset.cc b/src/reel_subtitle_asset.cc index 75116b2b..a90513d5 100644 --- a/src/reel_subtitle_asset.cc +++ b/src/reel_subtitle_asset.cc @@ -47,8 +47,8 @@ using boost::optional; using namespace dcp; ReelSubtitleAsset::ReelSubtitleAsset (boost::shared_ptr<SubtitleAsset> asset, Fraction edit_rate, int64_t intrinsic_duration, int64_t entry_point) - : ReelAsset (asset, edit_rate, intrinsic_duration, entry_point) - , ReelMXF (dynamic_pointer_cast<SMPTESubtitleAsset>(asset) ? dynamic_pointer_cast<SMPTESubtitleAsset>(asset)->key_id() : optional<string>()) + : ReelAsset (asset->id(), edit_rate, intrinsic_duration, entry_point) + , ReelMXF (asset, dynamic_pointer_cast<SMPTESubtitleAsset>(asset) ? dynamic_pointer_cast<SMPTESubtitleAsset>(asset)->key_id() : optional<string>()) { } @@ -76,7 +76,7 @@ ReelSubtitleAsset::key_type () const xmlpp::Node * ReelSubtitleAsset::write_to_cpl (xmlpp::Node* node, Standard standard) const { - xmlpp::Node* asset = ReelAsset::write_to_cpl (node, standard); + xmlpp::Node* asset = write_to_cpl_base (node, standard, hash()); if (key_id ()) { /* Find <Hash> */ @@ -86,3 +86,16 @@ ReelSubtitleAsset::write_to_cpl (xmlpp::Node* node, Standard standard) const return asset; } + +bool +ReelSubtitleAsset::equals (shared_ptr<const ReelSubtitleAsset> other, EqualityOptions opt, NoteHandler note) const +{ + if (!asset_equals (other, opt, note)) { + return false; + } + if (!mxf_equals (other, opt, note)) { + return false; + } + + return true; +} diff --git a/src/reel_subtitle_asset.h b/src/reel_subtitle_asset.h index 8e0edc49..4cc03cf1 100644 --- a/src/reel_subtitle_asset.h +++ b/src/reel_subtitle_asset.h @@ -56,6 +56,7 @@ public: explicit ReelSubtitleAsset (boost::shared_ptr<const cxml::Node>); xmlpp::Node* write_to_cpl (xmlpp::Node* node, Standard standard) const; + bool equals (boost::shared_ptr<const ReelSubtitleAsset>, EqualityOptions, NoteHandler) const; boost::shared_ptr<SubtitleAsset> asset () const { return asset_of_type<SubtitleAsset> (); diff --git a/src/types.cc b/src/types.cc index 9af5f119..d27b2ec1 100644 --- a/src/types.cc +++ b/src/types.cc @@ -369,3 +369,60 @@ dcp::content_kind_from_string (string kind) throw BadContentKindError (kind); } + +string +dcp::marker_to_string (dcp::Marker m) +{ + switch (m) { + case FFOC: + return "FFOC"; + case LFOC: + return "LFOC"; + case FFTC: + return "FFTC"; + case LFTC: + return "LFTC"; + case FFOI: + return "FFOI"; + case LFOI: + return "LFOI"; + case FFEC: + return "FFEC"; + case LFEC: + return "LFEC"; + case FFMC: + return "FFMC"; + case LFMC: + return "LFMC"; + } + + DCP_ASSERT (false); +} + +dcp::Marker +dcp::marker_from_string (string s) +{ + if (s == "FFOC") { + return FFOC; + } else if (s == "LFOC") { + return LFOC; + } else if (s == "FFTC") { + return FFTC; + } else if (s == "LFTC") { + return LFTC; + } else if (s == "FFOI") { + return FFOI; + } else if (s == "LFOI") { + return LFOI; + } else if (s == "FFEC") { + return FFEC; + } else if (s == "LFEC") { + return LFEC; + } else if (s == "FFMC") { + return FFMC; + } else if (s == "LFMC") { + return LFMC; + } + + DCP_ASSERT (false); +} diff --git a/src/types.h b/src/types.h index 2652524c..a0965e83 100644 --- a/src/types.h +++ b/src/types.h @@ -276,6 +276,22 @@ const float ASPECT_ADJUST_EPSILON = 1e-3; */ const float ALIGN_EPSILON = 1e-3; +enum Marker { + FFOC, ///< first frame of composition + LFOC, ///< last frame of composition + FFTC, ///< first frame of title credits + LFTC, ///< last frame of title credits + FFOI, ///< first frame of intermission + LFOI, ///< last frame of intermission + FFEC, ///< first frame of end credits + LFEC, ///< last frame of end credits + FFMC, ///< first frame of moving credits + LFMC ///< last frame of moving credits +}; + +std::string marker_to_string (Marker); +Marker marker_from_string (std::string); + } #endif diff --git a/src/verify.cc b/src/verify.cc index 4a656874..9ab9b150 100644 --- a/src/verify.cc +++ b/src/verify.cc @@ -61,19 +61,19 @@ enum Result { }; static Result -verify_asset (shared_ptr<DCP> dcp, shared_ptr<ReelAsset> reel_asset, function<void (float)> progress) +verify_asset (shared_ptr<DCP> dcp, shared_ptr<ReelMXF> reel_mxf, function<void (float)> progress) { - string const actual_hash = reel_asset->asset_ref()->hash(progress); + string const actual_hash = reel_mxf->asset_ref()->hash(progress); list<shared_ptr<PKL> > pkls = dcp->pkls(); /* We've read this DCP in so it must have at least one PKL */ DCP_ASSERT (!pkls.empty()); - shared_ptr<Asset> asset = reel_asset->asset_ref().asset(); + shared_ptr<Asset> asset = reel_mxf->asset_ref().asset(); optional<string> pkl_hash; BOOST_FOREACH (shared_ptr<PKL> i, pkls) { - pkl_hash = i->hash (reel_asset->asset_ref()->id()); + pkl_hash = i->hash (reel_mxf->asset_ref()->id()); if (pkl_hash) { break; } @@ -81,7 +81,7 @@ verify_asset (shared_ptr<DCP> dcp, shared_ptr<ReelAsset> reel_asset, function<vo DCP_ASSERT (pkl_hash); - optional<string> cpl_hash = reel_asset->hash(); + optional<string> cpl_hash = reel_mxf->hash(); if (cpl_hash && *cpl_hash != *pkl_hash) { return RESULT_CPL_PKL_DIFFER; } diff --git a/src/wscript b/src/wscript index ae881a8b..4b39a979 100644 --- a/src/wscript +++ b/src/wscript @@ -81,6 +81,7 @@ def build(bld): reel_mono_picture_asset.cc reel_mxf.cc reel_picture_asset.cc + reel_markers_asset.cc reel_sound_asset.cc reel_stereo_picture_asset.cc reel_subtitle_asset.cc diff --git a/test/dcp_test.cc b/test/dcp_test.cc index 7c7ff12e..ed3d473d 100644 --- a/test/dcp_test.cc +++ b/test/dcp_test.cc @@ -295,6 +295,7 @@ BOOST_AUTO_TEST_CASE (dcp_test5) shared_ptr<dcp::ReelMonoPictureAsset> (new dcp::ReelMonoPictureAsset (mp, 0)), shared_ptr<dcp::ReelSoundAsset> (new dcp::ReelSoundAsset (ms, 0)), shared_ptr<dcp::ReelSubtitleAsset> (), + shared_ptr<dcp::ReelMarkersAsset> (), shared_ptr<dcp::ReelAtmosAsset> (new dcp::ReelAtmosAsset (am, 0)) ) )); diff --git a/test/markers_test.cc b/test/markers_test.cc new file mode 100644 index 00000000..813736de --- /dev/null +++ b/test/markers_test.cc @@ -0,0 +1,106 @@ +/* + Copyright (C) 2019 Carl Hetherington <cth@carlh.net> + + This file is part of libdcp. + + libdcp is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + libdcp is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libdcp. If not, see <http://www.gnu.org/licenses/>. + + In addition, as a special exception, the copyright holders give + permission to link the code of portions of this program with the + OpenSSL library under certain conditions as described in each + individual source file, and distribute linked combinations + including the two. + + You must obey the GNU General Public License in all respects + for all of the code used other than OpenSSL. If you modify + file(s) with this exception, you may extend this exception to your + version of the file(s), but you are not obligated to do so. If you + do not wish to do so, delete this exception statement from your + version. If you delete this exception statement from all source + files in the program, then also delete it here. +*/ + +#include "cpl.h" +#include "reel.h" +#include "reel_markers_asset.h" +#include <boost/shared_ptr.hpp> +#include <boost/test/unit_test.hpp> + +using std::string; +using boost::shared_ptr; + +BOOST_AUTO_TEST_CASE (markers_write_test) +{ + dcp::CPL cpl("Markers test", dcp::TEST); + + shared_ptr<dcp::ReelMarkersAsset> asset (new dcp::ReelMarkersAsset(dcp::Fraction(24, 1), 0)); + asset->set (dcp::FFOC, dcp::Time(1, 1, 9, 16, 24)); + asset->set (dcp::LFOC, dcp::Time(2, 5, 3, 0, 24)); + asset->set (dcp::FFTC, dcp::Time(0, 6, 4, 2, 24)); + asset->set (dcp::LFTC, dcp::Time(0, 6, 4, 18, 24)); + asset->set (dcp::FFOI, dcp::Time(3, 6, 4, 18, 24)); + asset->set (dcp::LFOI, dcp::Time(3, 2, 4, 18, 24)); + asset->set (dcp::FFEC, dcp::Time(3, 2, 7, 18, 24)); + asset->set (dcp::LFEC, dcp::Time(3, 2, 8, 18, 24)); + asset->set (dcp::FFMC, dcp::Time(4, 2, 8, 18, 24)); + asset->set (dcp::LFMC, dcp::Time(4, 3, 8, 18, 24)); + + shared_ptr<dcp::Reel> reel (new dcp::Reel()); + reel->add (asset); + + cpl.add (reel); + + cpl.write_xml ("build/test/markers_test.xml", dcp::SMPTE, shared_ptr<dcp::CertificateChain>()); +} + +static void +note_handler (dcp::NoteType, string) +{ + +} + +BOOST_AUTO_TEST_CASE (markers_read_test, * boost::unit_test::depends_on("markers_write_test")) +{ + dcp::CPL cpl ("build/test/markers_test.xml"); + BOOST_CHECK_EQUAL (cpl.reels().size(), 1); + shared_ptr<dcp::Reel> reel = cpl.reels().front(); + shared_ptr<dcp::ReelMarkersAsset> markers = reel->main_markers (); + BOOST_REQUIRE (markers); + + BOOST_REQUIRE (markers->get(dcp::FFOC)); + BOOST_CHECK (markers->get(dcp::FFOC) == dcp::Time(1, 1, 9, 16, 24)); + BOOST_REQUIRE (markers->get(dcp::LFOC)); + BOOST_CHECK (markers->get(dcp::LFOC) == dcp::Time(2, 5, 3, 0, 24)); + BOOST_REQUIRE (markers->get(dcp::FFTC)); + BOOST_CHECK (markers->get (dcp::FFTC) == dcp::Time(0, 6, 4, 2, 24)); + BOOST_REQUIRE (markers->get(dcp::LFTC)); + BOOST_CHECK (markers->get (dcp::LFTC) == dcp::Time(0, 6, 4, 18, 24)); + BOOST_REQUIRE (markers->get(dcp::FFOI)); + BOOST_CHECK (markers->get (dcp::FFOI) == dcp::Time(3, 6, 4, 18, 24)); + BOOST_REQUIRE (markers->get(dcp::LFOI)); + BOOST_CHECK (markers->get (dcp::LFOI) == dcp::Time(3, 2, 4, 18, 24)); + BOOST_REQUIRE (markers->get(dcp::FFEC)); + BOOST_CHECK (markers->get (dcp::FFEC) == dcp::Time(3, 2, 7, 18, 24)); + BOOST_REQUIRE (markers->get(dcp::LFEC)); + BOOST_CHECK (markers->get (dcp::LFEC) == dcp::Time(3, 2, 8, 18, 24)); + BOOST_REQUIRE (markers->get(dcp::FFMC)); + BOOST_CHECK (markers->get (dcp::FFMC) == dcp::Time(4, 2, 8, 18, 24)); + BOOST_REQUIRE (markers->get(dcp::LFMC)); + BOOST_CHECK (markers->get (dcp::LFMC) == dcp::Time(4, 3, 8, 18, 24)); + + BOOST_CHECK (markers->equals(markers, dcp::EqualityOptions(), boost::bind(¬e_handler, _1, _2))); + + shared_ptr<dcp::ReelMarkersAsset> markers2 (new dcp::ReelMarkersAsset(dcp::Fraction(24, 1), 0)); + BOOST_CHECK (!markers->equals(markers2, dcp::EqualityOptions(), boost::bind(¬e_handler, _1, _2))); +} diff --git a/test/wscript b/test/wscript index 5838df68..53d84617 100644 --- a/test/wscript +++ b/test/wscript @@ -1,5 +1,5 @@ # -# Copyright (C) 2012-2018 Carl Hetherington <cth@carlh.net> +# Copyright (C) 2012-2019 Carl Hetherington <cth@carlh.net> # # This file is part of libdcp. # @@ -80,6 +80,7 @@ def build(bld): interop_load_font_test.cc local_time_test.cc make_digest_test.cc + markers_test.cc kdm_test.cc raw_convert_test.cc read_dcp_test.cc |
