2 * This file is part of FFmpeg.
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.
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.
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
22 #include "libavutil/file_open.h"
23 #include "libavutil/mem.h"
24 #include "libavutil/pixdesc.h"
29 static int opencl_filter_set_device(AVFilterContext
*avctx
,
32 OpenCLFilterContext
*ctx
= avctx
->priv
;
34 av_buffer_unref(&ctx
->device_ref
);
36 ctx
->device_ref
= av_buffer_ref(device
);
38 return AVERROR(ENOMEM
);
40 ctx
->device
= (AVHWDeviceContext
*)ctx
->device_ref
->data
;
41 ctx
->hwctx
= ctx
->device
->hwctx
;
46 int ff_opencl_filter_config_input(AVFilterLink
*inlink
)
48 FilterLink
*l
= ff_filter_link(inlink
);
49 AVFilterContext
*avctx
= inlink
->dst
;
50 OpenCLFilterContext
*ctx
= avctx
->priv
;
51 AVHWFramesContext
*input_frames
;
54 if (!l
->hw_frames_ctx
) {
55 av_log(avctx
, AV_LOG_ERROR
, "OpenCL filtering requires a "
56 "hardware frames context on the input.\n");
57 return AVERROR(EINVAL
);
60 // Extract the device and default output format from the first input.
61 if (avctx
->inputs
[0] != inlink
)
64 input_frames
= (AVHWFramesContext
*)l
->hw_frames_ctx
->data
;
65 if (input_frames
->format
!= AV_PIX_FMT_OPENCL
)
66 return AVERROR(EINVAL
);
68 err
= opencl_filter_set_device(avctx
, input_frames
->device_ref
);
72 // Default output parameters match input parameters.
73 if (ctx
->output_format
== AV_PIX_FMT_NONE
)
74 ctx
->output_format
= input_frames
->sw_format
;
75 if (!ctx
->output_width
)
76 ctx
->output_width
= inlink
->w
;
77 if (!ctx
->output_height
)
78 ctx
->output_height
= inlink
->h
;
83 int ff_opencl_filter_config_output(AVFilterLink
*outlink
)
85 FilterLink
*l
= ff_filter_link(outlink
);
86 AVFilterContext
*avctx
= outlink
->src
;
87 OpenCLFilterContext
*ctx
= avctx
->priv
;
88 AVBufferRef
*output_frames_ref
= NULL
;
89 AVHWFramesContext
*output_frames
;
92 av_buffer_unref(&l
->hw_frames_ctx
);
94 if (!ctx
->device_ref
) {
95 if (!avctx
->hw_device_ctx
) {
96 av_log(avctx
, AV_LOG_ERROR
, "OpenCL filtering requires an "
98 return AVERROR(EINVAL
);
101 err
= opencl_filter_set_device(avctx
, avctx
->hw_device_ctx
);
106 output_frames_ref
= av_hwframe_ctx_alloc(ctx
->device_ref
);
107 if (!output_frames_ref
) {
108 err
= AVERROR(ENOMEM
);
111 output_frames
= (AVHWFramesContext
*)output_frames_ref
->data
;
113 output_frames
->format
= AV_PIX_FMT_OPENCL
;
114 output_frames
->sw_format
= ctx
->output_format
;
115 output_frames
->width
= ctx
->output_width
;
116 output_frames
->height
= ctx
->output_height
;
118 err
= av_hwframe_ctx_init(output_frames_ref
);
120 av_log(avctx
, AV_LOG_ERROR
, "Failed to initialise output "
121 "frames: %d.\n", err
);
125 l
->hw_frames_ctx
= output_frames_ref
;
126 outlink
->w
= ctx
->output_width
;
127 outlink
->h
= ctx
->output_height
;
131 av_buffer_unref(&output_frames_ref
);
135 int ff_opencl_filter_init(AVFilterContext
*avctx
)
137 OpenCLFilterContext
*ctx
= avctx
->priv
;
139 ctx
->output_format
= AV_PIX_FMT_NONE
;
144 void ff_opencl_filter_uninit(AVFilterContext
*avctx
)
146 OpenCLFilterContext
*ctx
= avctx
->priv
;
150 cle
= clReleaseProgram(ctx
->program
);
151 if (cle
!= CL_SUCCESS
)
152 av_log(avctx
, AV_LOG_ERROR
, "Failed to release "
153 "program: %d.\n", cle
);
156 av_buffer_unref(&ctx
->device_ref
);
159 int ff_opencl_filter_load_program(AVFilterContext
*avctx
,
160 const char **program_source_array
,
163 OpenCLFilterContext
*ctx
= avctx
->priv
;
166 ctx
->program
= clCreateProgramWithSource(ctx
->hwctx
->context
, nb_strings
,
167 program_source_array
,
170 av_log(avctx
, AV_LOG_ERROR
, "Failed to create program: %d.\n", cle
);
174 cle
= clBuildProgram(ctx
->program
, 1, &ctx
->hwctx
->device_id
,
176 if (cle
!= CL_SUCCESS
) {
177 av_log(avctx
, AV_LOG_ERROR
, "Failed to build program: %d.\n", cle
);
179 if (cle
== CL_BUILD_PROGRAM_FAILURE
) {
183 clGetProgramBuildInfo(ctx
->program
, ctx
->hwctx
->device_id
,
184 CL_PROGRAM_BUILD_LOG
, 0, NULL
, &log_length
);
186 log
= av_malloc(log_length
);
188 cle
= clGetProgramBuildInfo(ctx
->program
,
189 ctx
->hwctx
->device_id
,
190 CL_PROGRAM_BUILD_LOG
,
191 log_length
, log
, NULL
);
192 if (cle
== CL_SUCCESS
)
193 av_log(avctx
, AV_LOG_ERROR
, "Build log:\n%s\n", log
);
199 clReleaseProgram(ctx
->program
);
207 int ff_opencl_filter_load_program_from_file(AVFilterContext
*avctx
,
208 const char *filename
)
213 const char *src_const
;
216 file
= avpriv_fopen_utf8(filename
, "r");
218 av_log(avctx
, AV_LOG_ERROR
, "Unable to open program "
219 "source file \"%s\".\n", filename
);
220 return AVERROR(ENOENT
);
226 err
= av_reallocp(&src
, len
);
230 err
= snprintf(src
, len
, "#line 1 \"%s\"\n", filename
);
232 err
= AVERROR(errno
);
236 err
= AVERROR(EINVAL
);
242 rb
= fread(src
+ pos
, 1, len
- pos
- 1, file
);
243 if (rb
== 0 && ferror(file
)) {
251 err
= av_reallocp(&src
, len
);
259 err
= ff_opencl_filter_load_program(avctx
, &src_const
, 1);
266 int ff_opencl_filter_work_size_from_image(AVFilterContext
*avctx
,
268 AVFrame
*frame
, int plane
,
272 cl_mem_object_type type
;
273 size_t width
, height
;
276 if (frame
->format
!= AV_PIX_FMT_OPENCL
) {
277 av_log(avctx
, AV_LOG_ERROR
, "Invalid frame format %s, "
278 "opencl required.\n", av_get_pix_fmt_name(frame
->format
));
279 return AVERROR(EINVAL
);
282 image
= (cl_mem
)frame
->data
[plane
];
284 av_log(avctx
, AV_LOG_ERROR
, "Plane %d required but not set.\n",
286 return AVERROR(EINVAL
);
289 cle
= clGetMemObjectInfo(image
, CL_MEM_TYPE
, sizeof(type
),
291 if (cle
!= CL_SUCCESS
) {
292 av_log(avctx
, AV_LOG_ERROR
, "Failed to query object type of "
293 "plane %d: %d.\n", plane
, cle
);
294 return AVERROR_UNKNOWN
;
296 if (type
!= CL_MEM_OBJECT_IMAGE2D
) {
297 av_log(avctx
, AV_LOG_ERROR
, "Plane %d is not a 2D image.\n",
299 return AVERROR(EINVAL
);
302 cle
= clGetImageInfo(image
, CL_IMAGE_WIDTH
, sizeof(size_t),
304 if (cle
!= CL_SUCCESS
) {
305 av_log(avctx
, AV_LOG_ERROR
, "Failed to query plane %d width: %d.\n",
307 return AVERROR_UNKNOWN
;
310 cle
= clGetImageInfo(image
, CL_IMAGE_HEIGHT
, sizeof(size_t),
312 if (cle
!= CL_SUCCESS
) {
313 av_log(avctx
, AV_LOG_ERROR
, "Failed to query plane %d height: %d.\n",
315 return AVERROR_UNKNOWN
;
318 if (block_alignment
) {
319 width
= FFALIGN(width
, block_alignment
);
320 height
= FFALIGN(height
, block_alignment
);
323 work_size
[0] = width
;
324 work_size
[1] = height
;
329 void ff_opencl_print_const_matrix_3x3(AVBPrint
*buf
, const char *name_str
,
333 av_bprintf(buf
, "__constant float %s[9] = {\n", name_str
);
334 for (i
= 0; i
< 3; i
++) {
335 for (j
= 0; j
< 3; j
++)
336 av_bprintf(buf
, " %.5ff,", mat
[i
][j
]);
337 av_bprintf(buf
, "\n");
339 av_bprintf(buf
, "};\n");
342 cl_ulong
ff_opencl_get_event_time(cl_event event
) {
346 clGetEventProfilingInfo(event
, CL_PROFILING_COMMAND_START
, sizeof(time_start
), &time_start
, NULL
);
347 clGetEventProfilingInfo(event
, CL_PROFILING_COMMAND_END
, sizeof(time_end
), &time_end
, NULL
);
349 return time_end
- time_start
;