1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2025-08-10 06:10:52 +02:00

vf_deinterlace_vaapi: Add support for field rate output

In order to work correctly with the i965 driver, this also fixes the
direction of forward/backward references - forward references are
intended to be those from the past to the current frame, not from the
current frame to the future.

(cherry picked from commit 9aa251c98c)
This commit is contained in:
Mark Thompson
2017-02-27 21:29:46 +00:00
parent 527a1e2131
commit bff7bec1d7

View File

@@ -22,6 +22,7 @@
#include <va/va_vpp.h> #include <va/va_vpp.h>
#include "libavutil/avassert.h" #include "libavutil/avassert.h"
#include "libavutil/common.h"
#include "libavutil/hwcontext.h" #include "libavutil/hwcontext.h"
#include "libavutil/hwcontext_vaapi.h" #include "libavutil/hwcontext_vaapi.h"
#include "libavutil/mem.h" #include "libavutil/mem.h"
@@ -42,6 +43,8 @@ typedef struct DeintVAAPIContext {
AVBufferRef *device_ref; AVBufferRef *device_ref;
int mode; int mode;
int field_rate;
int auto_enable;
int valid_ids; int valid_ids;
VAConfigID va_config; VAConfigID va_config;
@@ -63,6 +66,7 @@ typedef struct DeintVAAPIContext {
int queue_depth; int queue_depth;
int queue_count; int queue_count;
AVFrame *frame_queue[MAX_REFERENCES]; AVFrame *frame_queue[MAX_REFERENCES];
int extra_delay_for_timestamps;
VABufferID filter_buffer; VABufferID filter_buffer;
} DeintVAAPIContext; } DeintVAAPIContext;
@@ -211,8 +215,12 @@ static int deint_vaapi_build_filter_params(AVFilterContext *avctx)
return AVERROR(EIO); return AVERROR(EIO);
} }
ctx->extra_delay_for_timestamps = ctx->field_rate == 2 &&
ctx->pipeline_caps.num_backward_references == 0;
ctx->queue_depth = ctx->pipeline_caps.num_backward_references + ctx->queue_depth = ctx->pipeline_caps.num_backward_references +
ctx->pipeline_caps.num_forward_references + 1; ctx->pipeline_caps.num_forward_references +
ctx->extra_delay_for_timestamps + 1;
if (ctx->queue_depth > MAX_REFERENCES) { if (ctx->queue_depth > MAX_REFERENCES) {
av_log(avctx, AV_LOG_ERROR, "Pipeline requires too many " av_log(avctx, AV_LOG_ERROR, "Pipeline requires too many "
"references (%u forward, %u back).\n", "references (%u forward, %u back).\n",
@@ -227,6 +235,7 @@ static int deint_vaapi_build_filter_params(AVFilterContext *avctx)
static int deint_vaapi_config_output(AVFilterLink *outlink) static int deint_vaapi_config_output(AVFilterLink *outlink)
{ {
AVFilterContext *avctx = outlink->src; AVFilterContext *avctx = outlink->src;
AVFilterLink *inlink = avctx->inputs[0];
DeintVAAPIContext *ctx = avctx->priv; DeintVAAPIContext *ctx = avctx->priv;
AVVAAPIHWConfig *hwconfig = NULL; AVVAAPIHWConfig *hwconfig = NULL;
AVHWFramesConstraints *constraints = NULL; AVHWFramesConstraints *constraints = NULL;
@@ -326,8 +335,13 @@ static int deint_vaapi_config_output(AVFilterLink *outlink)
if (err < 0) if (err < 0)
goto fail; goto fail;
outlink->w = ctx->output_width; outlink->w = inlink->w;
outlink->h = ctx->output_height; outlink->h = inlink->h;
outlink->time_base = av_mul_q(inlink->time_base,
(AVRational) { 1, ctx->field_rate });
outlink->frame_rate = av_mul_q(inlink->frame_rate,
(AVRational) { ctx->field_rate, 1 });
outlink->hw_frames_ctx = av_buffer_ref(ctx->output_frames_ref); outlink->hw_frames_ctx = av_buffer_ref(ctx->output_frames_ref);
if (!outlink->hw_frames_ctx) { if (!outlink->hw_frames_ctx) {
@@ -375,7 +389,7 @@ static int deint_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame)
VABufferID params_id; VABufferID params_id;
VAStatus vas; VAStatus vas;
void *filter_params_addr = NULL; void *filter_params_addr = NULL;
int err, i; int err, i, field, current_frame_index;
av_log(avctx, AV_LOG_DEBUG, "Filter input: %s, %ux%u (%"PRId64").\n", av_log(avctx, AV_LOG_DEBUG, "Filter input: %s, %ux%u (%"PRId64").\n",
av_get_pix_fmt_name(input_frame->format), av_get_pix_fmt_name(input_frame->format),
@@ -394,17 +408,16 @@ static int deint_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame)
ctx->frame_queue[i] = input_frame; ctx->frame_queue[i] = input_frame;
} }
input_frame = current_frame_index = ctx->pipeline_caps.num_forward_references;
ctx->frame_queue[ctx->pipeline_caps.num_backward_references];
input_frame = ctx->frame_queue[current_frame_index];
input_surface = (VASurfaceID)(uintptr_t)input_frame->data[3]; input_surface = (VASurfaceID)(uintptr_t)input_frame->data[3];
for (i = 0; i < ctx->pipeline_caps.num_backward_references; i++)
backward_references[i] = (VASurfaceID)(uintptr_t)
ctx->frame_queue[ctx->pipeline_caps.num_backward_references -
i - 1]->data[3];
for (i = 0; i < ctx->pipeline_caps.num_forward_references; i++) for (i = 0; i < ctx->pipeline_caps.num_forward_references; i++)
forward_references[i] = (VASurfaceID)(uintptr_t) forward_references[i] = (VASurfaceID)(uintptr_t)
ctx->frame_queue[ctx->pipeline_caps.num_backward_references + ctx->frame_queue[current_frame_index - i - 1]->data[3];
i + 1]->data[3]; for (i = 0; i < ctx->pipeline_caps.num_backward_references; i++)
backward_references[i] = (VASurfaceID)(uintptr_t)
ctx->frame_queue[current_frame_index + i + 1]->data[3];
av_log(avctx, AV_LOG_DEBUG, "Using surface %#x for " av_log(avctx, AV_LOG_DEBUG, "Using surface %#x for "
"deinterlace input.\n", input_surface); "deinterlace input.\n", input_surface);
@@ -417,19 +430,14 @@ static int deint_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame)
av_log(avctx, AV_LOG_DEBUG, " %#x", forward_references[i]); av_log(avctx, AV_LOG_DEBUG, " %#x", forward_references[i]);
av_log(avctx, AV_LOG_DEBUG, "\n"); av_log(avctx, AV_LOG_DEBUG, "\n");
output_frame = av_frame_alloc(); for (field = 0; field < ctx->field_rate; field++) {
output_frame = ff_get_video_buffer(outlink, ctx->output_width,
ctx->output_height);
if (!output_frame) { if (!output_frame) {
err = AVERROR(ENOMEM); err = AVERROR(ENOMEM);
goto fail; goto fail;
} }
err = av_hwframe_get_buffer(ctx->output_frames_ref,
output_frame, 0);
if (err < 0) {
err = AVERROR(ENOMEM);
goto fail;
}
output_surface = (VASurfaceID)(uintptr_t)output_frame->data[3]; output_surface = (VASurfaceID)(uintptr_t)output_frame->data[3];
av_log(avctx, AV_LOG_DEBUG, "Using surface %#x for " av_log(avctx, AV_LOG_DEBUG, "Using surface %#x for "
"deinterlace output.\n", output_surface); "deinterlace output.\n", output_surface);
@@ -445,8 +453,8 @@ static int deint_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame)
params.surface = input_surface; params.surface = input_surface;
params.surface_region = &input_region; params.surface_region = &input_region;
params.surface_color_standard = vaapi_proc_colour_standard( params.surface_color_standard =
input_frame->colorspace); vaapi_proc_colour_standard(input_frame->colorspace);
params.output_region = NULL; params.output_region = NULL;
params.output_background_color = 0xff000000; params.output_background_color = 0xff000000;
@@ -455,6 +463,7 @@ static int deint_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame)
params.pipeline_flags = 0; params.pipeline_flags = 0;
params.filter_flags = VA_FRAME_PICTURE; params.filter_flags = VA_FRAME_PICTURE;
if (!ctx->auto_enable || input_frame->interlaced_frame) {
vas = vaMapBuffer(ctx->hwctx->display, ctx->filter_buffer, vas = vaMapBuffer(ctx->hwctx->display, ctx->filter_buffer,
&filter_params_addr); &filter_params_addr);
if (vas != VA_STATUS_SUCCESS) { if (vas != VA_STATUS_SUCCESS) {
@@ -465,8 +474,12 @@ static int deint_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame)
} }
filter_params = filter_params_addr; filter_params = filter_params_addr;
filter_params->flags = 0; filter_params->flags = 0;
if (input_frame->interlaced_frame && !input_frame->top_field_first) if (input_frame->top_field_first) {
filter_params->flags |= field ? VA_DEINTERLACING_BOTTOM_FIELD : 0;
} else {
filter_params->flags |= VA_DEINTERLACING_BOTTOM_FIELD_FIRST; filter_params->flags |= VA_DEINTERLACING_BOTTOM_FIELD_FIRST;
filter_params->flags |= field ? 0 : VA_DEINTERLACING_BOTTOM_FIELD;
}
filter_params_addr = NULL; filter_params_addr = NULL;
vas = vaUnmapBuffer(ctx->hwctx->display, ctx->filter_buffer); vas = vaUnmapBuffer(ctx->hwctx->display, ctx->filter_buffer);
if (vas != VA_STATUS_SUCCESS) if (vas != VA_STATUS_SUCCESS)
@@ -483,6 +496,11 @@ static int deint_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame)
params.num_backward_references = params.num_backward_references =
ctx->pipeline_caps.num_backward_references; ctx->pipeline_caps.num_backward_references;
} else {
params.filters = NULL;
params.num_filters = 0;
}
vas = vaBeginPicture(ctx->hwctx->display, vas = vaBeginPicture(ctx->hwctx->display,
ctx->va_context, output_surface); ctx->va_context, output_surface);
if (vas != VA_STATUS_SUCCESS) { if (vas != VA_STATUS_SUCCESS) {
@@ -535,11 +553,25 @@ static int deint_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame)
if (err < 0) if (err < 0)
goto fail; goto fail;
if (ctx->field_rate == 2) {
if (field == 0)
output_frame->pts = 2 * input_frame->pts;
else
output_frame->pts = input_frame->pts +
ctx->frame_queue[current_frame_index + 1]->pts;
}
output_frame->interlaced_frame = 0;
av_log(avctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64").\n", av_log(avctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64").\n",
av_get_pix_fmt_name(output_frame->format), av_get_pix_fmt_name(output_frame->format),
output_frame->width, output_frame->height, output_frame->pts); output_frame->width, output_frame->height, output_frame->pts);
return ff_filter_frame(outlink, output_frame); err = ff_filter_frame(outlink, output_frame);
if (err < 0)
break;
}
return err;
fail_after_begin: fail_after_begin:
vaRenderPicture(ctx->hwctx->display, ctx->va_context, &params_id, 1); vaRenderPicture(ctx->hwctx->display, ctx->va_context, &params_id, 1);
@@ -592,6 +624,17 @@ static const AVOption deint_vaapi_options[] = {
0, AV_OPT_TYPE_CONST, { .i64 = VAProcDeinterlacingMotionAdaptive }, .unit = "mode" }, 0, AV_OPT_TYPE_CONST, { .i64 = VAProcDeinterlacingMotionAdaptive }, .unit = "mode" },
{ "motion_compensated", "Use the motion compensated deinterlacing algorithm", { "motion_compensated", "Use the motion compensated deinterlacing algorithm",
0, AV_OPT_TYPE_CONST, { .i64 = VAProcDeinterlacingMotionCompensated }, .unit = "mode" }, 0, AV_OPT_TYPE_CONST, { .i64 = VAProcDeinterlacingMotionCompensated }, .unit = "mode" },
{ "rate", "Generate output at frame rate or field rate",
OFFSET(field_rate), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, 2, FLAGS, "rate" },
{ "frame", "Output at frame rate (one frame of output for each field-pair)",
0, AV_OPT_TYPE_CONST, { .i64 = 1 }, .unit = "rate" },
{ "field", "Output at field rate (one frame of output for each field)",
0, AV_OPT_TYPE_CONST, { .i64 = 2 }, .unit = "rate" },
{ "auto", "Only deinterlace fields, passing frames through unchanged",
OFFSET(auto_enable), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS },
{ NULL }, { NULL },
}; };