diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index d7db0106b4..f02f6588ff 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -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 --- diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index 39416d2a64..0301e6971d 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -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=`` + 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=`` 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 diff --git a/options/options.c b/options/options.c index 9e3e70385e..1a8ecaca2f 100644 --- a/options/options.c +++ b/options/options.c @@ -25,6 +25,7 @@ #include #include #include +#include #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, }, diff --git a/options/options.h b/options/options.h index 4de4a831bb..263caaa8de 100644 --- a/options/options.h +++ b/options/options.h @@ -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]; diff --git a/player/video.c b/player/video.c index e18f8cba70..23f8eefa33 100644 --- a/player/video.c +++ b/player/video.c @@ -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; }