summaryrefslogtreecommitdiffstats
path: root/player/playloop.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2016-01-12 23:49:00 +0100
committerwm4 <wm4@nowhere>2016-01-12 23:49:00 +0100
commite420464ba693a5920d4dc172b3f7e9a0c725e3d4 (patch)
treee149445377e94da3274f7d3f588449ed24ece3c1 /player/playloop.c
parent6fc0fe4426c1b71630d281cbc9e0406f8ad7deee (diff)
downloadmpv-e420464ba693a5920d4dc172b3f7e9a0c725e3d4.tar.bz2
mpv-e420464ba693a5920d4dc172b3f7e9a0c725e3d4.tar.xz
player: simplify backstepping
Basically reimplement it. The old implementation was quite stupid, and was probably done this way because video filtering and output used to be way less decoupled. Now we can reimplement it in a very simple way: when backstepping, seek to current time, but keep the last frame that was supposed to be discarded when reaching the target time. When the seek finishes, prepend the saved frame to the video frame queue. A disadvantage is that the new implementation fails to skip over timeline boundaries (ordered chapters etc.), but this never worked properly anyway. It's possible that this will be fixed some time in the future.
Diffstat (limited to 'player/playloop.c')
-rw-r--r--player/playloop.c116
1 files changed, 18 insertions, 98 deletions
diff --git a/player/playloop.c b/player/playloop.c
index 4d3e70b4f7..5226103733 100644
--- a/player/playloop.c
+++ b/player/playloop.c
@@ -133,9 +133,8 @@ void add_step_frame(struct MPContext *mpctx, int dir)
mpctx->step_frames += 1;
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;
+ if (!mpctx->hrseek_backstep || !mpctx->hrseek_active) {
+ queue_seek(mpctx, MPSEEK_BACKSTEP, 0, MPSEEK_VERY_EXACT, true);
pause_player(mpctx);
}
}
@@ -151,6 +150,7 @@ void reset_playback_state(struct MPContext *mpctx)
mpctx->hrseek_active = false;
mpctx->hrseek_framedrop = false;
mpctx->hrseek_lastframe = false;
+ mpctx->hrseek_backstep = false;
mpctx->playback_pts = MP_NOPTS_VALUE;
mpctx->last_seek_pts = MP_NOPTS_VALUE;
mpctx->cache_wait_time = 0;
@@ -167,7 +167,6 @@ static int mp_seek(MPContext *mpctx, struct seek_params seek,
bool timeline_fallthrough)
{
struct MPOpts *opts = mpctx->opts;
- uint64_t prev_seek_ts = mpctx->vo_pts_history_seek_ts;
int prev_step = mpctx->step_frames;
if (!mpctx->demuxer)
@@ -192,11 +191,20 @@ static int mp_seek(MPContext *mpctx, struct seek_params seek,
double target_time = MP_NOPTS_VALUE;
int direction = 0;
+ bool backstep = false;
switch (seek.type) {
case MPSEEK_ABSOLUTE:
target_time = seek.amount;
break;
+ case MPSEEK_BACKSTEP:
+ seek.type = MPSEEK_ABSOLUTE;
+ seek.amount = get_current_time(mpctx);
+ if (seek.amount == MP_NOPTS_VALUE)
+ seek.amount = 0;
+ target_time = seek.amount;
+ backstep = true;
+ break;
case MPSEEK_RELATIVE:
direction = seek.amount > 0 ? 1 : -1;
double cur = get_current_time(mpctx);
@@ -272,14 +280,8 @@ static int mp_seek(MPContext *mpctx, struct seek_params seek,
reset_playback_state(mpctx);
- if (timeline_fallthrough) {
- // Important if video reinit happens.
- mpctx->vo_pts_history_seek_ts = prev_seek_ts;
+ if (timeline_fallthrough)
mpctx->step_frames = prev_step;
- } else {
- mpctx->vo_pts_history_seek_ts++;
- mpctx->backstep_active = false;
- }
/* Use the target time as "current position" for further relative
* seeks etc until a new video frame has been decoded */
@@ -294,11 +296,13 @@ static int mp_seek(MPContext *mpctx, struct seek_params seek,
if (hr_seek || mpctx->timeline) {
mpctx->hrseek_active = true;
mpctx->hrseek_framedrop = !hr_seek_very_exact && opts->hr_seek_framedrop;
+ mpctx->hrseek_backstep = backstep;
mpctx->hrseek_pts = hr_seek ? seek.amount
: mpctx->timeline[mpctx->timeline_part].start;
- MP_VERBOSE(mpctx, "hr-seek, skipping to %f%s\n", mpctx->hrseek_pts,
- mpctx->hrseek_framedrop ? "" : " (no framedrop)");
+ MP_VERBOSE(mpctx, "hr-seek, skipping to %f%s%s\n", mpctx->hrseek_pts,
+ mpctx->hrseek_framedrop ? "" : " (no framedrop)",
+ mpctx->hrseek_backstep ? " (backstep)" : "");
}
mpctx->start_timestamp = mp_time_sec();
@@ -334,6 +338,7 @@ void queue_seek(struct MPContext *mpctx, enum seek_type type, double amount,
return;
case MPSEEK_ABSOLUTE:
case MPSEEK_FACTOR:
+ case MPSEEK_BACKSTEP:
*seek = (struct seek_params) {
.type = type,
.amount = amount,
@@ -670,89 +675,6 @@ static void handle_vo_events(struct MPContext *mpctx)
mp_notify(mpctx, MP_EVENT_WIN_STATE, NULL);
}
-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;
- }
- if (mpctx->vo_pts_history_pts[0] == pts) // may be called multiple times
- 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 void handle_backstep(struct MPContext *mpctx)
-{
- if (!mpctx->backstep_active)
- return;
-
- double current_pts = mpctx->last_vo_pts;
- mpctx->backstep_active = false;
- if (mpctx->d_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, MPSEEK_VERY_EXACT, true);
- } 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_ERR(mpctx, "Backstep failed.\n");
- queue_seek(mpctx, MPSEEK_ABSOLUTE, current_pts,
- MPSEEK_VERY_EXACT, true);
- } else if (!mpctx->hrseek_active) {
- MP_VERBOSE(mpctx, "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.)
- mp_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.
- if (mpctx->hrseek_active) {
- mpctx->hrseek_pts = current_pts + 10.0;
- mpctx->hrseek_framedrop = false;
- mpctx->backstep_active = true;
- }
- } else {
- mpctx->backstep_active = true;
- }
- }
- }
-}
-
static void handle_sstep(struct MPContext *mpctx)
{
struct MPOpts *opts = mpctx->opts;
@@ -1061,8 +983,6 @@ void run_playloop(struct MPContext *mpctx)
mp_process_input(mpctx);
- handle_backstep(mpctx);
-
handle_chapter_change(mpctx);
handle_force_window(mpctx, false);