FFmpeg
Loading...
Searching...
No Matches
vf_program_opencl.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 "config_components.h"
20
21#include "libavutil/avstring.h"
22#include "libavutil/log.h"
23#include "libavutil/mem.h"
24#include "libavutil/opt.h"
25#include "libavutil/pixdesc.h"
26
27#include "avfilter.h"
28#include "filters.h"
29#include "framesync.h"
30#include "opencl.h"
31#include "video.h"
32
51
53{
55 cl_int cle;
56 int err;
57
58 err = ff_opencl_filter_load_program_from_file(avctx, ctx->source_file);
59 if (err < 0)
60 return err;
61
62 ctx->command_queue = clCreateCommandQueue(ctx->ocf.hwctx->context,
63 ctx->ocf.hwctx->device_id,
64 0, &cle);
65 if (!ctx->command_queue) {
66 av_log(avctx, AV_LOG_ERROR, "Failed to create OpenCL "
67 "command queue: %d.\n", cle);
68 return AVERROR(EIO);
69 }
70
71 ctx->kernel = clCreateKernel(ctx->ocf.program, ctx->kernel_name, &cle);
72 if (!ctx->kernel) {
73 if (cle == CL_INVALID_KERNEL_NAME) {
74 av_log(avctx, AV_LOG_ERROR, "Kernel function '%s' not found in "
75 "program.\n", ctx->kernel_name);
76 } else {
77 av_log(avctx, AV_LOG_ERROR, "Failed to create kernel: %d.\n", cle);
78 }
79 return AVERROR(EIO);
80 }
81
82 ctx->loaded = 1;
83 return 0;
84}
85
87{
88 AVFilterLink *outlink = avctx->outputs[0];
90 AVFrame *output = NULL;
91 cl_int cle;
92 size_t global_work[2];
93 cl_mem src, dst;
94 int err, input, plane;
95
96 if (!ctx->loaded) {
97 err = program_opencl_load(avctx);
98 if (err < 0)
99 return err;
100 }
101
102 output = ff_get_video_buffer(outlink, outlink->w, outlink->h);
103 if (!output) {
104 err = AVERROR(ENOMEM);
105 goto fail;
106 }
107
108 for (plane = 0; plane < FF_ARRAY_ELEMS(output->data); plane++) {
109 dst = (cl_mem)output->data[plane];
110 if (!dst)
111 break;
112
113 cle = clSetKernelArg(ctx->kernel, 0, sizeof(cl_mem), &dst);
114 if (cle != CL_SUCCESS) {
115 av_log(avctx, AV_LOG_ERROR, "Failed to set kernel "
116 "destination image argument: %d.\n", cle);
117 err = AVERROR_UNKNOWN;
118 goto fail;
119 }
120 cle = clSetKernelArg(ctx->kernel, 1, sizeof(cl_uint), &ctx->index);
121 if (cle != CL_SUCCESS) {
122 av_log(avctx, AV_LOG_ERROR, "Failed to set kernel "
123 "index argument: %d.\n", cle);
124 err = AVERROR_UNKNOWN;
125 goto fail;
126 }
127
128 for (input = 0; input < ctx->nb_inputs; input++) {
129 av_assert0(ctx->frames[input]);
130
131 src = (cl_mem)ctx->frames[input]->data[plane];
133
134 cle = clSetKernelArg(ctx->kernel, 2 + input, sizeof(cl_mem), &src);
135 if (cle != CL_SUCCESS) {
136 av_log(avctx, AV_LOG_ERROR, "Failed to set kernel "
137 "source image argument %d: %d.\n", input, cle);
138 err = AVERROR_UNKNOWN;
139 goto fail;
140 }
141 }
142
143 err = ff_opencl_filter_work_size_from_image(avctx, global_work,
144 output, plane, 0);
145 if (err < 0)
146 goto fail;
147
148 av_log(avctx, AV_LOG_DEBUG, "Run kernel on plane %d (%zux%zu).\n",
149 plane, global_work[0], global_work[1]);
150
151 cle = clEnqueueNDRangeKernel(ctx->command_queue, ctx->kernel, 2, NULL,
152 global_work, NULL, 0, NULL, NULL);
153 CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to enqueue kernel: %d.\n", cle);
154 }
155
156 cle = clFinish(ctx->command_queue);
157 CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to finish command queue: %d.\n", cle);
158
159 if (ctx->nb_inputs > 0) {
160 err = av_frame_copy_props(output, ctx->frames[0]);
161 if (err < 0)
162 goto fail;
163 } else {
164 output->pts = ctx->index;
165 }
166 ++ctx->index;
167
168 av_log(ctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64").\n",
170 output->width, output->height, output->pts);
171
172 return ff_filter_frame(outlink, output);
173
174fail:
175 clFinish(ctx->command_queue);
176 av_frame_free(&output);
177 return err;
178}
179
181{
182 AVFilterContext *avctx = outlink->src;
183
184 return program_opencl_run(avctx);
185}
186
188{
189 AVFilterContext *avctx = fs->parent;
190 ProgramOpenCLContext *ctx = avctx->priv;
191 int err, i;
192
193 for (i = 0; i < ctx->nb_inputs; i++) {
194 err = ff_framesync_get_frame(&ctx->fs, i, &ctx->frames[i], 0);
195 if (err < 0)
196 return err;
197 }
198
199 return program_opencl_run(avctx);
200}
201
203{
204 ProgramOpenCLContext *ctx = avctx->priv;
205
206 av_assert0(ctx->nb_inputs > 0);
207
208 return ff_framesync_activate(&ctx->fs);
209}
210
212{
213 AVFilterContext *avctx = outlink->src;
214 ProgramOpenCLContext *ctx = avctx->priv;
215 int err;
216
217 err = ff_opencl_filter_config_output(outlink);
218 if (err < 0)
219 return err;
220
221 if (ctx->nb_inputs > 0) {
222 FFFrameSyncIn *in;
223 int i;
224
225 err = ff_framesync_init(&ctx->fs, avctx, ctx->nb_inputs);
226 if (err < 0)
227 return err;
228
229 ctx->fs.opaque = ctx;
230 ctx->fs.on_event = &program_opencl_filter;
231
232 in = ctx->fs.in;
233 for (i = 0; i < ctx->nb_inputs; i++) {
234 const AVFilterLink *inlink = avctx->inputs[i];
235
236 in[i].time_base = inlink->time_base;
237 in[i].sync = 1;
238 in[i].before = EXT_STOP;
239 in[i].after = EXT_INFINITY;
240 }
241
242 err = ff_framesync_configure(&ctx->fs);
243 if (err < 0)
244 return err;
245
246 } else {
247 outlink->time_base = av_inv_q(ctx->source_rate);
248 }
249
250 return 0;
251}
252
254{
255 ProgramOpenCLContext *ctx = avctx->priv;
256 int err;
257
259
260 ctx->ocf.output_width = ctx->width;
261 ctx->ocf.output_height = ctx->height;
262
263 if (!strcmp(avctx->filter->name, "openclsrc")) {
264 if (!ctx->ocf.output_width || !ctx->ocf.output_height) {
265 av_log(avctx, AV_LOG_ERROR, "OpenCL source requires output "
266 "dimensions to be specified.\n");
267 return AVERROR(EINVAL);
268 }
269
270 ctx->nb_inputs = 0;
271 ctx->ocf.output_format = ctx->source_format;
272 } else {
273 int i;
274
275 ctx->frames = av_calloc(ctx->nb_inputs, sizeof(*ctx->frames));
276 if (!ctx->frames)
277 return AVERROR(ENOMEM);
278
279 for (i = 0; i < ctx->nb_inputs; i++) {
280 AVFilterPad input;
281 memset(&input, 0, sizeof(input));
282
283 input.type = AVMEDIA_TYPE_VIDEO;
284 input.name = av_asprintf("input%d", i);
285 if (!input.name)
286 return AVERROR(ENOMEM);
287
289
290 err = ff_append_inpad_free_name(avctx, &input);
291 if (err < 0)
292 return err;
293 }
294 }
295
296 return 0;
297}
298
300{
301 ProgramOpenCLContext *ctx = avctx->priv;
302 cl_int cle;
303
304 if (ctx->nb_inputs > 0) {
306
307 av_freep(&ctx->frames);
308 }
309
310 if (ctx->kernel) {
311 cle = clReleaseKernel(ctx->kernel);
312 if (cle != CL_SUCCESS)
313 av_log(avctx, AV_LOG_ERROR, "Failed to release "
314 "kernel: %d.\n", cle);
315 }
316
317 if (ctx->command_queue) {
318 cle = clReleaseCommandQueue(ctx->command_queue);
319 if (cle != CL_SUCCESS)
320 av_log(avctx, AV_LOG_ERROR, "Failed to release "
321 "command queue: %d.\n", cle);
322 }
323
325}
326
327#define OFFSET(x) offsetof(ProgramOpenCLContext, x)
328#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM)
329
330#if CONFIG_PROGRAM_OPENCL_FILTER
331
332static const AVOption program_opencl_options[] = {
333 { "source", "OpenCL program source file", OFFSET(source_file),
334 AV_OPT_TYPE_STRING, { .str = NULL }, .flags = FLAGS },
335 { "kernel", "Kernel name in program", OFFSET(kernel_name),
336 AV_OPT_TYPE_STRING, { .str = NULL }, .flags = FLAGS },
337
338 { "inputs", "Number of inputs", OFFSET(nb_inputs),
339 AV_OPT_TYPE_INT, { .i64 = 1 }, 1, INT_MAX, FLAGS },
340
341 { "size", "Video size", OFFSET(width),
342 AV_OPT_TYPE_IMAGE_SIZE, { .str = NULL }, 0, 0, FLAGS },
343 { "s", "Video size", OFFSET(width),
344 AV_OPT_TYPE_IMAGE_SIZE, { .str = NULL }, 0, 0, FLAGS },
345
346 { NULL },
347};
348
350
351static const AVFilterPad program_opencl_outputs[] = {
352 {
353 .name = "default",
354 .type = AVMEDIA_TYPE_VIDEO,
355 .config_props = &program_opencl_config_output,
356 },
357};
358
360 .p.name = "program_opencl",
361 .p.description = NULL_IF_CONFIG_SMALL("Filter video using an OpenCL program"),
362 .p.priv_class = &program_opencl_class,
365 .p.inputs = NULL,
366 .priv_size = sizeof(ProgramOpenCLContext),
367 .preinit = &program_opencl_framesync_preinit,
371 FILTER_OUTPUTS(program_opencl_outputs),
373 .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
374};
375
376#endif
377
378#if CONFIG_OPENCLSRC_FILTER
379
380static const AVOption openclsrc_options[] = {
381 { "source", "OpenCL program source file", OFFSET(source_file),
382 AV_OPT_TYPE_STRING, { .str = NULL }, .flags = FLAGS },
383 { "kernel", "Kernel name in program", OFFSET(kernel_name),
384 AV_OPT_TYPE_STRING, { .str = NULL }, .flags = FLAGS },
385
386 { "size", "Video size", OFFSET(width),
387 AV_OPT_TYPE_IMAGE_SIZE, { .str = NULL }, 0, 0, FLAGS },
388 { "s", "Video size", OFFSET(width),
389 AV_OPT_TYPE_IMAGE_SIZE, { .str = NULL }, 0, 0, FLAGS },
390
391 { "format", "Video format", OFFSET(source_format),
392 AV_OPT_TYPE_PIXEL_FMT, { .i64 = AV_PIX_FMT_NONE }, -1, INT_MAX, FLAGS },
393
394 { "rate", "Video frame rate", OFFSET(source_rate),
395 AV_OPT_TYPE_VIDEO_RATE, { .str = "25" }, 0, INT_MAX, FLAGS },
396 { "r", "Video frame rate", OFFSET(source_rate),
397 AV_OPT_TYPE_VIDEO_RATE, { .str = "25" }, 0, INT_MAX, FLAGS },
398
399 { NULL },
400};
401
402AVFILTER_DEFINE_CLASS(openclsrc);
403
404static const AVFilterPad openclsrc_outputs[] = {
405 {
406 .name = "default",
407 .type = AVMEDIA_TYPE_VIDEO,
408 .config_props = &program_opencl_config_output,
409 .request_frame = &program_opencl_request_frame,
410 },
411};
412
414 .p.name = "openclsrc",
415 .p.description = NULL_IF_CONFIG_SMALL("Generate video using an OpenCL program"),
416 .p.priv_class = &openclsrc_class,
417 .p.inputs = NULL,
418 .p.flags = AVFILTER_FLAG_HWDEVICE,
419 .priv_size = sizeof(ProgramOpenCLContext),
422 FILTER_OUTPUTS(openclsrc_outputs),
424 .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
425};
426
427#endif
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition dsp.h:87
const FFFilter ff_vsrc_openclsrc
const FFFilter ff_vf_program_opencl
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition avassert.h:42
int ff_append_inpad_free_name(AVFilterContext *f, AVFilterPad *p)
Definition avfilter.c:132
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition avfilter.c:1068
Main libavfilter public API header.
char * av_asprintf(const char *fmt,...)
Definition avstring.c:115
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define fs(width, name, subs,...)
Definition cbs_vp9.c:200
#define FLAGS
Definition cmdutils.c:598
#define NULL
Definition coverity.c:32
int(* init)(AVBSFContext *ctx)
Definition dts2pts.c:608
int ff_framesync_configure(FFFrameSync *fs)
Configure a frame sync structure.
Definition framesync.c:137
int ff_framesync_activate(FFFrameSync *fs)
Examine the frames in the filter's input and try to produce output.
Definition framesync.c:352
int ff_framesync_get_frame(FFFrameSync *fs, unsigned in, AVFrame **rframe, unsigned get)
Get the current frame in an input.
Definition framesync.c:269
void ff_framesync_uninit(FFFrameSync *fs)
Free all memory currently allocated.
Definition framesync.c:301
int ff_framesync_init(FFFrameSync *fs, AVFilterContext *parent, unsigned nb_in)
Initialize a frame sync structure.
Definition framesync.c:86
#define FRAMESYNC_DEFINE_CLASS(name, context, field)
Definition framesync.h:352
@ EXT_INFINITY
Extend the frame to infinity.
Definition framesync.h:75
#define fail
Definition test.h:479
@ AV_OPT_TYPE_IMAGE_SIZE
Underlying C type is two consecutive integers.
Definition opt.h:302
@ AV_OPT_TYPE_PIXEL_FMT
Underlying C type is enum AVPixelFormat.
Definition opt.h:306
@ AV_OPT_TYPE_VIDEO_RATE
Underlying C type is AVRational.
Definition opt.h:314
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
Definition opt.h:275
#define AVFILTER_FLAG_HWDEVICE
The filter can create hardware frames using AVFilterContext.hw_device_ctx.
Definition avfilter.h:187
#define AVFILTER_FLAG_DYNAMIC_INPUTS
The number of the filter inputs is not determined just by AVFilter.inputs.
Definition avfilter.h:155
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition error.h:73
#define AVERROR(e)
Definition error.h:45
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition frame.c:64
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition frame.c:599
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition log.h:231
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
static av_always_inline AVRational av_inv_q(AVRational q)
Invert a rational.
Definition rational.h:159
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
static av_cold void uninit(AVBitStreamFilterContext *ctx)
static int activate(AVBitStreamFilterContext *ctx)
#define FILTER_OUTPUTS(array)
Definition filters.h:265
#define FF_FILTER_FLAG_HWFRAME_AWARE
The filter is aware of hardware frames, and any hardware frame context should not be automatically pr...
Definition filters.h:208
#define FILTER_SINGLE_PIXFMT(pix_fmt_)
Definition filters.h:254
#define AVFILTER_DEFINE_CLASS(fname)
Definition filters.h:478
#define av_cold
Definition attributes.h:117
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:88
void * av_calloc(size_t nmemb, size_t size)
Definition mem.c:264
Memory handling functions.
void ff_opencl_filter_uninit(AVFilterContext *avctx)
Uninitialise an OpenCL filter context.
Definition opencl.c:144
int ff_opencl_filter_config_input(AVFilterLink *inlink)
Check that the input link contains a suitable hardware frames context and extract the device from it.
Definition opencl.c:46
int ff_opencl_filter_init(AVFilterContext *avctx)
Initialise an OpenCL filter context.
Definition opencl.c:135
int ff_opencl_filter_work_size_from_image(AVFilterContext *avctx, size_t *work_size, AVFrame *frame, int plane, int block_alignment)
Find the work size needed needed for a given plane of an image.
Definition opencl.c:266
int ff_opencl_filter_config_output(AVFilterLink *outlink)
Create a suitable hardware frames context for the output.
Definition opencl.c:83
int ff_opencl_filter_load_program_from_file(AVFilterContext *avctx, const char *filename)
Load a new OpenCL program from a file.
Definition opencl.c:207
#define CL_FAIL_ON_ERROR(errcode,...)
A helper macro to handle OpenCL errors.
Definition opencl.h:74
AVOptions.
@ EXT_STOP
Completely stop all streams with this one.
Definition packetsync.h:62
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:3380
AVPixelFormat
Pixel format.
Definition pixfmt.h:71
@ AV_PIX_FMT_NONE
Definition pixfmt.h:72
@ AV_PIX_FMT_OPENCL
Hardware surfaces for OpenCL.
Definition pixfmt.h:358
#define FF_ARRAY_ELEMS(a)
static av_cold int preinit(AVBitStreamFilterContext *ctx)
Definition source.c:137
An instance of a filter.
Definition avfilter.h:273
AVFilterLink ** inputs
array of pointers to input links
Definition avfilter.h:281
const AVFilter * filter
the AVFilter of which this is an instance
Definition avfilter.h:276
void * priv
private data for use by the filter
Definition avfilter.h:288
AVFilterLink ** outputs
array of pointers to output links
Definition avfilter.h:285
A filter pad used for either input or output.
Definition filters.h:40
int(* config_props)(AVFilterLink *link)
Link configuration callback.
Definition filters.h:120
enum AVMediaType type
AVFilterPad type.
Definition filters.h:51
const char * name
Pad name.
Definition filters.h:46
const char * name
Filter name.
Definition avfilter.h:219
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition frame.h:574
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition frame.h:493
int width
Definition frame.h:544
int height
Definition frame.h:544
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames,...
Definition frame.h:559
AVOption.
Definition opt.h:428
Rational number (pair of numerator and denominator).
Definition rational.h:58
Input stream structure.
Definition framesync.h:102
enum FFFrameSyncExtMode after
Extrapolation mode for timestamps after the last frame.
Definition framesync.h:112
enum FFFrameSyncExtMode before
Extrapolation mode for timestamps before the first frame.
Definition framesync.h:107
AVRational time_base
Time base for the incoming frames.
Definition framesync.h:117
unsigned sync
Synchronization level: frames on input at the highest sync level will generate output frame events.
Definition framesync.h:160
Frame sync structure.
Definition framesync.h:168
OpenCLFilterContext ocf
enum AVPixelFormat source_format
cl_command_queue command_queue
#define av_freep(p)
#define av_log(a,...)
#define src
Definition vp8dsp.c:248
static AVFormatContext * ctx
Definition movenc.c:49
#define width
Definition dsp.h:89
static av_cold int program_opencl_init(AVFilterContext *avctx)
static av_cold void program_opencl_uninit(AVFilterContext *avctx)
static int program_opencl_activate(AVFilterContext *avctx)
static int program_opencl_load(AVFilterContext *avctx)
static int program_opencl_filter(FFFrameSync *fs)
static int program_opencl_request_frame(AVFilterLink *outlink)
static int program_opencl_config_output(AVFilterLink *outlink)
#define OFFSET(x)
static int program_opencl_run(AVFilterContext *avctx)
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition video.c:89