summaryrefslogtreecommitdiffstats
path: root/core/mplayer.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-05-05 19:37:29 +0200
committerwm4 <wm4@nowhere>2013-05-05 20:08:11 +0200
commitce9a854d54900d050cf1efcf26081d875223e448 (patch)
treeb3a50d4df4f88c28f6d36084edee2778de46979b /core/mplayer.c
parent38ce91170456913c9d7c4604615a5cca62c846bb (diff)
downloadmpv-ce9a854d54900d050cf1efcf26081d875223e448.tar.bz2
mpv-ce9a854d54900d050cf1efcf26081d875223e448.tar.xz
core: add playback resume feature (manual/opt-in)
A "watch later" command is now mapped to Shift+Q. This quits the player and stores the playback state in a config file in ~/.mpv/watch_later/. When calling the player with the same file again, playback is resumed at that time position. It's also possible to make mpv save playback state always on quit with the --save-position-on-quit option. Likewise, resuming can be disabled with the --no-resume-playback option. This also attempts to save some playback parameters, like fullscreen state or track selection. This will unconditionally override config settings and command line options (which is probably not what you would expect, but in general nobody will really care about this). Some things are not backed up, because that would cause various problems. Additional subtitle files, video filters, etc. are not stored because that would be too hard and fragile. Volume/mute state are not stored because it would mess up if the system mixer is used, or if the system mixer was readjusted in the meantime. Basically, the tradeoff between perfect state restoration and complexity/fragility makes it not worth to attempt to implement it perfectly, even if the result is a little bit inconsistent.
Diffstat (limited to 'core/mplayer.c')
-rw-r--r--core/mplayer.c125
1 files changed, 124 insertions, 1 deletions
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,