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");
153 return AVERROR_INVALIDDATA;
154 }
155 w++;
156 }
157 if (*rows > (SIZE_MAX / sizeof(int) / *cols)) {
158 av_log(log_ctx, AV_LOG_ERROR, "File with size %dx%d is too big\n",
159 *rows, *cols);
161 goto end;
162 }
163 if (!(*values = av_calloc(*cols, sizeof(**values) * *rows))) {
164 ret = AVERROR(ENOMEM);
165 goto end;
166 }
167
168 /* fill *values */
169 p = buf;
170 pend = buf + size-1;
171 for (i = 0; i < *rows; i++) {
172 for (j = 0;; j++) {
173 if (p > pend || *p == '\n') {
174 p++;
175 break;
176 } else
177 (*values)[*cols*i + j] = !!av_isgraph(*(p++));
178 }
179 }
180
181end:
182 av_file_unmap(buf, size);
183
184#ifdef DEBUG
185 {
186 char *line;
187 if (!(line = av_malloc(*cols + 1)))
188 return AVERROR(ENOMEM);
189 for (i = 0; i < *rows; i++) {
190 for (j = 0; j < *cols; j++)
191 line[j] = (*values)[i * *cols + j] ? '@' : ' ';
192 line[j] = 0;
193 av_log(log_ctx, AV_LOG_DEBUG, "%3d: %s\n", i, line);
194 }
195 av_free(line);
196 }
197#endif
198
199 return 0;
200}
201
202static int parse_iplconvkernel(IplConvKernel **kernel, char *buf, void *log_ctx)
203{
204 char shape_filename[128] = "", shape_str[32] = "rect";
205 int cols = 0, rows = 0, anchor_x = 0, anchor_y = 0, shape = CV_SHAPE_RECT;
206 int *values = NULL, ret = 0;
207
208 sscanf(buf, "%dx%d+%dx%d/%31[^=]=%127s", &cols, &rows, &anchor_x, &anchor_y, shape_str, shape_filename);
209
210 if (!strcmp(shape_str, "rect" )) shape = CV_SHAPE_RECT;
211 else if (!strcmp(shape_str, "cross" )) shape = CV_SHAPE_CROSS;
212 else if (!strcmp(shape_str, "ellipse")) shape = CV_SHAPE_ELLIPSE;
213 else if (!strcmp(shape_str, "custom" )) {
214 shape = CV_SHAPE_CUSTOM;
215 if ((ret = read_shape_from_file(&cols, &rows, &values, shape_filename, log_ctx)) < 0)
216 return ret;
217 } else {
218 av_log(log_ctx, AV_LOG_ERROR,
219 "Shape unspecified or type '%s' unknown.\n", shape_str);
220 ret = AVERROR(EINVAL);
221 goto out;
222 }
223
224 if (rows <= 0 || cols <= 0) {
225 av_log(log_ctx, AV_LOG_ERROR,
226 "Invalid non-positive values for shape size %dx%d\n", cols, rows);
227 ret = AVERROR(EINVAL);
228 goto out;
229 }
230
231 if (anchor_x < 0 || anchor_y < 0 || anchor_x >= cols || anchor_y >= rows) {
232 av_log(log_ctx, AV_LOG_ERROR,
233 "Shape anchor %dx%d is not inside the rectangle with size %dx%d.\n",
234 anchor_x, anchor_y, cols, rows);
235 ret = AVERROR(EINVAL);
236 goto out;
237 }
238
239 *kernel = cvCreateStructuringElementEx(cols, rows, anchor_x, anchor_y, shape, values);
240 if (!*kernel) {
241 ret = AVERROR(ENOMEM);
242 goto out;
243 }
244
245 av_log(log_ctx, AV_LOG_VERBOSE, "Structuring element: w:%d h:%d x:%d y:%d shape:%s\n",
246 rows, cols, anchor_x, anchor_y, shape_str);
247out:
248 av_freep(&values);
249 return ret;
250}
251
252typedef struct DilateContext {
254 IplConvKernel *kernel;
256
257static av_cold int dilate_init(AVFilterContext *ctx, const char *args)
258{
259 OCVContext *s = ctx->priv;
260 DilateContext *dilate = s->priv;
261 char default_kernel_str[] = "3x3+0x0/rect";
262 char *kernel_str = NULL;
263 const char *buf = args;
264 int ret;
265
266 if (args) {
267 kernel_str = av_get_token(&buf, "|");
268
269 if (!kernel_str)
270 return AVERROR(ENOMEM);
271 }
272
273 ret = parse_iplconvkernel(&dilate->kernel,
274 (!kernel_str || !*kernel_str) ? default_kernel_str
275 : kernel_str,
276 ctx);
277 av_free(kernel_str);
278 if (ret < 0)
279 return ret;
280
281 if (!buf || sscanf(buf, "|%d", &dilate->nb_iterations) != 1)
282 dilate->nb_iterations = 1;
283 av_log(ctx, AV_LOG_VERBOSE, "iterations_nb:%d\n", dilate->nb_iterations);
284 if (dilate->nb_iterations <= 0) {
285 av_log(ctx, AV_LOG_ERROR, "Invalid non-positive value '%d' for nb_iterations\n",
286 dilate->nb_iterations);
287 return AVERROR(EINVAL);
288 }
289 return 0;
290}
291
293{
294 OCVContext *s = ctx->priv;
295 DilateContext *dilate = s->priv;
296
297 if (!dilate)
298 return;
299 cvReleaseStructuringElement(&dilate->kernel);
300}
301
302static void dilate_end_frame_filter(AVFilterContext *ctx, IplImage *inimg, IplImage *outimg)
303{
304 OCVContext *s = ctx->priv;
305 DilateContext *dilate = s->priv;
306 cvDilate(inimg, outimg, dilate->kernel, dilate->nb_iterations);
307}
308
309static void erode_end_frame_filter(AVFilterContext *ctx, IplImage *inimg, IplImage *outimg)
310{
311 OCVContext *s = ctx->priv;
312 DilateContext *dilate = s->priv;
313 cvErode(inimg, outimg, dilate->kernel, dilate->nb_iterations);
314}
315
316typedef struct OCVFilterEntry {
317 const char *name;
318 size_t priv_size;
319 int (*init)(AVFilterContext *ctx, const char *args);
321 void (*end_frame_filter)(AVFilterContext *ctx, IplImage *inimg, IplImage *outimg);
323
329
331{
332 OCVContext *s = ctx->priv;
333 int i;
334
335 if (!s->name) {
336 av_log(ctx, AV_LOG_ERROR, "No libopencv filter name specified\n");
337 return AVERROR(EINVAL);
338 }
339 for (i = 0; i < FF_ARRAY_ELEMS(ocv_filter_entries); i++) {
341 if (!strcmp(s->name, entry->name)) {
342 s->init = entry->init;
343 s->uninit = entry->uninit;
344 s->end_frame_filter = entry->end_frame_filter;
345
346 if (!(s->priv = av_mallocz(entry->priv_size)))
347 return AVERROR(ENOMEM);
348 return s->init(ctx, s->params);
349 }
350 }
351
352 av_log(ctx, AV_LOG_ERROR, "No libopencv filter named '%s'\n", s->name);
353 return AVERROR(EINVAL);
354}
355
357{
358 OCVContext *s = ctx->priv;
359
360 if (s->uninit)
361 s->uninit(ctx);
362 av_freep(&s->priv);
363}
364
365static int filter_frame(AVFilterLink *inlink, AVFrame *in)
366{
367 AVFilterContext *ctx = inlink->dst;
368 OCVContext *s = ctx->priv;
369 AVFilterLink *outlink= inlink->dst->outputs[0];
370 AVFrame *out;
371 IplImage *inimg, *outimg;
372
373 out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
374 if (!out) {
375 av_frame_free(&in);
376 return AVERROR(ENOMEM);
377 }
379
380 fill_iplimage_from_frame(&inimg , in , inlink->format);
381 fill_iplimage_from_frame(&outimg, out, inlink->format);
382 s->end_frame_filter(ctx, inimg, outimg);
383 fill_frame_from_iplimage(out, outimg, inlink->format);
384
385 av_frame_free(&in);
386 cvReleaseImageHeader(&inimg);
387 cvReleaseImageHeader(&outimg);
388
389 return ff_filter_frame(outlink, out);
390}
391
392#define OFFSET(x) offsetof(OCVContext, x)
393#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM
394static const AVOption ocv_options[] = {
395 { "filter_name", NULL, OFFSET(name), AV_OPT_TYPE_STRING, .flags = FLAGS },
396 { "filter_params", NULL, OFFSET(params), AV_OPT_TYPE_STRING, .flags = FLAGS },
397 { NULL }
398};
399
401
403 {
404 .name = "default",
405 .type = AVMEDIA_TYPE_VIDEO,
406 .filter_frame = filter_frame,
407 },
408};
409
411 {
412 .name = "default",
413 .type = AVMEDIA_TYPE_VIDEO,
414 },
415};
416
418 .p.name = "ocv",
419 .p.description = NULL_IF_CONFIG_SMALL("Apply transform using libopencv."),
420 .p.priv_class = &ocv_class,
421 .priv_size = sizeof(OCVContext),
422 .init = init,
423 .uninit = uninit,
427};
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:598
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:142
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:55
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:88
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:264
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:472
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