diff options
-rw-r--r-- | DOCS/man/en/changes.rst | 2 | ||||
-rw-r--r-- | DOCS/man/en/options.rst | 43 | ||||
-rw-r--r-- | core/cfg-mplayer.h | 7 | ||||
-rw-r--r-- | core/m_option.c | 63 | ||||
-rw-r--r-- | core/m_option.h | 22 | ||||
-rw-r--r-- | core/mplayer.c | 68 | ||||
-rw-r--r-- | core/options.h | 6 | ||||
-rw-r--r-- | core/playlist_parser.c | 2 |
8 files changed, 122 insertions, 91 deletions
diff --git a/DOCS/man/en/changes.rst b/DOCS/man/en/changes.rst index 71d788a044..53d9179e6d 100644 --- a/DOCS/man/en/changes.rst +++ b/DOCS/man/en/changes.rst @@ -105,6 +105,8 @@ Command line switches -ni --avi-ni -benchmark --untimed (no stats) -xineramascreen --screen (different values) + -ss --start + -endpos --length =================================== =================================== input.conf and slave commands diff --git a/DOCS/man/en/options.rst b/DOCS/man/en/options.rst index 6b8041c192..7cc309de02 100644 --- a/DOCS/man/en/options.rst +++ b/DOCS/man/en/options.rst @@ -336,7 +336,7 @@ --chapter=<start[-end]> Specify which chapter to start playing at. Optionally specify which - chapter to end playing at (default: 1). + chapter to end playing at. Also see ``--start``. --chapter-merge-threshold=<number> Threshold for merging almost consecutive ordered chapter parts in @@ -518,20 +518,9 @@ enabled). These fonts can be used for SSA/ASS subtitle rendering (``--ass`` option). ---endpos=<[[hh:]mm:]ss[.ms]> - Stop at given time. - - *NOTE*: When used in conjunction with ``--ss`` option, ``--endpos`` time - will shift forward by seconds specified with ``--ss``. - - *EXAMPLE*: - - ``--endpos=56`` - Stop at 56 seconds. - ``--endpos=01:10:00`` - Stop at 1 hour 10 minutes. - ``--ss=10 --endpos=56`` - Stop at 1 minute 6 seconds. +--end=<relative time> + Stop at given absolute time. See ``--start`` for valid option values and + examples. --no-extbased, --extbased ``--no-extbased`` disables extension-based demuxer selection. By default, when the file type @@ -1057,6 +1046,10 @@ Encryption key the demuxer should use. This is the raw binary data of the key converted to a hexadecimal string. +--length=<relative time> + Stop after a given time relative to the start time. + See ``--start`` for valid option values and examples. + --lirc, --no-lirc Enable/disable LIRC support. Enabled by default. @@ -1515,7 +1508,7 @@ --sb=<n> Seek to byte position. Useful for playback from CD-ROM images or VOB files - with junk at the beginning. See also ``--ss``. + with junk at the beginning. See also ``--start``. --screenshot-format=<type> Set the image file type used for saving screenshots. @@ -1685,15 +1678,27 @@ inserted into the audio filter layer to compensate for the difference. The type of resampling can be controlled by the ``--af-adv`` option. ---ss=<time> +--start=<relative time> Seek to given time position. + The general format for absolute times is ``[[hh:]mm:]ss[.ms]``. If the time + is negated with ``-``, the seek is relative from the end of the file. + + It's also possible to seek to a percent position with ``pp%``. + *EXAMPLE*: - ``--ss=56`` + ``--start=56`` Seeks to 56 seconds. - ``--ss=01:10:00`` + ``--start=01:10:00`` Seeks to 1 hour 10 min. + ``--start=50%`` + Seeks to the middle of the file. + ``--start=30 --end=40`` + Seeks to 30 seconds, plays 10 seconds, and exits. + ``--start=-3:20 --length=10`` + Seeks to 3 minutes and 20 seconds before the end of the file, plays + 10 seconds, and exits. --ssf=<mode> Specifies software scaler parameters. diff --git a/core/cfg-mplayer.h b/core/cfg-mplayer.h index 776798aaad..b6e947be5f 100644 --- a/core/cfg-mplayer.h +++ b/core/cfg-mplayer.h @@ -376,14 +376,13 @@ const m_option_t common_opts[] = { // seek to byte/seconds position {"sb", &seek_to_byte, CONF_TYPE_INT64, CONF_MIN, 0, 0, NULL}, - OPT_TIME("ss", seek_to_sec, 0), + OPT_REL_TIME("start", play_start, 0), + OPT_REL_TIME("end", play_end, 0), + OPT_REL_TIME("length", play_length, 0), // start paused OPT_FLAG_ON("pause", start_paused, 0), - // stop at given position - {"endpos", &end_at, CONF_TYPE_TIME_SIZE, 0, 0, 0, NULL}, - // AVI specific: force non-interleaved mode {"avi-ni", &force_ni, CONF_TYPE_FLAG, 0, 0, 1, NULL}, diff --git a/core/m_option.c b/core/m_option.c index f64b4deb20..693c95cf96 100644 --- a/core/m_option.c +++ b/core/m_option.c @@ -1248,60 +1248,49 @@ const m_option_type_t m_option_type_time = { }; -// Time or size (-endpos) +// Relative time -static int parse_time_size(const m_option_t *opt, struct bstr name, - struct bstr param, void *dst) +static int parse_rel_time(const m_option_t *opt, struct bstr name, + struct bstr param, void *dst) { - m_time_size_t ts; - char unit[4]; - double end_at; + struct m_rel_time t = {0}; if (param.len == 0) return M_OPT_MISSING_PARAM; - ts.pos = 0; - /* End at size parsing */ - if (bstr_sscanf(param, "%lf%3s", &end_at, unit) == 2) { - ts.type = END_AT_SIZE; - if (!strcasecmp(unit, "b")) - ; - else if (!strcasecmp(unit, "kb")) - end_at *= 1024; - else if (!strcasecmp(unit, "mb")) - end_at *= 1024 * 1024; - else if (!strcasecmp(unit, "gb")) - end_at *= 1024 * 1024 * 1024; - else - ts.type = END_AT_NONE; - - if (ts.type == END_AT_SIZE) { - ts.pos = end_at; + // Percent pos + double percent; + if (bstr_sscanf(param, "%lf%%", &percent) == 1) { + if (percent >= 0 && percent <= 100) { + t.type = REL_TIME_PERCENT; + t.pos = percent; goto out; } } - /* End at time parsing. This has to be last because the parsing accepts - * even a number followed by garbage */ - if (!parse_timestring(param, &end_at, 0)) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - "Option %.*s: invalid time or size: '%.*s'\n", - BSTR_P(name), BSTR_P(param)); - return M_OPT_INVALID; + double sign = bstr_eatstart0(¶m, "-") ? -1 : +1; + double time; + if (parse_timestring(param, &time, 0)) { + t.type = sign ? REL_TIME_NEGATIVE : REL_TIME_ABSOLUTE; + t.pos = time; + goto out; } - ts.type = END_AT_TIME; - ts.pos = end_at; + mp_msg(MSGT_CFGPARSER, MSGL_ERR, + "Option %.*s: invalid time or size: '%.*s'\n", + BSTR_P(name), BSTR_P(param)); + return M_OPT_INVALID; + out: if (dst) - *(m_time_size_t *)dst = ts; + *(struct m_rel_time *)dst = t; return 1; } -const m_option_type_t m_option_type_time_size = { - .name = "Time or size", - .size = sizeof(m_time_size_t), - .parse = parse_time_size, +const m_option_type_t m_option_type_rel_time = { + .name = "Relative time or percent position", + .size = sizeof(struct m_rel_time), + .parse = parse_rel_time, .copy = copy_opt, }; diff --git a/core/m_option.h b/core/m_option.h index 7fec11895a..d7041f9cf4 100644 --- a/core/m_option.h +++ b/core/m_option.h @@ -44,7 +44,7 @@ extern const m_option_type_t m_option_type_double; extern const m_option_type_t m_option_type_string; extern const m_option_type_t m_option_type_string_list; extern const m_option_type_t m_option_type_time; -extern const m_option_type_t m_option_type_time_size; +extern const m_option_type_t m_option_type_rel_time; extern const m_option_type_t m_option_type_choice; extern const m_option_type_t m_option_type_print; @@ -58,13 +58,17 @@ extern const m_option_type_t m_option_type_afmt; // Callback used by m_option_type_print_func options. typedef int (*m_opt_func_full_t)(const m_option_t *, const char *, const char *); -#define END_AT_NONE 0 -#define END_AT_TIME 1 -#define END_AT_SIZE 2 -typedef struct { +enum m_rel_time_type { + REL_TIME_NONE, + REL_TIME_ABSOLUTE, + REL_TIME_NEGATIVE, + REL_TIME_PERCENT, +}; + +struct m_rel_time { double pos; - int type; -} m_time_size_t; + enum m_rel_time_type type; +}; // Extra definition needed for \ref m_option_type_obj_settings_list options. typedef struct { @@ -174,7 +178,6 @@ struct m_sub_options { #define CONF_TYPE_CUSTOM_URL (&m_option_type_custom_url) #define CONF_TYPE_OBJ_PARAMS (&m_option_type_obj_params) #define CONF_TYPE_TIME (&m_option_type_time) -#define CONF_TYPE_TIME_SIZE (&m_option_type_time_size) #define CONF_TYPE_CHOICE (&m_option_type_choice) // Possible option values. Code is allowed to access option data without going @@ -193,7 +196,7 @@ union m_option_value { m_span_t span; m_obj_settings_t *obj_settings_list; double time; - m_time_size_t time_size; + struct m_rel_time rel_time; }; //////////////////////////////////////////////////////////////////////////// @@ -506,6 +509,7 @@ static inline void m_option_free(const m_option_t *opt, void *dst) #define OPT_CHOICE_OR_INT(...) OPT_CHOICE_OR_INT_(__VA_ARGS__, .type = &m_option_type_choice) #define OPT_CHOICE_OR_INT_(optname, varname, flags, minval, maxval, choices, ...) OPT_GENERAL(optname, varname, (flags) | CONF_RANGE, .min = minval, .max = maxval, M_CHOICES(choices), __VA_ARGS__) #define OPT_TIME(...) OPT_GENERAL(__VA_ARGS__, .type = &m_option_type_time) +#define OPT_REL_TIME(...) OPT_GENERAL(__VA_ARGS__, .type = &m_option_type_rel_time) #define OPT_TRACKCHOICE(name, var) OPT_CHOICE_OR_INT(name, var, 0, 0, 8190, ({"no", -2}, {"auto", -1})) diff --git a/core/mplayer.c b/core/mplayer.c index 2923d15374..3d38330c0a 100644 --- a/core/mplayer.c +++ b/core/mplayer.c @@ -165,7 +165,7 @@ static const char help_text[] = _( "Usage: mpv [options] [url|path/]filename\n" "\n" "Basic options: (complete list in the man page)\n" -" --ss=<position> seek to given (seconds or hh:mm:ss) position\n" +" --start=<time> seek to given (percent, seconds, or hh:mm:ss) position\n" " --no-audio do not play sound\n" " --no-video do not play video\n" " --fs fullscreen playback\n" @@ -208,8 +208,6 @@ static int drop_frame_cnt; // total number of dropped frames static int64_t seek_to_byte; static double step_sec; -static m_time_size_t end_at = { .type = END_AT_NONE, .pos = 0 }; - // codecs: char **audio_codec_list; // override audio codec char **video_codec_list; // override video codec @@ -258,6 +256,39 @@ static float get_relative_time(struct MPContext *mpctx) return delta * 0.000001; } +static double rel_time_to_abs(struct MPContext *mpctx, struct m_rel_time t, + double fallback_time) +{ + double length = get_time_length(mpctx); + switch (t.type) { + case REL_TIME_ABSOLUTE: + return t.pos; + case REL_TIME_NEGATIVE: + if (length != 0) + return FFMAX(length - t.pos, 0.0); + break; + case REL_TIME_PERCENT: + if (length != 0) + return length * (t.pos / 100.0); + break; + } + return fallback_time; +} + +static double get_play_end_pts(struct MPContext *mpctx) +{ + struct MPOpts *opts = &mpctx->opts; + if (opts->play_end.type) { + return rel_time_to_abs(mpctx, opts->play_end, MP_NOPTS_VALUE); + } else if (opts->play_length.type) { + double start = rel_time_to_abs(mpctx, opts->play_start, -1); + double length = rel_time_to_abs(mpctx, opts->play_length, -1); + if (start != -1 && length != -1) + return start + length; + } + return MP_NOPTS_VALUE; +} + static void print_stream(struct MPContext *mpctx, struct track *t, int id) { struct sh_stream *s = t->stream; @@ -1138,17 +1169,20 @@ static void print_status(struct MPContext *mpctx, double a_pos, bool at_frame) } #ifdef CONFIG_ENCODING - float position = (get_current_time(mpctx) - opts->seek_to_sec) / - (get_time_length(mpctx) - opts->seek_to_sec); - if (end_at.type == END_AT_TIME) - position = max(position, (get_current_time(mpctx) - opts->seek_to_sec) - / (end_at.pos - opts->seek_to_sec)); + double startpos = rel_time_to_abs(mpctx, opts->play_start, 0); + double endpos = rel_time_to_abs(mpctx, opts->play_end, -1); + float position = (get_current_time(mpctx) - startpos) / + (get_time_length(mpctx) - startpos); + if (endpos != -1) + position = max(position, (get_current_time(mpctx) - startpos) + / (endpos - startpos)); if (play_n_frames_mf) position = max(position, 1.0 - play_n_frames / (double) play_n_frames_mf); char lavcbuf[80]; if (encode_lavc_getstatus(mpctx->encode_lavc_ctx, lavcbuf, sizeof(lavcbuf), - position, get_current_time(mpctx) - opts->seek_to_sec) >= 0) { + position, get_current_time(mpctx) - startpos) >= 0) + { // encoding stats saddf(line, width, "%s ", lavcbuf); } else @@ -2970,7 +3004,7 @@ static void run_playloop(struct MPContext *mpctx) struct MPOpts *opts = &mpctx->opts; bool full_audio_buffers = false; bool audio_left = false, video_left = false; - double endpts = end_at.type == END_AT_TIME ? end_at.pos : MP_NOPTS_VALUE; + double endpts = get_play_end_pts(mpctx); bool end_is_chapter = false; double sleeptime = WAKEUP_PERIOD; bool was_restart = mpctx->restart_playback; @@ -3325,7 +3359,7 @@ static void run_playloop(struct MPContext *mpctx) mpctx->seek = (struct seek_params) {0}; struct seek_params sp = { .type = MPSEEK_ABSOLUTE, - .amount = opts->seek_to_sec, + .amount = rel_time_to_abs(mpctx, opts->play_start, 0), .exact = 1, }; if (seek(mpctx, sp, false) != 0) { @@ -3963,10 +3997,10 @@ goto_enable_cache: mpctx->last_chapter_seek = -2; // If there's a timeline force an absolute seek to initialize state - if (opts->seek_to_sec || mpctx->timeline) { - queue_seek(mpctx, MPSEEK_ABSOLUTE, opts->seek_to_sec, 0); + double startpos = rel_time_to_abs(mpctx, opts->play_start, -1); + if (startpos != -1 || mpctx->timeline) { + queue_seek(mpctx, MPSEEK_ABSOLUTE, startpos, 0); seek(mpctx, mpctx->seek, false); - end_at.pos += opts->seek_to_sec; } if (opts->chapterrange[0] > 0) { double pts; @@ -3977,12 +4011,6 @@ goto_enable_cache: } } - if (end_at.type == END_AT_SIZE) { - mp_tmsg(MSGT_CPLAYER, MSGL_WARN, - "Option -endpos in mpv does not yet support size units.\n"); - end_at.type = END_AT_NONE; - } - mpctx->seek = (struct seek_params){ 0 }; get_relative_time(mpctx); // reset current delta // Make sure VO knows current pause state diff --git a/core/options.h b/core/options.h index 31d2726c19..03298554cd 100644 --- a/core/options.h +++ b/core/options.h @@ -1,6 +1,8 @@ #ifndef MPLAYER_OPTIONS_H #define MPLAYER_OPTIONS_H +#include "core/m_option.h" + typedef struct MPOpts { char **video_driver_list; char **audio_driver_list; @@ -69,7 +71,9 @@ typedef struct MPOpts { int consolecontrols; int doubleclick_time; int list_properties; - double seek_to_sec; + struct m_rel_time play_start; + struct m_rel_time play_end; + struct m_rel_time play_length; int start_paused; int audio_id; int video_id; diff --git a/core/playlist_parser.c b/core/playlist_parser.c index 98eebaa47e..67d58024c1 100644 --- a/core/playlist_parser.c +++ b/core/playlist_parser.c @@ -359,7 +359,7 @@ static bool parse_pls(play_tree_parser_t* p) { mp_msg(MSGT_PLAYTREE,MSGL_DBG2,"Adding entry %s\n",entries[num].file); playlist_add_file(p->pl,entries[num].file); if (entries[num].length) - playlist_entry_add_param(p->pl->last, bstr0("endpos"), bstr0(entries[num].length)); + playlist_entry_add_param(p->pl->last, bstr0("end"), bstr0(entries[num].length)); free(entries[num].file); } // When we have info in playtree we add these info |