FFmpeg
Loading...
Searching...
No Matches
vf_libopencv.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2010 Stefano Sabatini
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21/**
22 * @file
23 * libopencv wrapper functions
24 */
25
26#include "config.h"
27#include <opencv2/core/core_c.h>
28#include <opencv2/imgproc/imgproc_c.h>
29#include "libavutil/avassert.h"
30#include "libavutil/avstring.h"
31#include "libavutil/common.h"
32#include "libavutil/file.h"
33#include "libavutil/mem.h"
34#include "libavutil/opt.h"
35#include "avfilter.h"
36#include "filters.h"
37#include "formats.h"
38#include "video.h"
39
40static void fill_iplimage_from_frame(IplImage **_img, const AVFrame *frame, enum AVPixelFormat pixfmt)
41{
42 IplImage *img;
43 int depth, channels_nb;
44
45 if (pixfmt == AV_PIX_FMT_GRAY8) { depth = IPL_DEPTH_8U; channels_nb = 1; }
46 else if (pixfmt == AV_PIX_FMT_BGRA) { depth = IPL_DEPTH_8U; channels_nb = 4; }
47 else if (pixfmt == AV_PIX_FMT_BGR24) { depth = IPL_DEPTH_8U; channels_nb = 3; }
48 else av_unreachable("unsupported pix fmt");
49
50 *_img = img = cvCreateImageHeader((CvSize){frame->width, frame->height}, depth, channels_nb);
51 img->imageData = img->imageDataOrigin = frame->data[0];
52 img->dataOrder = IPL_DATA_ORDER_PIXEL;
53 img->origin = IPL_ORIGIN_TL;
54 img->widthStep = frame->linesize[0];
55}
56
57static void fill_frame_from_iplimage(AVFrame *frame, const IplImage *img, enum AVPixelFormat pixfmt)
58{
59 frame->linesize[0] = img->widthStep;
60 frame->data[0] = img->imageData;
61}
62
63typedef struct OCVContext {
64 const AVClass *class;
65 char *name;
66 char *params;
67 int (*init)(AVFilterContext *ctx, const char *args);
69 void (*end_frame_filter)(AVFilterContext *ctx, IplImage *inimg, IplImage *outimg);
70 void *priv;
72
73typedef struct SmoothContext {
74 int type;
76 double param3, param4;
78
79static av_cold int smooth_init(AVFilterContext *ctx, const char *args)
80{
81 OCVContext *s = ctx->priv;
82 SmoothContext *smooth = s->priv;
83 char type_str[128] = "gaussian";
84
85 smooth->param1 = 3;
86 smooth->param2 = 0;
87 smooth->param3 = 0.0;
88 smooth->param4 = 0.0;
89
90 if (args)
91 sscanf(args, "%127[^|]|%d|%d|%lf|%lf", type_str, &smooth->param1, &smooth->param2, &smooth->param3, &smooth->param4);
92
93 if (!strcmp(type_str, "blur" )) smooth->type = CV_BLUR;
94 else if (!strcmp(type_str, "blur_no_scale")) smooth->type = CV_BLUR_NO_SCALE;
95 else if (!strcmp(type_str, "median" )) smooth->type = CV_MEDIAN;
96 else if (!strcmp(type_str, "gaussian" )) smooth->type = CV_GAUSSIAN;
97 else if (!strcmp(type_str, "bilateral" )) smooth->type = CV_BILATERAL;
98 else {
99 av_log(ctx, AV_LOG_ERROR, "Smoothing type '%s' unknown.\n", type_str);
100 return AVERROR(EINVAL);
101 }
102
103 if (smooth->param1 < 0 || !(smooth->param1%2)) {
105 "Invalid value '%d' for param1, it has to be a positive odd number\n",
106 smooth->param1);
107 return AVERROR(EINVAL);
108 }
109 if ((smooth->type == CV_BLUR || smooth->type == CV_BLUR_NO_SCALE || smooth->type == CV_GAUSSIAN) &&
110 (smooth->param2 < 0 || (smooth->param2 && !(smooth->param2%2)))) {
112 "Invalid value '%d' for param2, it has to be zero or a positive odd number\n",
113 smooth->param2);
114 return AVERROR(EINVAL);
115 }
116
117 av_log(ctx, AV_LOG_VERBOSE, "type:%s param1:%d param2:%d param3:%f param4:%f\n",
118 type_str, smooth->param1, smooth->param2, smooth->param3, smooth->param4);
119 return 0;
120}
121
122static void smooth_end_frame_filter(AVFilterContext *ctx, IplImage *inimg, IplImage *outimg)
123{
124 OCVContext *s = ctx->priv;
125 SmoothContext *smooth = s->priv;
126 cvSmooth(inimg, outimg, smooth->type, smooth->param1, smooth->param2, smooth->param3, smooth->param4);
127}
128
129static int read_shape_from_file(int *cols, int *rows, int **values, const char *filename,
130 void *log_ctx)
131{
132 uint8_t *buf, *p, *pend;
133 size_t size;
134 int ret, i, j, w;
135
136 if ((ret = av_file_map(filename, &buf, &size, 0, log_ctx)) < 0)
137 return ret;
138
139 /* prescan file to get the number of lines and the maximum width */
140 w = 0;
141 for (i = 0; i < size; i++) {
142 if (buf[i] == '\n') {
143 if (*rows == INT_MAX) {
144 av_log(log_ctx, AV_LOG_ERROR, "Overflow on the number of rows in the file\n");
146 goto end;
147 }
148 ++(*rows);
149 *cols = FFMAX(*cols, w);
150 w = 0;
151 } else if (w == INT_MAX) {
152 av_log(log_ctx, AV_LOG_ERROR, "Overflow on the number of columns in the file\n");
154 goto end;
155 }
156 w++;
157 }
158 if (*cols == 0) {
159 av_log(log_ctx, AV_LOG_ERROR, "No columns in the shape file\n");
161 goto end;
162 }
163 if (*rows > (SIZE_MAX / sizeof(int) / *cols)) {
164 av_log(log_ctx, AV_LOG_ERROR, "File with size %dx%d is too big\n",
165 *rows, *cols);
167 goto end;
168 }
169 if (!(*values = av_calloc(*cols, sizeof(**values) * *rows))) {
170 ret = AVERROR(ENOMEM);
171 goto end;
172 }
173
174 /* fill *values */
175 p = buf;
176 pend = buf + size-1;
177 for (i = 0; i < *rows; i++) {
178 for (j = 0;; j++) {
179 if (p > pend || *p == '\n') {
180 p++;
181 break;
182 } else
183 (*values)[*cols*i + j] = !!av_isgraph(*(p++));
184 }
185 }
186
187end:
188 av_file_unmap(buf, size);
189 if (ret < 0)
190 return ret;
191
192#ifdef DEBUG
193 {
194 char *line;
195 if (!(line = av_malloc(*cols + 1)))
196 return AVERROR(ENOMEM);
197 for (i = 0; i < *rows; i++) {
198 for (j = 0; j < *cols; j++)
199 line[j] = (*values)[i * *cols + j] ? '@' : ' ';
200 line[j] = 0;
201 av_log(log_ctx, AV_LOG_DEBUG, "%3d: %s\n", i, line);
202 }
203 av_free(line);
204 }
205#endif
206
207 return 0;
208}
209
210static int parse_iplconvkernel(IplConvKernel **kernel, char *buf, void *log_ctx)
211{
212 char shape_filename[128] = "", shape_str[32] = "rect";
213 int cols = 0, rows = 0, anchor_x = 0, anchor_y = 0, shape = CV_SHAPE_RECT;
214 int *values = NULL, ret = 0;
215
216 sscanf(buf, "%dx%d+%dx%d/%31[^=]=%127s", &cols, &rows, &anchor_x, &anchor_y, shape_str, shape_filename);
217
218 if (!strcmp(shape_str, "rect" )) shape = CV_SHAPE_RECT;
219 else if (!strcmp(shape_str, "cross" )) shape = CV_SHAPE_CROSS;
220 else if (!strcmp(shape_str, "ellipse")) shape = CV_SHAPE_ELLIPSE;
221 else if (!strcmp(shape_str, "custom" )) {
222 shape = CV_SHAPE_CUSTOM;
223 if ((ret = read_shape_from_file(&cols, &rows, &values, shape_filename, log_ctx)) < 0)
224 return ret;
225 } else {
226 av_log(log_ctx, AV_LOG_ERROR,
227 "Shape unspecified or type '%s' unknown.\n", shape_str);
228 ret = AVERROR(EINVAL);
229 goto out;
230 }
231
232 if (rows <= 0 || cols <= 0) {
233 av_log(log_ctx, AV_LOG_ERROR,
234 "Invalid non-positive values for shape size %dx%d\n", cols, rows);
235 ret = AVERROR(EINVAL);
236 goto out;
237 }
238
239 if (anchor_x < 0 || anchor_y < 0 || anchor_x >= cols || anchor_y >= rows) {
240 av_log(log_ctx, AV_LOG_ERROR,
241 "Shape anchor %dx%d is not inside the rectangle with size %dx%d.\n",
242 anchor_x, anchor_y, cols, rows);
243 ret = AVERROR(EINVAL);
244 goto out;
245 }
246
247 *kernel = cvCreateStructuringElementEx(cols, rows, anchor_x, anchor_y, shape, values);
248 if (!*kernel) {
249 ret = AVERROR(ENOMEM);
250 goto out;
251 }
252
253 av_log(log_ctx, AV_LOG_VERBOSE, "Structuring element: w:%d h:%d x:%d y:%d shape:%s\n",
254 rows, cols, anchor_x, anchor_y, shape_str);
255out:
256 av_freep(&values);
257 return ret;
258}
259
260typedef struct DilateContext {
262 IplConvKernel *kernel;
264
265static av_cold int dilate_init(AVFilterContext *ctx, const char *args)
266{
267 OCVContext *s = ctx->priv;
268 DilateContext *dilate = s->priv;
269 char default_kernel_str[] = "3x3+0x0/rect";
270 char *kernel_str = NULL;
271 const char *buf = args;
272 int ret;
273
274 if (args) {
275 kernel_str = av_get_token(&buf, "|");
276
277 if (!kernel_str)
278 return AVERROR(ENOMEM);
279 }
280
281 ret = parse_iplconvkernel(&dilate->kernel,
282 (!kernel_str || !*kernel_str) ? default_kernel_str
283 : kernel_str,
284 ctx);
285 av_free(kernel_str);
286 if (ret < 0)
287 return ret;
288
289 if (!buf || sscanf(buf, "|%d", &dilate->nb_iterations) != 1)
290 dilate->nb_iterations = 1;
291 av_log(ctx, AV_LOG_VERBOSE, "iterations_nb:%d\n", dilate->nb_iterations);
292 if (dilate->nb_iterations <= 0) {
293 av_log(ctx, AV_LOG_ERROR, "Invalid non-positive value '%d' for nb_iterations\n",
294 dilate->nb_iterations);
295 return AVERROR(EINVAL);
296 }
297 return 0;
298}
299
301{
302 OCVContext *s = ctx->priv;
303 DilateContext *dilate = s->priv;
304
305 if (!dilate)
306 return;
307 cvReleaseStructuringElement(&dilate->kernel);
308}
309
310static void dilate_end_frame_filter(AVFilterContext *ctx, IplImage *inimg, IplImage *outimg)
311{
312 OCVContext *s = ctx->priv;
313 DilateContext *dilate = s->priv;
314 cvDilate(inimg, outimg, dilate->kernel, dilate->nb_iterations);
315}
316
317static void erode_end_frame_filter(AVFilterContext *ctx, IplImage *inimg, IplImage *outimg)
318{
319 OCVContext *s = ctx->priv;
320 DilateContext *dilate = s->priv;
321 cvErode(inimg, outimg, dilate->kernel, dilate->nb_iterations);
322}
323
324typedef struct OCVFilterEntry {
325 const char *name;
326 size_t priv_size;
327 int (*init)(AVFilterContext *ctx, const char *args);
329 void (*end_frame_filter)(AVFilterContext *ctx, IplImage *inimg, IplImage *outimg);
331
337
339{
340 OCVContext *s = ctx->priv;
341 int i;
342
343 if (!s->name) {
344 av_log(ctx, AV_LOG_ERROR, "No libopencv filter name specified\n");
345 return AVERROR(EINVAL);
346 }
347 for (i = 0; i < FF_ARRAY_ELEMS(ocv_filter_entries); i++) {
349 if (!strcmp(s->name, entry->name)) {
350 s->init = entry->init;
351 s->uninit = entry->uninit;
352 s->end_frame_filter = entry->end_frame_filter;
353
354 if (!(s->priv = av_mallocz(entry->priv_size)))
355 return AVERROR(ENOMEM);
356 return s->init(ctx, s->params);
357 }
358 }
359
360 av_log(ctx, AV_LOG_ERROR, "No libopencv filter named '%s'\n", s->name);
361 return AVERROR(EINVAL);
362}
363
365{
366 OCVContext *s = ctx->priv;
367
368 if (s->uninit)
369 s->uninit(ctx);
370 av_freep(&s->priv);
371}
372
373static int filter_frame(AVFilterLink *inlink, AVFrame *in)
374{
375 AVFilterContext *ctx = inlink->dst;
376 OCVContext *s = ctx->priv;
377 AVFilterLink *outlink= inlink->dst->outputs[0];
378 AVFrame *out;
379 IplImage *inimg, *outimg;
380
381 out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
382 if (!out) {
383 av_frame_free(&in);
384 return AVERROR(ENOMEM);
385 }
387
388 fill_iplimage_from_frame(&inimg , in , inlink->format);
389 fill_iplimage_from_frame(&outimg, out, inlink->format);
390 s->end_frame_filter(ctx, inimg, outimg);
391 fill_frame_from_iplimage(out, outimg, inlink->format);
392
393 av_frame_free(&in);
394 cvReleaseImageHeader(&inimg);
395 cvReleaseImageHeader(&outimg);
396
397 return ff_filter_frame(outlink, out);
398}
399
400#define OFFSET(x) offsetof(OCVContext, x)
401#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM
402static const AVOption ocv_options[] = {
403 { "filter_name", NULL, OFFSET(name), AV_OPT_TYPE_STRING, .flags = FLAGS },
404 { "filter_params", NULL, OFFSET(params), AV_OPT_TYPE_STRING, .flags = FLAGS },
405 { NULL }
406};
407
409
411 {
412 .name = "default",
413 .type = AVMEDIA_TYPE_VIDEO,
414 .filter_frame = filter_frame,
415 },
416};
417
419 {
420 .name = "default",
421 .type = AVMEDIA_TYPE_VIDEO,
422 },
423};
424
426 .p.name = "ocv",
427 .p.description = NULL_IF_CONFIG_SMALL("Apply transform using libopencv."),
428 .p.priv_class = &ocv_class,
429 .priv_size = sizeof(OCVContext),
430 .init = init,
431 .uninit = uninit,
435};
SwsAArch64OpImplParams params
Definition ops.c:51
const FFFilter ff_vf_ocv
#define entry
static FILE * out
static AVFormatContext * ctx
simple assert() macros that are a bit more flexible than ISO C assert().
#define av_unreachable(msg)
Asserts that are used as compiler optimization hints depending upon ASSERT_LEVEL and NBDEBUG.
Definition avassert.h:109
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 s(width, name)
Definition cbs_vp9.c:198
#define FLAGS
Definition cmdutils.c:596
common internal and external API header
#define NULL
Definition coverity.c:32
static AVFrame * frame
static int filter_frame(DBEDecodeContext *s, AVFrame *frame)
Definition dolby_e.c:1067
int(* init)(AVBSFContext *ctx)
Definition dts2pts.c:608
Misc file utilities.
@ 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 AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition error.h:61
#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_VERBOSE
Detailed information.
Definition log.h:226
#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_const int av_isgraph(int c)
Locale-independent conversion of ASCII isgraph.
Definition avstring.h:210
char * av_get_token(const char **buf, const char *term)
Unescape the given string until a non escaped terminating char, and return the token corresponding to...
Definition avstring.c:143
enum AVPixelFormat pixfmt
Definition kmsgrab.c:367
static av_cold void uninit(AVBitStreamFilterContext *ctx)
#define FILTER_INPUTS(array)
Definition filters.h:264
#define FILTER_OUTPUTS(array)
Definition filters.h:265
#define FILTER_PIXFMTS(...)
Definition filters.h:250
#define AVFILTER_DEFINE_CLASS(fname)
Definition filters.h:478
#define av_cold
Definition attributes.h:117
void av_file_unmap(uint8_t *bufptr, size_t size)
Unmap or free the buffer bufptr created by av_file_map().
Definition file.c:175
int av_file_map(const char *filename, uint8_t **bufptr, size_t *size, int log_offset, void *log_ctx)
Read the file with name filename, and put its content in a newly allocated buffer or map it with mmap...
Definition file.c:114
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:97
uint8_t w
Definition llvidencdsp.c:39
#define FFMAX(a, b)
Definition macros.h:47
void * av_calloc(size_t nmemb, size_t size)
Definition mem.c:370
Memory handling functions.
#define av_malloc(s)
Definition ops_static.c:52
AVOptions.
AVPixelFormat
Pixel format.
Definition pixfmt.h:71
@ AV_PIX_FMT_BGRA
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition pixfmt.h:102
@ AV_PIX_FMT_GRAY8
Y , 8bpp.
Definition pixfmt.h:81
@ AV_PIX_FMT_BGR24
packed RGB 8:8:8, 24bpp, BGRBGR...
Definition pixfmt.h:76
const char * name
Definition qsvenc.c:142
#define FF_ARRAY_ELEMS(a)
Describe the class of an AVClass context structure.
Definition log.h:76
An instance of a filter.
Definition avfilter.h:273
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:479
AVOption.
Definition opt.h:428
IplConvKernel * kernel
int(* init)(AVFilterContext *ctx, const char *args)
void(* uninit)(AVFilterContext *ctx)
void * priv
char * params
void(* end_frame_filter)(AVFilterContext *ctx, IplImage *inimg, IplImage *outimg)
char * name
void(* end_frame_filter)(AVFilterContext *ctx, IplImage *inimg, IplImage *outimg)
const char * name
void(* uninit)(AVFilterContext *ctx)
int(* init)(AVFilterContext *ctx, const char *args)
#define av_free(p)
#define av_mallocz(s)
#define av_freep(p)
#define av_log(a,...)
int size
#define img
static float smooth(DeshakeOpenCLContext *deshake_ctx, float *gauss_kernel, int length, float max_val, AVFifo *values)
static av_cold int smooth_init(AVFilterContext *ctx, const char *args)
static const AVOption ocv_options[]
static const AVFilterPad avfilter_vf_ocv_outputs[]
static void dilate_end_frame_filter(AVFilterContext *ctx, IplImage *inimg, IplImage *outimg)
static const AVFilterPad avfilter_vf_ocv_inputs[]
static void erode_end_frame_filter(AVFilterContext *ctx, IplImage *inimg, IplImage *outimg)
static const OCVFilterEntry ocv_filter_entries[]
static int parse_iplconvkernel(IplConvKernel **kernel, char *buf, void *log_ctx)
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
static void fill_frame_from_iplimage(AVFrame *frame, const IplImage *img, enum AVPixelFormat pixfmt)
static av_cold int dilate_init(AVFilterContext *ctx, const char *args)
static av_cold void uninit(AVFilterContext *ctx)
static int read_shape_from_file(int *cols, int *rows, int **values, const char *filename, void *log_ctx)
#define OFFSET(x)
static av_cold void dilate_uninit(AVFilterContext *ctx)
static void fill_iplimage_from_frame(IplImage **_img, const AVFrame *frame, enum AVPixelFormat pixfmt)
static void smooth_end_frame_filter(AVFilterContext *ctx, IplImage *inimg, IplImage *outimg)
static int dilate(IPlane *g, IPlane *f, chord_set *SE, LUT *Ty, int y0, int y1)
Definition vf_morpho.c:465
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