Flush audio decoder when a DCPDecoder finishes so that
[dcpomatic.git] / src / lib / dcp_decoder.cc
index 1098bb87a8c94a8df56cf2ca0f3a7d40cd24f72c..7bd7ddf68da2c00d14f3620160d055f78ebd21c1 100644 (file)
@@ -60,15 +60,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 +106,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 +211,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 +229,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 +274,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
                                        );
                        }
                }