Browse code

lavfi: Add some common code for OpenCL filtering

Mark Thompson authored on 2017/06/28 06:50:49
Showing 2 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,251 @@
0
+/*
1
+ * This file is part of FFmpeg.
2
+ *
3
+ * FFmpeg is free software; you can redistribute it and/or
4
+ * modify it under the terms of the GNU Lesser General Public
5
+ * License as published by the Free Software Foundation; either
6
+ * version 2.1 of the License, or (at your option) any later version.
7
+ *
8
+ * FFmpeg is distributed in the hope that it will be useful,
9
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
+ * Lesser General Public License for more details.
12
+ *
13
+ * You should have received a copy of the GNU Lesser General Public
14
+ * License along with FFmpeg; if not, write to the Free Software
15
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+ */
17
+
18
+#include <stdio.h>
19
+#include <string.h>
20
+
21
+#include "libavutil/hwcontext.h"
22
+#include "libavutil/hwcontext_opencl.h"
23
+#include "libavutil/mem.h"
24
+
25
+#include "avfilter.h"
26
+#include "formats.h"
27
+#include "opencl.h"
28
+
29
+int ff_opencl_filter_query_formats(AVFilterContext *avctx)
30
+{
31
+    const static enum AVPixelFormat pix_fmts[] = {
32
+        AV_PIX_FMT_OPENCL,
33
+        AV_PIX_FMT_NONE,
34
+    };
35
+    AVFilterFormats *formats;
36
+
37
+    formats = ff_make_format_list(pix_fmts);
38
+    if (!formats)
39
+        return AVERROR(ENOMEM);
40
+
41
+    return ff_set_common_formats(avctx, formats);
42
+}
43
+
44
+int ff_opencl_filter_config_input(AVFilterLink *inlink)
45
+{
46
+    AVFilterContext   *avctx = inlink->dst;
47
+    OpenCLFilterContext *ctx = avctx->priv;
48
+    AVHWFramesContext *input_frames;
49
+
50
+    if (!inlink->hw_frames_ctx) {
51
+        av_log(avctx, AV_LOG_ERROR, "OpenCL filtering requires a "
52
+               "hardware frames context on the input.\n");
53
+        return AVERROR(EINVAL);
54
+    }
55
+
56
+    // Extract the device and default output format from the first input.
57
+    if (avctx->inputs[0] != inlink)
58
+        return 0;
59
+
60
+    input_frames = (AVHWFramesContext*)inlink->hw_frames_ctx->data;
61
+
62
+    if (input_frames->format != AV_PIX_FMT_OPENCL)
63
+        return AVERROR(EINVAL);
64
+
65
+    ctx->device_ref = av_buffer_ref(input_frames->device_ref);
66
+    if (!ctx->device_ref)
67
+        return AVERROR(ENOMEM);
68
+    ctx->device = input_frames->device_ctx;
69
+    ctx->hwctx  = ctx->device->hwctx;
70
+
71
+    // Default output parameters match input parameters.
72
+    if (ctx->output_format == AV_PIX_FMT_NONE)
73
+        ctx->output_format = input_frames->sw_format;
74
+    if (!ctx->output_width)
75
+        ctx->output_width  = inlink->w;
76
+    if (!ctx->output_height)
77
+        ctx->output_height = inlink->h;
78
+
79
+    return 0;
80
+}
81
+
82
+int ff_opencl_filter_config_output(AVFilterLink *outlink)
83
+{
84
+    AVFilterContext   *avctx = outlink->src;
85
+    OpenCLFilterContext *ctx = avctx->priv;
86
+    AVBufferRef       *output_frames_ref = NULL;
87
+    AVHWFramesContext *output_frames;
88
+    int err;
89
+
90
+    av_buffer_unref(&outlink->hw_frames_ctx);
91
+
92
+    output_frames_ref = av_hwframe_ctx_alloc(ctx->device_ref);
93
+    if (!output_frames_ref) {
94
+        err = AVERROR(ENOMEM);
95
+        goto fail;
96
+    }
97
+    output_frames = (AVHWFramesContext*)output_frames_ref->data;
98
+
99
+    output_frames->format    = AV_PIX_FMT_OPENCL;
100
+    output_frames->sw_format = ctx->output_format;
101
+    output_frames->width     = ctx->output_width;
102
+    output_frames->height    = ctx->output_height;
103
+
104
+    err = av_hwframe_ctx_init(output_frames_ref);
105
+    if (err < 0) {
106
+        av_log(avctx, AV_LOG_ERROR, "Failed to initialise output "
107
+               "frames: %d.\n", err);
108
+        goto fail;
109
+    }
110
+
111
+    outlink->hw_frames_ctx = output_frames_ref;
112
+    outlink->w = ctx->output_width;
113
+    outlink->h = ctx->output_height;
114
+
115
+    return 0;
116
+fail:
117
+    av_buffer_unref(&output_frames_ref);
118
+    return err;
119
+}
120
+
121
+int ff_opencl_filter_init(AVFilterContext *avctx)
122
+{
123
+    OpenCLFilterContext *ctx = avctx->priv;
124
+
125
+    ctx->output_format = AV_PIX_FMT_NONE;
126
+
127
+    return 0;
128
+}
129
+
130
+void ff_opencl_filter_uninit(AVFilterContext *avctx)
131
+{
132
+    OpenCLFilterContext *ctx = avctx->priv;
133
+    cl_int cle;
134
+
135
+    if (ctx->program) {
136
+        cle = clReleaseProgram(ctx->program);
137
+        if (cle != CL_SUCCESS)
138
+            av_log(avctx, AV_LOG_ERROR, "Failed to release "
139
+                   "program: %d.\n", cle);
140
+    }
141
+
142
+    av_buffer_unref(&ctx->device_ref);
143
+}
144
+
145
+int ff_opencl_filter_load_program(AVFilterContext *avctx,
146
+                                  const char **program_source_array,
147
+                                  int nb_strings)
148
+{
149
+    OpenCLFilterContext *ctx = avctx->priv;
150
+    cl_int cle;
151
+
152
+    ctx->program = clCreateProgramWithSource(ctx->hwctx->context, nb_strings,
153
+                                             program_source_array,
154
+                                             NULL, &cle);
155
+    if (!ctx->program) {
156
+        av_log(avctx, AV_LOG_ERROR, "Failed to create program: %d.\n", cle);
157
+        return AVERROR(EIO);
158
+    }
159
+
160
+    cle = clBuildProgram(ctx->program, 1, &ctx->hwctx->device_id,
161
+                         NULL, NULL, NULL);
162
+    if (cle != CL_SUCCESS) {
163
+        av_log(avctx, AV_LOG_ERROR, "Failed to build program: %d.\n", cle);
164
+
165
+        if (cle == CL_BUILD_PROGRAM_FAILURE) {
166
+            char *log;
167
+            size_t log_length;
168
+
169
+            clGetProgramBuildInfo(ctx->program, ctx->hwctx->device_id,
170
+                                  CL_PROGRAM_BUILD_LOG, 0, NULL, &log_length);
171
+
172
+            log = av_malloc(log_length);
173
+            if (log) {
174
+                cle = clGetProgramBuildInfo(ctx->program,
175
+                                            ctx->hwctx->device_id,
176
+                                            CL_PROGRAM_BUILD_LOG,
177
+                                            log_length, log, NULL);
178
+                if (cle == CL_SUCCESS)
179
+                    av_log(avctx, AV_LOG_ERROR, "Build log:\n%s\n", log);
180
+            }
181
+
182
+            av_free(log);
183
+        }
184
+
185
+        clReleaseProgram(ctx->program);
186
+        ctx->program = NULL;
187
+        return AVERROR(EIO);
188
+    }
189
+
190
+    return 0;
191
+}
192
+
193
+int ff_opencl_filter_load_program_from_file(AVFilterContext *avctx,
194
+                                            const char *filename)
195
+{
196
+    FILE *file;
197
+    char *src = NULL;
198
+    size_t pos, len, rb;
199
+    const char *src_const;
200
+    int err;
201
+
202
+    file = fopen(filename, "r");
203
+    if (!file) {
204
+        av_log(avctx, AV_LOG_ERROR, "Unable to open program "
205
+               "source file \"%s\".\n", filename);
206
+        return AVERROR(ENOENT);
207
+    }
208
+
209
+    len = 1 << 16;
210
+    pos = 0;
211
+
212
+    err = av_reallocp(&src, len);
213
+    if (err < 0)
214
+        goto fail;
215
+
216
+    err = snprintf(src, len, "#line 1 \"%s\"\n", filename);
217
+    if (err < 0) {
218
+        err = AVERROR(errno);
219
+        goto fail;
220
+    }
221
+    if (err > len / 2) {
222
+        err = AVERROR(EINVAL);
223
+        goto fail;
224
+    }
225
+    pos = err;
226
+
227
+    while (1) {
228
+        rb = fread(src + pos, 1, len - pos - 1, file);
229
+        if (rb == 0 && ferror(file)) {
230
+            err = AVERROR(EIO);
231
+            goto fail;
232
+        }
233
+        pos += rb;
234
+        if (pos < len)
235
+            break;
236
+        len <<= 1;
237
+        err = av_reallocp(&src, len);
238
+        if (err < 0)
239
+            goto fail;
240
+    }
241
+    src[pos] = 0;
242
+
243
+    src_const = src;
244
+
245
+    err = ff_opencl_filter_load_program(avctx, &src_const, 1);
246
+fail:
247
+    fclose(file);
248
+    av_freep(&src);
249
+    return err;
250
+}
0 251
new file mode 100644
... ...
@@ -0,0 +1,87 @@
0
+/*
1
+ * This file is part of FFmpeg.
2
+ *
3
+ * FFmpeg is free software; you can redistribute it and/or
4
+ * modify it under the terms of the GNU Lesser General Public
5
+ * License as published by the Free Software Foundation; either
6
+ * version 2.1 of the License, or (at your option) any later version.
7
+ *
8
+ * FFmpeg is distributed in the hope that it will be useful,
9
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
+ * Lesser General Public License for more details.
12
+ *
13
+ * You should have received a copy of the GNU Lesser General Public
14
+ * License along with FFmpeg; if not, write to the Free Software
15
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+ */
17
+
18
+#ifndef AVFILTER_OPENCL_H
19
+#define AVFILTER_OPENCL_H
20
+
21
+#include "libavutil/buffer.h"
22
+#include "libavutil/hwcontext.h"
23
+#include "libavutil/hwcontext_opencl.h"
24
+#include "libavutil/pixfmt.h"
25
+
26
+#include "avfilter.h"
27
+
28
+typedef struct OpenCLFilterContext {
29
+    const AVClass     *class;
30
+
31
+    AVBufferRef       *device_ref;
32
+    AVHWDeviceContext *device;
33
+    AVOpenCLDeviceContext *hwctx;
34
+
35
+    cl_program         program;
36
+
37
+    enum AVPixelFormat output_format;
38
+    int                output_width;
39
+    int                output_height;
40
+} OpenCLFilterContext;
41
+
42
+/**
43
+ * Return that all inputs and outputs support only AV_PIX_FMT_OPENCL.
44
+ */
45
+int ff_opencl_filter_query_formats(AVFilterContext *avctx);
46
+
47
+/**
48
+ * Check that the input link contains a suitable hardware frames
49
+ * context and extract the device from it.
50
+ */
51
+int ff_opencl_filter_config_input(AVFilterLink *inlink);
52
+
53
+/**
54
+ * Create a suitable hardware frames context for the output.
55
+ */
56
+int ff_opencl_filter_config_output(AVFilterLink *outlink);
57
+
58
+/**
59
+ * Initialise an OpenCL filter context.
60
+ */
61
+int ff_opencl_filter_init(AVFilterContext *avctx);
62
+
63
+/**
64
+ * Uninitialise an OpenCL filter context.
65
+ */
66
+void ff_opencl_filter_uninit(AVFilterContext *avctx);
67
+
68
+/**
69
+ * Load a new OpenCL program from strings in memory.
70
+ *
71
+ * Creates a new program and compiles it for the current device.
72
+ * Will log any build errors if compilation fails.
73
+ */
74
+int ff_opencl_filter_load_program(AVFilterContext *avctx,
75
+                                  const char **program_source_array,
76
+                                  int nb_strings);
77
+
78
+/**
79
+ * Load a new OpenCL program from a file.
80
+ *
81
+ * Same as ff_opencl_filter_load_program(), but from a file.
82
+ */
83
+int ff_opencl_filter_load_program_from_file(AVFilterContext *avctx,
84
+                                            const char *filename);
85
+
86
+#endif /* AVFILTER_OPENCL_H */