summaryrefslogtreecommitdiffstats
path: root/player
diff options
context:
space:
mode:
Diffstat (limited to 'player')
-rw-r--r--player/core.h6
-rw-r--r--player/playloop.c28
-rw-r--r--player/video.c20
3 files changed, 47 insertions, 7 deletions
diff --git a/player/core.h b/player/core.h
index d3fc4195e2..1147d0e8f5 100644
--- a/player/core.h
+++ b/player/core.h
@@ -224,14 +224,16 @@ 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_frame[2];
+ struct mp_image *saved_frame; // for hrseek_lastframe
enum playback_status video_status, audio_status;
bool restart_complete;
/* Set if audio should be timed to start with video frame after seeking,
* not set when e.g. playing cover art */
bool sync_audio_to_video;
- bool hrseek_active;
- bool hrseek_framedrop;
+ 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
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
diff --git a/player/playloop.c b/player/playloop.c
index e20e088e00..67e7f22001 100644
--- a/player/playloop.c
+++ b/player/playloop.c
@@ -151,6 +151,7 @@ void reset_playback_state(struct MPContext *mpctx)
mpctx->hrseek_active = false;
mpctx->hrseek_framedrop = false;
+ mpctx->hrseek_lastframe = false;
mpctx->playback_pts = MP_NOPTS_VALUE;
mpctx->last_seek_pts = MP_NOPTS_VALUE;
mpctx->cache_wait_time = 0;
@@ -780,6 +781,28 @@ static void handle_loop_file(struct MPContext *mpctx)
}
}
+static void seek_to_last_frame(struct MPContext *mpctx)
+{
+ if (!mpctx->d_video)
+ return;
+ MP_VERBOSE(mpctx, "seeking to last frame...\n");
+ // Approximately seek close to the end of the file.
+ // Usually, it will seek some seconds before end.
+ double end = get_play_end_pts(mpctx);
+ if (end == MP_NOPTS_VALUE)
+ end = get_time_length(mpctx);
+ mp_seek(mpctx, (struct seek_params){
+ .type = MPSEEK_ABSOLUTE,
+ .amount = end,
+ .exact = 2, // "very exact", no framedrop
+ }, false);
+ // Make it exact: stop seek only if last frame was reached.
+ if (mpctx->hrseek_active) {
+ mpctx->hrseek_pts = 1e99; // "infinite"
+ mpctx->hrseek_lastframe = true;
+ }
+}
+
static void handle_keep_open(struct MPContext *mpctx)
{
struct MPOpts *opts = mpctx->opts;
@@ -787,8 +810,11 @@ static void handle_keep_open(struct MPContext *mpctx)
!playlist_get_next(mpctx->playlist, 1) && opts->loop_times < 0)
{
mpctx->stop_play = KEEP_PLAYING;
- if (mpctx->d_video)
+ if (mpctx->d_video) {
+ if (!vo_has_frame(mpctx->video_out)) // EOF not reached normally
+ seek_to_last_frame(mpctx);
mpctx->playback_pts = mpctx->last_vo_pts;
+ }
if (!mpctx->opts->pause)
pause_player(mpctx);
}
diff --git a/player/video.c b/player/video.c
index 506c7971a7..f0829a2c8d 100644
--- a/player/video.c
+++ b/player/video.c
@@ -214,6 +214,7 @@ void reset_video_state(struct MPContext *mpctx)
mp_image_unrefp(&mpctx->next_frame[0]);
mp_image_unrefp(&mpctx->next_frame[1]);
+ mp_image_unrefp(&mpctx->saved_frame);
mpctx->delay = 0;
mpctx->time_frame = 0;
@@ -534,6 +535,8 @@ static bool have_new_frame(struct MPContext *mpctx)
// returns VD_* code
static int video_output_image(struct MPContext *mpctx, double endpts)
{
+ bool hrseek = mpctx->hrseek_active && mpctx->video_status == STATUS_SYNCING;
+
if (mpctx->d_video->header->attached_picture) {
if (vo_has_frame(mpctx->video_out))
return VD_EOF;
@@ -591,16 +594,18 @@ static int video_output_image(struct MPContext *mpctx, double endpts)
add_frame_pts(mpctx, img->pts);
bool drop = false;
- bool hrseek = mpctx->hrseek_active
- && mpctx->video_status == STATUS_SYNCING;
- if (hrseek && img->pts < mpctx->hrseek_pts - .005)
- drop = true;
if ((endpts != MP_NOPTS_VALUE && img->pts >= endpts) ||
mpctx->max_frames == 0)
{
drop = true;
r = VD_EOF;
}
+ if (!drop && hrseek && mpctx->hrseek_lastframe) {
+ mp_image_setrefp(&mpctx->saved_frame, img);
+ drop = true;
+ }
+ if (hrseek && img->pts < mpctx->hrseek_pts - .005)
+ drop = true;
if (drop) {
talloc_free(img);
} else {
@@ -613,6 +618,13 @@ static int video_output_image(struct MPContext *mpctx, double endpts)
if (have_new_frame(mpctx) || (r <= 0 && mpctx->next_frame[0]))
return VD_NEW_FRAME;
+ // Last-frame seek
+ if (r <= 0 && hrseek && mpctx->hrseek_lastframe && mpctx->saved_frame) {
+ mpctx->next_frame[1] = mpctx->saved_frame;
+ mpctx->saved_frame = NULL;
+ return VD_PROGRESS;
+ }
+
return r;
}