diff options
author | wm4 <wm4@nowhere> | 2014-08-16 17:07:36 +0200 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2014-08-16 17:10:08 +0200 |
commit | b822faa6cfdae2c530d68f257a811c6184d237a6 (patch) | |
tree | 073cee68af958d205b00648cfacc4439b6d5d471 | |
parent | e6e3bc7cd97e7dc27d91bbf89902191b4408cb40 (diff) | |
download | mpv-b822faa6cfdae2c530d68f257a811c6184d237a6.tar.bz2 mpv-b822faa6cfdae2c530d68f257a811c6184d237a6.tar.xz |
demux: add option to control the readahead buffer by a duration value
--demuxer-readahead-secs now controls how much the demuxer should
readahead by an amount of seconds. This is based on the raw packet
timestamps. It's not always very exact. For example, h264 in Matroska
does not store any linear timestamps (only PTS values which are going
to be reordered by the decoder), so this heuristic is usually off by
several hundred milliseconds.
The decision whether to readahead is basically OR-ed with the other
--demuxer-readahead-packets options. Change the manpage descriptions
to subtly convey these semantics.
-rw-r--r-- | DOCS/man/options.rst | 16 | ||||
-rw-r--r-- | demux/demux.c | 20 | ||||
-rw-r--r-- | options/options.c | 2 | ||||
-rw-r--r-- | options/options.h | 1 |
4 files changed, 35 insertions, 4 deletions
diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index 9320a244ac..edbbc35419 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -2048,11 +2048,21 @@ Demuxer Run the demuxer in a separate thread, and let it prefetch a certain amount of packets (default: no). +``--demuxer-readahead-secs=N`` + If ``--demuxer-thread`` is enabled, this controls how much the demuxer + should buffer ahead in seconds (default: 0.2). As long as no packet has + a timestamp difference higher than the readahead amount relative to the + last packet returned to the decoder, the demuxer keeps reading. + + (This value tends to be fuzzy, because many file formats don't store linear + timestamps.) + ``--demuxer-readahead-packets=N`` If ``--demuxer-thread`` is enabled, this controls how much the demuxer - should buffer ahead. If the number of packets in the packet queue exceeds - ``--demuxer-readahead-packets``, or the total number of bytes exceeds - ``--demuxer-readahead-bytes``, the thread stops reading ahead. + should buffer ahead. As long as the number of packets in the packet queue + doesn't exceed ``--demuxer-readahead-packets``, and the total number of + bytes doesn't exceed ``--demuxer-readahead-bytes``, the thread keeps + reading ahead. Note that if you set these options near the maximum, you might get a packet queue overflow warning. diff --git a/demux/demux.c b/demux/demux.c index 5918da51a9..bb9363815e 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -110,6 +110,7 @@ struct demux_internal { bool last_eof; // last actual global EOF status bool eof; // whether we're in EOF state (reset for retry) bool autoselect; + double min_secs; int min_packs; int min_bytes; @@ -137,6 +138,8 @@ struct demux_stream { bool eof; // end of demuxed stream? (true if all buffer empty) 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 + double last_ts; // timestamp of the last packet added to queue struct demux_packet *head; struct demux_packet *tail; }; @@ -157,6 +160,7 @@ static void ds_flush(struct demux_stream *ds) ds->head = ds->tail = NULL; ds->packs = 0; ds->bytes = 0; + ds->last_ts = ds->base_ts = MP_NOPTS_VALUE; ds->eof = false; ds->active = false; } @@ -294,6 +298,7 @@ int demux_add_packet(struct sh_stream *stream, demux_packet_t *dp) // first packet in stream ds->head = ds->tail = dp; } + // obviously not true anymore ds->eof = false; in->last_eof = in->eof = false; @@ -303,6 +308,12 @@ int demux_add_packet(struct sh_stream *stream, demux_packet_t *dp) if (stream->type != STREAM_VIDEO && dp->pts == MP_NOPTS_VALUE) dp->pts = dp->dts; + double ts = dp->dts == MP_NOPTS_VALUE ? dp->pts : dp->dts; + if (ts != MP_NOPTS_VALUE && (ts > ds->last_ts || ts + 10 < ds->last_ts)) + ds->last_ts = ts; + if (ds->base_ts == MP_NOPTS_VALUE) + ds->base_ts = ds->last_ts; + MP_DBG(in, "append packet to %s: size=%d pts=%f dts=%f pos=%"PRIi64" " "[num=%zd size=%zd]\n", stream_type_name(stream->type), dp->len, dp->pts, dp->dts, dp->pos, ds->packs, ds->bytes); @@ -326,10 +337,12 @@ static bool read_packet(struct demux_internal *in) size_t packs = 0, bytes = 0; for (int n = 0; n < in->d_buffer->num_streams; n++) { struct demux_stream *ds = in->d_buffer->streams[n]->ds; - active |= ds->selected && ds->active; + active |= ds->active; read_more |= ds->active && !ds->head; packs += ds->packs; bytes += ds->bytes; + if (ds->active && ds->last_ts != MP_NOPTS_VALUE && in->min_secs > 0) + read_more |= ds->last_ts - ds->base_ts < in->min_secs; } MP_DBG(in, "packets=%zd, bytes=%zd, active=%d, more=%d\n", packs, bytes, active, read_more); @@ -475,6 +488,10 @@ static struct demux_packet *dequeue_packet(struct demux_stream *ds) ds->bytes -= pkt->len; ds->packs--; + double ts = pkt->dts == MP_NOPTS_VALUE ? pkt->pts : pkt->dts; + if (ts != MP_NOPTS_VALUE) + ds->base_ts = ts; + // This implies this function is actually called from "the" user thread. if (pkt && pkt->pos >= 0) ds->in->d_user->filepos = pkt->pos; @@ -791,6 +808,7 @@ static struct demuxer *open_given_type(struct mpv_global *global, .d_thread = talloc(demuxer, struct demuxer), .d_buffer = talloc(demuxer, struct demuxer), .d_user = demuxer, + .min_secs = demuxer->opts->demuxer_min_secs, .min_packs = demuxer->opts->demuxer_min_packs, .min_bytes = demuxer->opts->demuxer_min_bytes, }; diff --git a/options/options.c b/options/options.c index aacb1b725a..c96f6578b6 100644 --- a/options/options.c +++ b/options/options.c @@ -216,6 +216,7 @@ const m_option_t mp_opts[] = { OPT_STRING("audio-demuxer", audio_demuxer_name, 0), OPT_STRING("sub-demuxer", sub_demuxer_name, 0), OPT_FLAG("demuxer-thread", demuxer_thread, 0), + OPT_DOUBLE("demuxer-readahead-secs", demuxer_min_secs, M_OPT_MIN, .min = 0), OPT_INTRANGE("demuxer-readahead-packets", demuxer_min_packs, 0, 0, MAX_PACKS), OPT_INTRANGE("demuxer-readahead-bytes", demuxer_min_bytes, 0, 0, MAX_PACK_BYTES), @@ -600,6 +601,7 @@ const struct MPOpts mp_default_opts = { .demuxer_thread = 0, .demuxer_min_packs = MIN_PACKS, .demuxer_min_bytes = MIN_PACK_BYTES, + .demuxer_min_secs = 0.2, .network_rtsp_transport = 2, .chapterrange = {-1, -1}, .edition_id = -1, diff --git a/options/options.h b/options/options.h index 65007bd22e..7b3bf4b69d 100644 --- a/options/options.h +++ b/options/options.h @@ -184,6 +184,7 @@ typedef struct MPOpts { int demuxer_thread; int demuxer_min_packs; int demuxer_min_bytes; + double demuxer_min_secs; char *audio_demuxer_name; char *sub_demuxer_name; int mkv_subtitle_preroll; |