summaryrefslogtreecommitdiffstats
path: root/video/filter/vf_vavpp.c
diff options
context:
space:
mode:
Diffstat (limited to 'video/filter/vf_vavpp.c')
-rw-r--r--video/filter/vf_vavpp.c291
1 files changed, 114 insertions, 177 deletions
diff --git a/video/filter/vf_vavpp.c b/video/filter/vf_vavpp.c
index edee556232..608f1eea6f 100644
--- a/video/filter/vf_vavpp.c
+++ b/video/filter/vf_vavpp.c
@@ -25,8 +25,11 @@
#include "config.h"
#include "options/options.h"
-#include "vf.h"
+#include "filters/filter.h"
+#include "filters/filter_internal.h"
+#include "filters/user_filters.h"
#include "refqueue.h"
+
#include "video/fmt-conversion.h"
#include "video/vaapi.h"
#include "video/hwdec.h"
@@ -47,10 +50,14 @@ struct pipeline {
struct surface_refs forward, backward;
};
-struct vf_priv_s {
+struct opts {
int deint_type;
int interlaced_only;
int reversal_bug;
+};
+
+struct priv {
+ struct opts *opts;
bool do_deint;
VABufferID buffers[VAProcFilterCount];
int num_buffers;
@@ -65,15 +72,7 @@ struct vf_priv_s {
struct mp_refqueue *queue;
};
-static const struct vf_priv_s vf_priv_default = {
- .config = VA_INVALID_ID,
- .context = VA_INVALID_ID,
- .deint_type = 2,
- .interlaced_only = 1,
- .reversal_bug = 1,
-};
-
-static void add_surfaces(struct vf_priv_s *p, struct surface_refs *refs, int dir)
+static void add_surfaces(struct priv *p, struct surface_refs *refs, int dir)
{
for (int n = 0; n < refs->max_surfaces; n++) {
struct mp_image *s = mp_refqueue_get(p->queue, (1 + n) * dir);
@@ -96,18 +95,18 @@ static const int deint_algorithm[] = {
[5] = VAProcDeinterlacingMotionCompensated,
};
-static void flush_frames(struct vf_instance *vf)
+static void flush_frames(struct mp_filter *f)
{
- struct vf_priv_s *p = vf->priv;
+ struct priv *p = f->priv;
mp_refqueue_flush(p->queue);
}
-static void update_pipeline(struct vf_instance *vf)
+static void update_pipeline(struct mp_filter *vf)
{
- struct vf_priv_s *p = vf->priv;
+ struct priv *p = vf->priv;
VABufferID *filters = p->buffers;
int num_filters = p->num_buffers;
- if (p->deint_type && !p->do_deint) {
+ if (p->opts->deint_type && !p->do_deint) {
filters++;
num_filters--;
}
@@ -133,7 +132,7 @@ static void update_pipeline(struct vf_instance *vf)
p->pipe.num_output_colors = caps.num_output_color_standards;
p->pipe.forward.max_surfaces = caps.num_forward_references;
p->pipe.backward.max_surfaces = caps.num_backward_references;
- if (p->reversal_bug) {
+ if (p->opts->reversal_bug) {
int max = MPMAX(caps.num_forward_references, caps.num_backward_references);
mp_refqueue_set_refs(p->queue, max, max);
} else {
@@ -142,8 +141,8 @@ static void update_pipeline(struct vf_instance *vf)
}
mp_refqueue_set_mode(p->queue,
(p->do_deint ? MP_MODE_DEINT : 0) |
- (p->deint_type >= 2 ? MP_MODE_OUTPUT_FIELDS : 0) |
- (p->interlaced_only ? MP_MODE_INTERLACED_ONLY : 0));
+ (p->opts->deint_type >= 2 ? MP_MODE_OUTPUT_FIELDS : 0) |
+ (p->opts->interlaced_only ? MP_MODE_INTERLACED_ONLY : 0));
return;
nodeint:
@@ -151,9 +150,25 @@ nodeint:
mp_refqueue_set_mode(p->queue, 0);
}
-static struct mp_image *alloc_out(struct vf_instance *vf)
+static struct mp_image *alloc_out(struct mp_filter *vf)
{
- struct vf_priv_s *p = vf->priv;
+ struct priv *p = vf->priv;
+
+ struct mp_image *fmt = mp_refqueue_get_format(p->queue);
+ if (!fmt || !fmt->hwctx)
+ return NULL;
+
+ AVHWFramesContext *hw_frames = (void *)fmt->hwctx->data;
+ // VAAPI requires the full surface size to match for input and output.
+ int src_w = hw_frames->width;
+ int src_h = hw_frames->height;
+
+ if (!mp_update_av_hw_frames_pool(&p->hw_pool, p->av_device_ref,
+ IMGFMT_VAAPI, IMGFMT_NV12, src_w, src_h))
+ {
+ MP_ERR(vf, "Failed to create hw pool.\n");
+ return NULL;
+ }
AVFrame *av_frame = av_frame_alloc();
if (!av_frame)
@@ -169,13 +184,13 @@ static struct mp_image *alloc_out(struct vf_instance *vf)
MP_ERR(vf, "Unknown error.\n");
return NULL;
}
- mp_image_set_size(img, vf->fmt_in.w, vf->fmt_in.h);
+ mp_image_set_size(img, fmt->w, fmt->h);
return img;
}
-static struct mp_image *render(struct vf_instance *vf)
+static struct mp_image *render(struct mp_filter *vf)
{
- struct vf_priv_s *p = vf->priv;
+ struct priv *p = vf->priv;
struct mp_image *in = mp_refqueue_get(p->queue, 0);
struct mp_image *img = NULL;
@@ -184,7 +199,7 @@ static struct mp_image *render(struct vf_instance *vf)
VABufferID buffer = VA_INVALID_ID;
VASurfaceID in_id = va_surface_id(in);
- if (!p->pipe.filters || in_id == VA_INVALID_ID || !p->hw_pool)
+ if (!p->pipe.filters || in_id == VA_INVALID_ID)
goto cleanup;
img = alloc_out(vf);
@@ -243,7 +258,7 @@ static struct mp_image *render(struct vf_instance *vf)
param->filters = p->pipe.filters;
param->num_filters = p->pipe.num_filters;
- int dir = p->reversal_bug ? -1 : 1;
+ int dir = p->opts->reversal_bug ? -1 : 1;
add_surfaces(p, &p->pipe.forward, 1 * dir);
param->forward_references = p->pipe.forward.surfaces;
@@ -277,108 +292,29 @@ cleanup:
return NULL;
}
-static struct mp_image *upload(struct vf_instance *vf, struct mp_image *in)
-{
- // Since we do no scaling or csp conversion, we can allocate an output
- // surface for input too.
- struct mp_image *out = alloc_out(vf);
- if (!out)
- return NULL;
- if (!mp_image_hw_upload(out, in)) {
- talloc_free(out);
- return NULL;
- }
- mp_image_copy_attributes(out, in);
- return out;
-}
-
-static int filter_ext(struct vf_instance *vf, struct mp_image *in)
+static void vf_vavpp_process(struct mp_filter *f)
{
- struct vf_priv_s *p = vf->priv;
-
- update_pipeline(vf);
+ struct priv *p = f->priv;
- if (in && in->imgfmt != IMGFMT_VAAPI) {
- struct mp_image *tmp = upload(vf, in);
- talloc_free(in);
- in = tmp;
- if (!in)
- return -1;
- }
-
- mp_refqueue_add_input(p->queue, in);
- return 0;
-}
+ update_pipeline(f);
-static int filter_out(struct vf_instance *vf)
-{
- struct vf_priv_s *p = vf->priv;
+ mp_refqueue_execute_reinit(p->queue);
- if (!mp_refqueue_has_output(p->queue))
- return 0;
+ if (!mp_refqueue_can_output(p->queue))
+ return;
- // no filtering
if (!p->pipe.num_filters || !mp_refqueue_should_deint(p->queue)) {
+ // no filtering
struct mp_image *in = mp_refqueue_get(p->queue, 0);
- vf_add_output_frame(vf, mp_image_new_ref(in));
- mp_refqueue_next(p->queue);
- return 0;
- }
-
- struct mp_image *out = render(vf);
- mp_refqueue_next_field(p->queue);
- if (!out)
- return -1; // cannot render
- vf_add_output_frame(vf, out);
- return 0;
-}
-
-static int reconfig(struct vf_instance *vf, struct mp_image_params *in,
- struct mp_image_params *out)
-{
- struct vf_priv_s *p = vf->priv;
-
- flush_frames(vf);
- av_buffer_unref(&p->hw_pool);
-
- p->params = *in;
- *out = *in;
-
- int src_w = in->w;
- int src_h = in->h;
-
- if (in->imgfmt == IMGFMT_VAAPI) {
- if (!vf->in_hwframes_ref)
- return -1;
- AVHWFramesContext *hw_frames = (void *)vf->in_hwframes_ref->data;
- // VAAPI requires the full surface size to match for input and output.
- src_w = hw_frames->width;
- src_h = hw_frames->height;
+ mp_refqueue_write_out_pin(p->queue, mp_image_new_ref(in));
} else {
- out->imgfmt = IMGFMT_VAAPI;
- out->hw_subfmt = IMGFMT_NV12;
- }
-
- p->hw_pool = av_hwframe_ctx_alloc(p->av_device_ref);
- if (!p->hw_pool)
- return -1;
- AVHWFramesContext *hw_frames = (void *)p->hw_pool->data;
- hw_frames->format = AV_PIX_FMT_VAAPI;
- hw_frames->sw_format = imgfmt2pixfmt(out->hw_subfmt);
- hw_frames->width = src_w;
- hw_frames->height = src_h;
- if (av_hwframe_ctx_init(p->hw_pool) < 0) {
- MP_ERR(vf, "Failed to initialize libavutil vaapi frames pool.\n");
- av_buffer_unref(&p->hw_pool);
- return -1;
+ mp_refqueue_write_out_pin(p->queue, render(f));
}
-
- return 0;
}
-static void uninit(struct vf_instance *vf)
+static void uninit(struct mp_filter *vf)
{
- struct vf_priv_s *p = vf->priv;
+ struct priv *p = vf->priv;
for (int i = 0; i < p->num_buffers; i++)
vaDestroyBuffer(p->display, p->buffers[i]);
if (p->context != VA_INVALID_ID)
@@ -387,41 +323,23 @@ static void uninit(struct vf_instance *vf)
vaDestroyConfig(p->display, p->config);
av_buffer_unref(&p->hw_pool);
flush_frames(vf);
- mp_refqueue_free(p->queue);
+ talloc_free(p->queue);
av_buffer_unref(&p->av_device_ref);
}
-static int query_format(struct vf_instance *vf, unsigned int imgfmt)
-{
- if (imgfmt == IMGFMT_VAAPI || imgfmt == IMGFMT_NV12 || imgfmt == IMGFMT_420P)
- return vf_next_query_format(vf, IMGFMT_VAAPI);
- return 0;
-}
-
-static int control(struct vf_instance *vf, int request, void* data)
-{
- switch (request){
- case VFCTRL_SEEK_RESET:
- flush_frames(vf);
- return true;
- default:
- return CONTROL_UNKNOWN;
- }
-}
-
-static int va_query_filter_caps(struct vf_instance *vf, VAProcFilterType type,
+static int va_query_filter_caps(struct mp_filter *vf, VAProcFilterType type,
void *caps, unsigned int count)
{
- struct vf_priv_s *p = vf->priv;
+ struct priv *p = vf->priv;
VAStatus status = vaQueryVideoProcFilterCaps(p->display, p->context, type,
caps, &count);
return CHECK_VA_STATUS(vf, "vaQueryVideoProcFilterCaps()") ? count : 0;
}
-static VABufferID va_create_filter_buffer(struct vf_instance *vf, int bytes,
+static VABufferID va_create_filter_buffer(struct mp_filter *vf, int bytes,
int num, void *data)
{
- struct vf_priv_s *p = vf->priv;
+ struct priv *p = vf->priv;
VABufferID buffer;
VAStatus status = vaCreateBuffer(p->display, p->context,
VAProcFilterParameterBufferType,
@@ -429,9 +347,9 @@ static VABufferID va_create_filter_buffer(struct vf_instance *vf, int bytes,
return CHECK_VA_STATUS(vf, "vaCreateBuffer()") ? buffer : VA_INVALID_ID;
}
-static bool initialize(struct vf_instance *vf)
+static bool initialize(struct mp_filter *vf)
{
- struct vf_priv_s *p = vf->priv;
+ struct priv *p = vf->priv;
VAStatus status;
VAConfigID config;
@@ -458,14 +376,15 @@ static bool initialize(struct vf_instance *vf)
buffers[i] = VA_INVALID_ID;
for (int i = 0; i < num_filters; i++) {
if (filters[i] == VAProcFilterDeinterlacing) {
- if (p->deint_type < 1)
+ if (p->opts->deint_type < 1)
continue;
VAProcFilterCapDeinterlacing caps[VAProcDeinterlacingCount];
int num = va_query_filter_caps(vf, VAProcFilterDeinterlacing, caps,
VAProcDeinterlacingCount);
if (!num)
continue;
- VAProcDeinterlacingType algorithm = deint_algorithm[p->deint_type];
+ VAProcDeinterlacingType algorithm =
+ deint_algorithm[p->opts->deint_type];
for (int n=0; n < num; n++) { // find the algorithm
if (caps[n].type != algorithm)
continue;
@@ -482,47 +401,59 @@ static bool initialize(struct vf_instance *vf)
p->num_buffers = 0;
if (buffers[VAProcFilterDeinterlacing] != VA_INVALID_ID)
p->buffers[p->num_buffers++] = buffers[VAProcFilterDeinterlacing];
- p->do_deint = !!p->deint_type;
+ p->do_deint = !!p->opts->deint_type;
// next filters: p->buffers[p->num_buffers++] = buffers[next_filter];
return true;
}
-static int vf_open(vf_instance_t *vf)
+static const struct mp_filter_info vf_vavpp_filter = {
+ .name = "vavpp",
+ .process = vf_vavpp_process,
+ .reset = flush_frames,
+ .destroy = uninit,
+ .priv_size = sizeof(struct priv),
+};
+
+static struct mp_filter *vf_vavpp_create(struct mp_filter *parent, void *options)
{
- struct vf_priv_s *p = vf->priv;
-
- if (!vf->hwdec_devs)
- return 0;
-
- vf->reconfig = reconfig;
- vf->filter_ext = filter_ext;
- vf->filter_out = filter_out;
- vf->query_format = query_format;
- vf->uninit = uninit;
- vf->control = control;
-
- p->queue = mp_refqueue_alloc();
-
- hwdec_devices_request_all(vf->hwdec_devs);
- p->av_device_ref =
- hwdec_devices_get_lavc(vf->hwdec_devs, AV_HWDEVICE_TYPE_VAAPI);
- if (!p->av_device_ref) {
- uninit(vf);
- return 0;
+ struct mp_filter *f = mp_filter_create(parent, &vf_vavpp_filter);
+ if (!f) {
+ talloc_free(options);
+ return NULL;
}
+ mp_filter_add_pin(f, MP_PIN_IN, "in");
+ mp_filter_add_pin(f, MP_PIN_OUT, "out");
+
+ struct priv *p = f->priv;
+ p->opts = talloc_steal(p, options);
+ p->config = VA_INVALID_ID;
+ p->context = VA_INVALID_ID;
+
+ p->queue = mp_refqueue_alloc(f);
+
+ p->av_device_ref = mp_filter_load_hwdec_device(f, AV_HWDEVICE_TYPE_VAAPI);
+ if (!p->av_device_ref)
+ goto error;
+
AVHWDeviceContext *hwctx = (void *)p->av_device_ref->data;
AVVAAPIDeviceContext *vactx = hwctx->hwctx;
p->display = vactx->display;
- if (initialize(vf))
- return true;
- uninit(vf);
- return false;
+ mp_refqueue_add_in_format(p->queue, IMGFMT_VAAPI, 0);
+
+ if (!initialize(f))
+ goto error;
+
+ return f;
+
+error:
+ talloc_free(f);
+ return NULL;
}
-#define OPT_BASE_STRUCT struct vf_priv_s
+#define OPT_BASE_STRUCT struct opts
static const m_option_t vf_opts_fields[] = {
OPT_CHOICE("deint", deint_type, 0,
// The values must match with deint_algorithm[].
@@ -537,11 +468,17 @@ static const m_option_t vf_opts_fields[] = {
{0}
};
-const vf_info_t vf_info_vaapi = {
- .description = "VA-API Video Post-Process Filter",
- .name = "vavpp",
- .open = vf_open,
- .priv_size = sizeof(struct vf_priv_s),
- .priv_defaults = &vf_priv_default,
- .options = vf_opts_fields,
+const struct mp_user_filter_entry vf_vavpp = {
+ .desc = {
+ .description = "VA-API Video Post-Process Filter",
+ .name = "vavpp",
+ .priv_size = sizeof(OPT_BASE_STRUCT),
+ .priv_defaults = &(const OPT_BASE_STRUCT){
+ .deint_type = 2,
+ .interlaced_only = 1,
+ .reversal_bug = 1,
+ },
+ .options = vf_opts_fields,
+ },
+ .create = vf_vavpp_create,
};