demux, demux_mkv: fix seeking in cache with large codec delay

In this scenario, the demuxer will output timestamps offset by the codec
delay (e.g. negative timestamps at the start; mkv simulates those), and
the trimming in the decoder (often libavcodec, but ad_lavc.c in our
case) will adjust the timestamps back (e.g. stream actually starts at
0).

This offset needs to be taken into account when seeking. This worked in
the uncached case. (demux_mkv.c is a bit tricky in that the index is
already in the offset space, so it compensates even though the seek call
does not reference codec_delay.) But in the cached case, seeks backwards
did not seek enough, and forward they seeked too much.

Fix this by adding the codec delay to the index search. We need to get
"earlier" packets, so e.g. seeking to position 0 really gets the initial
packets with negative timestamps.

This also adjusts the seek range start. This is also pretty obvious: if
the beginning of the file is cached, the seek range should start at 0,
not a negative value. We compare 0-based timestamps to it later on.

Not sure if this is the best approach. I also could have thought
about/checked some corner cases harder. But fuck this shit.

Not fixing duration (who cares) or end trimming, which would reduce the
seek range and duration (who cares).
This commit is contained in:
wm4 2019-05-22 22:27:07 +02:00
parent 464e5613aa
commit c810e7f2e7
3 changed files with 10 additions and 1 deletions

View File

@ -1686,8 +1686,11 @@ static void adjust_seek_range_on_packet(struct demux_stream *ds,
if (queue->keyframe_latest) {
queue->keyframe_latest->kf_seek_pts = queue->keyframe_pts;
double old_end = queue->range->seek_end;
if (queue->seek_start == MP_NOPTS_VALUE)
if (queue->seek_start == MP_NOPTS_VALUE) {
queue->seek_start = queue->keyframe_pts;
if (queue->seek_start != MP_NOPTS_VALUE)
queue->seek_start += ds->sh->seek_preroll;
}
if (queue->keyframe_end_pts != MP_NOPTS_VALUE)
queue->seek_end = queue->keyframe_end_pts;
queue->is_eof = !dp;
@ -2976,6 +2979,8 @@ static void switch_current_range(struct demux_internal *in,
static struct demux_packet *find_seek_target(struct demux_queue *queue,
double pts, int flags)
{
pts -= queue->ds->sh->seek_preroll;
struct demux_packet *start = queue->head;
for (int n = 0; n < queue->num_index; n++) {
if (queue->index[n]->kf_seek_pts > pts)

View File

@ -1835,6 +1835,8 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
sh_a->extradata = extradata;
sh_a->extradata_size = extradata_len;
sh->seek_preroll = track->codec_delay;
demux_add_sh_stream(demuxer, sh);
return 0;

View File

@ -53,6 +53,8 @@ struct sh_stream {
bool missing_timestamps;
double seek_preroll;
// stream is a picture (such as album art)
struct demux_packet *attached_picture;