static bool filter_output_queued_frame(struct MPContext *mpctx) { struct sh_video *sh_video = mpctx->sh_video; struct vo *video_out = mpctx->video_out; struct mp_image *img = vf_chain_output_queued_frame(sh_video->vfilter); if (img) vo_queue_image(video_out, img); talloc_free(img); return !!img; }
// Fill the VO buffer with a newly filtered or decoded image. // returns VD_* code static int video_output_image(struct MPContext *mpctx, double endpts, bool reconfig_ok) { struct vf_chain *vf = mpctx->d_video->vfilter; struct vo *vo = mpctx->video_out; // Already enough video buffered in VO? // (This implies vo_has_next_frame(vo, false/true) returns true.) if (!vo_needs_new_image(vo) && vo->params) return 1; // Filter a new frame. int r = video_decode_and_filter(mpctx); if (r < 0) return r; // error vf_output_frame(vf, false); if (vf->output) { double pts = vf->output->pts; // Always add these; they make backstepping after seeking faster. add_frame_pts(mpctx, pts); bool drop = false; bool hrseek = mpctx->hrseek_active && mpctx->video_status == STATUS_SYNCING && !mpctx->d_video->header->attached_picture; if (hrseek && pts < mpctx->hrseek_pts - .005) drop = true; if (endpts != MP_NOPTS_VALUE && pts >= endpts) { drop = true; r = VD_EOF; } if (drop) { talloc_free(vf->output); vf->output = NULL; return r; } } // Filter output is different from VO input? bool need_vo_reconfig = !vo->params || !mp_image_params_equal(&vf->output_params, vo->params); if (need_vo_reconfig) { // Draining VO buffers. if (vo_has_next_frame(vo, true)) return 0; // EOF so that caller displays remaining VO frames // There was no decoded image yet - must not signal fake EOF. // Likewise, if there's no filtered frame yet, don't reconfig yet. if (!vf->output_params.imgfmt || !vf->output) return r; // Force draining. if (!reconfig_ok) return 0; struct mp_image_params p = vf->output_params; const struct vo_driver *info = mpctx->video_out->driver; MP_INFO(mpctx, "VO: [%s] %dx%d => %dx%d %s\n", info->name, p.w, p.h, p.d_w, p.d_h, vo_format_name(p.imgfmt)); MP_VERBOSE(mpctx, "VO: Description: %s\n", info->description); int vo_r = vo_reconfig(vo, &p, 0); if (vo_r < 0) { vf->initialized = -1; return VD_ERROR; } init_vo(mpctx); // Display the frame queued after this immediately. // (Neutralizes frame time calculation in update_video.) mpctx->video_next_pts = MP_NOPTS_VALUE; } // Queue new frame, if there's one. struct mp_image *img = vf_read_output_frame(vf); if (img) { vo_queue_image(vo, img); return VD_PROGRESS; } return r; // includes the true EOF case }