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, i;
134 int ret, j, w;
135
136 if ((ret = av_file_map(filename, &buf, &size, 0, log_ctx)) < 0)
137 return ret;
138
139 /* the file alone defines the size of the shape */
140 *cols = *rows = 0;
141
142 /* prescan file to get the number of lines and the maximum width,
143 * the last line need not be newline terminated */
144 w = 0;
145 for (i = 0; i < size || w; i++) {
146 if (i == size || buf[i] == '\n') {
147 if (*rows == INT_MAX) {
148 av_log(log_ctx, AV_LOG_ERROR, "Overflow on the number of rows in the file\n");
150 goto end;
151 }
152 ++(*rows);
153 *cols = FFMAX(*cols, w);
154 w = 0;
155 } else if (w == INT_MAX) {
156 av_log(log_ctx, AV_LOG_ERROR, "Overflow on the number of columns in the file\n");
158 goto end;
159 } else
160 w++;
161 }
162 if (*cols == 0) {
163 av_log(log_ctx, AV_LOG_ERROR, "No columns in the shape file\n");
165 goto end;
166 }
167 if (*rows > (SIZE_MAX / sizeof(int) / *cols)) {
168 av_log(log_ctx, AV_LOG_ERROR, "File with size %dx%d is too big\n",
169 *rows, *cols);
171 goto end;
172 }
173 if (!(*values = av_calloc(*cols, sizeof(**values) * *rows))) {
174 ret = AVERROR(ENOMEM);
175 goto end;
176 }
177
178 /* fill *values */
179 p = buf;
180 pend = buf + size-1;
181 for (i = 0; i < *rows; i++) {
182 for (j = 0;; j++) {
183 if (p > pend || *p == '\n') {
184 p++;
185 break;
186 } else
187 (*values)[*cols*i + j] = !!av_isgraph(*(p++));
188 }
189 }
190
191end:
192 av_file_unmap(buf, size);
193 if (ret < 0)
194 return ret;
195
196#ifdef DEBUG
197 {
198 char *line;
199 if (!(line = av_malloc(*cols + 1)))
200 return AVERROR(ENOMEM);
201 for (i = 0; i < *rows; i++) {
202 for (j = 0; j < *cols; j++)
203 line[j] = (*values)[i * *cols + j] ? '@' : ' ';
204 line[j] = 0;
205 av_log(log_ctx, AV_LOG_DEBUG, "%3zu: %s\n", i, line);
206 }
207 av_free(line);
208 }
209#endif
210
211 return 0;
212}
213
214static int parse_iplconvkernel(IplConvKernel **kernel, char *buf, void *log_ctx)
215{
216 char shape_filename[128] = "", shape_str[32] = "rect";
217 int cols = 0, rows = 0, anchor_x = 0, anchor_y = 0, shape = CV_SHAPE_RECT;
218 int *values = NULL, ret = 0;
219
220 sscanf(buf, "%dx%d+%dx%d/%31[^=]=%127s", &cols, &rows, &anchor_x, &anchor_y, shape_str, shape_filename);
221
222 if (!strcmp(shape_str, "rect" )) shape = CV_SHAPE_RECT;
223 else if (!strcmp(shape_str, "cross" )) shape = CV_SHAPE_CROSS;
224 else if (!strcmp(shape_str, "ellipse")) shape = CV_SHAPE_ELLIPSE;
225 else if (!strcmp(shape_str, "custom" )) {
226 shape = CV_SHAPE_CUSTOM;
227 if ((ret = read_shape_from_file(&cols, &rows, &values, shape_filename, log_ctx)) < 0)
228 goto out;
229 } else {
230 av_log(log_ctx, AV_LOG_ERROR,
231 "Shape unspecified or type '%s' unknown.\n", shape_str);
232 ret = AVERROR(EINVAL);
233 goto out;
234 }
235
236 if (rows <= 0 || cols <= 0) {
237 av_log(log_ctx, AV_LOG_ERROR,
238 "Invalid non-positive values for shape size %dx%d\n", cols, rows);
239 ret = AVERROR(EINVAL);
240 goto out;
241 }
242
243 if (anchor_x < 0 || anchor_y < 0 || anchor_x >= cols || anchor_y >= rows) {
244 av_log(log_ctx, AV_LOG_ERROR,
245 "Shape anchor %dx%d is not inside the rectangle with size %dx%d.\n",
246 anchor_x, anchor_y, cols, rows);
247 ret = AVERROR(EINVAL);
248 goto out;
249 }
250
251 *kernel = cvCreateStructuringElementEx(cols, rows, anchor_x, anchor_y, shape, values);
252 if (!*kernel) {
253 ret = AVERROR(ENOMEM);
254 goto out;
255 }
256
257 av_log(log_ctx, AV_LOG_VERBOSE, "Structuring element: w:%d h:%d x:%d y:%d shape:%s\n",
258 rows, cols, anchor_x, anchor_y, shape_str);
259out:
260 av_freep(&values);
261 return ret;
262}
263
264typedef struct DilateContext {
266 IplConvKernel *kernel;
268
269static av_cold int dilate_init(AVFilterContext *ctx, const char *args)
270{
271 OCVContext *s = ctx->priv;
272 DilateContext *dilate = s->priv;
273 char default_kernel_str[] = "3x3+0x0/rect";
274 char *kernel_str = NULL;
275 const char *buf = args;
276 int ret;
277
278 if (args) {
279 kernel_str = av_get_token(&buf, "|");
280
281 if (!kernel_str)
282 return AVERROR(ENOMEM);
283 }
284
285 ret = parse_iplconvkernel(&dilate->kernel,
286 (!kernel_str || !*kernel_str) ? default_kernel_str
287 : kernel_str,
288 ctx);
289 av_free(kernel_str);
290 if (ret < 0)
291 return ret;
292
293 if (!buf || sscanf(buf, "|%d", &dilate->nb_iterations) != 1)
294 dilate->nb_iterations = 1;
295 av_log(ctx, AV_LOG_VERBOSE, "iterations_nb:%d\n", dilate->nb_iterations);
296 if (dilate->nb_iterations <= 0) {
297 av_log(ctx, AV_LOG_ERROR, "Invalid non-positive value '%d' for nb_iterations\n",
298 dilate->nb_iterations);
299 return AVERROR(EINVAL);
300 }
301 return 0;
302}
303
305{
306 OCVContext *s = ctx->priv;
307 DilateContext *dilate = s->priv;
308
309 if (!dilate)
310 return;
311 cvReleaseStructuringElement(&dilate->kernel);
312}
313
314static void dilate_end_frame_filter(AVFilterContext *ctx, IplImage *inimg, IplImage *outimg)
315{
316 OCVContext *s = ctx->priv;
317 DilateContext *dilate = s->priv;
318 cvDilate(inimg, outimg, dilate->kernel, dilate->nb_iterations);
319}
320
321static void erode_end_frame_filter(AVFilterContext *ctx, IplImage *inimg, IplImage *outimg)
322{
323 OCVContext *s = ctx->priv;
324 DilateContext *dilate = s->priv;
325 cvErode(inimg, outimg, dilate->kernel, dilate->nb_iterations);
326}
327
328typedef struct OCVFilterEntry {
329 const char *name;
330 size_t priv_size;
331 int (*init)(AVFilterContext *ctx, const char *args);
333 void (*end_frame_filter)(AVFilterContext *ctx, IplImage *inimg, IplImage *outimg);
335
341
343{
344 OCVContext *s = ctx->priv;
345 int i;
346
347 if (!s->name) {
348 av_log(ctx, AV_LOG_ERROR, "No libopencv filter name specified\n");
349 return AVERROR(EINVAL);
350 }
351 for (i = 0; i < FF_ARRAY_ELEMS(ocv_filter_entries); i++) {
353 if (!strcmp(s->name, entry->name)) {
354 s->init = entry->init;
355 s->uninit = entry->uninit;
356 s->end_frame_filter = entry->end_frame_filter;
357
358 if (!(s->priv = av_mallocz(entry->priv_size)))
359 return AVERROR(ENOMEM);
360 return s->init(ctx, s->params);
361 }
362 }
363
364 av_log(ctx, AV_LOG_ERROR, "No libopencv filter named '%s'\n", s->name);
365 return AVERROR(EINVAL);
366}
367
369{
370 OCVContext *s = ctx->priv;
371
372 if (s->uninit)
373 s->uninit(ctx);
374 av_freep(&s->priv);
375}
376
377static int filter_frame(AVFilterLink *inlink, AVFrame *in)
378{
379 AVFilterContext *ctx = inlink->dst;
380 OCVContext *s = ctx->priv;
381 AVFilterLink *outlink= inlink->dst->outputs[0];
382 AVFrame *out;
383 IplImage *inimg, *outimg;
384
385 out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
386 if (!out) {
387 av_frame_free(&in);
388 return AVERROR(ENOMEM);
389 }
391
392 fill_iplimage_from_frame(&inimg , in , inlink->format);
393 fill_iplimage_from_frame(&outimg, out, inlink->format);
394 s->end_frame_filter(ctx, inimg, outimg);
395 fill_frame_from_iplimage(out, outimg, inlink->format);
396
397 av_frame_free(&in);
398 cvReleaseImageHeader(&inimg);
399 cvReleaseImageHeader(&outimg);
400
401 return ff_filter_frame(outlink, out);
402}
403
404#define OFFSET(x) offsetof(OCVContext, x)
405#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM
406static const AVOption ocv_options[] = {
407 { "filter_name", NULL, OFFSET(name), AV_OPT_TYPE_STRING, .flags = FLAGS },
408 { "filter_params", NULL, OFFSET(params), AV_OPT_TYPE_STRING, .flags = FLAGS },
409 { NULL }
410};
411
413
415 {
416 .name = "default",
417 .type = AVMEDIA_TYPE_VIDEO,
418 .filter_frame = filter_frame,
419 },
420};
421
423 {
424 .name = "default",
425 .type = AVMEDIA_TYPE_VIDEO,
426 },
427};
428
430 .p.name = "ocv",
431 .p.description = NULL_IF_CONFIG_SMALL("Apply transform using libopencv."),
432 .p.priv_class = &ocv_class,
433 .priv_size = sizeof(OCVContext),
434 .init = init,
435 .uninit = uninit,
439};
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:1076
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:279
#define FILTER_OUTPUTS(array)
Definition filters.h:280
#define FILTER_PIXFMTS(...)
Definition filters.h:265
#define AVFILTER_DEFINE_CLASS(fname)
Definition filters.h:493
#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:279
AVFilterLink ** outputs
array of pointers to output links
Definition avfilter.h:291
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:90