Destroy Job threads at the start of the subclass destructors,
[dcpomatic.git] / src / lib / dcp_decoder.cc
index 85dd280064ac02d8743420edee9cdf31e7a02552..e8ace8beedcfb61b2b0604103acd099c64e4b5d0 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2014-2018 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2014-2020 Carl Hetherington <cth@carlh.net>
 
     This file is part of DCP-o-matic.
 
@@ -28,6 +28,7 @@
 #include "ffmpeg_image_proxy.h"
 #include "image.h"
 #include "config.h"
+#include "frame_interval_checker.h"
 #include <dcp/dcp.h>
 #include <dcp/cpl.h>
 #include <dcp/reel.h>
@@ -60,15 +61,17 @@ DCPDecoder::DCPDecoder (shared_ptr<const Film> film, shared_ptr<const DCPContent
        , Decoder (film)
        , _decode_referenced (false)
 {
-       if (c->video) {
-               video.reset (new VideoDecoder (this, c));
-       }
-       if (c->audio) {
-               audio.reset (new AudioDecoder (this, c->audio, fast));
-       }
-       BOOST_FOREACH (shared_ptr<TextContent> i, c->text) {
-               /* XXX: this time here should be the time of the first subtitle, not 0 */
-               text.push_back (shared_ptr<TextDecoder> (new TextDecoder (this, i, ContentTime())));
+       if (c->can_be_played()) {
+               if (c->video) {
+                       video.reset (new VideoDecoder (this, c));
+               }
+               if (c->audio) {
+                       audio.reset (new AudioDecoder (this, c->audio, fast));
+               }
+               BOOST_FOREACH (shared_ptr<TextContent> i, c->text) {
+                       /* XXX: this time here should be the time of the first subtitle, not 0 */
+                       text.push_back (shared_ptr<TextDecoder> (new TextDecoder (this, i, ContentTime())));
+               }
        }
 
        list<shared_ptr<dcp::CPL> > cpl_list = cpls ();
@@ -104,7 +107,14 @@ DCPDecoder::DCPDecoder (shared_ptr<const Film> film, shared_ptr<const DCPContent
 bool
 DCPDecoder::pass ()
 {
-       if (_reel == _reels.end () || !_dcp_content->can_be_played ()) {
+       if (!_dcp_content->can_be_played()) {
+               return true;
+       }
+
+       if (_reel == _reels.end()) {
+               if (audio) {
+                       audio->flush ();
+               }
                return true;
        }
 
@@ -202,8 +212,14 @@ void
 DCPDecoder::pass_texts (ContentTime next, dcp::Size size)
 {
        list<shared_ptr<TextDecoder> >::const_iterator decoder = text.begin ();
+       if (decoder == text.end()) {
+               /* It's possible that there is now a main subtitle but no TextDecoders, for example if
+                  the CPL has just changed but the TextContent's texts have not been recreated yet.
+               */
+               return;
+       }
+
        if ((*_reel)->main_subtitle()) {
-               DCPOMATIC_ASSERT (decoder != text.end ());
                pass_texts (
                        next,
                        (*_reel)->main_subtitle()->asset(),
@@ -214,8 +230,8 @@ DCPDecoder::pass_texts (ContentTime next, dcp::Size size)
                        );
                ++decoder;
        }
+
        BOOST_FOREACH (shared_ptr<dcp::ReelClosedCaptionAsset> i, (*_reel)->closed_captions()) {
-               DCPOMATIC_ASSERT (decoder != text.end ());
                pass_texts (
                        next, i->asset(), _dcp_content->reference_text(TEXT_CLOSED_CAPTION), i->entry_point(), *decoder, size
                        );
@@ -400,3 +416,9 @@ DCPDecoder::set_forced_reduction (optional<int> reduction)
 {
        _forced_reduction = reduction;
 }
+
+ContentTime
+DCPDecoder::position () const
+{
+       return ContentTime::from_frames(_offset, _dcp_content->active_video_frame_rate(film())) + _next;
+}