Merge branch 'master' of ssh://git.carlh.net/home/carl/git/libdcp
authorCarl Hetherington <cth@carlh.net>
Sun, 17 Mar 2019 00:24:48 +0000 (00:24 +0000)
committerCarl Hetherington <cth@carlh.net>
Sun, 17 Mar 2019 00:24:48 +0000 (00:24 +0000)
33 files changed:
src/cpl.cc
src/cpl.h
src/dcp.cc
src/decrypted_kdm.cc
src/reel.cc
src/reel.h
src/reel_asset.cc
src/reel_asset.h
src/reel_atmos_asset.cc
src/reel_atmos_asset.h
src/reel_closed_caption_asset.cc
src/reel_closed_caption_asset.h
src/reel_markers_asset.cc [new file with mode: 0644]
src/reel_markers_asset.h [new file with mode: 0644]
src/reel_mono_picture_asset.cc
src/reel_mono_picture_asset.h
src/reel_mxf.cc
src/reel_mxf.h
src/reel_picture_asset.cc
src/reel_picture_asset.h
src/reel_sound_asset.cc
src/reel_sound_asset.h
src/reel_stereo_picture_asset.cc
src/reel_stereo_picture_asset.h
src/reel_subtitle_asset.cc
src/reel_subtitle_asset.h
src/types.cc
src/types.h
src/verify.cc
src/wscript
test/dcp_test.cc
test/markers_test.cc [new file with mode: 0644]
test/wscript

index 3eeb102c196b28ac83af9736ec1c997800ddded9..0bf1582490155786f9727acc45e3c199a62acf79 100644 (file)
@@ -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 ()) {
index 259281dc3e958b5df692ca9836b952e18464a988..553f54928795cb40bcfeffe10ce26b8ad337bd2f 100644 (file)
--- a/src/cpl.h
+++ b/src/cpl.h
@@ -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;
 
index 5d908530edc43561f5e8d1231a1f4837fbd6c4b4..52598610a808defa0031f8379e75c4cc89b01dc5 100644 (file)
@@ -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;
                        }
index 756028d15e18d6f563e3aa989a0fd3a4d5470d4e..4bd9a9d5bf7b655a2f62a102d82221bd32fe78cb 100644 (file)
@@ -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;
                }
        }
index 4b42ec0e686cf74b83ba65be3538c668c119eead..bda83531ac8228e674ed9da679447ebc997cb157 100644 (file)
@@ -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());
        }
index fa37c84041bb8b22731d6e18fcffabdad3e0021a..0a3cf19ae8b6a344d7d04468957bdf29f20edd47 100644 (file)
@@ -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;
 };
index 72a1937cc89f2a9ebc54935bc757ea459251ba00..caaf3eee45fc14ca6f560899840c1f5ac89aa239 100644 (file)
@@ -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;
 }
index 42409ab968d81cece48c499ca46819b995ed604c..4092a97a5c8ab5cf1ce69664ff34c632a6cac03a 100644 (file)
@@ -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 &lt;Reel&gt; 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 &lt;IntrinsicDuration&gt; from the reel's entry for this asset
+       int64_t _duration;            ///< The &lt;Duration&gt; from the reel's entry for this asset
 
 private:
        std::string _annotation_text; ///< The &lt;AnnotationText&gt; from the reel's entry for this asset
        Fraction _edit_rate;          ///< The &lt;EditRate&gt; from the reel's entry for this asset
-       int64_t _intrinsic_duration;  ///< The &lt;IntrinsicDuration&gt; from the reel's entry for this asset
        int64_t _entry_point;         ///< The &lt;EntryPoint&gt; from the reel's entry for this asset
-       int64_t _duration;            ///< The &lt;Duration&gt; 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;
 };
 
 }
index 636a7a79641a0ab47a47d1e3c44908ab0aa8e2aa..1ce8b6eabd3e6e8522195d00eb1a35b1e0c5c5b3 100644 (file)
@@ -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;
+}
index e93a54148a4fe9ff75ba4cbca49ef777a036e5d1..6fb4bf5162665ad5960e429df05bc11d7819644b 100644 (file)
@@ -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;
index b7629011694253325f45798b94dc01e5ab3fc7bf..435c3438c0cb3e45fff5fab6d3515b8719a3b43f 100644 (file)
@@ -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;
+}
index 80e444d9391315c1ccad073665485f90046f3195..6ed50ae01125a2d4f1dbf32673ae8056fd7160b7 100644 (file)
@@ -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 (file)
index 0000000..8c5f66d
--- /dev/null
@@ -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 (file)
index 0000000..4077fbb
--- /dev/null
@@ -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;
+};
+
+}
index e894764eea5a0b4008a7af8c0a51f730d387bf9c..36abb55eef8734e99d3f5f40ff75b1fa89204368 100644 (file)
@@ -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)
 {
index 4c5eaa083ae469a1a580659926f2f48d1493a1a4..099feafd997d843d2126288587dcf75a59f1d139 100644 (file)
@@ -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>);
 
index 9c2d3b60d062d7aefa976c4724e89287cb2b1aee..f170157ec0465b4cf464f4d0139b01e492028c5f 100644 (file)
@@ -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;
+}
index 916255790846314250b8a98457cbec96c1ea1f5f..7bc8f75b3dea771115d99498ba7cf7f7fcf61d8b 100644 (file)
@@ -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.
 
  *  @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 &lt;KeyId&gt; 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;
 };
 
 }
index 1933c769d3ae5687c4aa6894199db938e7c39cd1..5b4ced6735cf15037f68ae1f8b620f973a21429a 100644 (file)
@@ -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;
        }
 
index a20c216f0abb9f4dedc5293d29eb229264a25f8b..88729148c6fa9713e6447be1f9102ae333d12942 100644 (file)
@@ -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 {
index baacfe720ff77b29e4718938c3d19cbfc4aab98a..25259f427c6c596d6e974857826a05e2b9871907 100644 (file)
@@ -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;
+}
index 2fb01c8d110c06a6c06c87a9fb7a5d07794babf1..57d14bc6ed54a652915e52274e8a39ba76e96c19 100644 (file)
@@ -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 () {
index f194cca097a0659594e2ba9fc294ea59c5e8ffd4..8a169df2195084f2c9eceb2b9b550a1316c0d56e 100644 (file)
@@ -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)
 {
index c7223495bbc48d9fd2fb56efde09250cfe0e32c0..80353b77f6a7417496a023f6883274763b8dc83c 100644 (file)
@@ -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>);
 
index 75116b2b6782202a58497d990bc480d41fd0b034..a90513d5c1fed7aede33b306526a85bb181aa735 100644 (file)
@@ -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;
+}
index 8e0edc49567c59d56c93fb77935ce4f31eac7b2e..4cc03cf1a7d2ffcc0fee741a267d94a0b3cdddbf 100644 (file)
@@ -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> ();
index 9af5f119c666217e9fe5186a7c1599db3fc35bca..d27b2ec186ece6773d0646309040927b2afd0eae 100644 (file)
@@ -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);
+}
index 2652524cb52023af20b1beb0228912c91e2431d1..a0965e8364790fa6129e1cf4a72588ea6116c18f 100644 (file)
@@ -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
index 4a6568743597f2fc49452c57fcefd3ef2c850da4..9ab9b15031209cd431e97b451942dd2f7ebf5396 100644 (file)
@@ -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;
        }
index ae881a8bf6abd25554809eb7d09e2beff593bec4..4b39a979dd1cd19774b08edaaefb8ab1bc0fdd08 100644 (file)
@@ -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
index 7c7ff12eb2e66b213c90a74e872b51a0432d0e41..ed3d473d8c935c3c77b574b1a2eea12e48af4712 100644 (file)
@@ -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 (file)
index 0000000..813736d
--- /dev/null
@@ -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(&note_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(&note_handler, _1, _2)));
+}
index 5838df68bdeb88b6df2203eb2d0dada716ddb468..53d8461714e1d01a3de31320270292d943d905ab 100644 (file)
@@ -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