#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 namespace dcp;
/** 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 ())
- , _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)
+ , _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")))
+ , _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"))
{
}
class ReelAsset : public Object
{
public:
- 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 = 0;
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
};
}
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())
{
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)
+ : 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>())
{
--- /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 namespace dcp;
ReelPictureAsset::ReelPictureAsset (shared_ptr<PictureAsset> 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())
, _frame_rate (asset->frame_rate ())
, _screen_aspect_ratio (asset->screen_aspect_ratio ())
using namespace dcp;
ReelSoundAsset::ReelSoundAsset (shared_ptr<SoundAsset> 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())
{
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)
+ : 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>())
{
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