summaryrefslogtreecommitdiffstats
path: root/video/filter/vf.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-04-28 19:44:35 +0200
committerwm4 <wm4@nowhere>2014-04-28 22:23:31 +0200
commit42f65ce1083ca38605a8c775ee339cf0cc669cb8 (patch)
treef10e5c7b5e8646eb8b8c507f09866a76b68fd9d1 /video/filter/vf.c
parenta6dafb061fb4be0f02070acd92f8c6a0fde31823 (diff)
downloadmpv-42f65ce1083ca38605a8c775ee339cf0cc669cb8.tar.bz2
mpv-42f65ce1083ca38605a8c775ee339cf0cc669cb8.tar.xz
video: don't drop last frame when deinterlacing with yadif
Or in other words, add support for properly draining remaining frames from video filters. vf_yadif is buffering at least one frame, and the buffered frame was not retrieved on EOF. For most filters, ignore this for now, and just adjust them to the changed semantics of filter_ext. But for vf_lavfi (used by vf_yadif), real support is implemented. libavfilter handles this simply by passing a NULL frame to av_buffersrc_add_frame(), so we just have to make mp_to_av() handle NULL arguments. In load_next_vo_frame(), we first try to output a frame buffered in the VO, then the filter, and then (if EOF is reached and there's still no new frame) the VO again, with draining enabled. I guess this was implemented slightly incorrectly before, because the filter chain still could have had remaining output frames.
Diffstat (limited to 'video/filter/vf.c')
-rw-r--r--video/filter/vf.c20
1 files changed, 15 insertions, 5 deletions
diff --git a/video/filter/vf.c b/video/filter/vf.c
index 0d8f239721..021a0e21ae 100644
--- a/video/filter/vf.c
+++ b/video/filter/vf.c
@@ -363,14 +363,17 @@ static struct mp_image *vf_dequeue_output_frame(struct vf_instance *vf)
static int vf_do_filter(struct vf_instance *vf, struct mp_image *img)
{
assert(vf->fmt_in.imgfmt);
- vf_fix_img_params(img, &vf->fmt_in);
+ if (img)
+ vf_fix_img_params(img, &vf->fmt_in);
if (vf->filter_ext) {
return vf->filter_ext(vf, img);
} else {
- if (vf->filter)
- img = vf->filter(vf, img);
- vf_add_output_frame(vf, img);
+ if (img) {
+ if (vf->filter)
+ img = vf->filter(vf, img);
+ vf_add_output_frame(vf, img);
+ }
return 0;
}
}
@@ -379,6 +382,7 @@ static int vf_do_filter(struct vf_instance *vf, struct mp_image *img)
// Return >= 0 on success, < 0 on failure (even if output frames were produced)
int vf_filter_frame(struct vf_chain *c, struct mp_image *img)
{
+ assert(img);
if (c->initialized < 1) {
talloc_free(img);
return -1;
@@ -387,13 +391,19 @@ int vf_filter_frame(struct vf_chain *c, struct mp_image *img)
}
// Output the next queued image (if any) from the full filter chain.
-struct mp_image *vf_output_queued_frame(struct vf_chain *c)
+// eof: if set, assume there's no more input i.e. vf_filter_frame() will
+// not be called (until reset) - flush all internally delayed frames
+struct mp_image *vf_output_queued_frame(struct vf_chain *c, bool eof)
{
if (c->initialized < 1)
return NULL;
while (1) {
struct vf_instance *last = NULL;
for (struct vf_instance * cur = c->first; cur; cur = cur->next) {
+ // Flush remaining frames on EOF, but do that only if the previous
+ // filters have been flushed (i.e. they have no more output).
+ if (eof && !last)
+ vf_do_filter(cur, NULL);
if (cur->num_out_queued)
last = cur;
}