mirror of https://github.com/mpv-player/mpv
video: refactor aspects of queue and EOF handling
Instead of touching the 2-entry queue in mpctx->next_frame directly, move some of it to functions.
This commit is contained in:
parent
45ff6cef62
commit
7977961671
103
player/video.c
103
player/video.c
|
@ -547,11 +547,60 @@ static void adjust_sync(struct MPContext *mpctx, double v_pts, double frame_time
|
||||||
mpctx->total_avsync_change += change;
|
mpctx->total_avsync_change += change;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Move the frame in next_frame[1] to next_frame[0]. This makes the frame
|
||||||
|
// "known" to the playback logic. A frame in next_frame[0] is either "known" or
|
||||||
|
// NULL, so the moving must always be done by this function.
|
||||||
|
static void shift_new_frame(struct MPContext *mpctx)
|
||||||
|
{
|
||||||
|
if (mpctx->next_frame[0] || !mpctx->next_frame[1])
|
||||||
|
return;
|
||||||
|
|
||||||
|
mpctx->next_frame[0] = mpctx->next_frame[1];
|
||||||
|
mpctx->next_frame[1] = NULL;
|
||||||
|
|
||||||
|
double frame_time = 0;
|
||||||
|
double pts = mpctx->next_frame[0]->pts;
|
||||||
|
if (mpctx->video_pts != MP_NOPTS_VALUE) {
|
||||||
|
frame_time = pts - mpctx->video_pts;
|
||||||
|
if (frame_time <= 0 || frame_time >= 60) {
|
||||||
|
// Assume a PTS difference >= 60 seconds is a discontinuity.
|
||||||
|
MP_WARN(mpctx, "Invalid video timestamp: %f -> %f\n",
|
||||||
|
mpctx->video_pts, pts);
|
||||||
|
frame_time = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mpctx->video_next_pts = pts;
|
||||||
|
mpctx->delay -= frame_time;
|
||||||
|
if (mpctx->video_status >= STATUS_PLAYING) {
|
||||||
|
mpctx->time_frame += frame_time / mpctx->opts->playback_speed;
|
||||||
|
adjust_sync(mpctx, pts, frame_time);
|
||||||
|
}
|
||||||
|
mpctx->dropped_frames = 0;
|
||||||
|
MP_TRACE(mpctx, "frametime=%5.3f\n", frame_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Whether it's fine to call add_new_frame() now.
|
||||||
|
static bool needs_new_frame(struct MPContext *mpctx)
|
||||||
|
{
|
||||||
|
return !mpctx->next_frame[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Queue a frame to mpctx->next_frame[]. 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(frame);
|
||||||
|
mpctx->next_frame[1] = frame;
|
||||||
|
shift_new_frame(mpctx);
|
||||||
|
}
|
||||||
|
|
||||||
// Enough video filtered already to push one frame to the VO?
|
// Enough video filtered already to push one frame to the VO?
|
||||||
static bool have_new_frame(struct MPContext *mpctx)
|
// Set eof to true if no new frames are to be expected.
|
||||||
|
static bool have_new_frame(struct MPContext *mpctx, bool eof)
|
||||||
{
|
{
|
||||||
bool need_2nd = !!(mpctx->opts->frame_dropping & 1) // we need the duration
|
bool need_2nd = !!(mpctx->opts->frame_dropping & 1) // we need the duration
|
||||||
&& mpctx->video_pts != MP_NOPTS_VALUE; // ...except for the 1st frame
|
&& mpctx->video_pts != MP_NOPTS_VALUE // ...except for the 1st frame
|
||||||
|
&& !eof; // on EOF, drain the remaining frames
|
||||||
|
|
||||||
return mpctx->next_frame[0] && (!need_2nd || mpctx->next_frame[1]);
|
return mpctx->next_frame[0] && (!need_2nd || mpctx->next_frame[1]);
|
||||||
}
|
}
|
||||||
|
@ -575,40 +624,12 @@ static int video_output_image(struct MPContext *mpctx, double endpts)
|
||||||
return r <= 0 ? VD_EOF : VD_PROGRESS;
|
return r <= 0 ? VD_EOF : VD_PROGRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (have_new_frame(mpctx))
|
if (have_new_frame(mpctx, false))
|
||||||
return VD_NEW_FRAME;
|
|
||||||
|
|
||||||
if (!mpctx->next_frame[0] && mpctx->next_frame[1]) {
|
|
||||||
mpctx->next_frame[0] = mpctx->next_frame[1];
|
|
||||||
mpctx->next_frame[1] = NULL;
|
|
||||||
|
|
||||||
double frame_time = 0;
|
|
||||||
double pts = mpctx->next_frame[0]->pts;
|
|
||||||
if (mpctx->video_pts != MP_NOPTS_VALUE) {
|
|
||||||
frame_time = pts - mpctx->video_pts;
|
|
||||||
if (frame_time <= 0 || frame_time >= 60) {
|
|
||||||
// Assume a PTS difference >= 60 seconds is a discontinuity.
|
|
||||||
MP_WARN(mpctx, "Invalid video timestamp: %f -> %f\n",
|
|
||||||
mpctx->video_pts, pts);
|
|
||||||
frame_time = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mpctx->video_next_pts = pts;
|
|
||||||
mpctx->delay -= frame_time;
|
|
||||||
if (mpctx->video_status >= STATUS_PLAYING) {
|
|
||||||
mpctx->time_frame += frame_time / mpctx->opts->playback_speed;
|
|
||||||
adjust_sync(mpctx, pts, frame_time);
|
|
||||||
}
|
|
||||||
mpctx->dropped_frames = 0;
|
|
||||||
MP_TRACE(mpctx, "frametime=%5.3f\n", frame_time);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (have_new_frame(mpctx))
|
|
||||||
return VD_NEW_FRAME;
|
return VD_NEW_FRAME;
|
||||||
|
|
||||||
// Get a new frame if we need one.
|
// Get a new frame if we need one.
|
||||||
int r = VD_PROGRESS;
|
int r = VD_PROGRESS;
|
||||||
if (!mpctx->next_frame[1]) {
|
if (needs_new_frame(mpctx)) {
|
||||||
// Filter a new frame.
|
// Filter a new frame.
|
||||||
r = video_decode_and_filter(mpctx);
|
r = video_decode_and_filter(mpctx);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -634,23 +655,21 @@ static int video_output_image(struct MPContext *mpctx, double endpts)
|
||||||
if (drop) {
|
if (drop) {
|
||||||
talloc_free(img);
|
talloc_free(img);
|
||||||
} else {
|
} else {
|
||||||
mpctx->next_frame[1] = img;
|
add_new_frame(mpctx, img);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// On EOF, always allow the playloop to use the remaining frame.
|
|
||||||
if (have_new_frame(mpctx) || (r <= 0 && mpctx->next_frame[0]))
|
|
||||||
return VD_NEW_FRAME;
|
|
||||||
|
|
||||||
// Last-frame seek
|
// Last-frame seek
|
||||||
if (r <= 0 && hrseek && mpctx->hrseek_lastframe && mpctx->saved_frame) {
|
if (needs_new_frame(mpctx) && hrseek && mpctx->hrseek_lastframe &&
|
||||||
mpctx->next_frame[1] = mpctx->saved_frame;
|
mpctx->saved_frame)
|
||||||
|
{
|
||||||
|
add_new_frame(mpctx, mpctx->saved_frame);
|
||||||
mpctx->saved_frame = NULL;
|
mpctx->saved_frame = NULL;
|
||||||
return VD_PROGRESS;
|
r = VD_PROGRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
return r;
|
return have_new_frame(mpctx, r <= 0) ? VD_NEW_FRAME : r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update avsync before a new video frame is displayed. Actually, this can be
|
/* Update avsync before a new video frame is displayed. Actually, this can be
|
||||||
|
@ -852,6 +871,8 @@ void write_video(struct MPContext *mpctx, double endpts)
|
||||||
vo_queue_frame(vo, mpctx->next_frame[0], pts, duration);
|
vo_queue_frame(vo, mpctx->next_frame[0], pts, duration);
|
||||||
mpctx->next_frame[0] = NULL;
|
mpctx->next_frame[0] = NULL;
|
||||||
|
|
||||||
|
shift_new_frame(mpctx);
|
||||||
|
|
||||||
mpctx->shown_vframes++;
|
mpctx->shown_vframes++;
|
||||||
if (mpctx->video_status < STATUS_PLAYING) {
|
if (mpctx->video_status < STATUS_PLAYING) {
|
||||||
mpctx->video_status = STATUS_READY;
|
mpctx->video_status = STATUS_READY;
|
||||||
|
|
Loading…
Reference in New Issue