diff options
-rw-r--r-- | demux/demux.c | 45 | ||||
-rw-r--r-- | demux/demux.h | 6 | ||||
-rw-r--r-- | demux/demux_lavf.c | 1 | ||||
-rw-r--r-- | demux/demux_mkv.c | 1 |
4 files changed, 34 insertions, 19 deletions
diff --git a/demux/demux.c b/demux/demux.c index 9e5d6b2f7e..3d61444ee2 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -158,6 +158,8 @@ struct demux_stream { bool eof; // end of demuxed stream? (true if all buffer empty) bool need_refresh; // enabled mid-stream bool refreshing; + bool correct_dts; // packet DTS is strictly monotonically increasing + bool correct_pos; // packet pos is strictly monotonically increasing size_t packs; // number of packets in buffer size_t bytes; // total bytes of packets in buffer double base_ts; // timestamp of the last packet returned to decoder @@ -166,6 +168,7 @@ struct demux_stream { size_t last_br_bytes; // summed packet sizes since last bitrate calculation double bitrate; int64_t last_pos; + double last_dts; struct demux_packet *head; struct demux_packet *tail; @@ -205,6 +208,8 @@ static void ds_flush(struct demux_stream *ds) ds->refreshing = false; ds->need_refresh = false; ds->last_pos = -1; + ds->last_dts = MP_NOPTS_VALUE; + ds->correct_dts = ds->correct_pos = true; } void demux_set_ts_offset(struct demuxer *demuxer, double offset) @@ -405,14 +410,22 @@ static double get_refresh_seek_pts(struct demux_internal *in) double start_ts = in->ref_pts; bool needed = false; bool normal_seek = true; + bool refresh_possible = true; for (int n = 0; n < in->num_streams; n++) { struct demux_stream *ds = in->streams[n]->ds; + + if (!ds->selected) + continue; + if (ds->type == STREAM_VIDEO || ds->type == STREAM_AUDIO) start_ts = MP_PTS_MIN(start_ts, ds->base_ts); + needed |= ds->need_refresh; // If there were no other streams selected, we can use a normal seek. - normal_seek &= ds->need_refresh || !ds->selected; + normal_seek &= ds->need_refresh; ds->need_refresh = false; + + refresh_possible &= ds->correct_dts || ds->correct_pos; } if (!needed || start_ts == MP_NOPTS_VALUE || !demux->desc->seek || @@ -422,14 +435,16 @@ static double get_refresh_seek_pts(struct demux_internal *in) if (normal_seek) return start_ts; - if (!demux->allow_refresh_seeks) + if (!refresh_possible) { + MP_VERBOSE(in, "can't issue refresh seek\n"); return MP_NOPTS_VALUE; + } for (int n = 0; n < in->num_streams; n++) { struct demux_stream *ds = in->streams[n]->ds; - // Streams which didn't read any packets yet can return all packets, - // or they'd be stuck forever; affects newly selected streams too. - if (ds->last_pos != -1) + // Streams which didn't have any packets yet will return all packets, + // other streams return packets only starting from the last position. + if (ds->last_pos != -1 || ds->last_dts != MP_NOPTS_VALUE) ds->refreshing = true; } @@ -447,13 +462,18 @@ void demux_add_packet(struct sh_stream *stream, demux_packet_t *dp) struct demux_internal *in = ds->in; pthread_mutex_lock(&in->lock); - bool drop = false; + bool drop = ds->refreshing; if (ds->refreshing) { // Resume reading once the old position was reached (i.e. we start // returning packets where we left off before the refresh). - drop = dp->pos <= ds->last_pos; - if (dp->pos >= ds->last_pos) - ds->refreshing = false; + // If it's the same position, drop, but continue normally next time. + if (ds->correct_dts) { + ds->refreshing = dp->dts < ds->last_dts; + } else if (ds->correct_pos) { + ds->refreshing = dp->pos < ds->last_pos; + } else { + ds->refreshing = false; // should not happen + } } if (!ds->selected || in->seeking || drop) { @@ -462,10 +482,14 @@ void demux_add_packet(struct sh_stream *stream, demux_packet_t *dp) return; } + ds->correct_pos &= dp->pos >= 0 && dp->pos > ds->last_pos; + ds->correct_dts &= dp->dts != MP_NOPTS_VALUE && dp->dts > ds->last_dts; + ds->last_pos = dp->pos; + ds->last_dts = dp->dts; + dp->stream = stream->index; dp->next = NULL; - ds->last_pos = dp->pos; ds->packs++; ds->bytes += dp->len; if (ds->tail) { @@ -970,7 +994,6 @@ static void demux_copy(struct demuxer *dst, struct demuxer *src) dst->partially_seekable = src->partially_seekable; dst->filetype = src->filetype; dst->ts_resets_possible = src->ts_resets_possible; - dst->allow_refresh_seeks = src->allow_refresh_seeks; dst->fully_read = src->fully_read; dst->start_time = src->start_time; dst->priv = src->priv; diff --git a/demux/demux.h b/demux/demux.h index 8c07fe8933..8470047f9d 100644 --- a/demux/demux.h +++ b/demux/demux.h @@ -178,12 +178,6 @@ typedef struct demuxer { double start_time; // File format allows PTS resets (even if the current file is without) bool ts_resets_possible; - // Enable fast track switching hacks. This requires from the demuxer: - // - seeking is somewhat reliable; packet contents must not change - // - packet position (demux_packet.pos) is set, not negative, unique, and - // monotonically increasing - // - seeking leaves packet positions invariant - bool allow_refresh_seeks; // The file data was fully read, and there is no need to keep the stream // open, keep the cache active, or to run the demuxer thread. Generating // packets is not slow either (unlike e.g. libavdevice pseudo-demuxers). diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index e2221135f4..a38fb60435 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -865,7 +865,6 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check) demuxer->start_time = priv->avfc->start_time == AV_NOPTS_VALUE ? 0 : (double)priv->avfc->start_time / AV_TIME_BASE; - demuxer->allow_refresh_seeks = matches_avinputformat_name(priv, "mp4"); demuxer->fully_read = priv->format_hack.fully_read; return 0; diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c index f454f5fd20..6f45b5a5f2 100644 --- a/demux/demux_mkv.c +++ b/demux/demux_mkv.c @@ -1927,7 +1927,6 @@ static int demux_mkv_open(demuxer_t *demuxer, enum demux_check check) process_tags(demuxer); display_create_tracks(demuxer); add_coverart(demuxer); - demuxer->allow_refresh_seeks = true; probe_first_timestamp(demuxer); if (opts->demux_mkv->probe_duration) |