60 #include <libxml++/nodes/element.h>
67 using std::make_shared;
68 using std::shared_ptr;
69 using std::dynamic_pointer_cast;
74 Reel::Reel (std::shared_ptr<const cxml::Node> node, dcp::Standard standard)
75 :
Object (remove_urn_uuid (node->string_child (
"Id")))
77 auto asset_list = node->node_child (
"AssetList");
79 if (
auto main_picture = asset_list->optional_node_child(
"MainPicture")) {
80 _main_picture = make_shared<ReelMonoPictureAsset>(main_picture);
83 if (
auto main_stereoscopic_picture = asset_list->optional_node_child(
"MainStereoscopicPicture")) {
84 _main_picture = make_shared<ReelStereoPictureAsset>(main_stereoscopic_picture);
87 if (
auto main_sound = asset_list->optional_node_child(
"MainSound")) {
88 _main_sound = make_shared<ReelSoundAsset>(main_sound);
91 if (
auto main_subtitle = asset_list->optional_node_child(
"MainSubtitle")) {
93 case Standard::INTEROP:
94 _main_subtitle = make_shared<ReelInteropTextAsset>(main_subtitle);
97 _main_subtitle = make_shared<ReelSMPTETextAsset>(main_subtitle);
102 if (
auto main_caption = asset_list->optional_node_child(
"MainCaption")) {
104 case Standard::INTEROP:
107 case Standard::SMPTE:
108 _main_caption = make_shared<ReelSMPTETextAsset>(main_caption);
113 if (
auto main_markers = asset_list->optional_node_child(
"MainMarkers")) {
114 _main_markers = make_shared<ReelMarkersAsset>(main_markers);
117 auto closed_subtitles = asset_list->node_children(
"ClosedSubtitle");
118 for (
auto i: closed_subtitles) {
120 case Standard::INTEROP:
123 case Standard::SMPTE:
124 _closed_subtitles.push_back(make_shared<ReelSMPTETextAsset>(i));
131 auto closed_captions = asset_list->node_children (
"MainClosedCaption");
132 if (closed_captions.empty()) {
133 closed_captions = asset_list->node_children (
"ClosedCaption");
135 for (
auto i: closed_captions) {
137 case Standard::INTEROP:
138 _closed_captions.push_back(make_shared<ReelInteropTextAsset>(i));
140 case Standard::SMPTE:
141 _closed_captions.push_back(make_shared<ReelSMPTETextAsset>(i));
146 if (
auto atmos = asset_list->optional_node_child(
"AuxData")) {
147 _atmos = make_shared<ReelAtmosAsset>(atmos);
150 node->ignore_child (
"AnnotationText");
156 Reel::write_to_cpl (xmlpp::Element* node, Standard standard)
const
158 auto reel = cxml::add_child(node,
"Reel");
159 cxml::add_text_child(reel,
"Id",
"urn:uuid:" + _id);
160 auto asset_list = cxml::add_child(reel,
"AssetList");
163 _main_markers->write_to_cpl (asset_list, standard);
166 if (_main_picture && dynamic_pointer_cast<ReelMonoPictureAsset> (_main_picture)) {
168 _main_picture->write_to_cpl (asset_list, standard);
172 _main_sound->write_to_cpl (asset_list, standard);
175 if (_main_subtitle) {
176 _main_subtitle->write_to_cpl (asset_list, standard);
180 _main_caption->write_to_cpl(asset_list, standard);
183 for (
auto i: _closed_subtitles) {
184 i->write_to_cpl(asset_list, standard);
187 for (
auto i: _closed_captions) {
188 i->write_to_cpl (asset_list, standard);
191 if (_main_picture && dynamic_pointer_cast<ReelStereoPictureAsset> (_main_picture)) {
193 _main_picture->write_to_cpl (asset_list, standard);
197 _atmos->write_to_cpl (asset_list, standard);
205 Reel::equals(std::shared_ptr<const Reel> other,
EqualityOptions const& opt, NoteHandler note)
const
207 if ((_main_picture && !other->_main_picture) || (!_main_picture && other->_main_picture)) {
208 note (NoteType::ERROR,
"Reel: picture assets differ");
212 if (_main_picture && !_main_picture->equals (other->_main_picture, opt, note)) {
216 if ((_main_sound && !other->_main_sound) || (!_main_sound && other->_main_sound)) {
217 note (NoteType::ERROR,
"Reel: sound assets differ");
221 if (_main_sound && !_main_sound->equals (other->_main_sound, opt, note)) {
225 if ((_main_subtitle && !other->_main_subtitle) || (!_main_subtitle && other->_main_subtitle)) {
226 note (NoteType::ERROR,
"Reel: subtitle assets differ");
230 bool same_type =
false;
233 auto interop = dynamic_pointer_cast<ReelInteropTextAsset>(_main_subtitle);
234 auto interop_other = dynamic_pointer_cast<ReelInteropTextAsset>(other->_main_subtitle);
235 if (interop && interop_other) {
237 if (!interop->equals(interop_other, opt, note)) {
244 auto smpte = dynamic_pointer_cast<ReelSMPTETextAsset>(_main_subtitle);
245 auto smpte_other = dynamic_pointer_cast<ReelSMPTETextAsset>(other->_main_subtitle);
246 if (smpte && smpte_other) {
248 if (!smpte->equals(smpte_other, opt, note)) {
254 if ((_main_subtitle || other->_main_subtitle) && !same_type) {
258 if ((_main_markers && !other->_main_markers) || (!_main_markers && other->_main_markers)) {
259 note (NoteType::ERROR,
"Reel: one has markers and the other does not");
263 if (_main_markers && !_main_markers->equals(other->_main_markers, opt, note)) {
264 note (NoteType::ERROR,
"Reel: marker assets differ");
268 if (_closed_captions.size() != other->_closed_captions.size()) {
272 auto i = _closed_captions.begin();
273 auto j = other->_closed_captions.begin();
274 while (i != _closed_captions.end()) {
275 if (!(*i)->equals(*j, opt, note)) {
282 if ((_atmos && !other->_atmos) || (!_atmos && other->_atmos)) {
283 note (NoteType::ERROR,
"Reel: atmos assets differ");
287 if (_atmos && !_atmos->equals (other->_atmos, opt, note)) {
296 Reel::any_encrypted ()
const
299 for (
auto i: _closed_captions) {
300 if (i->encrypted()) {
306 (_main_picture && _main_picture->encrypted()) ||
307 (_main_sound && _main_sound->encrypted()) ||
308 (_main_subtitle && _main_subtitle->encrypted()) ||
310 (_atmos && _atmos->encrypted())
316 Reel::all_encrypted ()
const
319 for (
auto i: _closed_captions) {
320 if (!i->encrypted()) {
326 (!_main_picture || _main_picture->encrypted()) &&
327 (!_main_sound || _main_sound->encrypted()) &&
328 (!_main_subtitle || _main_subtitle->encrypted()) &&
330 (!_atmos || _atmos->encrypted())
338 give_kdm_to_assets (kdm);
343 _kdms.push_back (kdm);
350 for (
auto const& i: kdm.
keys()) {
351 if (_main_picture && i.id() == _main_picture->key_id() && _main_picture->asset_ref().resolved()) {
352 _main_picture->j2k_asset()->set_key(i.key());
354 if (_main_sound && i.id() == _main_sound->key_id() && _main_sound->asset_ref().resolved()) {
355 _main_sound->asset()->set_key (i.key());
357 if (_main_subtitle) {
358 auto smpte = dynamic_pointer_cast<ReelSMPTETextAsset>(_main_subtitle);
359 if (smpte && i.id() == smpte->key_id() && smpte->asset_ref().resolved()) {
360 smpte->smpte_asset()->set_key(i.key());
363 for (
auto j: _closed_captions) {
364 auto smpte = dynamic_pointer_cast<ReelSMPTETextAsset>(j);
365 if (smpte && i.id() == smpte->key_id() && smpte->asset_ref().resolved()) {
366 smpte->smpte_asset()->set_key(i.key());
369 if (_atmos && i.id() == _atmos->key_id() && _atmos->asset_ref().resolved()) {
370 _atmos->asset()->set_key (i.key());
377 Reel::add (shared_ptr<ReelAsset> asset)
379 if (
auto p = dynamic_pointer_cast<ReelPictureAsset>(asset)) {
381 }
else if (
auto so = dynamic_pointer_cast<ReelSoundAsset>(asset)) {
383 }
else if (
auto te = dynamic_pointer_cast<ReelTextAsset>(asset)) {
384 switch (te->type()) {
385 case TextType::OPEN_SUBTITLE:
388 case TextType::OPEN_CAPTION:
391 case TextType::CLOSED_SUBTITLE:
392 _closed_subtitles.push_back(te);
394 case TextType::CLOSED_CAPTION:
395 _closed_captions.push_back(te);
398 }
else if (
auto m = dynamic_pointer_cast<ReelMarkersAsset>(asset)) {
400 }
else if (
auto a = dynamic_pointer_cast<ReelAtmosAsset>(asset)) {
408 vector<shared_ptr<ReelAsset>>
409 Reel::assets ()
const
411 vector<shared_ptr<ReelAsset>> a;
413 a.push_back (_main_picture);
416 a.push_back (_main_sound);
418 if (_main_subtitle) {
419 a.push_back (_main_subtitle);
422 a.push_back(_main_caption);
424 std::copy (_closed_subtitles.begin(), _closed_subtitles.end(), back_inserter(a));
425 std::copy (_closed_captions.begin(), _closed_captions.end(), back_inserter(a));
427 a.push_back (_atmos);
434 Reel::resolve_refs (vector<shared_ptr<Asset>> assets)
437 _main_picture->asset_ref().resolve(assets);
441 _main_sound->asset_ref().resolve(assets);
444 auto resolve_interop_fonts = [&assets](shared_ptr<ReelTextAsset>(asset)) {
446 if (asset->asset_ref().resolved()) {
447 if (
auto iop = dynamic_pointer_cast<InteropTextAsset>(asset->asset_ref().asset())) {
448 iop->resolve_fonts(assets);
454 if (_main_subtitle) {
455 _main_subtitle->asset_ref().resolve(assets);
456 resolve_interop_fonts(_main_subtitle);
460 _main_caption->asset_ref().resolve(assets);
463 for (
auto i: _closed_subtitles) {
464 i->asset_ref().resolve(assets);
465 resolve_interop_fonts(i);
468 for (
auto i: _closed_captions) {
469 i->asset_ref().resolve(assets);
470 resolve_interop_fonts(i);
474 _atmos->asset_ref().resolve (assets);
477 for (
auto const& i: _kdms) {
478 give_kdm_to_assets (i);
484 Reel::duration ()
const
487 return _main_picture->actual_duration();
490 int64_t d = INT64_MAX;
493 d = min (d, _main_sound->actual_duration());
495 if (_main_subtitle) {
496 d = min (d, _main_subtitle->actual_duration());
499 d = min(d, _main_caption->actual_duration());
502 d = min (d, _main_markers->actual_duration());
504 for (
auto i: _closed_subtitles) {
505 d = min(d, i->actual_duration());
507 for (
auto i: _closed_captions) {
508 d = min (d, i->actual_duration());
511 d = min (d, _atmos->actual_duration());
514 DCP_ASSERT (d < INT64_MAX);
std::vector< DecryptedKDMKey > keys() const
A class to describe what "equality" means for a particular test.
Some part of a DCP that has a UUID.
Class to describe what equality means when calling Asset::equals().
MonoJ2KPictureAsset class.
Namespace for everything in libdcp.
ReelInteropTextAsset class.
ReelMonoPictureAsset class.
ReelSMPTETextAsset class.
ReelStereoPictureAsset class.
StereoJ2KPictureAsset class.
Utility methods and classes.