diff options
-rw-r--r-- | DOCS/man/options.rst | 23 | ||||
-rw-r--r-- | demux/demux.c | 28 | ||||
-rw-r--r-- | demux/demux.h | 6 | ||||
-rw-r--r-- | etc/example.conf | 2 | ||||
-rw-r--r-- | options/m_config.c | 2 | ||||
-rw-r--r-- | options/options.c | 10 | ||||
-rw-r--r-- | options/options.h | 5 | ||||
-rw-r--r-- | player/playloop.c | 54 | ||||
-rw-r--r-- | stream/stream.c | 1 |
9 files changed, 87 insertions, 44 deletions
diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index caa2dbbb28..65e7673a1f 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -2751,20 +2751,6 @@ Cache will not automatically enable the cache e.g. when playing from a network stream. Note that using ``--cache`` will always override this option. -``--cache-pause-below=<kBytes|no>`` - If the cache size goes below the specified value (in KB), pause and wait - until the size set by ``--cache-pause-restart`` is reached, then resume - playback (default: 50). If ``no`` is specified, this behavior is disabled. - - When the player is paused this way, the status line shows ``Buffering`` - instead of ``Paused``, and the OSD uses a clock symbol instead of the - normal paused symbol. - -``--cache-pause-restart=<kBytes>`` - If the cache is paused due to the ``--cache-pause-below`` functionality, - then the player unpauses as soon as the cache has this much data (in KB). - (Default: 100) - ``--cache-initial=<kBytes>`` Playback will start when the cache has been filled up with this many kilobytes of data (default: 0). @@ -2809,6 +2795,15 @@ Cache ``--no-cache`` Turn off input stream caching. See ``--cache``. +``--cache-secs=<seconds>`` + How many seconds of audio/video to prefetch if the cache is active. This + overrides the ``--demuxer-readahead-secs`` option if and only if the cache + is enabled. (Default: 10.) + +``--cache-pause``, ``--no-cache-pause`` + Whether the player should automatically pause when the cache runs low, + and unpause once more data is available ("buffering"). + Network ------- diff --git a/demux/demux.c b/demux/demux.c index e54027cc9d..2560a0736d 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -109,6 +109,7 @@ struct demux_internal { bool warned_queue_overflow; bool last_eof; // last actual global EOF status bool eof; // whether we're in EOF state (reset for retry) + bool idle; bool autoselect; double min_secs; int min_packs; @@ -144,6 +145,10 @@ struct demux_stream { struct demux_packet *tail; }; +// If one of the values is NOPTS, always pick the other one. +#define MP_PTS_MIN(a, b) ((a) == MP_NOPTS_VALUE || ((a) > (b)) ? (b) : (a)) +#define MP_PTS_MAX(a, b) ((a) == MP_NOPTS_VALUE || ((a) < (b)) ? (b) : (a)) + static void demuxer_sort_chapters(demuxer_t *demuxer); static void *demux_thread(void *pctx); static void update_cache(struct demux_internal *in); @@ -329,6 +334,7 @@ int demux_add_packet(struct sh_stream *stream, demux_packet_t *dp) static bool read_packet(struct demux_internal *in) { in->eof = false; + in->idle = true; // Check if we need to read a new packet. We do this if all queues are below // the minimum, or if a stream explicitly needs new packets. Also includes @@ -373,6 +379,7 @@ static bool read_packet(struct demux_internal *in) // Actually read a packet. Drop the lock while doing so, because waiting // for disk or network I/O can take time. + in->idle = false; pthread_mutex_unlock(&in->lock); struct demuxer *demux = in->d_thread; bool eof = !demux->desc->fill_buffer || demux->desc->fill_buffer(demux) <= 0; @@ -808,7 +815,8 @@ 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_secs = stream->uncached_stream ? demuxer->opts->demuxer_min_secs_cache + : demuxer->opts->demuxer_min_secs, .min_packs = demuxer->opts->demuxer_min_packs, .min_bytes = demuxer->opts->demuxer_min_bytes, }; @@ -1162,6 +1170,24 @@ static int cached_demux_control(struct demux_internal *in, int cmd, void *arg) in->tracks_switched = true; pthread_cond_signal(&in->wakeup); return DEMUXER_CTRL_OK; + case DEMUXER_CTRL_GET_READER_STATE: { + struct demux_ctrl_reader_state *r = arg; + *r = (struct demux_ctrl_reader_state){ + .eof = in->last_eof, + .idle = in->idle, + .ts_range = {MP_NOPTS_VALUE, MP_NOPTS_VALUE}, + }; + for (int n = 0; n < in->d_user->num_streams; n++) { + struct demux_stream *ds = in->d_user->streams[n]->ds; + if (ds->active) { + r->underrun |= !ds->head; + r->ts_range[0] = MP_PTS_MAX(r->ts_range[0], ds->base_ts); + r->ts_range[1] = MP_PTS_MIN(r->ts_range[1], ds->last_ts); + } + } + r->idle &= !r->underrun; + return DEMUXER_CTRL_OK; + } } return DEMUXER_CTRL_DONTKNOW; } diff --git a/demux/demux.h b/demux/demux.h index 92ef461077..d0f70c6f57 100644 --- a/demux/demux.h +++ b/demux/demux.h @@ -54,6 +54,12 @@ enum demux_ctrl { DEMUXER_CTRL_RESYNC, DEMUXER_CTRL_IDENTIFY_PROGRAM, DEMUXER_CTRL_STREAM_CTRL, + DEMUXER_CTRL_GET_READER_STATE, +}; + +struct demux_ctrl_reader_state { + bool eof, underrun, idle; + double ts_range[2]; // start, end }; struct demux_ctrl_stream_ctrl { diff --git a/etc/example.conf b/etc/example.conf index 4efe2c9b77..e335c8ea12 100644 --- a/etc/example.conf +++ b/etc/example.conf @@ -86,7 +86,7 @@ # # Disable the behavior that the player will pause if the cache goes below a # certain fill size. -#cache-pause-below=no +#cache-pause=no # # Read ahead about 5 seconds of audio and video packets. #demuxer-readahead-secs=5.0 diff --git a/options/m_config.c b/options/m_config.c index d8a5cceccb..479c2e952b 100644 --- a/options/m_config.c +++ b/options/m_config.c @@ -974,5 +974,7 @@ static const char *const replaced_opts = "|status-msg#--term-status-msg" "|idx#--index" "|forceidx#--index" + "|cache-pause-below#for 'no', use --no-cache-pause" + "|no-cache-pause-below#--no-cache-pause" "|" ; diff --git a/options/options.c b/options/options.c index 2ff524f522..a77568858d 100644 --- a/options/options.c +++ b/options/options.c @@ -144,9 +144,6 @@ const m_option_t mp_opts[] = { OPT_INTRANGE("cache-seek-min", stream_cache.seek_min, 0, 0, 0x7fffffff), OPT_STRING("cache-file", stream_cache.file, 0), OPT_INTRANGE("cache-file-size", stream_cache.file_max, 0, 0, 0x7fffffff), - OPT_CHOICE_OR_INT("cache-pause-below", stream_cache_pause, 0, 0, 0x7fffffff, - ({"no", 0})), - OPT_INTRANGE("cache-pause-restart", stream_cache_unpause, 0, 0, 0x7fffffff), #if HAVE_DVDREAD || HAVE_DVDNAV OPT_STRING("dvd-device", dvd_device, 0), @@ -220,6 +217,9 @@ const m_option_t mp_opts[] = { 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), + OPT_DOUBLE("cache-secs", demuxer_min_secs_cache, M_OPT_MIN, .min = 0), + OPT_FLAG("cache-pause", cache_pausing, 0), + OPT_DOUBLE("mf-fps", mf_fps, 0), OPT_STRING("mf-type", mf_type, 0), #if HAVE_TV @@ -598,13 +598,13 @@ const struct MPOpts mp_default_opts = { .seek_min = 500, .file_max = 1024 * 1024, }, - .stream_cache_pause = 50, - .stream_cache_unpause = 100, .demuxer_thread = 1, .demuxer_min_packs = 0, .demuxer_min_bytes = 0, .demuxer_min_secs = 0.2, .network_rtsp_transport = 2, + .demuxer_min_secs_cache = 10, + .cache_pausing = 1, .chapterrange = {-1, -1}, .edition_id = -1, .default_max_pts_correction = -1, diff --git a/options/options.h b/options/options.h index e5436383ad..4468d2abbd 100644 --- a/options/options.h +++ b/options/options.h @@ -123,8 +123,6 @@ typedef struct MPOpts { int use_filedir_conf; int network_rtsp_transport; struct mp_cache_opts stream_cache; - int stream_cache_pause; - int stream_cache_unpause; int chapterrange[2]; int edition_id; int correct_pts; @@ -189,6 +187,9 @@ typedef struct MPOpts { char *sub_demuxer_name; int mkv_subtitle_preroll; + double demuxer_min_secs_cache; + int cache_pausing; + struct image_writer_opts *screenshot_image_opts; char *screenshot_template; diff --git a/player/playloop.c b/player/playloop.c index c96f53471d..026e4fda83 100644 --- a/player/playloop.c +++ b/player/playloop.c @@ -520,32 +520,44 @@ static void handle_pause_on_low_cache(struct MPContext *mpctx) struct MPOpts *opts = mpctx->opts; if (!mpctx->demuxer) return; - int64_t fill = -1; - demux_stream_control(mpctx->demuxer, STREAM_CTRL_GET_CACHE_FILL, &fill); - int cache_kb = fill > 0 ? (fill + 1023) / 1024 : -1; - bool idle = mp_get_cache_idle(mpctx); - if (mpctx->paused && mpctx->paused_for_cache) { - if (cache_kb < 0 || cache_kb >= opts->stream_cache_unpause || idle) { - mpctx->paused_for_cache = false; - if (!opts->pause) - unpause_player(mpctx); - } - mpctx->sleeptime = MPMIN(mpctx->sleeptime, 0.2); - } else { - if (cache_kb >= 0 && cache_kb <= opts->stream_cache_pause && !idle && - opts->stream_cache_pause < opts->stream_cache_unpause) - { - bool prev_paused_user = opts->pause; - pause_player(mpctx); - mpctx->paused_for_cache = true; - opts->pause = prev_paused_user; + + struct demux_ctrl_reader_state s = + {.idle = true, .ts_range = {MP_NOPTS_VALUE, MP_NOPTS_VALUE}}; + demux_control(mpctx->demuxer, DEMUXER_CTRL_GET_READER_STATE, &s); + + double range = -1; + if (s.ts_range[0] != MP_NOPTS_VALUE && s.ts_range[1] != MP_NOPTS_VALUE) + range = s.ts_range[1] - s.ts_range[0]; + if (range < 0) + range = 1e20; // unknown/broken timestamps; disable + + if (mpctx->restart_complete) { + if (mpctx->paused && mpctx->paused_for_cache) { + if (!opts->cache_pausing || range >= 2.0 || s.eof) { + mpctx->paused_for_cache = false; + if (!opts->pause) + unpause_player(mpctx); + } + mpctx->sleeptime = MPMIN(mpctx->sleeptime, 0.2); + } else { + if (opts->cache_pausing && range < 0.5 && !s.eof) { + bool prev_paused_user = opts->pause; + pause_player(mpctx); + mpctx->paused_for_cache = true; + opts->pause = prev_paused_user; + } } } + + int idle = 1; + demux_stream_control(mpctx->demuxer, STREAM_CTRL_GET_CACHE_IDLE, &idle); + // Also update cache properties. - if (cache_kb > 0 || mpctx->next_cache_update > 0) { + bool busy = idle == 0 || !s.idle; + if (busy || mpctx->next_cache_update > 0) { double now = mp_time_sec(); if (mpctx->next_cache_update <= now) { - mpctx->next_cache_update = cache_kb > 0 ? now + 0.25 : 0; + mpctx->next_cache_update = busy ? now + 0.25 : 0; mp_notify(mpctx, MP_EVENT_CACHE_UPDATE, NULL); } if (mpctx->next_cache_update > 0) { diff --git a/stream/stream.c b/stream/stream.c index d600088267..7b8050dec0 100644 --- a/stream/stream.c +++ b/stream/stream.c @@ -782,6 +782,7 @@ static stream_t *open_cache(stream_t *orig, const char *name) cache->demuxer = talloc_strdup(cache, orig->demuxer); cache->lavf_type = talloc_strdup(cache, orig->lavf_type); cache->safe_origin = orig->safe_origin; + cache->streaming = orig->streaming, cache->opts = orig->opts; cache->global = orig->global; |