Destroy Job threads at the start of the subclass destructors,
[dcpomatic.git] / src / lib / dcp_decoder.cc
index 1098bb87a8c94a8df56cf2ca0f3a7d40cd24f72c..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
                        );
@@ -259,45 +275,20 @@ DCPDecoder::pass_texts (
                                strings.push_back (*is);
                        }
 
+                       /* XXX: perhaps these image subs should also be collected together like the string ones are;
+                          this would need to be done both here and in DCPSubtitleDecoder.
+                       */
+
                        shared_ptr<dcp::SubtitleImage> ii = dynamic_pointer_cast<dcp::SubtitleImage> (i);
                        if (ii) {
-                               FFmpegImageProxy proxy (ii->png_image());
-                               shared_ptr<Image> image = proxy.image().first;
-                               /* set up rect with height and width */
-                               dcpomatic::Rect<double> rect(0, 0, image->size().width / double(size.width), image->size().height / double(size.height));
-
-                               /* add in position */
-
-                               switch (ii->h_align()) {
-                               case dcp::HALIGN_LEFT:
-                                       rect.x += ii->h_position();
-                                       break;
-                               case dcp::HALIGN_CENTER:
-                                       rect.x += 0.5 + ii->h_position() - rect.width / 2;
-                                       break;
-                               case dcp::HALIGN_RIGHT:
-                                       rect.x += 1 - ii->h_position() - rect.width;
-                                       break;
-                               }
-
-                               switch (ii->v_align()) {
-                               case dcp::VALIGN_TOP:
-                                       rect.y += ii->v_position();
-                                       break;
-                               case dcp::VALIGN_CENTER:
-                                       rect.y += 0.5 + ii->v_position() - rect.height / 2;
-                                       break;
-                               case dcp::VALIGN_BOTTOM:
-                                       rect.y += 1 - ii->v_position() - rect.height;
-                                       break;
-                               }
-
-                               decoder->emit_bitmap (
+                               emit_subtitle_image (
                                        ContentTimePeriod (
                                                ContentTime::from_frames (_offset - entry_point, vfr) + ContentTime::from_seconds (i->in().as_seconds ()),
                                                ContentTime::from_frames (_offset - entry_point, vfr) + ContentTime::from_seconds (i->out().as_seconds ())
                                                ),
-                                       image, rect
+                                       *ii,
+                                       size,
+                                       decoder
                                        );
                        }
                }
@@ -425,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;
+}