+
+bool
+Reel::any_encrypted () const
+{
+ auto ecc = false;
+ for (auto i: _closed_captions) {
+ if (i->encrypted()) {
+ ecc = true;
+ }
+ }
+
+ bool esub = false;
+ if (_main_subtitle) {
+ if (auto enc = dynamic_pointer_cast<ReelEncryptableAsset>(_main_picture)) {
+ esub = enc->encrypted();
+ }
+ }
+
+ return (
+ (_main_picture && _main_picture->encrypted()) ||
+ (_main_sound && _main_sound->encrypted()) ||
+ esub ||
+ ecc ||
+ (_atmos && _atmos->encrypted())
+ );
+}
+
+
+bool
+Reel::all_encrypted () const
+{
+ auto ecc = true;
+ for (auto i: _closed_captions) {
+ if (!i->encrypted()) {
+ ecc = false;
+ }
+ }
+
+ /* It's ok if there's no subtitle, or it's not encryptable */
+ bool esub = true;
+ if (_main_subtitle) {
+ if (auto enc = dynamic_pointer_cast<ReelEncryptableAsset>(_main_picture)) {
+ esub = enc->encrypted();
+ }
+ }
+
+ return (
+ (!_main_picture || _main_picture->encrypted()) &&
+ (!_main_sound || _main_sound->encrypted()) &&
+ esub &&
+ ecc &&
+ (!_atmos || _atmos->encrypted())
+ );
+}
+
+
+void
+Reel::add (DecryptedKDM const & kdm)
+{
+ auto keys = kdm.keys ();
+
+ for (auto const& i: keys) {
+ if (_main_picture && i.id() == _main_picture->key_id()) {
+ _main_picture->asset()->set_key (i.key());
+ }
+ if (_main_sound && i.id() == _main_sound->key_id()) {
+ _main_sound->asset()->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());
+ }
+ }
+ }
+ if (_atmos && i.id() == _atmos->key_id()) {
+ _atmos->asset()->set_key (i.key());
+ }
+ }
+}
+
+
+void
+Reel::add (shared_ptr<ReelAsset> asset)
+{
+ auto p = dynamic_pointer_cast<ReelPictureAsset> (asset);
+ auto so = dynamic_pointer_cast<ReelSoundAsset> (asset);
+ auto su = dynamic_pointer_cast<ReelSubtitleAsset> (asset);
+ auto m = dynamic_pointer_cast<ReelMarkersAsset> (asset);
+ auto c = dynamic_pointer_cast<ReelClosedCaptionAsset> (asset);
+ auto a = dynamic_pointer_cast<ReelAtmosAsset> (asset);
+ if (p) {
+ _main_picture = p;
+ } else if (so) {
+ _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) {
+ _atmos = a;
+ }
+}
+
+
+vector<shared_ptr<ReelAsset>>
+Reel::assets () const
+{
+ vector<shared_ptr<ReelAsset>> a;
+ if (_main_picture) {
+ a.push_back (_main_picture);
+ }
+ if (_main_sound) {
+ a.push_back (_main_sound);
+ }
+ if (_main_subtitle) {
+ a.push_back (_main_subtitle);
+ }
+ std::copy (_closed_captions.begin(), _closed_captions.end(), back_inserter(a));
+ if (_atmos) {
+ a.push_back (_atmos);
+ }
+ return a;
+}
+
+
+void
+Reel::resolve_refs (vector<shared_ptr<Asset>> assets)
+{
+ if (_main_picture) {
+ _main_picture->asset_ref().resolve(assets);
+ }
+
+ if (_main_sound) {
+ _main_sound->asset_ref().resolve(assets);
+ }
+
+ if (_main_subtitle) {
+ _main_subtitle->asset_ref().resolve(assets);
+
+ /* Interop subtitle handling is all special cases */
+ if (_main_subtitle->asset_ref().resolved()) {
+ auto iop = dynamic_pointer_cast<InteropSubtitleAsset> (_main_subtitle->asset_ref().asset());
+ if (iop) {
+ iop->resolve_fonts (assets);
+ }
+ }
+ }
+
+ for (auto i: _closed_captions) {
+ i->asset_ref().resolve(assets);
+
+ /* Interop subtitle handling is all special cases */
+ if (i->asset_ref().resolved()) {
+ auto iop = dynamic_pointer_cast<InteropSubtitleAsset> (i->asset_ref().asset());
+ if (iop) {
+ iop->resolve_fonts (assets);
+ }
+ }
+ }
+
+ if (_atmos) {
+ _atmos->asset_ref().resolve (assets);
+ }
+}
+
+
+int64_t
+Reel::duration () const
+{
+ if (_main_picture) {
+ return _main_picture->actual_duration();
+ }
+
+ int64_t d = INT64_MAX;
+
+ if (_main_sound) {
+ d = min (d, _main_sound->actual_duration());
+ }
+ if (_main_subtitle) {
+ d = min (d, _main_subtitle->actual_duration());
+ }
+ if (_main_markers) {
+ d = min (d, _main_markers->actual_duration());
+ }
+ for (auto i: _closed_captions) {
+ d = min (d, i->actual_duration());
+ }
+ if (_atmos) {
+ d = min (d, _atmos->actual_duration());
+ }
+
+ DCP_ASSERT (d < INT64_MAX);
+
+ return d;
+}