FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
vf_scale_vaapi.c
Go to the documentation of this file.
1 /*
2  * This file is part of FFmpeg.
3  *
4  * FFmpeg is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * FFmpeg is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with FFmpeg; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 #include <string.h>
20 
21 #include <va/va.h>
22 #include <va/va_vpp.h>
23 
24 #include "libavutil/avassert.h"
25 #include "libavutil/hwcontext.h"
27 #include "libavutil/mem.h"
28 #include "libavutil/opt.h"
29 #include "libavutil/pixdesc.h"
30 
31 #include "avfilter.h"
32 #include "formats.h"
33 #include "internal.h"
34 
35 typedef struct ScaleVAAPIContext {
36  const AVClass *class;
37 
40 
41  int valid_ids;
42  VAConfigID va_config;
43  VAContextID va_context;
44 
47 
50 
55 
57 
58 
60 {
61  enum AVPixelFormat pix_fmts[] = {
63  };
64 
66  &avctx->inputs[0]->out_formats);
68  &avctx->outputs[0]->in_formats);
69 
70  return 0;
71 }
72 
74 {
75  if (ctx->va_context != VA_INVALID_ID) {
76  vaDestroyContext(ctx->hwctx->display, ctx->va_context);
77  ctx->va_context = VA_INVALID_ID;
78  }
79 
80  if (ctx->va_config != VA_INVALID_ID) {
81  vaDestroyConfig(ctx->hwctx->display, ctx->va_config);
82  ctx->va_config = VA_INVALID_ID;
83  }
84 
87  ctx->hwctx = 0;
88 
89  return 0;
90 }
91 
93 {
94  AVFilterContext *avctx = inlink->dst;
95  ScaleVAAPIContext *ctx = avctx->priv;
96 
98 
99  if (!inlink->hw_frames_ctx) {
100  av_log(avctx, AV_LOG_ERROR, "A hardware frames reference is "
101  "required to associate the processing device.\n");
102  return AVERROR(EINVAL);
103  }
104 
107 
108  return 0;
109 }
110 
112 {
113  AVFilterContext *avctx = outlink->src;
114  ScaleVAAPIContext *ctx = avctx->priv;
115  AVVAAPIHWConfig *hwconfig = NULL;
116  AVHWFramesConstraints *constraints = NULL;
117  AVVAAPIFramesContext *va_frames;
118  VAStatus vas;
119  int err, i;
120 
122 
124  ctx->hwctx = ((AVHWDeviceContext*)ctx->device_ref->data)->hwctx;
125 
126  av_assert0(ctx->va_config == VA_INVALID_ID);
127  vas = vaCreateConfig(ctx->hwctx->display, VAProfileNone,
128  VAEntrypointVideoProc, 0, 0, &ctx->va_config);
129  if (vas != VA_STATUS_SUCCESS) {
130  av_log(ctx, AV_LOG_ERROR, "Failed to create processing pipeline "
131  "config: %d (%s).\n", vas, vaErrorStr(vas));
132  err = AVERROR(EIO);
133  goto fail;
134  }
135 
136  hwconfig = av_hwdevice_hwconfig_alloc(ctx->device_ref);
137  if (!hwconfig) {
138  err = AVERROR(ENOMEM);
139  goto fail;
140  }
141  hwconfig->config_id = ctx->va_config;
142 
144  hwconfig);
145  if (!constraints) {
146  err = AVERROR(ENOMEM);
147  goto fail;
148  }
149 
150  if (ctx->output_format == AV_PIX_FMT_NONE)
151  ctx->output_format = ctx->input_frames->sw_format;
152  if (constraints->valid_sw_formats) {
153  for (i = 0; constraints->valid_sw_formats[i] != AV_PIX_FMT_NONE; i++) {
154  if (ctx->output_format == constraints->valid_sw_formats[i])
155  break;
156  }
157  if (constraints->valid_sw_formats[i] == AV_PIX_FMT_NONE) {
158  av_log(ctx, AV_LOG_ERROR, "Hardware does not support output "
159  "format %s.\n", av_get_pix_fmt_name(ctx->output_format));
160  err = AVERROR(EINVAL);
161  goto fail;
162  }
163  }
164 
165  if (ctx->output_width < constraints->min_width ||
166  ctx->output_height < constraints->min_height ||
167  ctx->output_width > constraints->max_width ||
168  ctx->output_height > constraints->max_height) {
169  av_log(ctx, AV_LOG_ERROR, "Hardware does not support scaling to "
170  "size %dx%d (constraints: width %d-%d height %d-%d).\n",
171  ctx->output_width, ctx->output_height,
172  constraints->min_width, constraints->max_width,
173  constraints->min_height, constraints->max_height);
174  err = AVERROR(EINVAL);
175  goto fail;
176  }
177 
179  if (!ctx->output_frames_ref) {
180  av_log(ctx, AV_LOG_ERROR, "Failed to create HW frame context "
181  "for output.\n");
182  err = AVERROR(ENOMEM);
183  goto fail;
184  }
185 
187 
190  ctx->output_frames->width = ctx->output_width;
191  ctx->output_frames->height = ctx->output_height;
192 
193  // The number of output frames we need is determined by what follows
194  // the filter. If it's an encoder with complex frame reference
195  // structures then this could be very high.
196  ctx->output_frames->initial_pool_size = 10;
197 
199  if (err < 0) {
200  av_log(ctx, AV_LOG_ERROR, "Failed to initialise VAAPI frame "
201  "context for output: %d\n", err);
202  goto fail;
203  }
204 
205  va_frames = ctx->output_frames->hwctx;
206 
207  av_assert0(ctx->va_context == VA_INVALID_ID);
208  vas = vaCreateContext(ctx->hwctx->display, ctx->va_config,
209  ctx->output_width, ctx->output_height,
210  VA_PROGRESSIVE,
211  va_frames->surface_ids, va_frames->nb_surfaces,
212  &ctx->va_context);
213  if (vas != VA_STATUS_SUCCESS) {
214  av_log(ctx, AV_LOG_ERROR, "Failed to create processing pipeline "
215  "context: %d (%s).\n", vas, vaErrorStr(vas));
216  return AVERROR(EIO);
217  }
218 
219  outlink->w = ctx->output_width;
220  outlink->h = ctx->output_height;
221 
223  if (!outlink->hw_frames_ctx) {
224  err = AVERROR(ENOMEM);
225  goto fail;
226  }
227 
228  av_freep(&hwconfig);
229  av_hwframe_constraints_free(&constraints);
230  return 0;
231 
232 fail:
234  av_freep(&hwconfig);
235  av_hwframe_constraints_free(&constraints);
236  return err;
237 }
238 
240 {
241  switch(av_cs) {
242 #define CS(av, va) case AVCOL_SPC_ ## av: return VAProcColorStandard ## va;
243  CS(BT709, BT709);
244  CS(BT470BG, BT601);
245  CS(SMPTE170M, SMPTE170M);
246  CS(SMPTE240M, SMPTE240M);
247 #undef CS
248  default:
249  return VAProcColorStandardNone;
250  }
251 }
252 
253 static int scale_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame)
254 {
255  AVFilterContext *avctx = inlink->dst;
256  AVFilterLink *outlink = avctx->outputs[0];
257  ScaleVAAPIContext *ctx = avctx->priv;
259  VASurfaceID input_surface, output_surface;
260  VAProcPipelineParameterBuffer params;
261  VABufferID params_id;
262  VAStatus vas;
263  int err;
264 
265  av_log(ctx, AV_LOG_DEBUG, "Filter input: %s, %ux%u (%"PRId64").\n",
266  av_get_pix_fmt_name(input_frame->format),
267  input_frame->width, input_frame->height, input_frame->pts);
268 
269  if (ctx->va_context == VA_INVALID_ID)
270  return AVERROR(EINVAL);
271 
272  input_surface = (VASurfaceID)(uintptr_t)input_frame->data[3];
273  av_log(ctx, AV_LOG_DEBUG, "Using surface %#x for scale input.\n",
274  input_surface);
275 
276  output_frame = av_frame_alloc();
277  if (!output_frame) {
278  av_log(ctx, AV_LOG_ERROR, "Failed to allocate output frame.");
279  err = AVERROR(ENOMEM);
280  goto fail;
281  }
282 
283  err = av_hwframe_get_buffer(ctx->output_frames_ref, output_frame, 0);
284  if (err < 0) {
285  av_log(ctx, AV_LOG_ERROR, "Failed to get surface for "
286  "output: %d\n.", err);
287  }
288 
289  output_surface = (VASurfaceID)(uintptr_t)output_frame->data[3];
290  av_log(ctx, AV_LOG_DEBUG, "Using surface %#x for scale output.\n",
291  output_surface);
292 
293  memset(&params, 0, sizeof(params));
294 
295  params.surface = input_surface;
296  params.surface_region = 0;
297  params.surface_color_standard =
299 
300  params.output_region = 0;
301  params.output_background_color = 0xff000000;
302  params.output_color_standard = params.surface_color_standard;
303 
304  params.pipeline_flags = 0;
305  params.filter_flags = VA_FILTER_SCALING_HQ;
306 
307  vas = vaBeginPicture(ctx->hwctx->display,
308  ctx->va_context, output_surface);
309  if (vas != VA_STATUS_SUCCESS) {
310  av_log(ctx, AV_LOG_ERROR, "Failed to attach new picture: "
311  "%d (%s).\n", vas, vaErrorStr(vas));
312  err = AVERROR(EIO);
313  goto fail;
314  }
315 
316  vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context,
317  VAProcPipelineParameterBufferType,
318  sizeof(params), 1, &params, &params_id);
319  if (vas != VA_STATUS_SUCCESS) {
320  av_log(ctx, AV_LOG_ERROR, "Failed to create parameter buffer: "
321  "%d (%s).\n", vas, vaErrorStr(vas));
322  err = AVERROR(EIO);
323  goto fail_after_begin;
324  }
325  av_log(ctx, AV_LOG_DEBUG, "Pipeline parameter buffer is %#x.\n",
326  params_id);
327 
328  vas = vaRenderPicture(ctx->hwctx->display, ctx->va_context,
329  &params_id, 1);
330  if (vas != VA_STATUS_SUCCESS) {
331  av_log(ctx, AV_LOG_ERROR, "Failed to render parameter buffer: "
332  "%d (%s).\n", vas, vaErrorStr(vas));
333  err = AVERROR(EIO);
334  goto fail_after_begin;
335  }
336 
337  vas = vaEndPicture(ctx->hwctx->display, ctx->va_context);
338  if (vas != VA_STATUS_SUCCESS) {
339  av_log(ctx, AV_LOG_ERROR, "Failed to start picture processing: "
340  "%d (%s).\n", vas, vaErrorStr(vas));
341  err = AVERROR(EIO);
342  goto fail_after_render;
343  }
344 
345  // This doesn't get freed automatically for some reason.
346  vas = vaDestroyBuffer(ctx->hwctx->display, params_id);
347  if (vas != VA_STATUS_SUCCESS) {
348  av_log(ctx, AV_LOG_ERROR, "Failed to free parameter buffer: "
349  "%d (%s).\n", vas, vaErrorStr(vas));
350  err = AVERROR(EIO);
351  goto fail;
352  }
353 
354  av_frame_copy_props(output_frame, input_frame);
355  av_frame_free(&input_frame);
356 
357  av_log(ctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64").\n",
358  av_get_pix_fmt_name(output_frame->format),
359  output_frame->width, output_frame->height, output_frame->pts);
360 
361  return ff_filter_frame(outlink, output_frame);
362 
363  // We want to make sure that if vaBeginPicture has been called, we also
364  // call vaRenderPicture and vaEndPicture. These calls may well fail or
365  // do something else nasty, but once we're in this failure case there
366  // isn't much else we can do.
367 fail_after_begin:
368  vaRenderPicture(ctx->hwctx->display, ctx->va_context, &params_id, 1);
369 fail_after_render:
370  vaEndPicture(ctx->hwctx->display, ctx->va_context);
371 fail:
372  av_frame_free(&input_frame);
373  av_frame_free(&output_frame);
374  return err;
375 }
376 
378 {
379  ScaleVAAPIContext *ctx = avctx->priv;
380 
381  ctx->va_config = VA_INVALID_ID;
382  ctx->va_context = VA_INVALID_ID;
383  ctx->valid_ids = 1;
384 
385  if (ctx->output_format_string) {
387  if (ctx->output_format == AV_PIX_FMT_NONE) {
388  av_log(ctx, AV_LOG_ERROR, "Invalid output format.\n");
389  return AVERROR(EINVAL);
390  }
391  } else {
392  // Use the input format once that is configured.
394  }
395 
396  return 0;
397 }
398 
400 {
401  ScaleVAAPIContext *ctx = avctx->priv;
402 
403  if (ctx->valid_ids)
405 
409 }
410 
411 
412 #define OFFSET(x) offsetof(ScaleVAAPIContext, x)
413 #define FLAGS (AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM)
414 static const AVOption scale_vaapi_options[] = {
415  { "w", "Output video width",
416  OFFSET(output_width), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, .flags = FLAGS },
417  { "h", "Output video height",
418  OFFSET(output_height), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, .flags = FLAGS },
419  { "format", "Output video format (software format of hardware frames)",
420  OFFSET(output_format_string), AV_OPT_TYPE_STRING, .flags = FLAGS },
421  { NULL },
422 };
423 
424 static const AVClass scale_vaapi_class = {
425  .class_name = "scale_vaapi",
426  .item_name = av_default_item_name,
427  .option = scale_vaapi_options,
428  .version = LIBAVUTIL_VERSION_INT,
429 };
430 
431 static const AVFilterPad scale_vaapi_inputs[] = {
432  {
433  .name = "default",
434  .type = AVMEDIA_TYPE_VIDEO,
435  .filter_frame = &scale_vaapi_filter_frame,
436  .config_props = &scale_vaapi_config_input,
437  },
438  { NULL }
439 };
440 
442  {
443  .name = "default",
444  .type = AVMEDIA_TYPE_VIDEO,
445  .config_props = &scale_vaapi_config_output,
446  },
447  { NULL }
448 };
449 
451  .name = "scale_vaapi",
452  .description = NULL_IF_CONFIG_SMALL("Scale to/from VAAPI surfaces."),
453  .priv_size = sizeof(ScaleVAAPIContext),
457  .inputs = scale_vaapi_inputs,
458  .outputs = scale_vaapi_outputs,
459  .priv_class = &scale_vaapi_class,
460 };
This struct aggregates all the (hardware/vendor-specific) "high-level" state, i.e.
Definition: hwcontext.h:53
#define NULL
Definition: coverity.c:32
void av_buffer_unref(AVBufferRef **buf)
Free a given reference and automatically free the buffer if there are no more references to it...
Definition: buffer.c:124
VAAPI-specific data associated with a frame pool.
This structure describes decoded (raw) audio or video data.
Definition: frame.h:184
char * output_format_string
VAConfigID va_config
AVOption.
Definition: opt.h:245
#define LIBAVUTIL_VERSION_INT
Definition: version.h:70
Main libavfilter public API header.
memory handling functions
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:35
#define CS(av, va)
static av_cold void scale_vaapi_uninit(AVFilterContext *avctx)
int width
The allocated dimensions of the frames in this pool.
Definition: hwcontext.h:221
void * av_hwdevice_hwconfig_alloc(AVBufferRef *ref)
Allocate a HW-specific configuration structure for a given HW device.
Definition: hwcontext.c:411
enum AVPixelFormat format
The pixel format identifying the underlying HW surface type.
Definition: hwcontext.h:201
static int vaapi_proc_colour_standard(enum AVColorSpace av_cs)
AVBufferRef * input_frames_ref
int max_width
The maximum size of frames in this hw_frames_ctx.
Definition: hwcontext.h:390
AVFilterFormats * ff_make_format_list(const int *fmts)
Create a list of supported formats.
Definition: formats.c:283
API-specific header for AV_HWDEVICE_TYPE_VAAPI.
void av_hwframe_constraints_free(AVHWFramesConstraints **constraints)
Free an AVHWFrameConstraints structure.
Definition: hwcontext.c:447
const char * name
Pad name.
Definition: internal.h:59
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:72
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:313
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1180
#define av_cold
Definition: attributes.h:82
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:140
static av_cold int uninit(AVCodecContext *avctx)
Definition: crystalhd.c:337
AVFilter ff_vf_scale_vaapi
AVOptions.
AVColorSpace
YUV colorspace type.
Definition: pixfmt.h:434
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition: frame.h:268
static int scale_vaapi_pipeline_uninit(ScaleVAAPIContext *ctx)
#define av_log(a,...)
static const AVOption scale_vaapi_options[]
A filter pad used for either input or output.
Definition: internal.h:53
static av_cold int scale_vaapi_init(AVFilterContext *avctx)
int width
width and height of the video frame
Definition: frame.h:236
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
AVVAAPIDeviceContext * hwctx
VAAPI hardware pipeline configuration details.
av_default_item_name
#define AVERROR(e)
Definition: error.h:43
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:153
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:176
static int scale_vaapi_config_output(AVFilterLink *outlink)
void * priv
private data for use by the filter
Definition: avfilter.h:320
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:197
GLenum GLint * params
Definition: opengl_enc.c:114
enum AVColorSpace colorspace
YUV colorspace type.
Definition: frame.h:426
simple assert() macros that are a bit more flexible than ISO C assert().
int av_hwframe_ctx_init(AVBufferRef *ref)
Finalize the context before use.
Definition: hwcontext.c:260
int av_hwframe_get_buffer(AVBufferRef *hwframe_ref, AVFrame *frame, int flags)
Allocate a new frame attached to the given AVHWFramesContext.
Definition: hwcontext.c:387
static const AVFilterPad scale_vaapi_inputs[]
#define fail()
Definition: checkasm.h:81
static int scale_vaapi_config_input(AVFilterLink *inlink)
int initial_pool_size
Initial size of the frame pool.
Definition: hwcontext.h:191
VAContextID va_context
int ff_formats_ref(AVFilterFormats *f, AVFilterFormats **ref)
Add *ref as a new reference to formats.
Definition: formats.c:440
AVFormatContext * ctx
Definition: movenc.c:48
static const AVClass scale_vaapi_class
static const AVFilterPad outputs[]
Definition: af_afftfilt.c:386
static int output_frame(H264Context *h, AVFrame *dst, H264Picture *srcp)
Definition: h264.c:1175
VADisplay display
The VADisplay handle, to be filled by the user.
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames...
Definition: frame.h:248
int min_width
The minimum size of frames in this hw_frames_ctx.
Definition: hwcontext.h:383
static const AVFilterPad inputs[]
Definition: af_afftfilt.c:376
This struct describes the constraints on hardware frames attached to a given device with a hardware-s...
Definition: hwcontext.h:365
#define FLAGS
AVHWFramesConstraints * av_hwdevice_get_hwframe_constraints(AVBufferRef *ref, const void *hwconfig)
Get the constraints on HW frames given a device and the HW-specific configuration to be used with tha...
Definition: hwcontext.c:422
uint8_t * data
The data buffer.
Definition: buffer.h:89
void * hwctx
The format-specific data, allocated and freed automatically along with this context.
Definition: hwcontext.h:154
Describe the class of an AVClass context structure.
Definition: log.h:67
Filter definition.
Definition: avfilter.h:142
enum AVPixelFormat output_format
This struct describes a set or pool of "hardware" frames (i.e.
Definition: hwcontext.h:116
static const AVFilterPad scale_vaapi_outputs[]
const char * name
Filter name.
Definition: avfilter.h:146
AVHWFramesContext * output_frames
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:317
static enum AVPixelFormat pix_fmts[]
Definition: libkvazaar.c:262
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:198
AVBufferRef * device_ref
A reference to the parent AVHWDeviceContext.
Definition: hwcontext.h:133
A reference to a data buffer.
Definition: buffer.h:81
static int query_formats(AVFilterContext *ctx)
Definition: aeval.c:244
AVBufferRef * av_hwframe_ctx_alloc(AVBufferRef *device_ref_in)
Allocate an AVHWFramesContext tied to a given device context.
Definition: hwcontext.c:174
AVHWFramesContext * input_frames
AVBufferRef * av_buffer_ref(AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition: buffer.c:92
static int scale_vaapi_query_formats(AVFilterContext *avctx)
enum AVPixelFormat * valid_sw_formats
A list of possible values for sw_format in the hw_frames_ctx, terminated by AV_PIX_FMT_NONE.
Definition: hwcontext.h:377
AVBufferRef * device_ref
#define OFFSET(x)
VAAPI connection details.
VAConfigID config_id
ID of a VAAPI pipeline configuration.
An instance of a filter.
Definition: avfilter.h:305
int height
Definition: frame.h:236
#define av_freep(p)
VASurfaceID * surface_ids
The surfaces IDs of all surfaces in the pool after creation.
enum AVPixelFormat av_get_pix_fmt(const char *name)
Return the pixel format corresponding to name.
Definition: pixdesc.c:2150
const char * av_get_pix_fmt_name(enum AVPixelFormat pix_fmt)
Return the short name for a pixel format, NULL in case pix_fmt is unknown.
Definition: pixdesc.c:2138
internal API functions
static int scale_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame)
enum AVPixelFormat sw_format
The pixel format identifying the actual data layout of the hardware frames.
Definition: hwcontext.h:214
AVBufferRef * output_frames_ref
AVPixelFormat
Pixel format.
Definition: pixfmt.h:60
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition: frame.c:580