player: add option to control duration of image display

The --image-display-duration option controls how long an image is
displayed. It's also possible to display the image forever (until manual
user interaction stops playback).

With this, the core drops the old method to "drain" video (i.e. waiting
for the last frame duration on end of playback). Instead, we reuse
MPContext.time_frame. The old mechanism was disabled for non-images
anyway.

Fixes #3425.
This commit is contained in:
wm4 2016-08-17 22:45:44 +02:00
parent 07f8b64754
commit f5bbb5aed2
5 changed files with 48 additions and 12 deletions

View File

@ -19,6 +19,10 @@ Interface changes
::
--- mpv 0.20.0 ---
- add --image-display-duration option - this also means that image duration
is not influenced by --mf-fps anymore in the general case (this is an
incompatible change)
--- mpv 0.19.0 ---
- deprecate "balance" option/property (no replacement)
--- mpv 0.18.1 ---

View File

@ -1873,6 +1873,23 @@ Window
file.mkv normally, then fail to open ``/dev/null``, then exit). (In
mpv 0.8.0, ``always`` was introduced, which restores the old behavior.)
``--image-display-duration=<seconds|inf>``
If the current file is an image, play the image for the given amount of
seconds (default: 1). ``inf`` means the file is kept open forever (until
the user stops playback manually).
Unlike ``--keep-open``, the player is not paused, but simply continues
playback until the time has elapsed. (It should not use any resources
during "playback".)
This affects image files, which are defined as having only 1 video frame
and no audio. The player may recognize certain non-images as images, for
example if ``--length`` is used to reduce the length to 1 frame, or if
you seek to the last frame.
This option does not affect the framerate used for ``mf://`` or
``--merge-files``. For that, use ``--mf-fps`` instead.
``--force-window=<yes|no|immediate>``
Create a video output window even if there is no video. This can be useful
when pretending that mpv is a GUI application. Currently, the window

View File

@ -25,6 +25,7 @@
#include <stddef.h>
#include <sys/types.h>
#include <limits.h>
#include <math.h>
#include "config.h"
@ -214,6 +215,8 @@ const m_option_t mp_opts[] = {
({"no", 0},
{"yes", 1},
{"always", 2})),
OPT_DOUBLE("image-display-duration", image_display_duration,
M_OPT_RANGE, 0, INFINITY),
OPT_CHOICE("index", index_mode, 0, ({"default", 1}, {"recreate", 0})),
@ -796,6 +799,7 @@ const struct MPOpts mp_default_opts = {
.play_frames = -1,
.rebase_start_time = 1,
.keep_open = 0,
.image_display_duration = 1.0,
.stream_id = { { [STREAM_AUDIO] = -1,
[STREAM_VIDEO] = -1,
[STREAM_SUB] = -1, },

View File

@ -190,6 +190,7 @@ typedef struct MPOpts {
int ignore_path_in_watch_later_config;
int pause;
int keep_open;
double image_display_duration;
char *lavfi_complex;
int stream_id[2][STREAM_TYPE_COUNT];
int stream_id_ff[STREAM_TYPE_COUNT];

View File

@ -1283,10 +1283,6 @@ static void calculate_frame_duration(struct MPContext *mpctx)
double pts1 = mpctx->next_frames[1]->pts;
if (pts0 != MP_NOPTS_VALUE && pts1 != MP_NOPTS_VALUE && pts1 >= pts0)
duration = pts1 - pts0;
} else {
// E.g. last frame on EOF. Only use it if it's significant.
if (demux_duration >= 0.1)
duration = demux_duration;
}
// The following code tries to compensate for rounded Matroska timestamps
@ -1350,17 +1346,31 @@ void write_video(struct MPContext *mpctx)
return;
if (r == VD_EOF) {
int prev_state = mpctx->video_status;
mpctx->video_status = STATUS_EOF;
if (mpctx->num_past_frames > 0 && mpctx->past_frames[0].duration > 0) {
if (vo_still_displaying(vo))
mpctx->video_status = STATUS_DRAINING;
}
mpctx->delay = 0;
mpctx->last_av_difference = 0;
if (mpctx->video_status <= STATUS_PLAYING) {
mpctx->video_status = STATUS_DRAINING;
get_relative_time(mpctx);
if (mpctx->num_past_frames == 1 && mpctx->past_frames[0].pts == 0 &&
!mpctx->ao_chain)
{
mpctx->time_frame += opts->image_display_duration;
} else {
mpctx->time_frame = 0;
}
}
if (mpctx->video_status == STATUS_DRAINING) {
mpctx->time_frame -= get_relative_time(mpctx);
mpctx->sleeptime = MPMIN(mpctx->sleeptime, mpctx->time_frame);
if (mpctx->time_frame <= 0) {
MP_VERBOSE(mpctx, "video EOF reached\n");
mpctx->video_status = STATUS_EOF;
}
}
MP_DBG(mpctx, "video EOF (status=%d)\n", mpctx->video_status);
if (prev_state != mpctx->video_status)
mpctx->sleeptime = 0;
return;
}