From 4c0577afdbb38d4cf15208fb2d74d180f44b4609 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 7 May 2017 21:47:58 +0100 Subject: [PATCH] Fix fill of timeline periods where there is no video. --- src/lib/player.cc | 157 +++++++++++++++++++------------ src/lib/player.h | 4 +- src/lib/text_subtitle_decoder.cc | 5 + 3 files changed, 103 insertions(+), 63 deletions(-) diff --git a/src/lib/player.cc b/src/lib/player.cc index 858e93c04..1110b41b0 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -527,27 +527,26 @@ Player::pass () } } - if (!earliest) { - /* No more content; fill up with silent black */ - DCPTimePeriod remaining_video (DCPTime(), _playlist->length()); - if (_last_video_time) { - remaining_video.from = _last_video_time.get(); - } - fill_video (remaining_video); - DCPTimePeriod remaining_audio (DCPTime(), _playlist->length()); - if (_last_audio_time) { - remaining_audio.from = _last_audio_time.get(); + if (earliest) { + earliest->done = earliest->decoder->pass (); + if (earliest->done && earliest->content->audio) { + /* Flush the Player audio system for this piece */ + BOOST_FOREACH (AudioStreamPtr i, earliest->content->audio->streams()) { + audio_flush (earliest, i); + } } - fill_audio (remaining_audio); - return true; } - earliest->done = earliest->decoder->pass (); - if (earliest->done && earliest->content->audio) { - /* Flush the Player audio system for this piece */ - BOOST_FOREACH (AudioStreamPtr i, earliest->content->audio->streams()) { - audio_flush (earliest, i); - } + if (_last_video_time) { + fill_video (DCPTimePeriod (_last_video_time.get(), earliest ? earliest_content : _playlist->length())); + } else if (_last_seek_time) { + fill_video (DCPTimePeriod (_last_seek_time.get(), _last_seek_time.get() + one_video_frame ())); + } + + /* XXX: fill audio */ + + if (!earliest) { + return true; } /* Emit any audio that is ready */ @@ -573,6 +572,7 @@ Player::pass () } if (_last_audio_time) { + /* XXX: does this remain necessary? */ fill_audio (DCPTimePeriod (_last_audio_time.get(), i->second)); } @@ -583,28 +583,9 @@ Player::pass () return false; } -void -Player::video (weak_ptr wp, ContentVideo video) +optional +Player::subtitles_for_frame (DCPTime time) const { - shared_ptr piece = wp.lock (); - if (!piece) { - return; - } - - FrameRateChange frc(piece->content->active_video_frame_rate(), _film->video_frame_rate()); - if (frc.skip && (video.frame % 2) == 1) { - return; - } - - /* Time and period of the frame we will emit */ - DCPTime const time = content_video_to_dcp (piece, video.frame); - DCPTimePeriod const period (time, time + one_video_frame()); - - /* Discard if it's outside the content's period or if it's before the last accurate seek */ - if (time < piece->content->position() || time >= piece->content->end() || (_last_video_time && time < _last_video_time)) { - return; - } - /* Get any subtitles */ optional subtitles; @@ -616,35 +597,62 @@ Player::video (weak_ptr wp, ContentVideo video) continue; } - if (!sub_piece->content->subtitle->use() || (!_always_burn_subtitles && !piece->content->subtitle->burn())) { + if (!sub_piece->content->subtitle->use() || (!_always_burn_subtitles && !sub_piece->content->subtitle->burn())) { continue; } - ActiveSubtitles sub = i->second; + BOOST_FOREACH (ActiveSubtitles j, i->second) { - if (sub.from > time || (sub.to && sub.to.get() <= time)) { - continue; - } + if (j.from > time || (j.to && j.to.get() <= time)) { + continue; + } - list sub_images; + list sub_images; - /* Image subtitles */ - list c = transform_image_subtitles (sub.subs.image); - copy (c.begin(), c.end(), back_inserter (sub_images)); + /* Image subtitles */ + list c = transform_image_subtitles (j.subs.image); + copy (c.begin(), c.end(), back_inserter (sub_images)); - /* Text subtitles (rendered to an image) */ - if (!sub.subs.text.empty ()) { - list s = render_subtitles (sub.subs.text, sub.subs.fonts, _video_container_size, time); - copy (s.begin (), s.end (), back_inserter (sub_images)); - } + /* Text subtitles (rendered to an image) */ + if (!j.subs.text.empty ()) { + list s = render_subtitles (j.subs.text, j.subs.fonts, _video_container_size, time); + copy (s.begin (), s.end (), back_inserter (sub_images)); + } - if (!sub_images.empty ()) { - subtitles = merge (sub_images); + if (!sub_images.empty ()) { + subtitles = merge (sub_images); + } } } + return subtitles; +} + +void +Player::video (weak_ptr wp, ContentVideo video) +{ + shared_ptr piece = wp.lock (); + if (!piece) { + return; + } + + FrameRateChange frc(piece->content->active_video_frame_rate(), _film->video_frame_rate()); + if (frc.skip && (video.frame % 2) == 1) { + return; + } + + /* Time and period of the frame we will emit */ + DCPTime const time = content_video_to_dcp (piece, video.frame); + DCPTimePeriod const period (time, time + one_video_frame()); + + /* Discard if it's outside the content's period or if it's before the last accurate seek */ + if (time < piece->content->position() || time >= piece->content->end() || (_last_video_time && time < _last_video_time)) { + return; + } + /* Fill gaps caused by (the hopefully rare event of) a decoder not emitting contiguous video */ + /* XXX: is this necessary? can it be done by the fill in pass? */ if (_last_video_time) { fill_video (DCPTimePeriod (_last_video_time.get(), time)); } @@ -664,6 +672,7 @@ Player::video (weak_ptr wp, ContentVideo video) ) ); + optional subtitles = subtitles_for_frame (time); if (subtitles) { _last_video->set_subtitle (subtitles.get ()); } @@ -675,8 +684,14 @@ Player::video (weak_ptr wp, ContentVideo video) /* Clear any finished _active_subtitles */ ActiveSubtitlesMap updated; for (ActiveSubtitlesMap::const_iterator i = _active_subtitles.begin(); i != _active_subtitles.end(); ++i) { - if (!i->second.to || i->second.to.get() >= time) { - updated[i->first] = i->second; + list as; + BOOST_FOREACH (ActiveSubtitles j, i->second) { + if (!j.to || j.to.get() >= time) { + as.push_back (j); + } + } + if (!as.empty ()) { + updated[i->first] = as; } } _active_subtitles = updated; @@ -832,7 +847,10 @@ Player::image_subtitle_start (weak_ptr wp, ContentImageSubtitle subtitle) ps.image.push_back (subtitle.sub); DCPTime from (content_time_to_dcp (piece, subtitle.from())); - _active_subtitles[wp] = ActiveSubtitles (ps, from); + if (_active_subtitles.find(wp) == _active_subtitles.end()) { + _active_subtitles[wp] = list(); + } + _active_subtitles[wp].push_back (ActiveSubtitles (ps, from)); } void @@ -871,7 +889,10 @@ Player::text_subtitle_start (weak_ptr wp, ContentTextSubtitle subtitle) ps.add_fonts (piece->content->subtitle->fonts ()); } - _active_subtitles[wp] = ActiveSubtitles (ps, from); + if (_active_subtitles.find(wp) == _active_subtitles.end()) { + _active_subtitles[wp] = list (); + } + _active_subtitles[wp].push_back (ActiveSubtitles (ps, from)); } void @@ -889,10 +910,14 @@ Player::subtitle_stop (weak_ptr wp, ContentTime to) DCPTime const dcp_to = content_time_to_dcp (piece, to); if (piece->content->subtitle->use() && !_always_burn_subtitles && !piece->content->subtitle->burn()) { - Subtitle (_active_subtitles[wp].subs, DCPTimePeriod (_active_subtitles[wp].from, dcp_to)); + Subtitle (_active_subtitles[wp].back().subs, DCPTimePeriod (_active_subtitles[wp].back().from, dcp_to)); } - _active_subtitles[wp].to = dcp_to; + _active_subtitles[wp].back().to = dcp_to; + + BOOST_FOREACH (SubtitleString& i, _active_subtitles[wp].back().subs.text) { + i.set_out (dcp::Time(dcp_to.seconds(), 1000)); + } } void @@ -932,6 +957,8 @@ Player::seek (DCPTime time, bool accurate) _last_video_time = optional (); _last_audio_time = optional (); } + + _last_seek_time = time; } shared_ptr @@ -970,8 +997,14 @@ Player::fill_video (DCPTimePeriod period) if (_playlist->video_content_at(j) && _last_video) { Video (shared_ptr (new PlayerVideo (*_last_video)), j); } else { - Video (black_player_video_frame(), j); + shared_ptr black = black_player_video_frame (); + optional subtitles = subtitles_for_frame (j); + if (subtitles) { + black->set_subtitle (subtitles.get ()); + } + Video (black, j); } + _last_video_time = j; } } } diff --git a/src/lib/player.h b/src/lib/player.h index 6d4f6836f..48dcd8892 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -116,6 +116,7 @@ private: std::pair, DCPTime> discard_audio ( boost::shared_ptr audio, DCPTime time, DCPTime discard_to ) const; + boost::optional subtitles_for_frame (DCPTime time) const; boost::shared_ptr _film; boost::shared_ptr _playlist; @@ -147,6 +148,7 @@ private: boost::optional _last_video_time; /** Time just after the last audio frame we emitted, or the last seek time */ boost::optional _last_audio_time; + boost::optional _last_seek_time; AudioMerger _audio_merger; @@ -182,7 +184,7 @@ private: DCPTime from; boost::optional to; }; - typedef std::map, ActiveSubtitles> ActiveSubtitlesMap; + typedef std::map, std::list > ActiveSubtitlesMap; ActiveSubtitlesMap _active_subtitles; boost::shared_ptr _audio_processor; diff --git a/src/lib/text_subtitle_decoder.cc b/src/lib/text_subtitle_decoder.cc index bdec17a8d..631e0cc0c 100644 --- a/src/lib/text_subtitle_decoder.cc +++ b/src/lib/text_subtitle_decoder.cc @@ -44,6 +44,11 @@ TextSubtitleDecoder::TextSubtitleDecoder (shared_ptr void TextSubtitleDecoder::seek (ContentTime time, bool accurate) { + time -= ContentTime::from_seconds (5); + if (time < ContentTime()) { + time = ContentTime(); + } + Decoder::seek (time, accurate); _next = 0; -- 2.30.2