From 9eba1ff84fd89e2ff04181799f2185c8575de16d Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 15 Mar 2019 22:46:00 +0000 Subject: Finish initial CPL markers support. --- src/reel.cc | 20 ++++++ src/reel.h | 10 ++- src/reel_asset.cc | 19 +++--- src/reel_asset.h | 7 +- src/reel_atmos_asset.cc | 2 +- src/reel_closed_caption_asset.cc | 2 +- src/reel_markers_asset.cc | 140 +++++++++++++++++++++++++++++++++++++++ src/reel_markers_asset.h | 61 +++++++++++++++++ src/reel_picture_asset.cc | 2 +- src/reel_sound_asset.cc | 2 +- src/reel_subtitle_asset.cc | 2 +- src/wscript | 1 + 12 files changed, 248 insertions(+), 20 deletions(-) create mode 100644 src/reel_markers_asset.cc create mode 100644 src/reel_markers_asset.h (limited to 'src') diff --git a/src/reel.cc b/src/reel.cc index 4b42ec0e..bda83531 100644 --- a/src/reel.cc +++ b/src/reel.cc @@ -42,6 +42,7 @@ #include "reel_stereo_picture_asset.h" #include "reel_sound_asset.h" #include "reel_subtitle_asset.h" +#include "reel_markers_asset.h" #include "decrypted_kdm_key.h" #include "decrypted_kdm.h" #include "interop_subtitle_asset.h" @@ -84,6 +85,11 @@ Reel::Reel (boost::shared_ptr node) _main_subtitle.reset (new ReelSubtitleAsset (main_subtitle)); } + shared_ptr 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 > 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 (_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 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 asset) shared_ptr p = dynamic_pointer_cast (asset); shared_ptr so = dynamic_pointer_cast (asset); shared_ptr su = dynamic_pointer_cast (asset); + shared_ptr m = dynamic_pointer_cast (asset); shared_ptr c = dynamic_pointer_cast (asset); shared_ptr a = dynamic_pointer_cast (asset); if (p) { @@ -258,6 +273,8 @@ Reel::add (shared_ptr 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 i, _closed_captions) { d = max (d, i->duration()); } diff --git a/src/reel.h b/src/reel.h index fa37c840..0a3cf19a 100644 --- a/src/reel.h +++ b/src/reel.h @@ -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 picture, boost::shared_ptr sound = boost::shared_ptr (), boost::shared_ptr subtitle = boost::shared_ptr (), + boost::shared_ptr markers = boost::shared_ptr (), boost::shared_ptr atmos = boost::shared_ptr () ) : _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 main_markers () const { + return _main_markers; + } + std::list > closed_captions () const { return _closed_captions; } @@ -118,6 +125,7 @@ private: boost::shared_ptr _main_picture; boost::shared_ptr _main_sound; boost::shared_ptr _main_subtitle; + boost::shared_ptr _main_markers; std::list > _closed_captions; boost::shared_ptr _atmos; }; diff --git a/src/reel_asset.cc b/src/reel_asset.cc index 22583223..caaf3eee 100644 --- a/src/reel_asset.cc +++ b/src/reel_asset.cc @@ -50,31 +50,28 @@ using boost::optional; 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, 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 node) : Object (remove_urn_uuid (node->string_child ("Id"))) + , _intrinsic_duration (node->number_child ("IntrinsicDuration")) + , _duration (node->number_child ("Duration")) , _annotation_text (node->optional_string_child ("AnnotationText").get_value_or ("")) , _edit_rate (Fraction (node->string_child ("EditRate"))) - , _intrinsic_duration (node->number_child ("IntrinsicDuration")) , _entry_point (node->number_child ("EntryPoint")) - , _duration (node->number_child ("Duration")) { } diff --git a/src/reel_asset.h b/src/reel_asset.h index 9f024239..4092a97a 100644 --- a/src/reel_asset.h +++ b/src/reel_asset.h @@ -65,7 +65,7 @@ class Asset; class ReelAsset : public Object { public: - ReelAsset (boost::shared_ptr 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); virtual xmlpp::Node* write_to_cpl (xmlpp::Node* node, Standard standard) const = 0; @@ -119,12 +119,13 @@ protected: xmlpp::Node* write_to_cpl_base (xmlpp::Node* node, Standard standard, boost::optional 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 }; } diff --git a/src/reel_atmos_asset.cc b/src/reel_atmos_asset.cc index f5dbc9fa..1ce8b6ea 100644 --- a/src/reel_atmos_asset.cc +++ b/src/reel_atmos_asset.cc @@ -47,7 +47,7 @@ using boost::shared_ptr; using namespace dcp; ReelAtmosAsset::ReelAtmosAsset (boost::shared_ptr 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()) { diff --git a/src/reel_closed_caption_asset.cc b/src/reel_closed_caption_asset.cc index f71c39f6..435c3438 100644 --- a/src/reel_closed_caption_asset.cc +++ b/src/reel_closed_caption_asset.cc @@ -50,7 +50,7 @@ using boost::optional; using namespace dcp; ReelClosedCaptionAsset::ReelClosedCaptionAsset (boost::shared_ptr 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(asset) ? dynamic_pointer_cast(asset)->key_id() : optional()) { diff --git a/src/reel_markers_asset.cc b/src/reel_markers_asset.cc new file mode 100644 index 00000000..8c5f66dd --- /dev/null +++ b/src/reel_markers_asset.cc @@ -0,0 +1,140 @@ +/* + Copyright (C) 2019 Carl Hetherington + + 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 . + + 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 +#include + +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("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