Fix build on old GCC.
[libdcp.git] / src / reel.cc
index 89056cffef26f68db9b81a4bde791597ba999112..e99f7140d809cb568befc96467da0daadb7e0bc4 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2014-2020 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2014-2021 Carl Hetherington <cth@carlh.net>
 
     This file is part of libdcp.
 
     files in the program, then also delete it here.
 */
 
+
+/** @file  src/reel.cc
+ *  @brief Reel class
+ */
+
+
 #include "reel.h"
 #include "util.h"
 #include "picture_asset.h"
 #include "reel_mono_picture_asset.h"
 #include "reel_stereo_picture_asset.h"
 #include "reel_sound_asset.h"
+#include "reel_interop_closed_caption_asset.h"
+#include "reel_interop_subtitle_asset.h"
+#include "reel_smpte_closed_caption_asset.h"
+#include "reel_smpte_subtitle_asset.h"
 #include "reel_subtitle_asset.h"
 #include "reel_markers_asset.h"
 #include "decrypted_kdm_key.h"
 #include "reel_atmos_asset.h"
 #include "reel_closed_caption_asset.h"
 #include <libxml++/nodes/element.h>
-#include <boost/foreach.hpp>
 #include <stdint.h>
 
-/* Centos 6 does not have this */
-#ifndef INT64_MAX
-#define INT64_MAX 0x7fffffffffffffff
-#endif
 
 using std::string;
 using std::cout;
@@ -67,34 +72,42 @@ using std::dynamic_pointer_cast;
 using std::vector;
 using namespace dcp;
 
-Reel::Reel (std::shared_ptr<const cxml::Node> node)
+
+Reel::Reel (std::shared_ptr<const cxml::Node> node, dcp::Standard standard)
        : Object (remove_urn_uuid (node->string_child ("Id")))
 {
        auto asset_list = node->node_child ("AssetList");
 
        auto main_picture = asset_list->optional_node_child ("MainPicture");
        if (main_picture) {
-               _main_picture.reset (new ReelMonoPictureAsset (main_picture));
+               _main_picture = make_shared<ReelMonoPictureAsset>(main_picture);
        }
 
        auto main_stereoscopic_picture = asset_list->optional_node_child ("MainStereoscopicPicture");
        if (main_stereoscopic_picture) {
-               _main_picture.reset (new ReelStereoPictureAsset (main_stereoscopic_picture));
+               _main_picture = make_shared<ReelStereoPictureAsset>(main_stereoscopic_picture);
        }
 
        auto main_sound = asset_list->optional_node_child ("MainSound");
        if (main_sound) {
-               _main_sound.reset (new ReelSoundAsset (main_sound));
+               _main_sound = make_shared<ReelSoundAsset>(main_sound);
        }
 
        auto main_subtitle = asset_list->optional_node_child ("MainSubtitle");
        if (main_subtitle) {
-               _main_subtitle.reset (new ReelSubtitleAsset (main_subtitle));
+               switch (standard) {
+                       case Standard::INTEROP:
+                               _main_subtitle = make_shared<ReelInteropSubtitleAsset>(main_subtitle);
+                               break;
+                       case Standard::SMPTE:
+                               _main_subtitle = make_shared<ReelSMPTESubtitleAsset>(main_subtitle);
+                               break;
+               }
        }
 
        auto main_markers = asset_list->optional_node_child ("MainMarkers");
        if (main_markers) {
-               _main_markers.reset (new ReelMarkersAsset (main_markers));
+               _main_markers = make_shared<ReelMarkersAsset>(main_markers);
        }
 
        /* XXX: it's not ideal that we silently tolerate Interop or SMPTE nodes here */
@@ -104,7 +117,14 @@ Reel::Reel (std::shared_ptr<const cxml::Node> node)
                closed_captions = asset_list->node_children ("ClosedCaption");
        }
        for (auto i: closed_captions) {
-               _closed_captions.push_back (make_shared<ReelClosedCaptionAsset>(i));
+               switch (standard) {
+                       case Standard::INTEROP:
+                               _closed_captions.push_back (make_shared<ReelInteropClosedCaptionAsset>(i));
+                               break;
+                       case Standard::SMPTE:
+                               _closed_captions.push_back (make_shared<ReelSMPTEClosedCaptionAsset>(i));
+                               break;
+               }
        }
 
        auto atmos = asset_list->optional_node_child ("AuxData");
@@ -116,6 +136,7 @@ Reel::Reel (std::shared_ptr<const cxml::Node> node)
        node->done ();
 }
 
+
 xmlpp::Element *
 Reel::write_to_cpl (xmlpp::Element* node, Standard standard) const
 {
@@ -156,11 +177,12 @@ Reel::write_to_cpl (xmlpp::Element* node, Standard standard) const
        return asset_list;
 }
 
+
 bool
 Reel::equals (std::shared_ptr<const Reel> other, EqualityOptions opt, NoteHandler note) const
 {
        if ((_main_picture && !other->_main_picture) || (!_main_picture && other->_main_picture)) {
-               note (DCP_ERROR, "Reel: picture assets differ");
+               note (NoteType::ERROR, "Reel: picture assets differ");
                return false;
        }
 
@@ -169,7 +191,7 @@ Reel::equals (std::shared_ptr<const Reel> other, EqualityOptions opt, NoteHandle
        }
 
        if ((_main_sound && !other->_main_sound) || (!_main_sound && other->_main_sound)) {
-               note (DCP_ERROR, "Reel: sound assets differ");
+               note (NoteType::ERROR, "Reel: sound assets differ");
                return false;
        }
 
@@ -178,21 +200,45 @@ Reel::equals (std::shared_ptr<const Reel> other, EqualityOptions opt, NoteHandle
        }
 
        if ((_main_subtitle && !other->_main_subtitle) || (!_main_subtitle && other->_main_subtitle)) {
-               note (DCP_ERROR, "Reel: subtitle assets differ");
+               note (NoteType::ERROR, "Reel: subtitle assets differ");
                return false;
        }
 
-       if (_main_subtitle && !_main_subtitle->equals (other->_main_subtitle, opt, note)) {
+       bool same_type = false;
+
+       {
+               auto interop = dynamic_pointer_cast<ReelInteropSubtitleAsset>(_main_subtitle);
+               auto interop_other = dynamic_pointer_cast<ReelInteropSubtitleAsset>(other->_main_subtitle);
+               if (interop && interop_other) {
+                       same_type = true;
+                       if (!interop->equals(interop_other, opt, note)) {
+                               return false;
+                       }
+               }
+       }
+
+       {
+               auto smpte = dynamic_pointer_cast<ReelSMPTESubtitleAsset>(_main_subtitle);
+               auto smpte_other = dynamic_pointer_cast<ReelSMPTESubtitleAsset>(other->_main_subtitle);
+               if (smpte && smpte_other) {
+                       same_type = true;
+                       if (!smpte->equals(smpte_other, opt, note)) {
+                               return false;
+                       }
+               }
+       }
+
+       if ((_main_subtitle || other->_main_subtitle) && !same_type) {
                return false;
        }
 
        if ((_main_markers && !other->_main_markers) || (!_main_markers && other->_main_markers)) {
-               note (DCP_ERROR, "Reel: one has markers and the other does not");
+               note (NoteType::ERROR, "Reel: one has markers and the other does not");
                return false;
        }
 
        if (_main_markers && !_main_markers->equals(other->_main_markers, opt, note)) {
-               note (DCP_ERROR, "Reel: marker assets differ");
+               note (NoteType::ERROR, "Reel: marker assets differ");
                return false;
        }
 
@@ -211,7 +257,7 @@ Reel::equals (std::shared_ptr<const Reel> other, EqualityOptions opt, NoteHandle
        }
 
        if ((_atmos && !other->_atmos) || (!_atmos && other->_atmos)) {
-               note (DCP_ERROR, "Reel: atmos assets differ");
+               note (NoteType::ERROR, "Reel: atmos assets differ");
                return false;
        }
 
@@ -222,8 +268,9 @@ Reel::equals (std::shared_ptr<const Reel> other, EqualityOptions opt, NoteHandle
        return true;
 }
 
+
 bool
-Reel::encrypted () const
+Reel::any_encrypted () const
 {
        auto ecc = false;
        for (auto i: _closed_captions) {
@@ -233,14 +280,35 @@ Reel::encrypted () const
        }
 
        return (
-               (_main_picture && _main_picture->encrypted ()) ||
-               (_main_sound && _main_sound->encrypted ()) ||
-               (_main_subtitle && _main_subtitle->encrypted ()) ||
+               (_main_picture && _main_picture->encrypted()) ||
+               (_main_sound && _main_sound->encrypted()) ||
+               (_main_subtitle && _main_subtitle->encrypted()) ||
                ecc ||
-               (_atmos && _atmos->encrypted ())
+               (_atmos && _atmos->encrypted())
                );
 }
 
+
+bool
+Reel::all_encrypted () const
+{
+       auto ecc = true;
+       for (auto i: _closed_captions) {
+               if (!i->encrypted()) {
+                       ecc = false;
+               }
+       }
+
+       return (
+               (!_main_picture || _main_picture->encrypted()) &&
+               (!_main_sound || _main_sound->encrypted()) &&
+               (!_main_subtitle || _main_subtitle->encrypted()) &&
+               ecc &&
+               (!_atmos || _atmos->encrypted())
+              );
+}
+
+
 void
 Reel::add (DecryptedKDM const & kdm)
 {
@@ -253,18 +321,16 @@ Reel::add (DecryptedKDM const & kdm)
                if (_main_sound && i.id() == _main_sound->key_id()) {
                        _main_sound->asset()->set_key (i.key());
                }
-               if (_main_subtitle && i.id() == _main_subtitle->key_id()) {
-                       shared_ptr<SMPTESubtitleAsset> s = dynamic_pointer_cast<SMPTESubtitleAsset> (_main_subtitle->asset());
-                       if (s) {
-                               s->set_key (i.key());
+               if (_main_subtitle) {
+                       auto smpte = dynamic_pointer_cast<ReelSMPTESubtitleAsset>(_main_picture);
+                       if (smpte && i.id() == smpte->key_id()) {
+                               smpte->smpte_asset()->set_key(i.key());
                        }
                }
                for (auto j: _closed_captions) {
-                       if (i.id() == j->key_id()) {
-                               auto s = dynamic_pointer_cast<SMPTESubtitleAsset> (j->asset());
-                               if (s) {
-                                       s->set_key (i.key());
-                               }
+                       auto smpte = dynamic_pointer_cast<ReelSMPTESubtitleAsset>(j);
+                       if (smpte && i.id() == smpte->key_id()) {
+                               smpte->smpte_asset()->set_key(i.key());
                        }
                }
                if (_atmos && i.id() == _atmos->key_id()) {
@@ -273,6 +339,7 @@ Reel::add (DecryptedKDM const & kdm)
        }
 }
 
+
 void
 Reel::add (shared_ptr<ReelAsset> asset)
 {
@@ -297,6 +364,7 @@ Reel::add (shared_ptr<ReelAsset> asset)
        }
 }
 
+
 vector<shared_ptr<ReelAsset>>
 Reel::assets () const
 {
@@ -317,19 +385,20 @@ Reel::assets () const
        return a;
 }
 
+
 void
 Reel::resolve_refs (vector<shared_ptr<Asset>> assets)
 {
        if (_main_picture) {
-               _main_picture->asset_ref().resolve (assets);
+               _main_picture->asset_ref().resolve(assets);
        }
 
        if (_main_sound) {
-               _main_sound->asset_ref().resolve (assets);
+               _main_sound->asset_ref().resolve(assets);
        }
 
        if (_main_subtitle) {
-               _main_subtitle->asset_ref().resolve (assets);
+               _main_subtitle->asset_ref().resolve(assets);
 
                /* Interop subtitle handling is all special cases */
                if (_main_subtitle->asset_ref().resolved()) {
@@ -357,6 +426,7 @@ Reel::resolve_refs (vector<shared_ptr<Asset>> assets)
        }
 }
 
+
 int64_t
 Reel::duration () const
 {