FFmpeg  4.0
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 <stdio.h>
20 #include <string.h>
21 
22 #include "libavutil/hwcontext.h"
24 #include "libavutil/mem.h"
25 #include "libavutil/pixdesc.h"
26 
27 #include "avfilter.h"
28 #include "formats.h"
29 #include "opencl.h"
30 
32 {
33  const static enum AVPixelFormat pix_fmts[] = {
36  };
38 
39  formats = ff_make_format_list(pix_fmts);
40  if (!formats)
41  return AVERROR(ENOMEM);
42 
43  return ff_set_common_formats(avctx, formats);
44 }
45 
47  AVBufferRef *device)
48 {
49  OpenCLFilterContext *ctx = avctx->priv;
50 
52 
53  ctx->device_ref = av_buffer_ref(device);
54  if (!ctx->device_ref)
55  return AVERROR(ENOMEM);
56 
57  ctx->device = (AVHWDeviceContext*)ctx->device_ref->data;
58  ctx->hwctx = ctx->device->hwctx;
59 
60  return 0;
61 }
62 
64 {
65  AVFilterContext *avctx = inlink->dst;
66  OpenCLFilterContext *ctx = avctx->priv;
67  AVHWFramesContext *input_frames;
68  int err;
69 
70  if (!inlink->hw_frames_ctx) {
71  av_log(avctx, AV_LOG_ERROR, "OpenCL filtering requires a "
72  "hardware frames context on the input.\n");
73  return AVERROR(EINVAL);
74  }
75 
76  // Extract the device and default output format from the first input.
77  if (avctx->inputs[0] != inlink)
78  return 0;
79 
80  input_frames = (AVHWFramesContext*)inlink->hw_frames_ctx->data;
81  if (input_frames->format != AV_PIX_FMT_OPENCL)
82  return AVERROR(EINVAL);
83 
84  err = opencl_filter_set_device(avctx, input_frames->device_ref);
85  if (err < 0)
86  return err;
87 
88  // Default output parameters match input parameters.
89  if (ctx->output_format == AV_PIX_FMT_NONE)
90  ctx->output_format = input_frames->sw_format;
91  if (!ctx->output_width)
92  ctx->output_width = inlink->w;
93  if (!ctx->output_height)
94  ctx->output_height = inlink->h;
95 
96  return 0;
97 }
98 
100 {
101  AVFilterContext *avctx = outlink->src;
102  OpenCLFilterContext *ctx = avctx->priv;
103  AVBufferRef *output_frames_ref = NULL;
104  AVHWFramesContext *output_frames;
105  int err;
106 
107  av_buffer_unref(&outlink->hw_frames_ctx);
108 
109  if (!ctx->device_ref) {
110  if (!avctx->hw_device_ctx) {
111  av_log(avctx, AV_LOG_ERROR, "OpenCL filtering requires an "
112  "OpenCL device.\n");
113  return AVERROR(EINVAL);
114  }
115 
116  err = opencl_filter_set_device(avctx, avctx->hw_device_ctx);
117  if (err < 0)
118  return err;
119  }
120 
121  output_frames_ref = av_hwframe_ctx_alloc(ctx->device_ref);
122  if (!output_frames_ref) {
123  err = AVERROR(ENOMEM);
124  goto fail;
125  }
126  output_frames = (AVHWFramesContext*)output_frames_ref->data;
127 
128  output_frames->format = AV_PIX_FMT_OPENCL;
129  output_frames->sw_format = ctx->output_format;
130  output_frames->width = ctx->output_width;
131  output_frames->height = ctx->output_height;
132 
133  err = av_hwframe_ctx_init(output_frames_ref);
134  if (err < 0) {
135  av_log(avctx, AV_LOG_ERROR, "Failed to initialise output "
136  "frames: %d.\n", err);
137  goto fail;
138  }
139 
140  outlink->hw_frames_ctx = output_frames_ref;
141  outlink->w = ctx->output_width;
142  outlink->h = ctx->output_height;
143 
144  return 0;
145 fail:
146  av_buffer_unref(&output_frames_ref);
147  return err;
148 }
149 
151 {
152  OpenCLFilterContext *ctx = avctx->priv;
153 
155 
156  return 0;
157 }
158 
160 {
161  OpenCLFilterContext *ctx = avctx->priv;
162  cl_int cle;
163 
164  if (ctx->program) {
165  cle = clReleaseProgram(ctx->program);
166  if (cle != CL_SUCCESS)
167  av_log(avctx, AV_LOG_ERROR, "Failed to release "
168  "program: %d.\n", cle);
169  }
170 
172 }
173 
175  const char **program_source_array,
176  int nb_strings)
177 {
178  OpenCLFilterContext *ctx = avctx->priv;
179  cl_int cle;
180 
181  ctx->program = clCreateProgramWithSource(ctx->hwctx->context, nb_strings,
182  program_source_array,
183  NULL, &cle);
184  if (!ctx->program) {
185  av_log(avctx, AV_LOG_ERROR, "Failed to create program: %d.\n", cle);
186  return AVERROR(EIO);
187  }
188 
189  cle = clBuildProgram(ctx->program, 1, &ctx->hwctx->device_id,
190  NULL, NULL, NULL);
191  if (cle != CL_SUCCESS) {
192  av_log(avctx, AV_LOG_ERROR, "Failed to build program: %d.\n", cle);
193 
194  if (cle == CL_BUILD_PROGRAM_FAILURE) {
195  char *log;
196  size_t log_length;
197 
198  clGetProgramBuildInfo(ctx->program, ctx->hwctx->device_id,
199  CL_PROGRAM_BUILD_LOG, 0, NULL, &log_length);
200 
201  log = av_malloc(log_length);
202  if (log) {
203  cle = clGetProgramBuildInfo(ctx->program,
204  ctx->hwctx->device_id,
205  CL_PROGRAM_BUILD_LOG,
206  log_length, log, NULL);
207  if (cle == CL_SUCCESS)
208  av_log(avctx, AV_LOG_ERROR, "Build log:\n%s\n", log);
209  }
210 
211  av_free(log);
212  }
213 
214  clReleaseProgram(ctx->program);
215  ctx->program = NULL;
216  return AVERROR(EIO);
217  }
218 
219  return 0;
220 }
221 
223  const char *filename)
224 {
225  FILE *file;
226  char *src = NULL;
227  size_t pos, len, rb;
228  const char *src_const;
229  int err;
230 
231  file = fopen(filename, "r");
232  if (!file) {
233  av_log(avctx, AV_LOG_ERROR, "Unable to open program "
234  "source file \"%s\".\n", filename);
235  return AVERROR(ENOENT);
236  }
237 
238  len = 1 << 16;
239  pos = 0;
240 
241  err = av_reallocp(&src, len);
242  if (err < 0)
243  goto fail;
244 
245  err = snprintf(src, len, "#line 1 \"%s\"\n", filename);
246  if (err < 0) {
247  err = AVERROR(errno);
248  goto fail;
249  }
250  if (err > len / 2) {
251  err = AVERROR(EINVAL);
252  goto fail;
253  }
254  pos = err;
255 
256  while (1) {
257  rb = fread(src + pos, 1, len - pos - 1, file);
258  if (rb == 0 && ferror(file)) {
259  err = AVERROR(EIO);
260  goto fail;
261  }
262  pos += rb;
263  if (pos < len)
264  break;
265  len <<= 1;
266  err = av_reallocp(&src, len);
267  if (err < 0)
268  goto fail;
269  }
270  src[pos] = 0;
271 
272  src_const = src;
273 
274  err = ff_opencl_filter_load_program(avctx, &src_const, 1);
275 fail:
276  fclose(file);
277  av_freep(&src);
278  return err;
279 }
280 
282  size_t *work_size,
283  AVFrame *frame, int plane,
284  int block_alignment)
285 {
286  cl_mem image;
287  cl_mem_object_type type;
288  size_t width, height;
289  cl_int cle;
290 
291  if (frame->format != AV_PIX_FMT_OPENCL) {
292  av_log(avctx, AV_LOG_ERROR, "Invalid frame format %s, "
293  "opencl required.\n", av_get_pix_fmt_name(frame->format));
294  return AVERROR(EINVAL);
295  }
296 
297  image = (cl_mem)frame->data[plane];
298  if (!image) {
299  av_log(avctx, AV_LOG_ERROR, "Plane %d required but not set.\n",
300  plane);
301  return AVERROR(EINVAL);
302  }
303 
304  cle = clGetMemObjectInfo(image, CL_MEM_TYPE, sizeof(type),
305  &type, NULL);
306  if (cle != CL_SUCCESS) {
307  av_log(avctx, AV_LOG_ERROR, "Failed to query object type of "
308  "plane %d: %d.\n", plane, cle);
309  return AVERROR_UNKNOWN;
310  }
311  if (type != CL_MEM_OBJECT_IMAGE2D) {
312  av_log(avctx, AV_LOG_ERROR, "Plane %d is not a 2D image.\n",
313  plane);
314  return AVERROR(EINVAL);
315  }
316 
317  cle = clGetImageInfo(image, CL_IMAGE_WIDTH, sizeof(size_t),
318  &width, NULL);
319  if (cle != CL_SUCCESS) {
320  av_log(avctx, AV_LOG_ERROR, "Failed to query plane %d width: %d.\n",
321  plane, cle);
322  return AVERROR_UNKNOWN;
323  }
324 
325  cle = clGetImageInfo(image, CL_IMAGE_HEIGHT, sizeof(size_t),
326  &height, NULL);
327  if (cle != CL_SUCCESS) {
328  av_log(avctx, AV_LOG_ERROR, "Failed to query plane %d height: %d.\n",
329  plane, cle);
330  return AVERROR_UNKNOWN;
331  }
332 
333  if (block_alignment) {
334  width = FFALIGN(width, block_alignment);
335  height = FFALIGN(height, block_alignment);
336  }
337 
338  work_size[0] = width;
339  work_size[1] = height;
340 
341  return 0;
342 }
This struct aggregates all the (hardware/vendor-specific) "high-level" state, i.e.
Definition: hwcontext.h:60
int plane
Definition: avisynth_c.h:422
API-specific header for AV_HWDEVICE_TYPE_OPENCL.
#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:125
This structure describes decoded (raw) audio or video data.
Definition: frame.h:218
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:281
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:63
int ff_opencl_filter_query_formats(AVFilterContext *avctx)
Return that all inputs and outputs support only AV_PIX_FMT_OPENCL.
Definition: opencl.c:31
Main libavfilter public API header.
Memory handling functions.
int width
The allocated dimensions of the frames in this pool.
Definition: hwcontext.h:228
AVBufferRef * hw_device_ctx
For filters which will create hardware frames, sets the device the filter should create them in...
Definition: avfilter.h:394
enum AVPixelFormat format
The pixel format identifying the underlying HW surface type.
Definition: hwcontext.h:208
#define src
Definition: vp8dsp.c:254
int ff_opencl_filter_init(AVFilterContext *avctx)
Initialise an OpenCL filter context.
Definition: opencl.c:150
AVOpenCLDeviceContext * hwctx
Definition: opencl.h:40
AVFilterFormats * ff_make_format_list(const int *fmts)
Create a list of supported formats.
Definition: formats.c:283
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:346
#define av_malloc(s)
cl_device_id device_id
The primary device ID of the device.
AVHWDeviceContext * device
Definition: opencl.h:39
static AVFrame * frame
void * hwctx
The format-specific data, allocated and freed by libavutil along with this context.
Definition: hwcontext.h:91
#define height
int ff_opencl_filter_config_output(AVFilterLink *outlink)
Create a suitable hardware frames context for the output.
Definition: opencl.c:99
#define FFALIGN(x, a)
Definition: macros.h:48
#define av_log(a,...)
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
int ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
A helper for query_formats() which sets all links to the same list of formats.
Definition: formats.c:568
#define AVERROR(e)
Definition: error.h:43
void * priv
private data for use by the filter
Definition: avfilter.h:353
uint16_t width
Definition: gdv.c:47
int av_hwframe_ctx_init(AVBufferRef *ref)
Finalize the context before use.
Definition: hwcontext.c:329
#define fail()
Definition: checkasm.h:116
enum AVPixelFormat output_format
Definition: opencl.h:44
AVFormatContext * ctx
Definition: movenc.c:48
static int opencl_filter_set_device(AVFilterContext *avctx, AVBufferRef *device)
Definition: opencl.c:46
Hardware surfaces for OpenCL.
Definition: pixfmt.h:331
int ff_opencl_filter_load_program_from_file(AVFilterContext *avctx, const char *filename)
Load a new OpenCL program from a file.
Definition: opencl.c:222
if(ret< 0)
Definition: vf_mcdeint.c:279
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames...
Definition: frame.h:291
int av_reallocp(void *ptr, size_t size)
Allocate, reallocate, or free a block of memory through a pointer to a pointer.
Definition: mem.c:163
uint8_t * data
The data buffer.
Definition: buffer.h:89
This struct describes a set or pool of "hardware" frames (i.e.
Definition: hwcontext.h:123
cl_device_type type
#define snprintf
Definition: snprintf.h:34
static enum AVPixelFormat pix_fmts[]
Definition: libkvazaar.c:266
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:232
AVBufferRef * device_ref
A reference to the parent AVHWDeviceContext.
Definition: hwcontext.h:140
A reference to a data buffer.
Definition: buffer.h:81
AVBufferRef * av_hwframe_ctx_alloc(AVBufferRef *device_ref_in)
Allocate an AVHWFramesContext tied to a given device context.
Definition: hwcontext.c:243
void ff_opencl_filter_uninit(AVFilterContext *avctx)
Uninitialise an OpenCL filter context.
Definition: opencl.c:159
AVBufferRef * av_buffer_ref(AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition: buffer.c:93
AVBufferRef * device_ref
Definition: opencl.h:38
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition: error.h:71
#define av_free(p)
int len
cl_context context
The OpenCL context which will contain all operations and frames on this device.
A list of supported formats for one end of a filter link.
Definition: formats.h:64
An instance of a filter.
Definition: avfilter.h:338
#define av_freep(p)
cl_program program
Definition: opencl.h:42
formats
Definition: signature.h:48
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:174
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:2279
enum AVPixelFormat sw_format
The pixel format identifying the actual data layout of the hardware frames.
Definition: hwcontext.h:221
AVPixelFormat
Pixel format.
Definition: pixfmt.h:60