core: add --keep-open, which doesn't close the file on EOF

The --keep-open option causes mpv not to close the current file.
Instead, it will pause, and allow the user to seek around. When
seeking beyond the end of the file, mpv does a precise seek back to
the previous last known position that produced video output.

In some corner cases, mpv might not be able to produce video output at
all, despite having created a VO. (Possibly when only 1 frame could be
decoded, but the video filter chain queues frames. Then a VO would be
created, without sending an actual video frame to the VO.) In these
cases, the VO window will not redraw, not even OSD.

Based on a patch by coax [1].

[1] http://devel.mplayer2.org/ticket/210#comment:4
This commit is contained in:
wm4 2012-11-13 00:56:20 +01:00
parent b7052b431c
commit f1175cd905
6 changed files with 31 additions and 1 deletions

View File

@ -877,6 +877,17 @@
disable the window manager hints that force the window aspect ratio.
(Ignored in fullscreen mode.)
--keep-open
Do not terminate when playing or seeking beyond the end of the file.
Instead, pause the player. When trying to seek beyond end of the file, the
player will pause at an arbitrary playback position (or, in corner cases,
not redraw the window at all).
*NOTE*: this option is not respected when using ``--frames``, ``--end``,
``--length``, or when passing a chapter range to ``--chapter``. Explicitly
skipping to the next file or skipping beyond the last chapter will terminate
playback as well, even if ``--keep-open`` is given.
--key-fifo-size=<2-65000>
Specify the size of the FIFO that buffers key events (default: 7). If it
is too small some events may be lost. The main disadvantage of setting it

View File

@ -380,8 +380,8 @@ const m_option_t common_opts[] = {
OPT_REL_TIME("end", play_end, 0),
OPT_REL_TIME("length", play_length, 0),
// start paused
OPT_FLAG_ON("pause", start_paused, 0),
OPT_FLAG_ON("keep-open", keep_open, 0),
// AVI specific: force non-interleaved mode
{"avi-ni", &force_ni, CONF_TYPE_FLAG, 0, 0, 1, NULL},

View File

@ -39,6 +39,7 @@ void set_default_mplayer_options(struct MPOpts *opts)
.term_osd = 2,
.consolecontrols = 1,
.doubleclick_time = 300,
.keep_open = 0,
.audio_id = -1,
.video_id = -1,
.sub_id = -1,

View File

@ -215,6 +215,9 @@ typedef struct MPContext {
* (or at least queued to be flipped by VO) */
double video_pts;
double last_seek_pts;
// As video_pts, but is not reset when seeking away. (For the very short
// period of time until a new frame is decoded and shown.)
double last_vo_pts;
// used to prevent hanging in some error cases
unsigned int start_timestamp;

View File

@ -3183,6 +3183,7 @@ static void run_playloop(struct MPContext *mpctx)
vo_new_frame_imminent(vo);
struct sh_video *sh_video = mpctx->sh_video;
mpctx->video_pts = sh_video->pts;
mpctx->last_vo_pts = mpctx->video_pts;
update_subtitles(mpctx, sh_video->pts);
update_osd_msg(mpctx);
draw_osd(mpctx);
@ -3369,6 +3370,18 @@ static void run_playloop(struct MPContext *mpctx)
queue_seek(mpctx, MPSEEK_RELATIVE, step_sec, 0);
}
if (opts->keep_open && mpctx->stop_play == AT_END_OF_FILE) {
mpctx->stop_play = KEEP_PLAYING;
pause_player(mpctx);
if (mpctx->video_out && !mpctx->video_out->hasframe) {
// Force screen refresh to make OSD usable
double seek_to = mpctx->last_vo_pts;
if (seek_to == MP_NOPTS_VALUE)
seek_to = 0; // arbitrary default
queue_seek(mpctx, MPSEEK_ABSOLUTE, seek_to, 1);
}
}
/* Looping. */
if (opts->loop_times >= 0 && (mpctx->stop_play == AT_END_OF_FILE ||
mpctx->stop_play == PT_NEXT_ENTRY)) {
@ -4019,6 +4032,7 @@ goto_enable_cache:
mpctx->drop_message_shown = 0;
mpctx->restart_playback = true;
mpctx->video_pts = 0;
mpctx->last_vo_pts = MP_NOPTS_VALUE;
mpctx->last_seek_pts = 0;
mpctx->hrseek_active = false;
mpctx->hrseek_framedrop = false;

View File

@ -77,6 +77,7 @@ typedef struct MPOpts {
struct m_rel_time play_end;
struct m_rel_time play_length;
int start_paused;
int keep_open;
int audio_id;
int video_id;
int sub_id;