summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2012-11-15 18:49:17 +0100
committerwm4 <wm4@nowhere>2012-11-16 21:21:15 +0100
commit51503a05778290edc0bb77276b67d33ca0e10783 (patch)
tree4745d8d476e788fe0a36c1151dd28118cac0a911 /core
parentb4b86e9286ba175ba0da4d19e165660bed7002e4 (diff)
downloadmpv-51503a05778290edc0bb77276b67d33ca0e10783.tar.bz2
mpv-51503a05778290edc0bb77276b67d33ca0e10783.tar.xz
options: rename -ss and -endpos, allow relative times
Rename the -ss option to -start, and -endpos to -length. Add a -end option. The -end option always specifies an absolute end time, as opposed to -endpos/-length. All these options (--start, --end, --length) now accept relative times. Percent positions (e.g. "--start=30%") are interpreted as fractions of the file duration. Negative times (e.g. "--start=-1:00) are interpreted relative to the end of the file. Chapters (e.g. "--start=#3") yield the chapter's time position. The chapter support might be able to replace --chapter completely, but for now I am not sure how well this works out with e.g. DVDs and BDs, and a separate --chapter option is useful interface-wise.
Diffstat (limited to 'core')
-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
6 files changed, 96 insertions, 72 deletions
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