2013-09-20 13:55:13 +00:00
|
|
|
/*
|
|
|
|
* This file is part of mpv.
|
|
|
|
*
|
|
|
|
* 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 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.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with mpv. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <va/va.h>
|
|
|
|
#include <va/va_vpp.h>
|
|
|
|
|
|
|
|
#include "config.h"
|
2013-12-17 01:02:25 +00:00
|
|
|
#include "options/options.h"
|
2013-09-20 13:55:13 +00:00
|
|
|
#include "vf.h"
|
|
|
|
#include "video/vaapi.h"
|
2013-11-23 20:26:31 +00:00
|
|
|
#include "video/hwdec.h"
|
2014-03-17 17:22:25 +00:00
|
|
|
#include "video/mp_image_pool.h"
|
2013-09-20 13:55:13 +00:00
|
|
|
|
2013-12-21 17:11:01 +00:00
|
|
|
static bool check_error(struct vf_instance *vf, VAStatus status, const char *msg)
|
2013-09-20 13:55:13 +00:00
|
|
|
{
|
|
|
|
if (status == VA_STATUS_SUCCESS)
|
|
|
|
return true;
|
2013-12-21 17:11:01 +00:00
|
|
|
MP_ERR(vf, "%s: %s\n", msg, vaErrorStr(status));
|
2013-09-20 13:55:13 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct surface_refs {
|
|
|
|
VASurfaceID *surfaces;
|
|
|
|
int num_allocated;
|
|
|
|
int num_required;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct pipeline {
|
|
|
|
VABufferID *filters;
|
|
|
|
int num_filters;
|
|
|
|
VAProcColorStandardType input_colors[VAProcColorStandardCount];
|
|
|
|
VAProcColorStandardType output_colors[VAProcColorStandardCount];
|
|
|
|
int num_input_colors, num_output_colors;
|
|
|
|
struct surface_refs forward, backward;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct vf_priv_s {
|
|
|
|
double prev_pts;
|
|
|
|
int deint_type; // 0: none, 1: discard, 2: double fps
|
|
|
|
bool do_deint;
|
|
|
|
VABufferID buffers[VAProcFilterCount];
|
|
|
|
int num_buffers;
|
|
|
|
VAConfigID config;
|
|
|
|
VAContextID context;
|
|
|
|
struct mp_image_params params;
|
|
|
|
VADisplay display;
|
|
|
|
struct mp_vaapi_ctx *va;
|
|
|
|
struct pipeline pipe;
|
2014-03-17 17:22:25 +00:00
|
|
|
struct mp_image_pool *pool;
|
|
|
|
int current_rt_format;
|
2013-09-20 13:55:13 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const struct vf_priv_s vf_priv_default = {
|
|
|
|
.prev_pts = MP_NOPTS_VALUE,
|
|
|
|
.config = VA_INVALID_ID,
|
|
|
|
.context = VA_INVALID_ID,
|
|
|
|
.deint_type = 2,
|
|
|
|
};
|
|
|
|
|
2015-01-23 12:25:24 +00:00
|
|
|
// The array items must match with the "deint" suboption values.
|
|
|
|
static const int deint_algorithm[] = {
|
|
|
|
[0] = VAProcDeinterlacingNone,
|
|
|
|
[1] = VAProcDeinterlacingNone, // first-field, special-cased
|
|
|
|
[2] = VAProcDeinterlacingBob,
|
|
|
|
[3] = VAProcDeinterlacingWeave,
|
|
|
|
[4] = VAProcDeinterlacingMotionAdaptive,
|
|
|
|
[5] = VAProcDeinterlacingMotionCompensated,
|
|
|
|
};
|
|
|
|
|
2013-09-20 13:55:13 +00:00
|
|
|
static inline void realloc_refs(struct surface_refs *refs, int num)
|
|
|
|
{
|
|
|
|
if (refs->num_allocated < num) {
|
|
|
|
refs->surfaces = realloc(refs->surfaces, sizeof(VASurfaceID)*num);
|
|
|
|
refs->num_allocated = num;
|
|
|
|
}
|
|
|
|
refs->num_required = num;
|
|
|
|
}
|
|
|
|
|
2013-12-21 17:11:01 +00:00
|
|
|
static bool update_pipeline(struct vf_instance *vf, bool deint)
|
2013-09-20 13:55:13 +00:00
|
|
|
{
|
2013-12-21 17:11:01 +00:00
|
|
|
struct vf_priv_s *p = vf->priv;
|
2013-09-20 13:55:13 +00:00
|
|
|
VABufferID *filters = p->buffers;
|
|
|
|
int num_filters = p->num_buffers;
|
|
|
|
if (p->deint_type && !deint) {
|
|
|
|
++filters;
|
|
|
|
--num_filters;
|
|
|
|
}
|
|
|
|
if (filters == p->pipe.filters && num_filters == p->pipe.num_filters)
|
|
|
|
return true;
|
|
|
|
p->pipe.forward.num_required = p->pipe.backward.num_required = 0;
|
|
|
|
p->pipe.num_input_colors = p->pipe.num_output_colors = 0;
|
|
|
|
p->pipe.num_filters = 0;
|
|
|
|
p->pipe.filters = NULL;
|
|
|
|
if (!num_filters)
|
|
|
|
return false;
|
|
|
|
VAProcPipelineCaps caps;
|
|
|
|
caps.input_color_standards = p->pipe.input_colors;
|
|
|
|
caps.output_color_standards = p->pipe.output_colors;
|
|
|
|
caps.num_input_color_standards = VAProcColorStandardCount;
|
|
|
|
caps.num_output_color_standards = VAProcColorStandardCount;
|
|
|
|
VAStatus status = vaQueryVideoProcPipelineCaps(p->display, p->context,
|
|
|
|
filters, num_filters, &caps);
|
2013-12-21 17:11:01 +00:00
|
|
|
if (!check_error(vf, status, "vaQueryVideoProcPipelineCaps()"))
|
2013-09-20 13:55:13 +00:00
|
|
|
return false;
|
|
|
|
p->pipe.filters = filters;
|
|
|
|
p->pipe.num_filters = num_filters;
|
|
|
|
p->pipe.num_input_colors = caps.num_input_color_standards;
|
|
|
|
p->pipe.num_output_colors = caps.num_output_color_standards;
|
|
|
|
realloc_refs(&p->pipe.forward, caps.num_forward_references);
|
|
|
|
realloc_refs(&p->pipe.backward, caps.num_backward_references);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int get_deint_field(struct vf_priv_s *p, int i,
|
|
|
|
const struct mp_image *mpi)
|
|
|
|
{
|
|
|
|
if (!p->do_deint || !(mpi->fields & MP_IMGFIELD_INTERLACED))
|
|
|
|
return VA_FRAME_PICTURE;
|
|
|
|
return !!(mpi->fields & MP_IMGFIELD_TOP_FIRST) ^ i ? VA_TOP_FIELD : VA_BOTTOM_FIELD;
|
|
|
|
}
|
|
|
|
|
2014-03-17 17:22:35 +00:00
|
|
|
static struct mp_image *render(struct vf_instance *vf, struct mp_image *in,
|
2013-09-20 13:55:13 +00:00
|
|
|
unsigned int flags)
|
|
|
|
{
|
2013-12-21 17:11:01 +00:00
|
|
|
struct vf_priv_s *p = vf->priv;
|
2014-03-17 17:22:35 +00:00
|
|
|
VASurfaceID in_id = va_surface_id(in);
|
|
|
|
if (!p->pipe.filters || in_id == VA_INVALID_ID)
|
2013-09-20 13:55:13 +00:00
|
|
|
return NULL;
|
2014-03-17 17:22:25 +00:00
|
|
|
struct mp_image *img = mp_image_pool_get(p->pool, IMGFMT_VAAPI, in->w, in->h);
|
|
|
|
if (!img)
|
2013-09-20 13:55:13 +00:00
|
|
|
return NULL;
|
|
|
|
enum {Begun = 1, Rendered = 2};
|
|
|
|
int state = 0;
|
|
|
|
do { // not a loop, just for break
|
2014-03-17 17:22:35 +00:00
|
|
|
VASurfaceID id = va_surface_id(img);
|
2014-03-17 17:22:25 +00:00
|
|
|
if (id == VA_INVALID_ID)
|
|
|
|
break;
|
|
|
|
VAStatus status = vaBeginPicture(p->display, p->context, id);
|
2013-12-21 17:11:01 +00:00
|
|
|
if (!check_error(vf, status, "vaBeginPicture()"))
|
2013-09-20 13:55:13 +00:00
|
|
|
break;
|
|
|
|
state |= Begun;
|
|
|
|
VABufferID buffer = VA_INVALID_ID;
|
|
|
|
VAProcPipelineParameterBuffer *param = NULL;
|
|
|
|
status = vaCreateBuffer(p->display, p->context,
|
|
|
|
VAProcPipelineParameterBufferType,
|
|
|
|
sizeof(*param), 1, NULL, &buffer);
|
2013-12-21 17:11:01 +00:00
|
|
|
if (!check_error(vf, status, "vaCreateBuffer()"))
|
2013-09-20 13:55:13 +00:00
|
|
|
break;
|
|
|
|
status = vaMapBuffer(p->display, buffer, (void**)¶m);
|
2013-12-21 17:11:01 +00:00
|
|
|
if (!check_error(vf, status, "vaMapBuffer()"))
|
2013-09-20 13:55:13 +00:00
|
|
|
break;
|
2015-05-15 08:34:39 +00:00
|
|
|
|
2015-03-08 18:58:58 +00:00
|
|
|
VAProcFilterParameterBufferDeinterlacing *filter_params;
|
|
|
|
status = vaMapBuffer(p->display, *(p->pipe.filters), (void**)&filter_params);
|
|
|
|
if (!check_error(vf, status, "vaMapBuffer()"))
|
|
|
|
break;
|
|
|
|
filter_params->flags = flags & VA_TOP_FIELD ? 0 : VA_DEINTERLACING_BOTTOM_FIELD;
|
|
|
|
vaUnmapBuffer(p->display, *(p->pipe.filters));
|
2015-05-15 08:34:39 +00:00
|
|
|
|
2014-03-17 17:22:35 +00:00
|
|
|
param->surface = in_id;
|
2013-09-20 13:55:13 +00:00
|
|
|
param->surface_region = NULL;
|
|
|
|
param->output_region = NULL;
|
|
|
|
param->output_background_color = 0;
|
|
|
|
param->filter_flags = flags;
|
|
|
|
param->filters = p->pipe.filters;
|
|
|
|
param->num_filters = p->pipe.num_filters;
|
|
|
|
vaUnmapBuffer(p->display, buffer);
|
|
|
|
param->forward_references = p->pipe.forward.surfaces;
|
|
|
|
param->backward_references = p->pipe.backward.surfaces;
|
|
|
|
param->num_forward_references = p->pipe.forward.num_required;
|
|
|
|
param->num_backward_references = p->pipe.backward.num_required;
|
|
|
|
status = vaRenderPicture(p->display, p->context, &buffer, 1);
|
2013-12-21 17:11:01 +00:00
|
|
|
if (!check_error(vf, status, "vaRenderPicture()"))
|
2013-09-20 13:55:13 +00:00
|
|
|
break;
|
|
|
|
state |= Rendered;
|
|
|
|
} while (false);
|
|
|
|
if (state & Begun)
|
|
|
|
vaEndPicture(p->display, p->context);
|
|
|
|
if (state & Rendered)
|
2014-03-17 17:22:25 +00:00
|
|
|
return img;
|
|
|
|
talloc_free(img);
|
2013-09-20 13:55:13 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// return value: the number of created images
|
2013-12-21 17:11:01 +00:00
|
|
|
static int process(struct vf_instance *vf, struct mp_image *in,
|
2013-09-20 13:55:13 +00:00
|
|
|
struct mp_image **out1, struct mp_image **out2)
|
|
|
|
{
|
2013-12-21 17:11:01 +00:00
|
|
|
struct vf_priv_s *p = vf->priv;
|
2013-09-20 13:55:13 +00:00
|
|
|
const bool deint = p->do_deint && p->deint_type > 0;
|
2013-12-21 17:11:01 +00:00
|
|
|
if (!update_pipeline(vf, deint) || !p->pipe.filters) // no filtering
|
2013-09-20 13:55:13 +00:00
|
|
|
return 0;
|
|
|
|
const unsigned int csp = va_get_colorspace_flag(p->params.colorspace);
|
|
|
|
const unsigned int field = get_deint_field(p, 0, in);
|
2014-03-17 17:22:35 +00:00
|
|
|
*out1 = render(vf, in, field | csp);
|
2013-09-20 13:55:13 +00:00
|
|
|
if (!*out1) // cannot render
|
|
|
|
return 0;
|
|
|
|
mp_image_copy_attributes(*out1, in);
|
2015-01-23 12:25:24 +00:00
|
|
|
// first-field only
|
|
|
|
if (field == VA_FRAME_PICTURE || (p->do_deint && p->deint_type < 2))
|
2013-09-20 13:55:13 +00:00
|
|
|
return 1;
|
|
|
|
const double add = (in->pts - p->prev_pts)*0.5;
|
|
|
|
if (p->prev_pts == MP_NOPTS_VALUE || add <= 0.0 || add > 0.5) // no pts, skip it
|
|
|
|
return 1;
|
2014-03-17 17:22:35 +00:00
|
|
|
*out2 = render(vf, in, get_deint_field(p, 1, in) | csp);
|
2013-09-20 13:55:13 +00:00
|
|
|
if (!*out2) // cannot render
|
|
|
|
return 1;
|
|
|
|
mp_image_copy_attributes(*out2, in);
|
|
|
|
(*out2)->pts = in->pts + add;
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
2013-12-21 17:11:01 +00:00
|
|
|
static struct mp_image *upload(struct vf_instance *vf, struct mp_image *in)
|
2013-09-20 13:55:13 +00:00
|
|
|
{
|
2013-12-21 17:11:01 +00:00
|
|
|
struct vf_priv_s *p = vf->priv;
|
2014-03-17 17:22:25 +00:00
|
|
|
struct mp_image *out = mp_image_pool_get(p->pool, IMGFMT_VAAPI, in->w, in->h);
|
|
|
|
if (!out)
|
|
|
|
return NULL;
|
2014-03-17 17:22:35 +00:00
|
|
|
if (va_surface_upload(out, in) < 0) {
|
2014-03-17 17:22:25 +00:00
|
|
|
talloc_free(out);
|
|
|
|
return NULL;
|
|
|
|
}
|
2013-09-20 13:55:13 +00:00
|
|
|
mp_image_copy_attributes(out, in);
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int filter_ext(struct vf_instance *vf, struct mp_image *in)
|
|
|
|
{
|
|
|
|
struct vf_priv_s *p = vf->priv;
|
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.
2014-04-28 17:44:35 +00:00
|
|
|
if (!in)
|
|
|
|
return 0;
|
2014-03-17 17:22:35 +00:00
|
|
|
int rt_format = in->imgfmt == IMGFMT_VAAPI ? va_surface_rt_format(in)
|
|
|
|
: VA_RT_FORMAT_YUV420;
|
2014-03-17 17:22:25 +00:00
|
|
|
if (!p->pool || p->current_rt_format != rt_format) {
|
|
|
|
talloc_free(p->pool);
|
|
|
|
p->pool = mp_image_pool_new(20);
|
|
|
|
va_pool_set_allocator(p->pool, p->va, rt_format);
|
|
|
|
p->current_rt_format = rt_format;
|
2013-09-20 13:55:13 +00:00
|
|
|
}
|
2014-03-17 17:22:35 +00:00
|
|
|
if (in->imgfmt != IMGFMT_VAAPI) {
|
2013-12-21 17:11:01 +00:00
|
|
|
struct mp_image *tmp = upload(vf, in);
|
2013-09-20 13:55:13 +00:00
|
|
|
talloc_free(in);
|
|
|
|
in = tmp;
|
2014-03-17 17:22:25 +00:00
|
|
|
if (!in)
|
|
|
|
return -1;
|
2013-09-20 13:55:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct mp_image *out1, *out2;
|
|
|
|
const double pts = in->pts;
|
2013-12-21 17:11:01 +00:00
|
|
|
const int num = process(vf, in, &out1, &out2);
|
2013-09-20 13:55:13 +00:00
|
|
|
if (!num)
|
|
|
|
vf_add_output_frame(vf, in);
|
|
|
|
else {
|
|
|
|
vf_add_output_frame(vf, out1);
|
|
|
|
if (num > 1)
|
|
|
|
vf_add_output_frame(vf, out2);
|
|
|
|
talloc_free(in);
|
|
|
|
}
|
|
|
|
p->prev_pts = pts;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-12-07 18:35:55 +00:00
|
|
|
static int reconfig(struct vf_instance *vf, struct mp_image_params *in,
|
|
|
|
struct mp_image_params *out)
|
2013-09-20 13:55:13 +00:00
|
|
|
{
|
|
|
|
struct vf_priv_s *p = vf->priv;
|
|
|
|
|
|
|
|
p->prev_pts = MP_NOPTS_VALUE;
|
2013-12-07 18:35:55 +00:00
|
|
|
p->params = *in;
|
|
|
|
*out = *in;
|
|
|
|
out->imgfmt = IMGFMT_VAAPI;
|
|
|
|
return 0;
|
2013-09-20 13:55:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void uninit(struct vf_instance *vf)
|
|
|
|
{
|
|
|
|
struct vf_priv_s *p = vf->priv;
|
|
|
|
for (int i=0; i<p->num_buffers; ++i)
|
|
|
|
vaDestroyBuffer(p->display, p->buffers[i]);
|
|
|
|
if (p->context != VA_INVALID_ID)
|
|
|
|
vaDestroyContext(p->display, p->context);
|
|
|
|
if (p->config != VA_INVALID_ID)
|
|
|
|
vaDestroyConfig(p->display, p->config);
|
|
|
|
free(p->pipe.forward.surfaces);
|
|
|
|
free(p->pipe.backward.surfaces);
|
2014-03-17 17:22:25 +00:00
|
|
|
talloc_free(p->pool);
|
2013-09-20 13:55:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int query_format(struct vf_instance *vf, unsigned int imgfmt)
|
|
|
|
{
|
|
|
|
struct vf_priv_s *p = vf->priv;
|
2015-01-21 21:12:30 +00:00
|
|
|
if (imgfmt == IMGFMT_VAAPI || va_image_format_from_imgfmt(p->va, imgfmt))
|
2013-09-20 13:55:13 +00:00
|
|
|
return vf_next_query_format(vf, IMGFMT_VAAPI);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int control(struct vf_instance *vf, int request, void* data)
|
|
|
|
{
|
|
|
|
struct vf_priv_s *p = vf->priv;
|
|
|
|
switch (request){
|
|
|
|
case VFCTRL_GET_DEINTERLACE:
|
|
|
|
*(int*)data = !!p->do_deint;
|
|
|
|
return true;
|
|
|
|
case VFCTRL_SET_DEINTERLACE:
|
|
|
|
p->do_deint = *(int*)data;
|
|
|
|
return true;
|
|
|
|
default:
|
2013-12-07 18:33:38 +00:00
|
|
|
return CONTROL_UNKNOWN;
|
2013-09-20 13:55:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-21 17:11:01 +00:00
|
|
|
static int va_query_filter_caps(struct vf_instance *vf, VAProcFilterType type,
|
2013-09-20 13:55:13 +00:00
|
|
|
void *caps, unsigned int count)
|
|
|
|
{
|
2013-12-21 17:11:01 +00:00
|
|
|
struct vf_priv_s *p = vf->priv;
|
2013-09-20 13:55:13 +00:00
|
|
|
VAStatus status = vaQueryVideoProcFilterCaps(p->display, p->context, type,
|
|
|
|
caps, &count);
|
2013-12-21 17:11:01 +00:00
|
|
|
return check_error(vf, status, "vaQueryVideoProcFilterCaps()") ? count : 0;
|
2013-09-20 13:55:13 +00:00
|
|
|
}
|
|
|
|
|
2013-12-21 17:11:01 +00:00
|
|
|
static VABufferID va_create_filter_buffer(struct vf_instance *vf, int bytes,
|
2013-09-20 13:55:13 +00:00
|
|
|
int num, void *data)
|
|
|
|
{
|
2013-12-21 17:11:01 +00:00
|
|
|
struct vf_priv_s *p = vf->priv;
|
2013-09-20 13:55:13 +00:00
|
|
|
VABufferID buffer;
|
|
|
|
VAStatus status = vaCreateBuffer(p->display, p->context,
|
|
|
|
VAProcFilterParameterBufferType,
|
|
|
|
bytes, num, data, &buffer);
|
2013-12-21 17:11:01 +00:00
|
|
|
return check_error(vf, status, "vaCreateBuffer()") ? buffer : VA_INVALID_ID;
|
2013-09-20 13:55:13 +00:00
|
|
|
}
|
|
|
|
|
2013-12-21 17:11:01 +00:00
|
|
|
static bool initialize(struct vf_instance *vf)
|
2013-09-20 13:55:13 +00:00
|
|
|
{
|
2013-12-21 17:11:01 +00:00
|
|
|
struct vf_priv_s *p = vf->priv;
|
2013-09-20 13:55:13 +00:00
|
|
|
VAStatus status;
|
|
|
|
|
|
|
|
VAConfigID config;
|
|
|
|
status = vaCreateConfig(p->display, VAProfileNone, VAEntrypointVideoProc,
|
|
|
|
NULL, 0, &config);
|
2013-12-21 17:11:01 +00:00
|
|
|
if (!check_error(vf, status, "vaCreateConfig()")) // no entrypoint for video porc
|
2013-09-20 13:55:13 +00:00
|
|
|
return false;
|
|
|
|
p->config = config;
|
|
|
|
|
|
|
|
VAContextID context;
|
|
|
|
status = vaCreateContext(p->display, p->config, 0, 0, 0, NULL, 0, &context);
|
2013-12-21 17:11:01 +00:00
|
|
|
if (!check_error(vf, status, "vaCreateContext()"))
|
2013-09-20 13:55:13 +00:00
|
|
|
return false;
|
|
|
|
p->context = context;
|
|
|
|
|
|
|
|
VAProcFilterType filters[VAProcFilterCount];
|
|
|
|
int num_filters = VAProcFilterCount;
|
|
|
|
status = vaQueryVideoProcFilters(p->display, p->context, filters, &num_filters);
|
2013-12-21 17:11:01 +00:00
|
|
|
if (!check_error(vf, status, "vaQueryVideoProcFilters()"))
|
2013-09-20 13:55:13 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
VABufferID buffers[VAProcFilterCount];
|
|
|
|
for (int i=0; i<VAProcFilterCount; ++i)
|
|
|
|
buffers[i] = VA_INVALID_ID;
|
|
|
|
for (int i=0; i<num_filters; ++i) {
|
|
|
|
if (filters[i] == VAProcFilterDeinterlacing) {
|
2015-01-23 12:25:24 +00:00
|
|
|
if (p->deint_type < 2)
|
2013-09-20 13:55:13 +00:00
|
|
|
continue;
|
|
|
|
VAProcFilterCapDeinterlacing caps[VAProcDeinterlacingCount];
|
2013-12-21 17:11:01 +00:00
|
|
|
int num = va_query_filter_caps(vf, VAProcFilterDeinterlacing, caps,
|
2013-09-20 13:55:13 +00:00
|
|
|
VAProcDeinterlacingCount);
|
|
|
|
if (!num)
|
|
|
|
continue;
|
2015-01-23 12:25:24 +00:00
|
|
|
VAProcDeinterlacingType algorithm = deint_algorithm[p->deint_type];
|
|
|
|
for (int n=0; n < num; n++) { // find the algorithm
|
2013-11-01 12:00:15 +00:00
|
|
|
if (caps[n].type != algorithm)
|
2013-09-20 13:55:13 +00:00
|
|
|
continue;
|
|
|
|
VAProcFilterParameterBufferDeinterlacing param;
|
|
|
|
param.type = VAProcFilterDeinterlacing;
|
|
|
|
param.algorithm = algorithm;
|
|
|
|
buffers[VAProcFilterDeinterlacing] =
|
2013-12-21 17:11:01 +00:00
|
|
|
va_create_filter_buffer(vf, sizeof(param), 1, ¶m);
|
2013-09-20 13:55:13 +00:00
|
|
|
}
|
2015-01-23 12:25:24 +00:00
|
|
|
if (buffers[VAProcFilterDeinterlacing] == VA_INVALID_ID)
|
|
|
|
MP_WARN(vf, "Selected deinterlacing algorithm not supported.\n");
|
2013-09-20 13:55:13 +00:00
|
|
|
} // check other filters
|
|
|
|
}
|
|
|
|
p->num_buffers = 0;
|
|
|
|
if (buffers[VAProcFilterDeinterlacing] != VA_INVALID_ID)
|
|
|
|
p->buffers[p->num_buffers++] = buffers[VAProcFilterDeinterlacing];
|
|
|
|
p->do_deint = !!p->deint_type;
|
|
|
|
// next filters: p->buffers[p->num_buffers++] = buffers[next_filter];
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-12-03 23:01:38 +00:00
|
|
|
static int vf_open(vf_instance_t *vf)
|
2013-09-20 13:55:13 +00:00
|
|
|
{
|
|
|
|
vf->reconfig = reconfig;
|
|
|
|
vf->filter_ext = filter_ext;
|
|
|
|
vf->query_format = query_format;
|
|
|
|
vf->uninit = uninit;
|
|
|
|
vf->control = control;
|
|
|
|
|
|
|
|
struct vf_priv_s *p = vf->priv;
|
2015-01-22 14:32:23 +00:00
|
|
|
if (!vf->hwdec)
|
|
|
|
return false;
|
2013-12-07 18:32:44 +00:00
|
|
|
hwdec_request_api(vf->hwdec, "vaapi");
|
2015-01-22 14:32:23 +00:00
|
|
|
p->va = vf->hwdec->hwctx ? vf->hwdec->hwctx->vaapi_ctx : NULL;
|
2013-09-20 13:55:13 +00:00
|
|
|
if (!p->va || !p->va->display)
|
|
|
|
return false;
|
|
|
|
p->display = p->va->display;
|
2013-12-21 17:11:01 +00:00
|
|
|
if (initialize(vf))
|
2013-09-20 13:55:13 +00:00
|
|
|
return true;
|
|
|
|
uninit(vf);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define OPT_BASE_STRUCT struct vf_priv_s
|
|
|
|
static const m_option_t vf_opts_fields[] = {
|
|
|
|
OPT_CHOICE("deint", deint_type, 0,
|
2015-01-23 12:25:24 +00:00
|
|
|
// The values must match with deint_algorithm[].
|
2013-09-20 13:55:13 +00:00
|
|
|
({"no", 0},
|
|
|
|
{"first-field", 1},
|
2015-01-23 12:25:24 +00:00
|
|
|
{"bob", 2},
|
|
|
|
{"weave", 3},
|
|
|
|
{"motion-adaptive", 4},
|
|
|
|
{"motion-compensated", 5})),
|
2013-09-20 13:55:13 +00:00
|
|
|
{0}
|
|
|
|
};
|
|
|
|
|
|
|
|
const vf_info_t vf_info_vaapi = {
|
2013-10-23 17:06:42 +00:00
|
|
|
.description = "VA-API Video Post-Process Filter",
|
2013-09-20 13:55:13 +00:00
|
|
|
.name = "vavpp",
|
2013-10-23 17:06:42 +00:00
|
|
|
.open = vf_open,
|
2013-09-20 13:55:13 +00:00
|
|
|
.priv_size = sizeof(struct vf_priv_s),
|
|
|
|
.priv_defaults = &vf_priv_default,
|
|
|
|
.options = vf_opts_fields,
|
|
|
|
};
|