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 ()) {
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 ()) {
/*
- Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2014-2019 Carl Hetherington <cth@carlh.net>
This file is part of libdcp.
namespace dcp {
-class ReelAsset;
+class ReelMXF;
class Reel;
class XMLMetadata;
class MXFMetadata;
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;
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;
}
{
/* 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;
}
}
#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"
_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");
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);
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;
}
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) {
_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) {
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());
}
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:
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)
{}
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;
}
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;
};
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);
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;
}
}
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";
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;
}
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;
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;
}
_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.
/** @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;
};
}
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())
{
}
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;
+}
}
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;
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>())
{
}
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> */
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;
+}
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> ();
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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;
+};
+
+}
using boost::shared_ptr;
using namespace dcp;
-ReelMonoPictureAsset::ReelMonoPictureAsset ()
-{
-
-}
-
ReelMonoPictureAsset::ReelMonoPictureAsset (boost::shared_ptr<MonoPictureAsset> asset, int64_t entry_point)
: ReelPictureAsset (asset, entry_point)
{
/*
- Copyright (C) 2014-2017 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2014-2019 Carl Hetherington <cth@carlh.net>
This file is part of libdcp.
class ReelMonoPictureAsset : public ReelPictureAsset
{
public:
- ReelMonoPictureAsset ();
ReelMonoPictureAsset (boost::shared_ptr<MonoPictureAsset> asset, int64_t entry_point);
explicit ReelMonoPictureAsset (boost::shared_ptr<const cxml::Node>);
/*
- Copyright (C) 2012-2015 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2019 Carl Hetherington <cth@carlh.net>
This file is part of libdcp.
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;
+}
/*
- 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>
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.
*/
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;
};
}
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 ())
{
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) {
}
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;
}
/*
- Copyright (C) 2014-2015 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2014-2019 Carl Hetherington <cth@carlh.net>
This file is part of libdcp.
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 {
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())
{
}
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> */
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;
+}
/*
- Copyright (C) 2014-2015 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2014-2019 Carl Hetherington <cth@carlh.net>
This file is part of libdcp.
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 () {
/*
- Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2014-2019 Carl Hetherington <cth@carlh.net>
This file is part of libdcp.
using boost::shared_ptr;
using namespace dcp;
-ReelStereoPictureAsset::ReelStereoPictureAsset ()
-{
-
-}
-
ReelStereoPictureAsset::ReelStereoPictureAsset (boost::shared_ptr<StereoPictureAsset> mxf, int64_t entry_point)
: ReelPictureAsset (mxf, entry_point)
{
/*
- Copyright (C) 2014-2015 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2014-2019 Carl Hetherington <cth@carlh.net>
This file is part of libdcp.
class ReelStereoPictureAsset : public ReelPictureAsset
{
public:
- ReelStereoPictureAsset ();
ReelStereoPictureAsset (boost::shared_ptr<StereoPictureAsset> content, int64_t entry_point);
explicit ReelStereoPictureAsset (boost::shared_ptr<const cxml::Node>);
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>())
{
}
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> */
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;
+}
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> ();
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);
+}
*/
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
};
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;
}
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;
}
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
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))
)
));
--- /dev/null
+/*
+ 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)));
+}
#
-# Copyright (C) 2012-2018 Carl Hetherington <cth@carlh.net>
+# Copyright (C) 2012-2019 Carl Hetherington <cth@carlh.net>
#
# This file is part of libdcp.
#
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