summaryrefslogtreecommitdiffstats
path: root/core/mplayer.c
diff options
context:
space:
mode:
Diffstat (limited to 'core/mplayer.c')
-rw-r--r--core/mplayer.c99
1 files changed, 93 insertions, 6 deletions
diff --git a/core/mplayer.c b/core/mplayer.c
index aa7a538a73..08a3d8256d 100644
--- a/core/mplayer.c
+++ b/core/mplayer.c
@@ -2404,6 +2404,7 @@ int reinit_video_chain(struct MPContext *mpctx)
sh_video->next_frame_time = 0;
mpctx->restart_playback = true;
mpctx->delay = 0;
+ mpctx->vo_pts_history_seek_ts++;
// ========== Init display (sh_video->disp_w*sh_video->disp_h/out_fmt) ============
@@ -2419,6 +2420,40 @@ no_video:
return 0;
}
+static void add_frame_pts(struct MPContext *mpctx, double pts)
+{
+ if (pts == MP_NOPTS_VALUE || mpctx->hrseek_framedrop) {
+ mpctx->vo_pts_history_seek_ts++; // mark discontinuity
+ return;
+ }
+ for (int n = MAX_NUM_VO_PTS - 1; n >= 1; n--) {
+ mpctx->vo_pts_history_seek[n] = mpctx->vo_pts_history_seek[n - 1];
+ mpctx->vo_pts_history_pts[n] = mpctx->vo_pts_history_pts[n - 1];
+ }
+ mpctx->vo_pts_history_seek[0] = mpctx->vo_pts_history_seek_ts;
+ mpctx->vo_pts_history_pts[0] = pts;
+}
+
+static double find_previous_pts(struct MPContext *mpctx, double pts)
+{
+ for (int n = 0; n < MAX_NUM_VO_PTS - 1; n++) {
+ if (pts == mpctx->vo_pts_history_pts[n] &&
+ mpctx->vo_pts_history_seek[n] != 0 &&
+ mpctx->vo_pts_history_seek[n] == mpctx->vo_pts_history_seek[n + 1])
+ {
+ return mpctx->vo_pts_history_pts[n + 1];
+ }
+ }
+ return MP_NOPTS_VALUE;
+}
+
+static double get_last_frame_pts(struct MPContext *mpctx)
+{
+ if (mpctx->vo_pts_history_seek[0] == mpctx->vo_pts_history_seek_ts)
+ return mpctx->vo_pts_history_pts[0];
+ return MP_NOPTS_VALUE;
+}
+
static bool filter_output_queued_frame(struct MPContext *mpctx)
{
struct sh_video *sh_video = mpctx->sh_video;
@@ -2571,6 +2606,7 @@ static double update_video(struct MPContext *mpctx)
if (pts == MP_NOPTS_VALUE)
pts = sh_video->last_pts;
}
+ add_frame_pts(mpctx, pts);
if (mpctx->hrseek_active && pts < mpctx->hrseek_pts - .005) {
vo_skip_frame(video_out);
return 0;
@@ -2658,12 +2694,20 @@ static bool redraw_osd(struct MPContext *mpctx)
return true;
}
-void add_step_frame(struct MPContext *mpctx)
+void add_step_frame(struct MPContext *mpctx, int dir)
{
- mpctx->step_frames++;
- if (mpctx->video_out && mpctx->sh_video && mpctx->video_out->config_ok)
- vo_control(mpctx->video_out, VOCTRL_PAUSE, NULL);
- unpause_player(mpctx);
+ if (dir > 0) {
+ mpctx->step_frames += 1;
+ if (mpctx->video_out && mpctx->sh_video && mpctx->video_out->config_ok)
+ vo_control(mpctx->video_out, VOCTRL_PAUSE, NULL);
+ unpause_player(mpctx);
+ } else if (dir < 0) {
+ if (!mpctx->backstep_active && !mpctx->hrseek_active) {
+ mpctx->backstep_active = true;
+ mpctx->backstep_start_seek_ts = mpctx->vo_pts_history_seek_ts;
+ pause_player(mpctx);
+ }
+ }
}
static void seek_reset(struct MPContext *mpctx, bool reset_ao, bool reset_ac)
@@ -2701,6 +2745,8 @@ static void seek_reset(struct MPContext *mpctx, bool reset_ao, bool reset_ac)
mpctx->drop_frame_cnt = 0;
mpctx->dropped_frames = 0;
mpctx->playback_pts = MP_NOPTS_VALUE;
+ mpctx->vo_pts_history_seek_ts++;
+ mpctx->backstep_active = false;
#ifdef CONFIG_ENCODING
encode_lavc_discontinuity(mpctx->encode_lavc_ctx);
@@ -3488,7 +3534,7 @@ static void run_playloop(struct MPContext *mpctx)
sleeptime = 0;
} else if (mpctx->paused && video_left) {
// force redrawing OSD by framestepping
- add_step_frame(mpctx);
+ add_step_frame(mpctx, 1);
sleeptime = 0;
}
}
@@ -3525,6 +3571,46 @@ static void run_playloop(struct MPContext *mpctx)
break;
}
+ if (mpctx->backstep_active) {
+ double current_pts = mpctx->last_vo_pts;
+ mpctx->backstep_active = false;
+ if (mpctx->sh_video && current_pts != MP_NOPTS_VALUE) {
+ double seek_pts = find_previous_pts(mpctx, current_pts);
+ if (seek_pts != MP_NOPTS_VALUE) {
+ queue_seek(mpctx, MPSEEK_ABSOLUTE, seek_pts, 1);
+ } else {
+ double last = get_last_frame_pts(mpctx);
+ if (last != MP_NOPTS_VALUE && last >= current_pts &&
+ mpctx->backstep_start_seek_ts != mpctx->vo_pts_history_seek_ts)
+ {
+ mp_msg(MSGT_CPLAYER, MSGL_ERR, "Backstep failed.\n");
+ queue_seek(mpctx, MPSEEK_ABSOLUTE, current_pts, 1);
+ } else if (!mpctx->hrseek_active) {
+ mp_msg(MSGT_CPLAYER, MSGL_V, "Start backstep indexing.\n");
+ // Force it to index the video up until current_pts.
+ // The whole point is getting frames _before_ that PTS,
+ // so apply an arbitrary offset. (In theory the offset
+ // has to be large enough to reach the previous frame.)
+ seek(mpctx, (struct seek_params){
+ .type = MPSEEK_ABSOLUTE,
+ .amount = current_pts - 1.0,
+ }, false);
+ // Don't leave hr-seek mode. If all goes right, hr-seek
+ // mode is cancelled as soon as the frame before
+ // current_pts is found during hr-seeking.
+ // Note that current_pts should be part of the index,
+ // otherwise we can't find the previous frame, so set the
+ // seek target an arbitrary amount of time after it.
+ mpctx->hrseek_pts = current_pts + 10.0;
+ mpctx->hrseek_framedrop = false;
+ mpctx->backstep_active = true;
+ } else {
+ mpctx->backstep_active = true;
+ }
+ }
+ }
+ }
+
// handle -sstep
if (opts->step_sec > 0 && !mpctx->stop_play && !mpctx->paused &&
!mpctx->restart_playback)
@@ -4128,6 +4214,7 @@ goto_enable_cache: ;
mpctx->hrseek_active = false;
mpctx->hrseek_framedrop = false;
mpctx->step_frames = 0;
+ mpctx->backstep_active = false;
mpctx->total_avsync_change = 0;
mpctx->last_chapter_seek = -2;
mpctx->playing_msg_shown = false;