FFmpeg
Loading...
Searching...
No Matches
vf_overlay_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 "libavutil/log.h"
20#include "libavutil/opt.h"
21#include "libavutil/pixdesc.h"
22
23#include "avfilter.h"
24#include "filters.h"
25#include "framesync.h"
26#include "opencl.h"
27#include "opencl_source.h"
28#include "video.h"
29
47
49 enum AVPixelFormat main_format,
50 enum AVPixelFormat overlay_format)
51{
53 cl_int cle;
54 const char *source = ff_source_overlay_cl;
55 const char *kernel;
56 const AVPixFmtDescriptor *main_desc, *overlay_desc;
57 int err, i, main_planes, overlay_planes;
58
59 main_desc = av_pix_fmt_desc_get(main_format);
60 overlay_desc = av_pix_fmt_desc_get(overlay_format);
61
62 main_planes = overlay_planes = 0;
63 for (i = 0; i < main_desc->nb_components; i++)
64 main_planes = FFMAX(main_planes,
65 main_desc->comp[i].plane + 1);
66 for (i = 0; i < overlay_desc->nb_components; i++)
67 overlay_planes = FFMAX(overlay_planes,
68 overlay_desc->comp[i].plane + 1);
69
70 ctx->nb_planes = main_planes;
71 ctx->x_subsample = 1 << main_desc->log2_chroma_w;
72 ctx->y_subsample = 1 << main_desc->log2_chroma_h;
73
74 if (ctx->x_position % ctx->x_subsample ||
75 ctx->y_position % ctx->y_subsample) {
76 av_log(avctx, AV_LOG_WARNING, "Warning: overlay position (%d, %d) "
77 "does not match subsampling (%d, %d).\n",
78 ctx->x_position, ctx->y_position,
79 ctx->x_subsample, ctx->y_subsample);
80 }
81
82 if (main_planes == overlay_planes) {
83 if (main_desc->nb_components == overlay_desc->nb_components)
84 kernel = "overlay_no_alpha";
85 else
86 kernel = "overlay_internal_alpha";
87 ctx->alpha_separate = 0;
88 } else {
89 kernel = "overlay_external_alpha";
90 ctx->alpha_separate = 1;
91 }
92
93 av_log(avctx, AV_LOG_DEBUG, "Using kernel %s.\n", kernel);
94
95 err = ff_opencl_filter_load_program(avctx, &source, 1);
96 if (err < 0)
97 goto fail;
98
99 ctx->command_queue = clCreateCommandQueue(ctx->ocf.hwctx->context,
100 ctx->ocf.hwctx->device_id,
101 0, &cle);
102 CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create OpenCL "
103 "command queue %d.\n", cle);
104
105 ctx->kernel = clCreateKernel(ctx->ocf.program, kernel, &cle);
106 CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create kernel %d.\n", cle);
107
108 ctx->initialised = 1;
109 return 0;
110
111fail:
112 if (ctx->command_queue)
113 clReleaseCommandQueue(ctx->command_queue);
114 if (ctx->kernel)
115 clReleaseKernel(ctx->kernel);
116 return err;
117}
118
120{
121 AVFilterContext *avctx = fs->parent;
122 AVFilterLink *outlink = avctx->outputs[0];
123 OverlayOpenCLContext *ctx = avctx->priv;
124 AVFrame *input_main, *input_overlay;
125 AVFrame *output;
126 cl_mem mem;
127 cl_int cle, x, y;
128 size_t global_work[2];
129 int kernel_arg = 0;
130 int err, plane;
131
132 err = ff_framesync_get_frame(fs, 0, &input_main, 0);
133 if (err < 0)
134 return err;
135 err = ff_framesync_get_frame(fs, 1, &input_overlay, 0);
136 if (err < 0)
137 return err;
138
139 if (!ctx->initialised) {
140 AVHWFramesContext *main_fc =
141 (AVHWFramesContext*)input_main->hw_frames_ctx->data;
142 AVHWFramesContext *overlay_fc =
143 (AVHWFramesContext*)input_overlay->hw_frames_ctx->data;
144
145 err = overlay_opencl_load(avctx, main_fc->sw_format,
146 overlay_fc->sw_format);
147 if (err < 0)
148 return err;
149 }
150
151 output = ff_get_video_buffer(outlink, outlink->w, outlink->h);
152 if (!output) {
153 err = AVERROR(ENOMEM);
154 goto fail;
155 }
156
157 for (plane = 0; plane < ctx->nb_planes; plane++) {
158 kernel_arg = 0;
159
160 mem = (cl_mem)output->data[plane];
161 CL_SET_KERNEL_ARG(ctx->kernel, kernel_arg, cl_mem, &mem);
162 kernel_arg++;
163
164 mem = (cl_mem)input_main->data[plane];
165 CL_SET_KERNEL_ARG(ctx->kernel, kernel_arg, cl_mem, &mem);
166 kernel_arg++;
167
168 mem = (cl_mem)input_overlay->data[plane];
169 CL_SET_KERNEL_ARG(ctx->kernel, kernel_arg, cl_mem, &mem);
170 kernel_arg++;
171
172 if (ctx->alpha_separate) {
173 mem = (cl_mem)input_overlay->data[ctx->nb_planes];
174 CL_SET_KERNEL_ARG(ctx->kernel, kernel_arg, cl_mem, &mem);
175 kernel_arg++;
176 }
177
178 x = ctx->x_position / (plane == 0 ? 1 : ctx->x_subsample);
179 y = ctx->y_position / (plane == 0 ? 1 : ctx->y_subsample);
180
181 CL_SET_KERNEL_ARG(ctx->kernel, kernel_arg, cl_int, &x);
182 kernel_arg++;
183 CL_SET_KERNEL_ARG(ctx->kernel, kernel_arg, cl_int, &y);
184 kernel_arg++;
185
186 if (ctx->alpha_separate) {
187 cl_int alpha_adj_x = plane == 0 ? 1 : ctx->x_subsample;
188 cl_int alpha_adj_y = plane == 0 ? 1 : ctx->y_subsample;
189
190 CL_SET_KERNEL_ARG(ctx->kernel, kernel_arg, cl_int, &alpha_adj_x);
191 kernel_arg++;
192 CL_SET_KERNEL_ARG(ctx->kernel, kernel_arg, cl_int, &alpha_adj_y);
193 kernel_arg++;
194 }
195
196 err = ff_opencl_filter_work_size_from_image(avctx, global_work,
197 output, plane, 0);
198 if (err < 0)
199 goto fail;
200
201 cle = clEnqueueNDRangeKernel(ctx->command_queue, ctx->kernel, 2, NULL,
202 global_work, NULL, 0, NULL, NULL);
203 CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to enqueue overlay kernel "
204 "for plane %d: %d.\n", plane, cle);
205 }
206
207 cle = clFinish(ctx->command_queue);
208 CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to finish command queue: %d.\n", cle);
209
210 err = av_frame_copy_props(output, input_main);
211
212 av_log(avctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64").\n",
214 output->width, output->height, output->pts);
215
216 return ff_filter_frame(outlink, output);
217
218fail:
219 av_frame_free(&output);
220 return err;
221}
222
224{
225 AVFilterContext *avctx = outlink->src;
226 OverlayOpenCLContext *ctx = avctx->priv;
227 int err;
228
229 err = ff_opencl_filter_config_output(outlink);
230 if (err < 0)
231 return err;
232
233 err = ff_framesync_init_dualinput(&ctx->fs, avctx);
234 if (err < 0)
235 return err;
236
237 return ff_framesync_configure(&ctx->fs);
238}
239
241{
242 OverlayOpenCLContext *ctx = avctx->priv;
243
244 ctx->fs.on_event = &overlay_opencl_blend;
245
246 return ff_opencl_filter_init(avctx);
247}
248
250{
251 OverlayOpenCLContext *ctx = avctx->priv;
252
253 return ff_framesync_activate(&ctx->fs);
254}
255
257{
258 OverlayOpenCLContext *ctx = avctx->priv;
259 cl_int cle;
260
261 if (ctx->kernel) {
262 cle = clReleaseKernel(ctx->kernel);
263 if (cle != CL_SUCCESS)
264 av_log(avctx, AV_LOG_ERROR, "Failed to release "
265 "kernel: %d.\n", cle);
266 }
267
268 if (ctx->command_queue) {
269 cle = clReleaseCommandQueue(ctx->command_queue);
270 if (cle != CL_SUCCESS)
271 av_log(avctx, AV_LOG_ERROR, "Failed to release "
272 "command queue: %d.\n", cle);
273 }
274
276
278}
279
280#define OFFSET(x) offsetof(OverlayOpenCLContext, x)
281#define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM)
283 { "x", "Overlay x position",
284 OFFSET(x_position), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, .flags = FLAGS },
285 { "y", "Overlay y position",
286 OFFSET(y_position), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, .flags = FLAGS },
287 { NULL },
288};
289
290AVFILTER_DEFINE_CLASS(overlay_opencl);
291
293 {
294 .name = "main",
295 .type = AVMEDIA_TYPE_VIDEO,
296 .config_props = &ff_opencl_filter_config_input,
297 },
298 {
299 .name = "overlay",
300 .type = AVMEDIA_TYPE_VIDEO,
301 .config_props = &ff_opencl_filter_config_input,
302 },
303};
304
306 {
307 .name = "default",
308 .type = AVMEDIA_TYPE_VIDEO,
309 .config_props = &overlay_opencl_config_output,
310 },
311};
312
314 .p.name = "overlay_opencl",
315 .p.description = NULL_IF_CONFIG_SMALL("Overlay one video on top of another"),
316 .p.priv_class = &overlay_opencl_class,
317 .p.flags = AVFILTER_FLAG_HWDEVICE,
318 .priv_size = sizeof(OverlayOpenCLContext),
325 .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
326};
const FFFilter ff_vf_overlay_opencl
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.
#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
int ff_framesync_init_dualinput(FFFrameSync *fs, AVFilterContext *parent)
Initialize a frame sync structure for dualinput.
Definition framesync.c:372
void ff_framesync_uninit(FFFrameSync *fs)
Free all memory currently allocated.
Definition framesync.c:301
#define fail
Definition test.h:479
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
#define AVFILTER_FLAG_HWDEVICE
The filter can create hardware frames using AVFilterContext.hw_device_ctx.
Definition avfilter.h:187
#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_WARNING
Something somehow does not look correct.
Definition log.h:216
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
static av_cold void uninit(AVBitStreamFilterContext *ctx)
static int activate(AVBitStreamFilterContext *ctx)
#define FILTER_INPUTS(array)
Definition filters.h:264
#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
#define FFMAX(a, b)
Definition macros.h:47
void ff_opencl_filter_uninit(AVFilterContext *avctx)
Uninitialise an OpenCL filter context.
Definition opencl.c:144
int ff_opencl_filter_load_program(AVFilterContext *avctx, const char **program_source_array, int nb_strings)
Load a new OpenCL program from strings in memory.
Definition opencl.c:159
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
#define CL_SET_KERNEL_ARG(kernel, arg_num, type, arg)
set argument to specific Kernel.
Definition opencl.h:61
#define CL_FAIL_ON_ERROR(errcode,...)
A helper macro to handle OpenCL errors.
Definition opencl.h:74
const char * ff_source_overlay_cl
AVOptions.
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
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition pixdesc.c:3460
AVPixelFormat
Pixel format.
Definition pixfmt.h:71
@ AV_PIX_FMT_OPENCL
Hardware surfaces for OpenCL.
Definition pixfmt.h:358
uint8_t * data
The data buffer.
Definition buffer.h:90
int plane
Which of the 4 planes contains the component.
Definition pixdesc.h:34
An instance of a filter.
Definition avfilter.h:273
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
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
AVBufferRef * hw_frames_ctx
For hwaccel-format frames, this should be a reference to the AVHWFramesContext describing the frame.
Definition frame.h:769
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
This struct describes a set or pool of "hardware" frames (i.e.
Definition hwcontext.h:118
enum AVPixelFormat sw_format
The pixel format identifying the actual data layout of the hardware frames.
Definition hwcontext.h:213
AVOption.
Definition opt.h:428
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition pixdesc.h:69
AVComponentDescriptor comp[4]
Parameters that describe how pixels are packed.
Definition pixdesc.h:105
uint8_t log2_chroma_w
Amount to shift the luma width right to find the chroma width.
Definition pixdesc.h:80
uint8_t log2_chroma_h
Amount to shift the luma height right to find the chroma height.
Definition pixdesc.h:89
uint8_t nb_components
The number of components each pixel has, (1-4)
Definition pixdesc.h:71
Frame sync structure.
Definition framesync.h:168
cl_command_queue command_queue
OpenCLFilterContext ocf
#define av_log(a,...)
static AVFormatContext * ctx
Definition movenc.c:49
static int overlay_opencl_load(AVFilterContext *avctx, enum AVPixelFormat main_format, enum AVPixelFormat overlay_format)
static av_cold int overlay_opencl_init(AVFilterContext *avctx)
static int overlay_opencl_config_output(AVFilterLink *outlink)
static int overlay_opencl_activate(AVFilterContext *avctx)
static const AVFilterPad overlay_opencl_outputs[]
static int overlay_opencl_blend(FFFrameSync *fs)
static av_cold void overlay_opencl_uninit(AVFilterContext *avctx)
#define OFFSET(x)
static const AVOption overlay_opencl_options[]
static const AVFilterPad overlay_opencl_inputs[]
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