diff options
-rw-r--r-- | DOCS/man/en/input.rst | 4 | ||||
-rw-r--r-- | DOCS/man/en/mpv.rst | 4 | ||||
-rw-r--r-- | DOCS/man/en/options.rst | 13 | ||||
-rw-r--r-- | core/cfg-mplayer.h | 3 | ||||
-rw-r--r-- | core/command.c | 6 | ||||
-rw-r--r-- | core/defaultopts.c | 1 | ||||
-rw-r--r-- | core/input/input.c | 1 | ||||
-rw-r--r-- | core/input/input.h | 1 | ||||
-rw-r--r-- | core/mp_core.h | 1 | ||||
-rw-r--r-- | core/mplayer.c | 125 | ||||
-rw-r--r-- | core/options.h | 2 | ||||
-rw-r--r-- | core/path.c | 14 | ||||
-rw-r--r-- | core/path.h | 2 | ||||
-rw-r--r-- | etc/input.conf | 1 |
14 files changed, 177 insertions, 1 deletions
diff --git a/DOCS/man/en/input.rst b/DOCS/man/en/input.rst index 7938502573..6d1072353f 100644 --- a/DOCS/man/en/input.rst +++ b/DOCS/man/en/input.rst @@ -169,6 +169,10 @@ run "<command>" quit [<code>] Exit the player using the given exit code. +quit_watch_later + Exit player, and store current playback position. Playing that file later + will seek to the previous position on start. + sub_add "<file>" Load the given subtitle file. It's not selected as current subtitle after loading. diff --git a/DOCS/man/en/mpv.rst b/DOCS/man/en/mpv.rst index 9a62333983..2ebdcab506 100644 --- a/DOCS/man/en/mpv.rst +++ b/DOCS/man/en/mpv.rst @@ -90,6 +90,10 @@ p / SPACE q / ESC Stop playing and quit. +Q + Like ``q``, but store the current playback position. Playing the same file + later will resume at the old playback position if possible. + U Stop playing (and quit if ``--idle`` is not used). diff --git a/DOCS/man/en/options.rst b/DOCS/man/en/options.rst index 766c3ae562..3a98ca9c93 100644 --- a/DOCS/man/en/options.rst +++ b/DOCS/man/en/options.rst @@ -1329,6 +1329,10 @@ Do not play sound. With some demuxers this may not work. In those cases you can try ``--ao=null`` instead. +--no-resume-playback + Do not restore playback position from ``~/.mpv/watch_later/``. + See ``quit_watch_later`` input command. + --no-sub Disables display of internal and external subtitles. @@ -1791,6 +1795,15 @@ grayscale output with this option. Not supported by all video output drivers. +--save-position-on-quit + Always save the current playback position on quit. When this file is + played again later, the player will seek to the old playback position on + start. This affects any form of stopping playback (quitting, going to the + next file). + + This behavior is disabled by default, but is always available when quitting + the player with Shift+Q. + --sb=<n> Seek to byte position. Useful for playback from CD-ROM images or VOB files with junk at the beginning. See also ``--start``. diff --git a/core/cfg-mplayer.h b/core/cfg-mplayer.h index 570c403f9c..f2e90d07d2 100644 --- a/core/cfg-mplayer.h +++ b/core/cfg-mplayer.h @@ -650,6 +650,9 @@ const m_option_t mplayer_opts[]={ {"{", NULL, CONF_TYPE_STORE, CONF_NOCFG, 0, 0, NULL}, {"}", NULL, CONF_TYPE_STORE, CONF_NOCFG, 0, 0, NULL}, + OPT_FLAG("resume-playback", position_resume, 0), + OPT_FLAG("save-position-on-quit", position_save_on_quit, 0), + OPT_FLAG("ordered-chapters", ordered_chapters, 0), OPT_INTRANGE("chapter-merge-threshold", chapter_merge_threshold, 0, 0, 10000), diff --git a/core/command.c b/core/command.c index 4831c939c0..72d6f34469 100644 --- a/core/command.c +++ b/core/command.c @@ -1856,6 +1856,12 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd) mpctx->quit_player_rc = cmd->args[0].v.i; break; + case MP_CMD_QUIT_WATCH_LATER: + mp_write_watch_later_conf(mpctx); + mpctx->stop_play = PT_QUIT; + mpctx->quit_player_rc = 0; + break; + case MP_CMD_PLAYLIST_NEXT: case MP_CMD_PLAYLIST_PREV: { diff --git a/core/defaultopts.c b/core/defaultopts.c index 03d697d732..b80bea5c1e 100644 --- a/core/defaultopts.c +++ b/core/defaultopts.c @@ -52,6 +52,7 @@ void set_default_mplayer_options(struct MPOpts *opts) .ordered_chapters = 1, .chapter_merge_threshold = 100, .load_config = 1, + .position_resume = 1, .stream_cache_min_percent = 20.0, .stream_cache_seek_min_percent = 50.0, .stream_cache_pause = 10.0, diff --git a/core/input/input.c b/core/input/input.c index 31b807d92f..7ba6b64cdc 100644 --- a/core/input/input.c +++ b/core/input/input.c @@ -126,6 +126,7 @@ static const mp_cmd_t mp_cmds[] = { }}, { MP_CMD_SPEED_MULT, "speed_mult", { ARG_FLOAT } }, { MP_CMD_QUIT, "quit", { OARG_INT(0) } }, + { MP_CMD_QUIT_WATCH_LATER, "quit_watch_later", }, { MP_CMD_STOP, "stop", }, { MP_CMD_FRAME_STEP, "frame_step", }, { MP_CMD_FRAME_BACK_STEP, "frame_back_step", }, diff --git a/core/input/input.h b/core/input/input.h index ff79222c9b..367abedfca 100644 --- a/core/input/input.h +++ b/core/input/input.h @@ -28,6 +28,7 @@ enum mp_command_type { MP_CMD_IGNORE, MP_CMD_SEEK, MP_CMD_QUIT, + MP_CMD_QUIT_WATCH_LATER, MP_CMD_PLAYLIST_NEXT, MP_CMD_PLAYLIST_PREV, MP_CMD_OSD, diff --git a/core/mp_core.h b/core/mp_core.h index 9588a77b24..2590eefb96 100644 --- a/core/mp_core.h +++ b/core/mp_core.h @@ -321,6 +321,7 @@ struct track *mp_track_by_tid(struct MPContext *mpctx, enum stream_type type, bool mp_remove_track(struct MPContext *mpctx, struct track *track); struct playlist_entry *mp_next_file(struct MPContext *mpctx, int direction); int mp_get_cache_percent(struct MPContext *mpctx); +void mp_write_watch_later_conf(struct MPContext *mpctx); // timeline/tl_matroska.c void build_ordered_chapter_timeline(struct MPContext *mpctx); diff --git a/core/mplayer.c b/core/mplayer.c index 9028cbafce..a6cc189df6 100644 --- a/core/mplayer.c +++ b/core/mplayer.c @@ -21,6 +21,7 @@ #include <stdbool.h> #include <math.h> #include <assert.h> +#include <ctype.h> #ifdef PTW32_STATIC_LIB #include <pthread.h> @@ -28,6 +29,7 @@ #include <libavutil/intreadwrite.h> #include <libavutil/attributes.h> +#include <libavutil/md5.h> #include <libavcodec/version.h> @@ -763,6 +765,121 @@ static void load_per_file_config(m_config_t *conf, const char * const file, } } +static bool might_be_an_url(bstr f) +{ + return bstr_find0(f, "://") >= 0; +} + +#define MP_WATCH_LATER_CONF "watch_later" + +static char *get_playback_resume_config_filename(const char *fname) +{ + char *res = NULL; + void *tmp = talloc_new(NULL); + const char *realpath = fname; + if (!might_be_an_url(bstr0(fname))) { + char *cwd = mp_getcwd(tmp); + if (!cwd) + goto exit; + realpath = mp_path_join(tmp, bstr0(cwd), bstr0(fname)); + } + uint8_t md5[16]; + av_md5_sum(md5, realpath, strlen(realpath)); + char *conf = talloc_strdup(tmp, ""); + for (int i = 0; i < 16; i++) + conf = talloc_asprintf_append(conf, "%02X", md5[i]); + + conf = talloc_asprintf(tmp, "%s/%s", MP_WATCH_LATER_CONF, conf); + + res = mp_find_user_config_file(conf); + +exit: + talloc_free(tmp); + return res; +} + +static const char *backup_properties[] = { + "osd-level", + //"loop", + "speed", + "edition", + "pause", + //"volume", + //"mute", + "audio-delay", + //"balance", + "fullscreen", + "colormatrix", + "colormatrix-input-range", + "colormatrix-output-range", + "ontop", + "border", + "gamma", + "brightness", + "contrast", + "saturation", + "hue", + "panscan", + "aid", + "vid", + "sid", + "sub-delay", + "sub-pos", + //"sub-visibility", + "sub-scale", + "ass-use-margins", + "ass-vsfilter-aspect-compat", + "ass-style-override", + 0 +}; + +void mp_write_watch_later_conf(struct MPContext *mpctx) +{ + void *tmp = talloc_new(NULL); + char *filename = mpctx->filename; + if (!filename) + goto exit; + + double pos = get_current_time(mpctx); + int percent = get_percent_pos(mpctx); + if (percent < 1 || percent > 99 || pos == MP_NOPTS_VALUE) + goto exit; + + mk_config_dir(MP_WATCH_LATER_CONF); + + char *conffile = get_playback_resume_config_filename(mpctx->filename); + talloc_steal(tmp, conffile); + if (!conffile) + goto exit; + + FILE *file = fopen(conffile, "wb"); + if (!file) + goto exit; + fprintf(file, "start=%f\n", pos); + for (int i = 0; backup_properties[i]; i++) { + const char *pname = backup_properties[i]; + char *tmp = NULL; + int r = mp_property_do(pname, M_PROPERTY_GET_STRING, &tmp, mpctx); + if (r == M_PROPERTY_OK) + fprintf(file, "%s=%s\n", pname, tmp); + talloc_free(tmp); + } + fclose(file); + +exit: + talloc_free(tmp); +} + +static void load_playback_resume(m_config_t *conf, const char *file) +{ + char *fname = get_playback_resume_config_filename(file); + if (fname) { + try_load_config(conf, fname); + unlink(fname); + } + talloc_free(fname); +} + static void load_per_file_options(m_config_t *conf, struct playlist_param *params, int params_count) @@ -3988,7 +4105,9 @@ static void play_current_file(struct MPContext *mpctx) load_per_output_config(mpctx->mconfig, PROFILE_CFG_AO, opts->audio_driver_list[0]); - assert(mpctx->playlist->current); + if (opts->position_resume) + load_playback_resume(mpctx->mconfig, mpctx->filename); + load_per_file_options(mpctx->mconfig, mpctx->playlist->current->params, mpctx->playlist->current->num_params); @@ -4283,6 +4402,9 @@ goto_enable_cache: ; terminate_playback: // don't jump here after ao/vo/getch initialization! + if (opts->position_save_on_quit && mpctx->stop_play != PT_RESTART) + mp_write_watch_later_conf(mpctx); + if (mpctx->step_frames) opts->pause = 1; @@ -4566,6 +4688,7 @@ int main(int argc, char *argv[]) init_input(mpctx); mpctx->playlist->current = mpctx->playlist->first; + play_files(mpctx); exit_player(mpctx, mpctx->stop_play == PT_QUIT ? EXIT_QUIT : EXIT_EOF, diff --git a/core/options.h b/core/options.h index 4729d7ca6a..276745492d 100644 --- a/core/options.h +++ b/core/options.h @@ -125,6 +125,8 @@ typedef struct MPOpts { int play_frames; double step_sec; int64_t seek_to_byte; + int position_resume; + int position_save_on_quit; int pause; int keep_open; int audio_id; diff --git a/core/path.c b/core/path.c index ed53d5d465..e373df21ab 100644 --- a/core/path.c +++ b/core/path.c @@ -31,6 +31,7 @@ #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> +#include <errno.h> #include "config.h" #include "core/mp_msg.h" #include "core/path.h" @@ -178,6 +179,19 @@ char *mp_path_join(void *talloc_ctx, struct bstr p1, struct bstr p2) have_separator ? "" : "/", BSTR_P(p2)); } +char *mp_getcwd(void *talloc_ctx) +{ + char *wd = talloc_array(talloc_ctx, char, 20); + while (getcwd(wd, talloc_get_size(wd)) == NULL) { + if (errno != ERANGE) { + talloc_free(wd); + return NULL; + } + wd = talloc_realloc(talloc_ctx, wd, char, talloc_get_size(wd) * 2); + } + return wd; +} + bool mp_path_exists(const char *path) { struct stat st; diff --git a/core/path.h b/core/path.h index 3711be44b9..a3033199df 100644 --- a/core/path.h +++ b/core/path.h @@ -51,6 +51,8 @@ struct bstr mp_dirname(const char *path); */ char *mp_path_join(void *talloc_ctx, struct bstr p1, struct bstr p2); +char *mp_getcwd(void *talloc_ctx); + bool mp_path_exists(const char *path); bool mp_path_isdir(const char *path); diff --git a/etc/input.conf b/etc/input.conf index 300f20c307..5dbb7c8a06 100644 --- a/etc/input.conf +++ b/etc/input.conf @@ -56,6 +56,7 @@ PGDWN seek -600 } speed_mult 2.0 BS set speed 1.0 # reset speed to normal q quit +Q quit_watch_later q {encode} quit ESC quit p cycle pause # toggle pause/playback mode |