0
0
mirror of https://github.com/mpv-player/mpv.git synced 2024-09-20 03:52:22 +02:00

core: automatically pause on low cache

When the cache fill status goes below a certain threshold, automatically
pause the player. When the cache is filled again, unpause again.

This is intended to help with streaming from http. It's better to pause
a while, rather than exposing extremely crappy behavior when packet
reads during decoding block the entire player.

In theory, we should try to increase the cache if underruns happen too
often. Unfortunately, changing the cache implementation would be very
hard, because it's insane code (forks, uses shared memory and "volatile"
etc.). So for now, this just reduces the frequency of the stuttering if
the network is absolutely too slow to play the stream in realtime.
This commit is contained in:
wm4 2012-12-02 00:22:54 +01:00
parent c02f252938
commit 3486f59fe2
8 changed files with 66 additions and 5 deletions

View File

@ -261,9 +261,18 @@
from slow media, but can also have negative effects, especially with file
formats that require a lot of seeking, such as mp4. See also ``--no-cache``.
--cache-pause=<no|percentage>
If the cache percentage goes below the specified value, pause and wait
until the percentage set by ``--cache-min`` is reached, then resume
playback (default: 10). 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-min=<percentage>
Playback will start when the cache has been filled up to <percentage> of
the total.
the total (default: 20).
--cache-seek-min=<percentage>
If a seek is to be made to a position within <percentage> of the cache

View File

@ -329,6 +329,8 @@ const m_option_t common_opts[] = {
OPT_FLOATRANGE("cache-min", stream_cache_min_percent, 0, 0, 99),
OPT_FLOATRANGE("cache-seek-min", stream_cache_seek_min_percent, 0, 0, 99),
OPT_CHOICE_OR_INT("cache-pause", stream_cache_pause, 0,
0, 40, ({"no", -1})),
#endif /* CONFIG_STREAM_CACHE */
{"cdrom-device", &cdrom_device, CONF_TYPE_STRING, 0, 0, 0, NULL},
#ifdef CONFIG_DVDREAD

View File

@ -32,6 +32,7 @@ void set_default_mplayer_options(struct MPOpts *opts)
.chapter_merge_threshold = 100,
.stream_cache_min_percent = 20.0,
.stream_cache_seek_min_percent = 50.0,
.stream_cache_pause = 10.0,
.chapterrange = {-1, -1},
.edition_id = -1,
.user_correct_pts = -1,

View File

@ -257,6 +257,8 @@ typedef struct MPContext {
// step this many frames, then pause
int step_frames;
bool paused_for_cache;
// Set after showing warning about decoding being too slow for realtime
// playback rate. Used to avoid showing it multiple times.
bool drop_message_shown;

View File

@ -1051,6 +1051,14 @@ static int get_cache_percent(struct MPContext *mpctx)
return -1;
}
static bool get_cache_idle(struct MPContext *mpctx)
{
int idle = 0;
if (mpctx->stream)
stream_control(mpctx->stream, STREAM_CTRL_GET_CACHE_IDLE, &idle);
return idle;
}
/**
* \brief append a formatted string
* \param buf buffer to print into
@ -1131,8 +1139,12 @@ static void print_status(struct MPContext *mpctx)
line[0] = '\0';
// Playback status
if (mpctx->paused)
if (mpctx->paused_for_cache) {
saddf(line, width, "(Buffering) ");
} else if (mpctx->paused) {
saddf(line, width, "(Paused) ");
}
if (mpctx->sh_audio)
saddf(line, width, "A");
if (mpctx->sh_video)
@ -1458,8 +1470,15 @@ static void sadd_osd_status(char *buffer, int len, struct MPContext *mpctx,
{
bool fractions = mpctx->opts.osd_fractions;
int sym = mpctx->osd_function;
if (!sym)
sym = mpctx->paused || mpctx->step_frames ? OSD_PAUSE : OSD_PLAY;
if (!sym) {
if (mpctx->paused_for_cache) {
sym = OSD_CLOCK;
} else if (mpctx->paused || mpctx->step_frames) {
sym = OSD_PAUSE;
} else {
sym = OSD_PLAY;
}
}
saddf_osd_function_sym(buffer, len, sym);
sadd_hhmmssff(buffer, len, get_current_time(mpctx), fractions);
if (full) {
@ -2579,6 +2598,7 @@ void unpause_player(struct MPContext *mpctx)
return;
mpctx->paused = 0;
mpctx->osd_function = 0;
mpctx->paused_for_cache = false;
if (mpctx->ao && mpctx->sh_audio)
ao_resume(mpctx->ao);
@ -3070,6 +3090,22 @@ static void update_avsync(struct MPContext *mpctx)
}
}
static void handle_pause_on_low_cache(struct MPContext *mpctx)
{
struct MPOpts *opts = &mpctx->opts;
int cache = get_cache_percent(mpctx);
bool idle = get_cache_idle(mpctx);
if (mpctx->paused && mpctx->paused_for_cache) {
if (cache < 0 || cache >= opts->stream_cache_min_percent || idle)
unpause_player(mpctx);
} else if (!mpctx->paused) {
if (cache >= 0 && cache <= opts->stream_cache_pause && !idle) {
pause_player(mpctx);
mpctx->paused_for_cache = true;
}
}
}
static void run_playloop(struct MPContext *mpctx)
{
struct MPOpts *opts = &mpctx->opts;
@ -3390,6 +3426,8 @@ static void run_playloop(struct MPContext *mpctx)
//================= Keyboard events, SEEKing ====================
handle_pause_on_low_cache(mpctx);
mp_cmd_t *cmd;
while ((cmd = mp_input_get_cmd(mpctx->input, 0, 1)) != NULL) {
/* Allow running consecutive seek commands to combine them,

View File

@ -55,6 +55,7 @@ typedef struct MPOpts {
int stream_cache_size;
float stream_cache_min_percent;
float stream_cache_seek_min_percent;
int stream_cache_pause;
int chapterrange[2];
int edition_id;
int correct_pts;

View File

@ -93,6 +93,7 @@ typedef struct {
volatile int control_res;
volatile double stream_time_length;
volatile double stream_time_pos;
volatile int idle;
} cache_vars_t;
static void cache_wakeup(stream_t *s)
@ -420,6 +421,7 @@ static void cache_mainloop(cache_vars_t *s) {
#endif
do {
if (!cache_fill(s)) {
s->idle = 1;
#if FORKED_CACHE
// Let signal wake us up, we cannot leave this
// enabled since we do not handle EINTR in most places.
@ -436,8 +438,10 @@ static void cache_mainloop(cache_vars_t *s) {
sa.sa_handler = SIG_IGN;
sigaction(SIGUSR1, &sa, NULL);
#endif
} else
} else {
sleep_count = 0;
s->idle = 0;
}
} while (cache_execute_control(s));
}
@ -624,6 +628,9 @@ int cache_do_control(stream_t *stream, int cmd, void *arg) {
case STREAM_CTRL_GET_CACHE_FILL:
*(int64_t *)arg = s->max_filepos - s->read_filepos;
return STREAM_OK;
case STREAM_CTRL_GET_CACHE_IDLE:
*(int *)arg = s->idle;
return STREAM_OK;
case STREAM_CTRL_SEEK_TO_TIME:
s->control_double_arg = *(double *)arg;
s->control = cmd;

View File

@ -100,6 +100,7 @@
#define STREAM_CTRL_GET_CURRENT_TITLE 14
#define STREAM_CTRL_GET_CACHE_SIZE 15
#define STREAM_CTRL_GET_CACHE_FILL 16
#define STREAM_CTRL_GET_CACHE_IDLE 17
struct stream_lang_req {
int type; // STREAM_AUDIO, STREAM_SUB