avfilter/af_pan: fix null pointer dereference on empty token
[ffmpeg.git] / libavfilter / vf_scale_vaapi.c
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"
26 #include "libavutil/hwcontext_vaapi.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 #include "scale.h"
35
36 typedef struct ScaleVAAPIContext {
37     const AVClass *class;
38
39     AVVAAPIDeviceContext *hwctx;
40     AVBufferRef *device_ref;
41
42     int valid_ids;
43     VAConfigID  va_config;
44     VAContextID va_context;
45
46     AVBufferRef       *input_frames_ref;
47     AVHWFramesContext *input_frames;
48
49     AVBufferRef       *output_frames_ref;
50     AVHWFramesContext *output_frames;
51
52     char *output_format_string;
53     enum AVPixelFormat output_format;
54
55     char *w_expr;      // width expression string
56     char *h_expr;      // height expression string
57
58     int output_width;  // computed width
59     int output_height; // computed height
60 } ScaleVAAPIContext;
61
62
63 static int scale_vaapi_query_formats(AVFilterContext *avctx)
64 {
65     enum AVPixelFormat pix_fmts[] = {
66         AV_PIX_FMT_VAAPI, AV_PIX_FMT_NONE,
67     };
68     int err;
69
70     if ((err = ff_formats_ref(ff_make_format_list(pix_fmts),
71                               &avctx->inputs[0]->out_formats)) < 0)
72         return err;
73     if ((err = ff_formats_ref(ff_make_format_list(pix_fmts),
74                               &avctx->outputs[0]->in_formats)) < 0)
75         return err;
76
77     return 0;
78 }
79
80 static int scale_vaapi_pipeline_uninit(ScaleVAAPIContext *ctx)
81 {
82     if (ctx->va_context != VA_INVALID_ID) {
83         vaDestroyContext(ctx->hwctx->display, ctx->va_context);
84         ctx->va_context = VA_INVALID_ID;
85     }
86
87     if (ctx->va_config != VA_INVALID_ID) {
88         vaDestroyConfig(ctx->hwctx->display, ctx->va_config);
89         ctx->va_config = VA_INVALID_ID;
90     }
91
92     av_buffer_unref(&ctx->output_frames_ref);
93     av_buffer_unref(&ctx->device_ref);
94     ctx->hwctx = 0;
95
96     return 0;
97 }
98
99 static int scale_vaapi_config_input(AVFilterLink *inlink)
100 {
101     AVFilterContext *avctx = inlink->dst;
102     ScaleVAAPIContext *ctx = avctx->priv;
103
104     scale_vaapi_pipeline_uninit(ctx);
105
106     if (!inlink->hw_frames_ctx) {
107         av_log(avctx, AV_LOG_ERROR, "A hardware frames reference is "
108                "required to associate the processing device.\n");
109         return AVERROR(EINVAL);
110     }
111
112     ctx->input_frames_ref = av_buffer_ref(inlink->hw_frames_ctx);
113     ctx->input_frames = (AVHWFramesContext*)ctx->input_frames_ref->data;
114
115     return 0;
116 }
117
118 static int scale_vaapi_config_output(AVFilterLink *outlink)
119 {
120     AVFilterLink *inlink = outlink->src->inputs[0];
121     AVFilterContext *avctx = outlink->src;
122     ScaleVAAPIContext *ctx = avctx->priv;
123     AVVAAPIHWConfig *hwconfig = NULL;
124     AVHWFramesConstraints *constraints = NULL;
125     AVVAAPIFramesContext *va_frames;
126     VAStatus vas;
127     int err, i;
128
129     scale_vaapi_pipeline_uninit(ctx);
130
131     ctx->device_ref = av_buffer_ref(ctx->input_frames->device_ref);
132     ctx->hwctx = ((AVHWDeviceContext*)ctx->device_ref->data)->hwctx;
133
134     av_assert0(ctx->va_config == VA_INVALID_ID);
135     vas = vaCreateConfig(ctx->hwctx->display, VAProfileNone,
136                          VAEntrypointVideoProc, 0, 0, &ctx->va_config);
137     if (vas != VA_STATUS_SUCCESS) {
138         av_log(ctx, AV_LOG_ERROR, "Failed to create processing pipeline "
139                "config: %d (%s).\n", vas, vaErrorStr(vas));
140         err = AVERROR(EIO);
141         goto fail;
142     }
143
144     hwconfig = av_hwdevice_hwconfig_alloc(ctx->device_ref);
145     if (!hwconfig) {
146         err = AVERROR(ENOMEM);
147         goto fail;
148     }
149     hwconfig->config_id = ctx->va_config;
150
151     constraints = av_hwdevice_get_hwframe_constraints(ctx->device_ref,
152                                                       hwconfig);
153     if (!constraints) {
154         err = AVERROR(ENOMEM);
155         goto fail;
156     }
157
158     if (ctx->output_format == AV_PIX_FMT_NONE)
159         ctx->output_format = ctx->input_frames->sw_format;
160     if (constraints->valid_sw_formats) {
161         for (i = 0; constraints->valid_sw_formats[i] != AV_PIX_FMT_NONE; i++) {
162             if (ctx->output_format == constraints->valid_sw_formats[i])
163                 break;
164         }
165         if (constraints->valid_sw_formats[i] == AV_PIX_FMT_NONE) {
166             av_log(ctx, AV_LOG_ERROR, "Hardware does not support output "
167                    "format %s.\n", av_get_pix_fmt_name(ctx->output_format));
168             err = AVERROR(EINVAL);
169             goto fail;
170         }
171     }
172
173     if ((err = ff_scale_eval_dimensions(ctx,
174                                         ctx->w_expr, ctx->h_expr,
175                                         inlink, outlink,
176                                         &ctx->output_width, &ctx->output_height)) < 0)
177         goto fail;
178
179     if (ctx->output_width  < constraints->min_width  ||
180         ctx->output_height < constraints->min_height ||
181         ctx->output_width  > constraints->max_width  ||
182         ctx->output_height > constraints->max_height) {
183         av_log(ctx, AV_LOG_ERROR, "Hardware does not support scaling to "
184                "size %dx%d (constraints: width %d-%d height %d-%d).\n",
185                ctx->output_width, ctx->output_height,
186                constraints->min_width,  constraints->max_width,
187                constraints->min_height, constraints->max_height);
188         err = AVERROR(EINVAL);
189         goto fail;
190     }
191
192     ctx->output_frames_ref = av_hwframe_ctx_alloc(ctx->device_ref);
193     if (!ctx->output_frames_ref) {
194         av_log(ctx, AV_LOG_ERROR, "Failed to create HW frame context "
195                "for output.\n");
196         err = AVERROR(ENOMEM);
197         goto fail;
198     }
199
200     ctx->output_frames = (AVHWFramesContext*)ctx->output_frames_ref->data;
201
202     ctx->output_frames->format    = AV_PIX_FMT_VAAPI;
203     ctx->output_frames->sw_format = ctx->output_format;
204     ctx->output_frames->width     = ctx->output_width;
205     ctx->output_frames->height    = ctx->output_height;
206
207     // The number of output frames we need is determined by what follows
208     // the filter.  If it's an encoder with complex frame reference
209     // structures then this could be very high.
210     ctx->output_frames->initial_pool_size = 10;
211
212     err = av_hwframe_ctx_init(ctx->output_frames_ref);
213     if (err < 0) {
214         av_log(ctx, AV_LOG_ERROR, "Failed to initialise VAAPI frame "
215                "context for output: %d\n", err);
216         goto fail;
217     }
218
219     va_frames = ctx->output_frames->hwctx;
220
221     av_assert0(ctx->va_context == VA_INVALID_ID);
222     vas = vaCreateContext(ctx->hwctx->display, ctx->va_config,
223                           ctx->output_width, ctx->output_height,
224                           VA_PROGRESSIVE,
225                           va_frames->surface_ids, va_frames->nb_surfaces,
226                           &ctx->va_context);
227     if (vas != VA_STATUS_SUCCESS) {
228         av_log(ctx, AV_LOG_ERROR, "Failed to create processing pipeline "
229                "context: %d (%s).\n", vas, vaErrorStr(vas));
230         return AVERROR(EIO);
231     }
232
233     outlink->w = ctx->output_width;
234     outlink->h = ctx->output_height;
235
236     outlink->hw_frames_ctx = av_buffer_ref(ctx->output_frames_ref);
237     if (!outlink->hw_frames_ctx) {
238         err = AVERROR(ENOMEM);
239         goto fail;
240     }
241
242     av_freep(&hwconfig);
243     av_hwframe_constraints_free(&constraints);
244     return 0;
245
246 fail:
247     av_buffer_unref(&ctx->output_frames_ref);
248     av_freep(&hwconfig);
249     av_hwframe_constraints_free(&constraints);
250     return err;
251 }
252
253 static int vaapi_proc_colour_standard(enum AVColorSpace av_cs)
254 {
255     switch(av_cs) {
256 #define CS(av, va) case AVCOL_SPC_ ## av: return VAProcColorStandard ## va;
257         CS(BT709,     BT709);
258         CS(BT470BG,   BT601);
259         CS(SMPTE170M, SMPTE170M);
260         CS(SMPTE240M, SMPTE240M);
261 #undef CS
262     default:
263         return VAProcColorStandardNone;
264     }
265 }
266
267 static int scale_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame)
268 {
269     AVFilterContext *avctx = inlink->dst;
270     AVFilterLink *outlink = avctx->outputs[0];
271     ScaleVAAPIContext *ctx = avctx->priv;
272     AVFrame *output_frame = NULL;
273     VASurfaceID input_surface, output_surface;
274     VAProcPipelineParameterBuffer params;
275     VABufferID params_id;
276     VAStatus vas;
277     int err;
278
279     av_log(ctx, AV_LOG_DEBUG, "Filter input: %s, %ux%u (%"PRId64").\n",
280            av_get_pix_fmt_name(input_frame->format),
281            input_frame->width, input_frame->height, input_frame->pts);
282
283     if (ctx->va_context == VA_INVALID_ID)
284         return AVERROR(EINVAL);
285
286     input_surface = (VASurfaceID)(uintptr_t)input_frame->data[3];
287     av_log(ctx, AV_LOG_DEBUG, "Using surface %#x for scale input.\n",
288            input_surface);
289
290     output_frame = av_frame_alloc();
291     if (!output_frame) {
292         av_log(ctx, AV_LOG_ERROR, "Failed to allocate output frame.");
293         err = AVERROR(ENOMEM);
294         goto fail;
295     }
296
297     err = av_hwframe_get_buffer(ctx->output_frames_ref, output_frame, 0);
298     if (err < 0) {
299         av_log(ctx, AV_LOG_ERROR, "Failed to get surface for "
300                "output: %d\n.", err);
301     }
302
303     output_surface = (VASurfaceID)(uintptr_t)output_frame->data[3];
304     av_log(ctx, AV_LOG_DEBUG, "Using surface %#x for scale output.\n",
305            output_surface);
306
307     memset(&params, 0, sizeof(params));
308
309     params.surface = input_surface;
310     params.surface_region = 0;
311     params.surface_color_standard =
312         vaapi_proc_colour_standard(input_frame->colorspace);
313
314     params.output_region = 0;
315     params.output_background_color = 0xff000000;
316     params.output_color_standard = params.surface_color_standard;
317
318     params.pipeline_flags = 0;
319     params.filter_flags = VA_FILTER_SCALING_HQ;
320
321     vas = vaBeginPicture(ctx->hwctx->display,
322                          ctx->va_context, output_surface);
323     if (vas != VA_STATUS_SUCCESS) {
324         av_log(ctx, AV_LOG_ERROR, "Failed to attach new picture: "
325                "%d (%s).\n", vas, vaErrorStr(vas));
326         err = AVERROR(EIO);
327         goto fail;
328     }
329
330     vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context,
331                          VAProcPipelineParameterBufferType,
332                          sizeof(params), 1, &params, &params_id);
333     if (vas != VA_STATUS_SUCCESS) {
334         av_log(ctx, AV_LOG_ERROR, "Failed to create parameter buffer: "
335                "%d (%s).\n", vas, vaErrorStr(vas));
336         err = AVERROR(EIO);
337         goto fail_after_begin;
338     }
339     av_log(ctx, AV_LOG_DEBUG, "Pipeline parameter buffer is %#x.\n",
340            params_id);
341
342     vas = vaRenderPicture(ctx->hwctx->display, ctx->va_context,
343                           &params_id, 1);
344     if (vas != VA_STATUS_SUCCESS) {
345         av_log(ctx, AV_LOG_ERROR, "Failed to render parameter buffer: "
346                "%d (%s).\n", vas, vaErrorStr(vas));
347         err = AVERROR(EIO);
348         goto fail_after_begin;
349     }
350
351     vas = vaEndPicture(ctx->hwctx->display, ctx->va_context);
352     if (vas != VA_STATUS_SUCCESS) {
353         av_log(ctx, AV_LOG_ERROR, "Failed to start picture processing: "
354                "%d (%s).\n", vas, vaErrorStr(vas));
355         err = AVERROR(EIO);
356         goto fail_after_render;
357     }
358
359     if (ctx->hwctx->driver_quirks &
360         AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS) {
361         vas = vaDestroyBuffer(ctx->hwctx->display, params_id);
362         if (vas != VA_STATUS_SUCCESS) {
363             av_log(ctx, AV_LOG_ERROR, "Failed to free parameter buffer: "
364                    "%d (%s).\n", vas, vaErrorStr(vas));
365             // And ignore.
366         }
367     }
368
369     av_frame_copy_props(output_frame, input_frame);
370     av_frame_free(&input_frame);
371
372     av_log(ctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64").\n",
373            av_get_pix_fmt_name(output_frame->format),
374            output_frame->width, output_frame->height, output_frame->pts);
375
376     return ff_filter_frame(outlink, output_frame);
377
378     // We want to make sure that if vaBeginPicture has been called, we also
379     // call vaRenderPicture and vaEndPicture.  These calls may well fail or
380     // do something else nasty, but once we're in this failure case there
381     // isn't much else we can do.
382 fail_after_begin:
383     vaRenderPicture(ctx->hwctx->display, ctx->va_context, &params_id, 1);
384 fail_after_render:
385     vaEndPicture(ctx->hwctx->display, ctx->va_context);
386 fail:
387     av_frame_free(&input_frame);
388     av_frame_free(&output_frame);
389     return err;
390 }
391
392 static av_cold int scale_vaapi_init(AVFilterContext *avctx)
393 {
394     ScaleVAAPIContext *ctx = avctx->priv;
395
396     ctx->va_config  = VA_INVALID_ID;
397     ctx->va_context = VA_INVALID_ID;
398     ctx->valid_ids  = 1;
399
400     if (ctx->output_format_string) {
401         ctx->output_format = av_get_pix_fmt(ctx->output_format_string);
402         if (ctx->output_format == AV_PIX_FMT_NONE) {
403             av_log(ctx, AV_LOG_ERROR, "Invalid output format.\n");
404             return AVERROR(EINVAL);
405         }
406     } else {
407         // Use the input format once that is configured.
408         ctx->output_format = AV_PIX_FMT_NONE;
409     }
410
411     return 0;
412 }
413
414 static av_cold void scale_vaapi_uninit(AVFilterContext *avctx)
415 {
416     ScaleVAAPIContext *ctx = avctx->priv;
417
418     if (ctx->valid_ids)
419         scale_vaapi_pipeline_uninit(ctx);
420
421     av_buffer_unref(&ctx->input_frames_ref);
422     av_buffer_unref(&ctx->output_frames_ref);
423     av_buffer_unref(&ctx->device_ref);
424 }
425
426
427 #define OFFSET(x) offsetof(ScaleVAAPIContext, x)
428 #define FLAGS (AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM)
429 static const AVOption scale_vaapi_options[] = {
430     { "w", "Output video width",
431       OFFSET(w_expr), AV_OPT_TYPE_STRING, {.str = "iw"}, .flags = FLAGS },
432     { "h", "Output video height",
433       OFFSET(h_expr), AV_OPT_TYPE_STRING, {.str = "ih"}, .flags = FLAGS },
434     { "format", "Output video format (software format of hardware frames)",
435       OFFSET(output_format_string), AV_OPT_TYPE_STRING, .flags = FLAGS },
436     { NULL },
437 };
438
439 static const AVClass scale_vaapi_class = {
440     .class_name = "scale_vaapi",
441     .item_name  = av_default_item_name,
442     .option     = scale_vaapi_options,
443     .version    = LIBAVUTIL_VERSION_INT,
444 };
445
446 static const AVFilterPad scale_vaapi_inputs[] = {
447     {
448         .name         = "default",
449         .type         = AVMEDIA_TYPE_VIDEO,
450         .filter_frame = &scale_vaapi_filter_frame,
451         .config_props = &scale_vaapi_config_input,
452     },
453     { NULL }
454 };
455
456 static const AVFilterPad scale_vaapi_outputs[] = {
457     {
458         .name = "default",
459         .type = AVMEDIA_TYPE_VIDEO,
460         .config_props = &scale_vaapi_config_output,
461     },
462     { NULL }
463 };
464
465 AVFilter ff_vf_scale_vaapi = {
466     .name          = "scale_vaapi",
467     .description   = NULL_IF_CONFIG_SMALL("Scale to/from VAAPI surfaces."),
468     .priv_size     = sizeof(ScaleVAAPIContext),
469     .init          = &scale_vaapi_init,
470     .uninit        = &scale_vaapi_uninit,
471     .query_formats = &scale_vaapi_query_formats,
472     .inputs        = scale_vaapi_inputs,
473     .outputs       = scale_vaapi_outputs,
474     .priv_class    = &scale_vaapi_class,
475 };