From 9f42760538f02699945803f4a98b4dd8c4202774 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 27 May 2016 17:01:36 +0200 Subject: vf_vdpaupp: use refqueue helper This makes vf_vdpaupp use the deinterlacer helper code already used by vf_vavpp. I nice side-effect is that this also removes some traces of code originating from vo_vdpau.c, so we can switch it to LGPL. Extend the refqueue helper with a deint setting. If not set, mp_refqueue_should_deint() always returns false, which slightly simplifies vf_vdpaupp. It's of no consequence to vf_vavpp (other than it has to set it to get expected behavior). --- video/filter/vf_vdpaupp.c | 170 +++++++++++++++++----------------------------- 1 file changed, 64 insertions(+), 106 deletions(-) (limited to 'video/filter/vf_vdpaupp.c') diff --git a/video/filter/vf_vdpaupp.c b/video/filter/vf_vdpaupp.c index 23afeafe6a..077faba0b3 100644 --- a/video/filter/vf_vdpaupp.c +++ b/video/filter/vf_vdpaupp.c @@ -1,20 +1,18 @@ /* * This file is part of mpv. * - * Parts based on fragments of vo_vdpau.c: Copyright (C) 2009 Uoti Urpala - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * mpv is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. * * mpv is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . + * You should have received a copy of the GNU Lesser General Public + * License along with mpv. If not, see . */ #include @@ -33,6 +31,7 @@ #include "video/vdpau.h" #include "video/vdpau_mixer.h" #include "vf.h" +#include "refqueue.h" // Note: this filter does no actual filtering; it merely sets appropriate // flags on vdpau images (mp_vdpau_mixer_frame) to do the appropriate @@ -40,13 +39,7 @@ struct vf_priv_s { struct mp_vdpau_ctx *ctx; - - // This is needed to supply past/future fields and to calculate the - // interpolated timestamp. - struct mp_image *buffered[3]; - int num_buffered; - - int prev_pos; // last field that was output + struct mp_refqueue *queue; int def_deintmode; int deint_enabled; @@ -54,128 +47,89 @@ struct vf_priv_s { struct mp_vdpau_mixer_opts opts; }; -static void forget_frames(struct vf_instance *vf) +static int filter_ext(struct vf_instance *vf, struct mp_image *mpi) { struct vf_priv_s *p = vf->priv; - for (int n = 0; n < p->num_buffered; n++) - talloc_free(p->buffered[n]); - p->num_buffered = 0; - p->prev_pos = 0; -} -#define FIELD_VALID(p, f) ((f) >= 0 && (f) < (p)->num_buffered * 2) + if (p->opts.deint >= 2) { + mp_refqueue_set_refs(p->queue, 1, 1); // 2 past fields, 1 future field + } else { + mp_refqueue_set_refs(p->queue, 0, 0); + } + mp_refqueue_set_mode(p->queue, + (p->deint_enabled ? MP_MODE_DEINT : 0) | + (p->interlaced_only ? MP_MODE_INTERLACED_ONLY : 0) | + (p->opts.deint >= 2 ? MP_MODE_OUTPUT_FIELDS : 0)); + + if (mpi) { + struct mp_image *new = mp_vdpau_upload_video_surface(p->ctx, mpi); + talloc_free(mpi); + if (!new) + return -1; + mpi = new; + + if (mp_vdpau_mixed_frame_get(mpi)) { + MP_ERR(vf, "Can't apply vdpaupp filter multiple times.\n"); + vf_add_output_frame(vf, mpi); + return -1; + } + } + + mp_refqueue_add_input(p->queue, mpi); + return 0; +} static VdpVideoSurface ref_field(struct vf_priv_s *p, struct mp_vdpau_mixer_frame *frame, int pos) { - if (!FIELD_VALID(p, pos)) - return VDP_INVALID_HANDLE; - struct mp_image *mpi = mp_image_new_ref(p->buffered[pos / 2]); + struct mp_image *mpi = mp_image_new_ref(mp_refqueue_get_field(p->queue, pos)); if (!mpi) return VDP_INVALID_HANDLE; talloc_steal(frame, mpi); return (uintptr_t)mpi->planes[3]; } -// pos==0 means last field of latest frame, 1 earlier field of latest frame, -// 2 last field of previous frame and so on -static bool output_field(struct vf_instance *vf, int pos, bool deint) +static int filter_out(struct vf_instance *vf) { struct vf_priv_s *p = vf->priv; - if (!FIELD_VALID(p, pos)) - return false; + if (!mp_refqueue_has_output(p->queue)) + return 0; - struct mp_image *mpi = mp_vdpau_mixed_frame_create(p->buffered[pos / 2]); + struct mp_image *mpi = + mp_vdpau_mixed_frame_create(mp_refqueue_get_field(p->queue, 0)); if (!mpi) - return false; // skip output on OOM + return -1; // OOM struct mp_vdpau_mixer_frame *frame = mp_vdpau_mixed_frame_get(mpi); - frame->field = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME; - if (p->opts.deint && deint) { - int top_field_first = !!(mpi->fields & MP_IMGFIELD_TOP_FIRST); - frame->field = top_field_first ^ (pos & 1) ? - VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD: - VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD; + if (!mp_refqueue_should_deint(p->queue)) { + frame->field = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME; + } else if (mp_refqueue_is_top_field(p->queue)) { + frame->field = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD; + } else { + frame->field = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD; } - frame->future[0] = ref_field(p, frame, pos - 1); - frame->current = ref_field(p, frame, pos); - frame->past[0] = ref_field(p, frame, pos + 1); - frame->past[1] = ref_field(p, frame, pos + 2); + frame->future[0] = ref_field(p, frame, 1); + frame->current = ref_field(p, frame, 0); + frame->past[0] = ref_field(p, frame, -1); + frame->past[1] = ref_field(p, frame, -2); frame->opts = p->opts; mpi->planes[3] = (void *)(uintptr_t)frame->current; - // Interpolate timestamps of extra fields (these always have even indexes) - int idx = pos / 2; - if (idx > 0 && !(pos & 1) && p->opts.deint >= 2 && deint) { - double pts1 = p->buffered[idx - 1]->pts; - double pts2 = p->buffered[idx]->pts; - double diff = pts1 - pts2; - mpi->pts = diff > 0 && diff < 0.5 ? (pts1 + pts2) / 2 : pts2; - } + mp_refqueue_next_field(p->queue); vf_add_output_frame(vf, mpi); - return true; -} - -static int filter_ext(struct vf_instance *vf, struct mp_image *mpi) -{ - struct vf_priv_s *p = vf->priv; - int maxbuffer = p->opts.deint >= 2 ? 3 : 2; - bool eof = !mpi; - - if (mpi) { - struct mp_image *new = mp_vdpau_upload_video_surface(p->ctx, mpi); - talloc_free(mpi); - if (!new) - return -1; - mpi = new; - - if (mp_vdpau_mixed_frame_get(mpi)) { - MP_ERR(vf, "Can't apply vdpaupp filter multiple times.\n"); - vf_add_output_frame(vf, mpi); - return -1; - } - - while (p->num_buffered >= maxbuffer) { - talloc_free(p->buffered[p->num_buffered - 1]); - p->num_buffered--; - } - for (int n = p->num_buffered; n > 0; n--) - p->buffered[n] = p->buffered[n - 1]; - p->buffered[0] = mpi; - p->num_buffered++; - p->prev_pos += 2; - } - - bool deint = (mpi && (mpi->fields & MP_IMGFIELD_INTERLACED)) || !p->interlaced_only; - - while (1) { - int current = p->prev_pos - 1; - if (!FIELD_VALID(p, current)) - break; - // No field-splitting deinterlace -> only output first field (odd index) - if ((current & 1) || (deint && p->opts.deint >= 2)) { - // Wait for enough future frames being buffered. - // (Past frames are always around if available at all.) - if (!eof && !FIELD_VALID(p, current - 1)) - break; - if (!output_field(vf, current, deint)) - break; - } - p->prev_pos = current; - } - return 0; } static int reconfig(struct vf_instance *vf, struct mp_image_params *in, struct mp_image_params *out) { - forget_frames(vf); + struct vf_priv_s *p = vf->priv; + mp_refqueue_flush(p->queue); *out = *in; out->imgfmt = IMGFMT_VDPAU; return 0; @@ -194,7 +148,7 @@ static int control(vf_instance_t *vf, int request, void *data) switch (request) { case VFCTRL_SEEK_RESET: - forget_frames(vf); + mp_refqueue_flush(p->queue); return CONTROL_OK; case VFCTRL_GET_DEINTERLACE: *(int *)data = !!p->deint_enabled; @@ -209,7 +163,9 @@ static int control(vf_instance_t *vf, int request, void *data) static void uninit(struct vf_instance *vf) { - forget_frames(vf); + struct vf_priv_s *p = vf->priv; + + mp_refqueue_free(p->queue); } static int vf_open(vf_instance_t *vf) @@ -218,11 +174,13 @@ static int vf_open(vf_instance_t *vf) vf->reconfig = reconfig; vf->filter_ext = filter_ext; - vf->filter = NULL; + vf->filter_out = filter_out; vf->query_format = query_format; vf->control = control; vf->uninit = uninit; + p->queue = mp_refqueue_alloc(); + p->ctx = hwdec_devices_load(vf->hwdec_devs, HWDEC_VDPAU); if (!p->ctx) return 0; -- cgit v1.2.3