// Fill mpctx->next_frames[] with a newly filtered or decoded image. // 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; if (mpctx->num_next_frames >= 1) return VD_NEW_FRAME; int r = video_decode_and_filter(mpctx); video_filter(mpctx, true); // force EOF filtering (avoid decoding more) mpctx->next_frames[0] = vf_read_output_frame(mpctx->d_video->vfilter); if (mpctx->next_frames[0]) { mpctx->next_frames[0]->pts = MP_NOPTS_VALUE; mpctx->num_next_frames = 1; } return r <= 0 ? VD_EOF : VD_PROGRESS; } if (have_new_frame(mpctx, false)) return VD_NEW_FRAME; // Get a new frame if we need one. int r = VD_PROGRESS; if (needs_new_frame(mpctx)) { // Filter a new frame. r = video_decode_and_filter(mpctx); if (r < 0) 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) { r = VD_EOF; } else if (hrseek && mpctx->hrseek_lastframe) { mp_image_setrefp(&mpctx->saved_frame, img); } else if (hrseek && img->pts < mpctx->hrseek_pts - .005) { /* just skip */ } else { add_new_frame(mpctx, img); img = NULL; } talloc_free(img); } } // Last-frame seek if (r <= 0 && hrseek && mpctx->hrseek_lastframe && mpctx->saved_frame) { add_new_frame(mpctx, mpctx->saved_frame); mpctx->saved_frame = NULL; r = VD_PROGRESS; } return have_new_frame(mpctx, r <= 0) ? VD_NEW_FRAME : r; }
// Fill mpctx->next_frame[] with a newly filtered or decoded image. // 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; if (mpctx->next_frame[0]) return VD_NEW_FRAME; int r = video_decode_and_filter(mpctx); video_filter(mpctx, true); // force EOF filtering (avoid decoding more) mpctx->next_frame[0] = vf_read_output_frame(mpctx->d_video->vfilter); if (mpctx->next_frame[0]) mpctx->next_frame[0]->pts = MP_NOPTS_VALUE; return r <= 0 ? VD_EOF : VD_PROGRESS; } if (have_new_frame(mpctx)) 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 pts = mpctx->next_frame[0]->pts; double last_pts = mpctx->video_pts; if (last_pts == MP_NOPTS_VALUE) last_pts = pts; double frame_time = pts - last_pts; if (frame_time < 0 || frame_time >= 60) { // Assume a PTS difference >= 60 seconds is a discontinuity. MP_WARN(mpctx, "Jump in video pts: %f -> %f\n", last_pts, pts); frame_time = 0; } mpctx->video_next_pts = pts; if (mpctx->d_audio) mpctx->delay -= frame_time; if (mpctx->video_status >= STATUS_READY) { 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; // Get a new frame if we need one. int r = VD_PROGRESS; if (!mpctx->next_frame[1]) { // Filter a new frame. r = video_decode_and_filter(mpctx); if (r < 0) 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); bool drop = false; 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 { mpctx->next_frame[1] = 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 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; }