From c2adc362e4ce0a64d7e7a1c6b634b024d862c8c1 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sat, 21 Feb 2026 02:37:42 +0100 Subject: Handle FFmpeg content with only subtitles enabled better. Previously if some FFmpeg content was set to use only its subtitles, and the first subtitle was 1 minute in to the content, the content would be selected for pass() until its first minute had been scanned. This could be slow, and incorrect as on the way to this 1 minute we want to look at other content. Here we store the PTS of dropped packets to use as a fallback position when there is no video or audio enabled. --- src/lib/ffmpeg_decoder.cc | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'src/lib/ffmpeg_decoder.cc') diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index ec85bb56c..294db777d 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -102,6 +102,8 @@ FFmpegDecoder::FFmpegDecoder (shared_ptr film, shared_ptrffmpeg_audio_streams()) { _next_time[i] = boost::optional(); } + + _dropped_time.resize(_format_context->nb_streams); } @@ -240,6 +242,9 @@ FFmpegDecoder::pass () decode_and_process_subtitle_packet (packet); } else if (audio) { decode_and_process_audio_packet (packet); + } else { + DCPOMATIC_ASSERT(static_cast(_dropped_time.size()) > si); + _dropped_time[si] = dcpomatic::ContentTime::from_seconds(packet->pts * av_q2d(_format_context->streams[si]->time_base) + _pts_offset.seconds()); } if (_have_current_subtitle && _current_subtitle_to && position() > *_current_subtitle_to) { @@ -466,6 +471,10 @@ FFmpegDecoder::seek (ContentTime time, bool accurate) for (auto& i: _next_time) { i.second = boost::optional(); } + + for (auto& dropped: _dropped_time) { + dropped = boost::none; + } } @@ -846,3 +855,34 @@ FFmpegDecoder::process_ass_subtitle (string ass, ContentTime from) only_text()->emit_plain_start (from, i); } } + + +ContentTime +FFmpegDecoder::position() const +{ + optional pos; + auto f = film(); + + if (video && !video->ignore() && (!pos || video->position(f).get_value_or(ContentTime()) < *pos)) { + pos = video->position(f); + } + + if (audio && !audio->ignore() && (!pos || audio->position(f).get_value_or(ContentTime()) < *pos)) { + pos = audio->position(f); + } + + if (!pos) { + for (auto dropped: _dropped_time) { + if (dropped) { + if (pos) { + pos = std::min(*pos, *dropped); + } else { + pos = *dropped; + } + } + } + } + + return pos.get_value_or(ContentTime()); +} + -- cgit v1.2.3