summaryrefslogtreecommitdiffstats
path: root/mplayer.c
diff options
context:
space:
mode:
authorUoti Urpala <uau@glyph.nonexistent.invalid>2010-12-15 01:09:47 +0200
committerUoti Urpala <uau@glyph.nonexistent.invalid>2010-12-20 19:02:16 +0200
commitf0649f13d698eb6aeffeaacd6801b666c4366caf (patch)
tree809200e48f70f5a13e8a1d27f688f7b92348a744 /mplayer.c
parent23f598e0ee2151923a44077f510cd484f239480b (diff)
downloadmpv-f0649f13d698eb6aeffeaacd6801b666c4366caf.tar.bz2
mpv-f0649f13d698eb6aeffeaacd6801b666c4366caf.tar.xz
core: add support for precise non-keyframe-limited seeks
Add support for seeking to an arbitrary non-keyframe position by decoding video starting from the previous keyframe. Whether to use this functionality when seeking is controlled by the new option -hr-seek and a new third argument to the "seek" command. The default is to use it for absolute seeks (like chapter seeks) but not for relative ones. Because there's currently no support for cutting encoded audio some desync is expected if encoded audio passthrough is used. Currently precise seeks always go to the first frame with timestamp equal to or greater than the target position; there's no support for "matching or earlier" backwards seeks at frame level.
Diffstat (limited to 'mplayer.c')
-rw-r--r--mplayer.c45
1 files changed, 35 insertions, 10 deletions
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,