summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/man/en/mplayer.121
-rw-r--r--DOCS/tech/slave.txt14
-rw-r--r--cfg-mplayer.h2
-rw-r--r--command.c16
-rw-r--r--input/input.c2
-rw-r--r--mp_core.h3
-rw-r--r--mplayer.c45
-rw-r--r--options.h1
8 files changed, 82 insertions, 22 deletions
diff --git a/DOCS/man/en/mplayer.1 b/DOCS/man/en/mplayer.1
index a6c103ce25..95ef58de81 100644
--- a/DOCS/man/en/mplayer.1
+++ b/DOCS/man/en/mplayer.1
@@ -909,6 +909,27 @@ mplayer \-heartbeat\-cmd "gnome\-screensaver\-command \-p" file
.PD 1
.
.TP
+.B \-hr\-seek off|absolute|always
+Select when to use precise seeks that are not limited to keyframes.
+Such seeks require decoding video from the previous keyframe up to the target
+position and so can take some time depending on decoding performance.
+For some video formats precise seeks are disabled. This option selects the
+default choice to use for seeks; it's possible to explicitly override that
+default in the definition of key bindings and in slave mode commands.
+.PD 0
+.RSs
+.IPs off
+Never use precise seeks.
+.IPs absolute
+Use precise seeks if the seek is to an absolute position in the file,
+such as a chapter seek, but not for relative seeks like the default
+behavior of arrow keys (default).
+.IPs always
+Use precise seeks whenever possible.
+.RE
+.PD 1
+.
+.TP
.B \-identify
Shorthand for \-msglevel identify=4.
Show file parameters in an easily parseable format.
diff --git a/DOCS/tech/slave.txt b/DOCS/tech/slave.txt
index be0ebf9937..6187affab5 100644
--- a/DOCS/tech/slave.txt
+++ b/DOCS/tech/slave.txt
@@ -272,11 +272,16 @@ radio_step_channel <-1|1>
radio_step_freq <value>
Tune frequency by the <value> (positive - up, negative - down).
-seek <value> [type]
+seek <value> [type] [hr-seek]
Seek to some place in the movie.
- 0 is a relative seek of +/- <value> seconds (default).
- 1 is a seek to <value> % in the movie.
- 2 is a seek to an absolute position of <value> seconds.
+ type = 0 is a relative seek of +/- <value> seconds (default).
+ type = 1 is a seek to <value> % in the movie.
+ type = 2 is a seek to an absolute position of <value> seconds.
+ The hr-seek parameter controls whether to use precise seeks (not limited
+ to keyframe positions in video).
+ hr-seek = 0 means use default set with option -hr-seek (default).
+ hr-seek = 1 means force precise seek if possible.
+ hr-seek = -1 means force non-precise seek.
seek_chapter <value> [type]
Seek to the start of a chapter.
@@ -513,6 +518,7 @@ name type min max get set step comment
osdlevel int 0 3 X X X as -osdlevel
speed float 0.01 100 X X X as -speed
loop int -1 X X X as -loop
+hr_seek string X X X as -hr-seek
pts_association_mode string X X X as -pts-association-mode
pause flag 0 1 X 1 if paused, use with pausing_keep_force
filename string X file playing wo path
diff --git a/cfg-mplayer.h b/cfg-mplayer.h
index 3545b77716..7f0ee1f729 100644
--- a/cfg-mplayer.h
+++ b/cfg-mplayer.h
@@ -312,6 +312,8 @@ const m_option_t mplayer_opts[]={
OPT_CHOICE("pts-association-mode", user_pts_assoc_mode, 0,
({"auto", 0}, {"decoder", 1}, {"sort", 2})),
OPT_MAKE_FLAGS("initial-audio-sync", initial_audio_sync, 0),
+ OPT_CHOICE("hr-seek", hr_seek, 0,
+ ({"off", -1}, {"absolute", 0}, {"always", 1}, {"on", 1})),
OPT_FLAG_CONSTANTS("noautosync", autosync, 0, 0, -1),
OPT_INTRANGE("autosync", autosync, 0, 0, 10000),
diff --git a/command.c b/command.c
index 394bf566c4..c1519d001d 100644
--- a/command.c
+++ b/command.c
@@ -2219,6 +2219,8 @@ static const m_option_t mp_properties[] = {
M_OPT_RANGE, 0, 1, NULL },
{ "pts_association_mode", mp_property_generic_option, &m_option_type_choice,
0, 0, 0, "pts-association-mode" },
+ { "hr_seek", mp_property_generic_option, &m_option_type_choice,
+ 0, 0, 0, "hr-seek" },
// Audio
{ "volume", mp_property_volume, CONF_TYPE_FLOAT,
@@ -2393,6 +2395,7 @@ static struct property_osd_display {
{ "chapter", -1, -1, NULL },
{ "capturing", 0, -1, _("Capturing: %s") },
{ "pts_association_mode", 0, -1, "PTS association mode: %s" },
+ { "hr_seek", 0, -1, "hr-seek: %s" },
// audio
{ "volume", OSD_VOLUME, -1, _("Volume") },
{ "mute", 0, -1, _("Mute: %s") },
@@ -2713,20 +2716,19 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
if (!set_property_command(mpctx, cmd))
switch (cmd->id) {
case MP_CMD_SEEK:{
- float v;
- int abs;
mpctx->add_osd_seek_info = true;
- v = cmd->args[0].v.f;
- abs = (cmd->nargs > 1) ? cmd->args[1].v.i : 0;
+ float v = cmd->args[0].v.f;
+ int abs = (cmd->nargs > 1) ? cmd->args[1].v.i : 0;
+ int exact = (cmd->nargs > 2) ? cmd->args[2].v.i : 0;
if (abs == 2) { /* Absolute seek to a specific timestamp in seconds */
- queue_seek(mpctx, MPSEEK_ABSOLUTE, v, 0);
+ queue_seek(mpctx, MPSEEK_ABSOLUTE, v, exact);
mpctx->osd_function = v > get_current_time(mpctx) ?
OSD_FFW : OSD_REW;
} else if (abs) { /* Absolute seek by percentage */
- queue_seek(mpctx, MPSEEK_FACTOR, v / 100.0, 0);
+ queue_seek(mpctx, MPSEEK_FACTOR, v / 100.0, exact);
mpctx->osd_function = OSD_FFW; // Direction isn't set correctly
} else {
- queue_seek(mpctx, MPSEEK_RELATIVE, v, 0);
+ queue_seek(mpctx, MPSEEK_RELATIVE, v, exact);
mpctx->osd_function = (v > 0) ? OSD_FFW : OSD_REW;
}
}
diff --git a/input/input.c b/input/input.c
index c08f3d49f0..72725a5409 100644
--- a/input/input.c
+++ b/input/input.c
@@ -86,7 +86,7 @@ static const mp_cmd_t mp_cmds[] = {
{ MP_CMD_RADIO_SET_FREQ, "radio_set_freq", 1, { {MP_CMD_ARG_FLOAT,{0}}, {-1,{0}} } },
{ MP_CMD_RADIO_STEP_FREQ, "radio_step_freq", 1, { {MP_CMD_ARG_FLOAT,{0}}, {-1,{0}} } },
#endif
- { MP_CMD_SEEK, "seek", 1, { {MP_CMD_ARG_FLOAT,{0}}, {MP_CMD_ARG_INT,{0}}, {-1,{0}} } },
+ { MP_CMD_SEEK, "seek", 1, { {MP_CMD_ARG_FLOAT,{0}}, {MP_CMD_ARG_INT,{0}}, {MP_CMD_ARG_INT,{0}}, {-1,{0}} } },
{ MP_CMD_EDL_MARK, "edl_mark", 0, { {-1,{0}} } },
{ MP_CMD_AUDIO_DELAY, "audio_delay", 1, { {MP_CMD_ARG_FLOAT,{0}}, {MP_CMD_ARG_INT,{0}}, {-1,{0}} } },
{ MP_CMD_SPEED_INCR, "speed_incr", 1, { {MP_CMD_ARG_FLOAT,{0}}, {-1,{0}} } },
diff --git a/mp_core.h b/mp_core.h
index c64de2cdbe..7f6bb2ccf4 100644
--- a/mp_core.h
+++ b/mp_core.h
@@ -129,6 +129,9 @@ typedef struct MPContext {
* stream by cutting samples or adding silence at the beginning to make
* audio playback position match video position. */
bool syncing_audio;
+ bool hrseek_active;
+ bool hrseek_framedrop;
+ double hrseek_pts;
// AV sync: the next frame should be shown when the audio out has this
// much (in seconds) buffered data left. Increased when more data is
// written to the ao, decreased when moving to the next frame.
diff --git a/mplayer.c b/mplayer.c
index 7eb2d138b5..f209ca0214 100644
--- a/mplayer.c
+++ b/mplayer.c
@@ -2558,7 +2558,8 @@ static double update_video(struct MPContext *mpctx)
while (1) {
current_module = "filter_video";
- if (vo_get_buffered_frame(video_out, false) >= 0)
+ if (!mpctx->hrseek_active
+ && vo_get_buffered_frame(video_out, false) >= 0)
break;
// XXX Time used in this call is not counted in any performance
// timer now
@@ -2578,7 +2579,10 @@ static double update_video(struct MPContext *mpctx)
if (in_size > max_framesize)
max_framesize = in_size;
current_module = "decode video";
- int framedrop_type = check_framedrop(mpctx, sh_video->frametime);
+ if (pts >= mpctx->hrseek_pts - .005)
+ mpctx->hrseek_framedrop = false;
+ int framedrop_type = mpctx->hrseek_framedrop ? 1 :
+ check_framedrop(mpctx, sh_video->frametime);
void *decoded_frame = decode_video(sh_video, packet, in_size,
framedrop_type, pts);
if (decoded_frame) {
@@ -2603,6 +2607,9 @@ static double update_video(struct MPContext *mpctx)
if (pts == MP_NOPTS_VALUE)
pts = sh_video->last_pts;
}
+ if (mpctx->hrseek_active && pts < mpctx->hrseek_pts - .005)
+ return 0;
+ mpctx->hrseek_active = false;
sh_video->pts = pts;
if (sh_video->last_pts == MP_NOPTS_VALUE)
sh_video->last_pts = sh_video->pts;
@@ -2808,6 +2815,8 @@ static void seek_reset(struct MPContext *mpctx)
edl_seek_reset(mpctx);
+ mpctx->hrseek_active = false;
+ mpctx->hrseek_framedrop = false;
mpctx->total_avsync_change = 0;
audio_time_usage = 0; video_time_usage = 0; vout_time_usage = 0;
drop_frame_cnt = 0;
@@ -2854,9 +2863,15 @@ static double timeline_set_from_time(struct MPContext *mpctx, double pts,
// return -1 if seek failed (non-seekable stream?), 0 otherwise
static int seek(MPContext *mpctx, struct seek_params seek)
{
+ struct MPOpts *opts = &mpctx->opts;
+
current_module = "seek";
if (mpctx->stop_play == AT_END_OF_FILE)
mpctx->stop_play = KEEP_PLAYING;
+ bool hr_seek = mpctx->demuxer->accurate_seek && opts->correct_pts;
+ hr_seek &= seek.exact >= 0 && seek.type != MPSEEK_FACTOR;
+ hr_seek &= opts->hr_seek == 0 && seek.type == MPSEEK_ABSOLUTE
+ || opts->hr_seek > 0 || seek.exact > 0;
if (seek.type == MPSEEK_FACTOR
|| seek.type == MPSEEK_ABSOLUTE
&& seek.amount < mpctx->last_chapter_pts
@@ -2899,7 +2914,7 @@ static int seek(MPContext *mpctx, struct seek_params seek)
case MPSEEK_ABSOLUTE:
demuxer_style |= SEEK_ABSOLUTE;
}
- if (seek.direction < 0)
+ if (hr_seek || seek.direction < 0)
demuxer_style |= SEEK_BACKWARD;
else if (seek.direction > 0)
demuxer_style |= SEEK_FORWARD;
@@ -2918,6 +2933,12 @@ static int seek(MPContext *mpctx, struct seek_params seek)
if (seek.type == MPSEEK_ABSOLUTE)
mpctx->video_pts = seek.amount;
+ if (hr_seek) {
+ mpctx->hrseek_active = true;
+ mpctx->hrseek_framedrop = true;
+ mpctx->hrseek_pts = seek.amount;
+ }
+
mpctx->start_timestamp = GetTimerMS();
return 0;
@@ -3129,9 +3150,10 @@ static void run_playloop(struct MPContext *mpctx)
vo_fps = mpctx->sh_video->fps;
bool blit_frame = mpctx->video_out->frame_loaded;
- if (!blit_frame) {
+ if (!blit_frame || mpctx->hrseek_active) {
double frame_time = update_video(mpctx);
blit_frame = mpctx->video_out->frame_loaded;
+ blit_frame &= !mpctx->hrseek_active;
mp_dbg(MSGT_AVSYNC, MSGL_DBG2, "*** ftime=%5.3f ***\n", frame_time);
if (mpctx->sh_video->vf_initialized < 0) {
mp_tmsg(MSGT_CPLAYER, MSGL_FATAL,
@@ -4547,6 +4569,15 @@ if(play_n_frames==0){
mpctx->stop_play=PT_NEXT_ENTRY; goto goto_next_file;
}
+ mpctx->time_frame = 0;
+ mpctx->drop_message_shown = 0;
+ mpctx->restart_playback = true;
+ mpctx->video_pts = 0;
+ mpctx->hrseek_active = false;
+ mpctx->hrseek_framedrop = false;
+ mpctx->total_avsync_change = 0;
+ mpctx->last_chapter_seek = -1;
+
// If there's a timeline force an absolute seek to initialize state
if (seek_to_sec || mpctx->timeline) {
queue_seek(mpctx, MPSEEK_ABSOLUTE, seek_to_sec, 0);
@@ -4577,12 +4608,6 @@ if (mpctx->stream->type == STREAMTYPE_DVDNAV) {
mpctx->seek = (struct seek_params){0};
get_relative_time(mpctx); // reset current delta
- mpctx->time_frame = 0;
- mpctx->drop_message_shown = 0;
- mpctx->restart_playback = true;
- mpctx->video_pts = 0;
- mpctx->total_avsync_change = 0;
- mpctx->last_chapter_seek = -1;
// Make sure VO knows current pause state
if (mpctx->sh_video)
vo_control(mpctx->video_out, mpctx->paused ? VOCTRL_PAUSE : VOCTRL_RESUME,
diff --git a/options.h b/options.h
index 66048e77b2..12ac475f9e 100644
--- a/options.h
+++ b/options.h
@@ -47,6 +47,7 @@ typedef struct MPOpts {
int user_correct_pts;
int user_pts_assoc_mode;
int initial_audio_sync;
+ int hr_seek;
int autosync;
int softsleep;
int rtc;