2 Copyright (C) 2014-2017 Carl Hetherington <cth@carlh.net>
4 This file is part of libdcp.
6 libdcp is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 libdcp is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with libdcp. If not, see <http://www.gnu.org/licenses/>.
19 In addition, as a special exception, the copyright holders give
20 permission to link the code of portions of this program with the
21 OpenSSL library under certain conditions as described in each
22 individual source file, and distribute linked combinations
25 You must obey the GNU General Public License in all respects
26 for all of the code used other than OpenSSL. If you modify
27 file(s) with this exception, you may extend this exception to your
28 version of the file(s), but you are not obligated to do so. If you
29 do not wish to do so, delete this exception statement from your
30 version. If you delete this exception statement from all source
31 files in the program, then also delete it here.
36 #include "picture_asset.h"
37 #include "mono_picture_asset.h"
38 #include "stereo_picture_asset.h"
39 #include "sound_asset.h"
40 #include "subtitle_asset.h"
41 #include "reel_mono_picture_asset.h"
42 #include "reel_stereo_picture_asset.h"
43 #include "reel_sound_asset.h"
44 #include "reel_subtitle_asset.h"
45 #include "decrypted_kdm_key.h"
46 #include "decrypted_kdm.h"
47 #include "interop_subtitle_asset.h"
48 #include "smpte_subtitle_asset.h"
49 #include "reel_atmos_asset.h"
50 #include "reel_closed_caption_asset.h"
51 #include <libxml++/nodes/element.h>
52 #include <boost/foreach.hpp>
58 using boost::shared_ptr;
59 using boost::dynamic_pointer_cast;
62 Reel::Reel (boost::shared_ptr<const cxml::Node> node)
63 : Object (remove_urn_uuid (node->string_child ("Id")))
65 shared_ptr<cxml::Node> asset_list = node->node_child ("AssetList");
67 shared_ptr<cxml::Node> main_picture = asset_list->optional_node_child ("MainPicture");
69 _main_picture.reset (new ReelMonoPictureAsset (main_picture));
72 shared_ptr<cxml::Node> main_stereoscopic_picture = asset_list->optional_node_child ("MainStereoscopicPicture");
73 if (main_stereoscopic_picture) {
74 _main_picture.reset (new ReelStereoPictureAsset (main_stereoscopic_picture));
77 shared_ptr<cxml::Node> main_sound = asset_list->optional_node_child ("MainSound");
79 _main_sound.reset (new ReelSoundAsset (main_sound));
82 shared_ptr<cxml::Node> main_subtitle = asset_list->optional_node_child ("MainSubtitle");
84 _main_subtitle.reset (new ReelSubtitleAsset (main_subtitle));
87 /* XXX: it's not ideal that we silently tolerate Interop or SMPTE nodes here */
88 shared_ptr<cxml::Node> closed_caption = asset_list->optional_node_child ("MainClosedCaption");
89 if (!closed_caption) {
90 closed_caption = asset_list->optional_node_child ("ClosedCaption");
93 _closed_caption.reset (new ReelClosedCaptionAsset (closed_caption));
96 shared_ptr<cxml::Node> atmos = asset_list->optional_node_child ("AuxData");
98 _atmos.reset (new ReelAtmosAsset (atmos));
101 node->ignore_child ("AnnotationText");
106 Reel::write_to_cpl (xmlpp::Element* node, Standard standard) const
108 xmlpp::Element* reel = node->add_child ("Reel");
109 reel->add_child("Id")->add_child_text ("urn:uuid:" + make_uuid());
110 xmlpp::Element* asset_list = reel->add_child ("AssetList");
112 if (_main_picture && dynamic_pointer_cast<ReelMonoPictureAsset> (_main_picture)) {
113 /* Mono pictures come before other stuff... */
114 _main_picture->write_to_cpl (asset_list, standard);
118 _main_sound->write_to_cpl (asset_list, standard);
121 if (_main_subtitle) {
122 _main_subtitle->write_to_cpl (asset_list, standard);
125 if (_closed_caption) {
126 _closed_caption->write_to_cpl (asset_list, standard);
129 if (_main_picture && dynamic_pointer_cast<ReelStereoPictureAsset> (_main_picture)) {
130 /* ... but stereo pictures must come after */
131 _main_picture->write_to_cpl (asset_list, standard);
135 _atmos->write_to_cpl (asset_list, standard);
140 Reel::equals (boost::shared_ptr<const Reel> other, EqualityOptions opt, NoteHandler note) const
142 if ((_main_picture && !other->_main_picture) || (!_main_picture && other->_main_picture)) {
143 note (DCP_ERROR, "Reel: assets differ");
147 if (_main_picture && !_main_picture->equals (other->_main_picture, opt, note)) {
151 if ((_main_sound && !other->_main_sound) || (!_main_sound && other->_main_sound)) {
152 note (DCP_ERROR, "Reel: assets differ");
156 if (_main_sound && !_main_sound->equals (other->_main_sound, opt, note)) {
160 if ((_main_subtitle && !other->_main_subtitle) || (!_main_subtitle && other->_main_subtitle)) {
161 note (DCP_ERROR, "Reel: assets differ");
165 if (_main_subtitle && !_main_subtitle->equals (other->_main_subtitle, opt, note)) {
169 if (_closed_caption && !_closed_caption->equals (other->_closed_caption, opt, note)) {
173 if ((_atmos && !other->_atmos) || (!_atmos && other->_atmos)) {
174 note (DCP_ERROR, "Reel: assets differ");
178 if (_atmos && !_atmos->equals (other->_atmos, opt, note)) {
186 Reel::encrypted () const
189 (_main_picture && _main_picture->encrypted ()) ||
190 (_main_sound && _main_sound->encrypted ()) ||
191 (_main_subtitle && _main_subtitle->encrypted ()) ||
192 (_closed_caption && _closed_caption->encrypted ()) ||
193 (_atmos && _atmos->encrypted ())
198 Reel::add (DecryptedKDM const & kdm)
200 list<DecryptedKDMKey> keys = kdm.keys ();
202 for (list<DecryptedKDMKey>::iterator i = keys.begin(); i != keys.end(); ++i) {
203 if (_main_picture && i->id() == _main_picture->key_id()) {
204 _main_picture->asset()->set_key (i->key ());
206 if (_main_sound && i->id() == _main_sound->key_id()) {
207 _main_sound->asset()->set_key (i->key ());
209 if (_main_subtitle && i->id() == _main_subtitle->key_id()) {
210 shared_ptr<SMPTESubtitleAsset> s = dynamic_pointer_cast<SMPTESubtitleAsset> (_main_subtitle->asset());
212 s->set_key (i->key ());
215 if (_closed_caption && i->id() == _closed_caption->key_id()) {
216 shared_ptr<SMPTESubtitleAsset> s = dynamic_pointer_cast<SMPTESubtitleAsset> (_closed_caption->asset());
218 s->set_key (i->key ());
221 if (_atmos && i->id() == _atmos->key_id()) {
222 _atmos->asset()->set_key (i->key ());
228 Reel::add (shared_ptr<ReelAsset> asset)
230 shared_ptr<ReelPictureAsset> p = dynamic_pointer_cast<ReelPictureAsset> (asset);
231 shared_ptr<ReelSoundAsset> so = dynamic_pointer_cast<ReelSoundAsset> (asset);
232 shared_ptr<ReelSubtitleAsset> su = dynamic_pointer_cast<ReelSubtitleAsset> (asset);
233 shared_ptr<ReelClosedCaptionAsset> c = dynamic_pointer_cast<ReelClosedCaptionAsset> (asset);
234 shared_ptr<ReelAtmosAsset> a = dynamic_pointer_cast<ReelAtmosAsset> (asset);
249 Reel::resolve_refs (list<shared_ptr<Asset> > assets)
252 _main_picture->asset_ref().resolve (assets);
256 _main_sound->asset_ref().resolve (assets);
259 if (_main_subtitle) {
260 _main_subtitle->asset_ref().resolve (assets);
262 /* Interop subtitle handling is all special cases */
263 if (_main_subtitle->asset_ref().resolved()) {
264 shared_ptr<InteropSubtitleAsset> iop = dynamic_pointer_cast<InteropSubtitleAsset> (_main_subtitle->asset_ref().asset());
266 iop->resolve_fonts (assets);
271 if (_closed_caption) {
272 _closed_caption->asset_ref().resolve(assets);
274 /* Interop subtitle handling is all special cases */
275 if (_closed_caption->asset_ref().resolved()) {
276 shared_ptr<InteropSubtitleAsset> iop = dynamic_pointer_cast<InteropSubtitleAsset> (_closed_caption->asset_ref().asset());
278 iop->resolve_fonts (assets);
284 _atmos->asset_ref().resolve (assets);
289 Reel::duration () const
294 d = max (d, _main_picture->duration ());
297 d = max (d, _main_sound->duration ());
299 if (_main_subtitle) {
300 d = max (d, _main_subtitle->duration ());
302 if (_closed_caption) {
303 d = max (d, _closed_caption->duration ());
306 d = max (d, _atmos->duration ());