summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/man/en/changes.rst2
-rw-r--r--DOCS/man/en/options.rst43
-rw-r--r--core/cfg-mplayer.h7
-rw-r--r--core/m_option.c63
-rw-r--r--core/m_option.h22
-rw-r--r--core/mplayer.c68
-rw-r--r--core/options.h6
-rw-r--r--core/playlist_parser.c2
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(&param, "-") ? -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