diff options
author | Uoti Urpala <uau@glyph.nonexistent.invalid> | 2010-12-15 01:09:47 +0200 |
---|---|---|
committer | Uoti Urpala <uau@glyph.nonexistent.invalid> | 2010-12-20 19:02:16 +0200 |
commit | f0649f13d698eb6aeffeaacd6801b666c4366caf (patch) | |
tree | 809200e48f70f5a13e8a1d27f688f7b92348a744 /mplayer.c | |
parent | 23f598e0ee2151923a44077f510cd484f239480b (diff) | |
download | mpv-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.c | 45 |
1 files changed, 35 insertions, 10 deletions
@@ -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, |