Possibly improve shuffler behaviour (use one for all content if any 3D is present).
[dcpomatic.git] / src / lib / player.cc
index 58ea4f2dea660ac6db81c51fbe55767573661c20..53b1733330764aa5b76b988f58b096da6a331f62 100644 (file)
@@ -166,8 +166,19 @@ Player::setup_pieces_unlocked ()
        auto old_pieces = _pieces;
        _pieces.clear ();
 
-       _shuffler.reset (new Shuffler());
-       _shuffler->Video.connect(bind(&Player::video, this, _1, _2));
+       auto playlist_content = playlist()->content();
+       bool const have_threed = std::any_of(
+               playlist_content.begin(),
+               playlist_content.end(),
+               [](shared_ptr<const Content> c) {
+                       return c->video && (c->video->frame_type() == VideoFrameType::THREE_D_LEFT || c->video->frame_type() == VideoFrameType::THREE_D_RIGHT);
+               });
+
+
+       if (have_threed) {
+               _shuffler.reset(new Shuffler());
+               _shuffler->Video.connect(bind(&Player::video, this, _1, _2));
+       }
 
        for (auto i: playlist()->content()) {
 
@@ -219,7 +230,7 @@ Player::setup_pieces_unlocked ()
                _pieces.push_back (piece);
 
                if (decoder->video) {
-                       if (i->video->frame_type() == VideoFrameType::THREE_D_LEFT || i->video->frame_type() == VideoFrameType::THREE_D_RIGHT) {
+                       if (have_threed) {
                                /* We need a Shuffler to cope with 3D L/R video data arriving out of sequence */
                                decoder->video->Data.connect (bind(&Shuffler::video, _shuffler.get(), weak_ptr<Piece>(piece), _1));
                        } else {
@@ -810,7 +821,9 @@ Player::pass ()
        }
 
        if (done) {
-               _shuffler->flush ();
+               if (_shuffler) {
+                       _shuffler->flush ();
+               }
                for (auto const& i: _delay) {
                        do_emit_video(i.first, i.second);
                }
@@ -881,13 +894,13 @@ Player::open_subtitles_for_frame (DCPTime time) const
 
 
 void
-Player::video (weak_ptr<Piece> wp, ContentVideo video)
+Player::video (weak_ptr<Piece> weak_piece, ContentVideo video)
 {
        if (_suspended) {
                return;
        }
 
-       auto piece = wp.lock ();
+       auto piece = weak_piece.lock ();
        if (!piece) {
                return;
        }
@@ -927,7 +940,7 @@ Player::video (weak_ptr<Piece> wp, ContentVideo video)
 
                /* Fill if we have more than half a frame to do */
                if ((fill_to - fill_from) > one_video_frame() / 2) {
-                       auto last = _last_video.find (wp);
+                       auto last = _last_video.find (weak_piece);
                        if (_film->three_d()) {
                                auto fill_to_eyes = video.eyes;
                                if (fill_to_eyes == Eyes::BOTH) {
@@ -971,7 +984,7 @@ Player::video (weak_ptr<Piece> wp, ContentVideo video)
 
        auto const content_video = piece->content->video;
 
-       _last_video[wp] = std::make_shared<PlayerVideo>(
+       _last_video[weak_piece] = std::make_shared<PlayerVideo>(
                video.image,
                content_video->actual_crop(),
                content_video->fade (_film, video.frame),
@@ -994,7 +1007,7 @@ Player::video (weak_ptr<Piece> wp, ContentVideo video)
        DCPTime t = time;
        for (int i = 0; i < frc.repeat; ++i) {
                if (t < piece->content->end(_film)) {
-                       emit_video (_last_video[wp], t);
+                       emit_video (_last_video[weak_piece], t);
                }
                t += one_video_frame ();
        }
@@ -1002,7 +1015,7 @@ Player::video (weak_ptr<Piece> wp, ContentVideo video)
 
 
 void
-Player::audio (weak_ptr<Piece> wp, AudioStreamPtr stream, ContentAudio content_audio)
+Player::audio (weak_ptr<Piece> weak_piece, AudioStreamPtr stream, ContentAudio content_audio)
 {
        if (_suspended) {
                return;
@@ -1010,7 +1023,7 @@ Player::audio (weak_ptr<Piece> wp, AudioStreamPtr stream, ContentAudio content_a
 
        DCPOMATIC_ASSERT (content_audio.audio->frames() > 0);
 
-       auto piece = wp.lock ();
+       auto piece = weak_piece.lock ();
        if (!piece) {
                return;
        }
@@ -1092,58 +1105,61 @@ Player::audio (weak_ptr<Piece> wp, AudioStreamPtr stream, ContentAudio content_a
 
 
 void
-Player::bitmap_text_start (weak_ptr<Piece> wp, weak_ptr<const TextContent> wc, ContentBitmapText subtitle)
+Player::bitmap_text_start (weak_ptr<Piece> weak_piece, weak_ptr<const TextContent> weak_content, ContentBitmapText subtitle)
 {
        if (_suspended) {
                return;
        }
 
-       auto piece = wp.lock ();
-       auto text = wc.lock ();
-       if (!piece || !text) {
+       auto piece = weak_piece.lock ();
+       auto content = weak_content.lock ();
+       if (!piece || !content) {
                return;
        }
 
-       /* Apply content's subtitle offsets */
-       subtitle.sub.rectangle.x += text->x_offset ();
-       subtitle.sub.rectangle.y += text->y_offset ();
+       PlayerText ps;
+       for (auto& sub: subtitle.subs)
+       {
+               /* Apply content's subtitle offsets */
+               sub.rectangle.x += content->x_offset ();
+               sub.rectangle.y += content->y_offset ();
 
-       /* Apply a corrective translation to keep the subtitle centred after the scale that is coming up */
-       subtitle.sub.rectangle.x -= subtitle.sub.rectangle.width * ((text->x_scale() - 1) / 2);
-       subtitle.sub.rectangle.y -= subtitle.sub.rectangle.height * ((text->y_scale() - 1) / 2);
+               /* Apply a corrective translation to keep the subtitle centred after the scale that is coming up */
+               sub.rectangle.x -= sub.rectangle.width * ((content->x_scale() - 1) / 2);
+               sub.rectangle.y -= sub.rectangle.height * ((content->y_scale() - 1) / 2);
 
-       /* Apply content's subtitle scale */
-       subtitle.sub.rectangle.width *= text->x_scale ();
-       subtitle.sub.rectangle.height *= text->y_scale ();
+               /* Apply content's subtitle scale */
+               sub.rectangle.width *= content->x_scale ();
+               sub.rectangle.height *= content->y_scale ();
 
-       PlayerText ps;
-       auto image = subtitle.sub.image;
+               auto image = sub.image;
 
-       /* We will scale the subtitle up to fit _video_container_size */
-       int const width = subtitle.sub.rectangle.width * _video_container_size.width;
-       int const height = subtitle.sub.rectangle.height * _video_container_size.height;
-       if (width == 0 || height == 0) {
-               return;
-       }
+               /* We will scale the subtitle up to fit _video_container_size */
+               int const width = sub.rectangle.width * _video_container_size.width;
+               int const height = sub.rectangle.height * _video_container_size.height;
+               if (width == 0 || height == 0) {
+                       return;
+               }
 
-       dcp::Size scaled_size (width, height);
-       ps.bitmap.push_back (BitmapText(image->scale(scaled_size, dcp::YUVToRGB::REC601, image->pixel_format(), Image::Alignment::PADDED, _fast), subtitle.sub.rectangle));
-       DCPTime from (content_time_to_dcp (piece, subtitle.from()));
+               dcp::Size scaled_size (width, height);
+               ps.bitmap.push_back (BitmapText(image->scale(scaled_size, dcp::YUVToRGB::REC601, image->pixel_format(), Image::Alignment::PADDED, _fast), sub.rectangle));
+       }
 
-       _active_texts[static_cast<int>(text->type())].add_from (wc, ps, from);
+       DCPTime from(content_time_to_dcp(piece, subtitle.from()));
+       _active_texts[static_cast<int>(content->type())].add_from(weak_content, ps, from);
 }
 
 
 void
-Player::plain_text_start (weak_ptr<Piece> wp, weak_ptr<const TextContent> wc, ContentStringText subtitle)
+Player::plain_text_start (weak_ptr<Piece> weak_piece, weak_ptr<const TextContent> weak_content, ContentStringText subtitle)
 {
        if (_suspended) {
                return;
        }
 
-       auto piece = wp.lock ();
-       auto text = wc.lock ();
-       if (!piece || !text) {
+       auto piece = weak_piece.lock ();
+       auto content = weak_content.lock ();
+       if (!piece || !content) {
                return;
        }
 
@@ -1155,10 +1171,10 @@ Player::plain_text_start (weak_ptr<Piece> wp, weak_ptr<const TextContent> wc, Co
        }
 
        for (auto s: subtitle.subs) {
-               s.set_h_position (s.h_position() + text->x_offset ());
-               s.set_v_position (s.v_position() + text->y_offset ());
-               float const xs = text->x_scale();
-               float const ys = text->y_scale();
+               s.set_h_position (s.h_position() + content->x_offset());
+               s.set_v_position (s.v_position() + content->y_offset());
+               float const xs = content->x_scale();
+               float const ys = content->y_scale();
                float size = s.size();
 
                /* Adjust size to express the common part of the scaling;
@@ -1175,31 +1191,31 @@ Player::plain_text_start (weak_ptr<Piece> wp, weak_ptr<const TextContent> wc, Co
                }
 
                s.set_in (dcp::Time(from.seconds(), 1000));
-               ps.string.push_back (StringText (s, text->outline_width()));
-               ps.add_fonts (text->fonts ());
+               ps.string.push_back (StringText (s, content->outline_width()));
+               ps.add_fonts (content->fonts ());
        }
 
-       _active_texts[static_cast<int>(text->type())].add_from (wc, ps, from);
+       _active_texts[static_cast<int>(content->type())].add_from(weak_content, ps, from);
 }
 
 
 void
-Player::subtitle_stop (weak_ptr<Piece> wp, weak_ptr<const TextContent> wc, ContentTime to)
+Player::subtitle_stop (weak_ptr<Piece> weak_piece, weak_ptr<const TextContent> weak_content, ContentTime to)
 {
        if (_suspended) {
                return;
        }
 
-       auto text = wc.lock ();
-       if (!text) {
+       auto content = weak_content.lock ();
+       if (!content) {
                return;
        }
 
-       if (!_active_texts[static_cast<int>(text->type())].have(wc)) {
+       if (!_active_texts[static_cast<int>(content->type())].have(weak_content)) {
                return;
        }
 
-       shared_ptr<Piece> piece = wp.lock ();
+       auto piece = weak_piece.lock ();
        if (!piece) {
                return;
        }
@@ -1210,11 +1226,11 @@ Player::subtitle_stop (weak_ptr<Piece> wp, weak_ptr<const TextContent> wc, Conte
                return;
        }
 
-       auto from = _active_texts[static_cast<int>(text->type())].add_to (wc, dcp_to);
+       auto from = _active_texts[static_cast<int>(content->type())].add_to(weak_content, dcp_to);
 
-       bool const always = (text->type() == TextType::OPEN_SUBTITLE && _always_burn_open_subtitles);
-       if (text->use() && !always && !text->burn()) {
-               Text (from.first, text->type(), text->dcp_track().get_value_or(DCPTextTrack()), DCPTimePeriod (from.second, dcp_to));
+       bool const always = (content->type() == TextType::OPEN_SUBTITLE && _always_burn_open_subtitles);
+       if (content->use() && !always && !content->burn()) {
+               Text (from.first, content->type(), content->dcp_track().get_value_or(DCPTextTrack()), DCPTimePeriod(from.second, dcp_to));
        }
 }
 
@@ -1429,6 +1445,22 @@ Player::content_time_to_dcp (shared_ptr<const Content> content, ContentTime t)
 }
 
 
+optional<ContentTime>
+Player::dcp_to_content_time (shared_ptr<const Content> content, DCPTime t)
+{
+       boost::mutex::scoped_lock lm (_mutex);
+
+       for (auto i: _pieces) {
+               if (i->content == content) {
+                       return dcp_to_content_time (i, t);
+               }
+       }
+
+       /* We couldn't find this content; perhaps things are being changed over */
+       return {};
+}
+
+
 shared_ptr<const Playlist>
 Player::playlist () const
 {