summaryrefslogtreecommitdiffstats
path: root/player
diff options
context:
space:
mode:
Diffstat (limited to 'player')
-rw-r--r--player/core.h17
-rw-r--r--player/loadfile.c1
-rw-r--r--player/playloop.c116
-rw-r--r--player/video.c21
4 files changed, 38 insertions, 117 deletions
diff --git a/player/core.h b/player/core.h
index 7098b3bd46..5c5466a3ae 100644
--- a/player/core.h
+++ b/player/core.h
@@ -66,6 +66,7 @@ enum seek_type {
MPSEEK_RELATIVE,
MPSEEK_ABSOLUTE,
MPSEEK_FACTOR,
+ MPSEEK_BACKSTEP,
};
enum seek_precision {
@@ -259,9 +260,10 @@ typedef struct MPContext {
struct vo *video_out;
// next_frame[0] is the next frame, next_frame[1] the one after that.
- struct mp_image *next_frames[VO_MAX_REQ_FRAMES];
+ // The +1 is for adding 1 additional frame in backstep mode.
+ struct mp_image *next_frames[VO_MAX_REQ_FRAMES + 1];
int num_next_frames;
- struct mp_image *saved_frame; // for hrseek_lastframe
+ struct mp_image *saved_frame; // for hrseek_lastframe and hrseek_backstep
enum playback_status video_status, audio_status;
bool restart_complete;
@@ -285,6 +287,7 @@ typedef struct MPContext {
bool hrseek_active; // skip all data until hrseek_pts
bool hrseek_framedrop; // allow decoder to drop frames before hrseek_pts
bool hrseek_lastframe; // drop everything until last frame reached
+ bool hrseek_backstep; // go to frame before seek target
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
@@ -320,15 +323,7 @@ typedef struct MPContext {
int last_chapter;
- // History of video frames timestamps that were queued in the VO
- // This includes even skipped frames during hr-seek
- double vo_pts_history_pts[MAX_NUM_VO_PTS];
- // Whether the PTS at vo_pts_history[n] is after a seek reset
- uint64_t vo_pts_history_seek[MAX_NUM_VO_PTS];
- uint64_t vo_pts_history_seek_ts;
- uint64_t backstep_start_seek_ts;
- bool backstep_active;
- // Past timestamps etc. (stupidly duplicated with vo_pts_history).
+ // Past timestamps etc.
// The newest frame is at index 0.
struct frame_info *past_frames;
int num_past_frames;
diff --git a/player/loadfile.c b/player/loadfile.c
index cdf3d5b0f8..ee555ed421 100644
--- a/player/loadfile.c
+++ b/player/loadfile.c
@@ -1044,7 +1044,6 @@ static void play_current_file(struct MPContext *mpctx)
mpctx->paused = false;
mpctx->paused_for_cache = false;
mpctx->playing_msg_shown = false;
- mpctx->backstep_active = false;
mpctx->max_frames = -1;
mpctx->video_speed = mpctx->audio_speed = opts->playback_speed;
mpctx->speed_factor_a = mpctx->speed_factor_v = 1.0;
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);
diff --git a/player/video.c b/player/video.c
index 28c6ac4d5c..33f3b4b970 100644
--- a/player/video.c
+++ b/player/video.c
@@ -310,7 +310,6 @@ int reinit_video_chain(struct MPContext *mpctx)
vo_set_paused(mpctx->video_out, mpctx->paused);
mpctx->sync_audio_to_video = !sh->attached_picture;
- mpctx->vo_pts_history_seek_ts++;
// If we switch on video again, ensure audio position matches up.
if (mpctx->d_audio)
@@ -603,7 +602,7 @@ static int get_req_frames(struct MPContext *mpctx, bool eof)
return mpctx->opts->video_sync == VS_DEFAULT ? 1 : 2;
int req = vo_get_num_req_frames(mpctx->video_out);
- return MPCLAMP(req, 2, MP_ARRAY_SIZE(mpctx->next_frames));
+ return MPCLAMP(req, 2, MP_ARRAY_SIZE(mpctx->next_frames) - 1);
}
// Whether it's fine to call add_new_frame() now.
@@ -615,7 +614,7 @@ static bool needs_new_frame(struct MPContext *mpctx)
// Queue a frame to mpctx->next_frames[]. Call only if needs_new_frame() signals ok.
static void add_new_frame(struct MPContext *mpctx, struct mp_image *frame)
{
- assert(needs_new_frame(mpctx));
+ assert(mpctx->num_next_frames < MP_ARRAY_SIZE(mpctx->next_frames));
assert(frame);
mpctx->next_frames[mpctx->num_next_frames++] = frame;
if (mpctx->num_next_frames == 1)
@@ -662,9 +661,6 @@ static int video_output_image(struct MPContext *mpctx, double endpts)
return r; // error
struct mp_image *img = vf_read_output_frame(mpctx->d_video->vfilter);
if (img) {
- // Always add these; they make backstepping after seeking faster.
- add_frame_pts(mpctx, img->pts);
-
if (endpts != MP_NOPTS_VALUE && img->pts >= endpts) {
r = VD_EOF;
} else if (mpctx->max_frames == 0) {
@@ -672,8 +668,19 @@ static int video_output_image(struct MPContext *mpctx, double endpts)
} else if (hrseek && mpctx->hrseek_lastframe) {
mp_image_setrefp(&mpctx->saved_frame, img);
} else if (hrseek && img->pts < mpctx->hrseek_pts - .005) {
- /* just skip */
+ /* just skip - but save if backstep active */
+ if (mpctx->hrseek_backstep)
+ mp_image_setrefp(&mpctx->saved_frame, img);
} else {
+ if (mpctx->hrseek_backstep) {
+ if (mpctx->saved_frame) {
+ add_new_frame(mpctx, mpctx->saved_frame);
+ mpctx->saved_frame = NULL;
+ } else {
+ MP_WARN(mpctx, "Backstep failed.\n");
+ }
+ mpctx->hrseek_backstep = false;
+ }
add_new_frame(mpctx, img);
img = NULL;
}