mirror of
https://github.com/librempeg/librempeg
synced 2024-11-21 16:44:05 +00:00
remove obsolete opencv filter wrapper
This commit is contained in:
parent
408b71ede4
commit
a8b4e3681c
@ -18,6 +18,7 @@ version <next>:
|
|||||||
- removed DEC Alpha DSP and support code
|
- removed DEC Alpha DSP and support code
|
||||||
- perlin video source filter
|
- perlin video source filter
|
||||||
- YUV colorspace negotiation for codecs and filters, obsoleting YUVJ
|
- YUV colorspace negotiation for codecs and filters, obsoleting YUVJ
|
||||||
|
- removed ocv filter wrapper
|
||||||
|
|
||||||
version 7.0:
|
version 7.0:
|
||||||
- DXV DXT1 encoder
|
- DXV DXT1 encoder
|
||||||
|
8
configure
vendored
8
configure
vendored
@ -251,7 +251,6 @@ External library support:
|
|||||||
--enable-libmp3lame enable MP3 encoding via libmp3lame [no]
|
--enable-libmp3lame enable MP3 encoding via libmp3lame [no]
|
||||||
--enable-libopencore-amrnb enable AMR-NB de/encoding via libopencore-amrnb [no]
|
--enable-libopencore-amrnb enable AMR-NB de/encoding via libopencore-amrnb [no]
|
||||||
--enable-libopencore-amrwb enable AMR-WB decoding via libopencore-amrwb [no]
|
--enable-libopencore-amrwb enable AMR-WB decoding via libopencore-amrwb [no]
|
||||||
--enable-libopencv enable video filtering via libopencv [no]
|
|
||||||
--enable-libopenh264 enable H.264 encoding via OpenH264 [no]
|
--enable-libopenh264 enable H.264 encoding via OpenH264 [no]
|
||||||
--enable-libopenjpeg enable JPEG 2000 encoding via OpenJPEG [no]
|
--enable-libopenjpeg enable JPEG 2000 encoding via OpenJPEG [no]
|
||||||
--enable-libopenmpt enable decoding tracked files via libopenmpt [no]
|
--enable-libopenmpt enable decoding tracked files via libopenmpt [no]
|
||||||
@ -1931,7 +1930,6 @@ EXTERNAL_LIBRARY_LIST="
|
|||||||
libmodplug
|
libmodplug
|
||||||
libmp3lame
|
libmp3lame
|
||||||
libmysofa
|
libmysofa
|
||||||
libopencv
|
|
||||||
libopenh264
|
libopenh264
|
||||||
libopenjpeg
|
libopenjpeg
|
||||||
libopenmpt
|
libopenmpt
|
||||||
@ -2287,7 +2285,6 @@ HEADERS_LIST="
|
|||||||
machine_ioctl_bt848_h
|
machine_ioctl_bt848_h
|
||||||
machine_ioctl_meteor_h
|
machine_ioctl_meteor_h
|
||||||
malloc_h
|
malloc_h
|
||||||
opencv2_core_core_c_h
|
|
||||||
OpenGL_gl3_h
|
OpenGL_gl3_h
|
||||||
poll_h
|
poll_h
|
||||||
pthread_np_h
|
pthread_np_h
|
||||||
@ -3893,7 +3890,6 @@ nlmeans_opencl_filter_deps="opencl"
|
|||||||
nlmeans_vulkan_filter_deps="vulkan spirv_compiler"
|
nlmeans_vulkan_filter_deps="vulkan spirv_compiler"
|
||||||
nnedi_filter_deps="gpl"
|
nnedi_filter_deps="gpl"
|
||||||
ocr_filter_deps="libtesseract"
|
ocr_filter_deps="libtesseract"
|
||||||
ocv_filter_deps="libopencv"
|
|
||||||
openclsrc_filter_deps="opencl"
|
openclsrc_filter_deps="opencl"
|
||||||
overlay_opencl_filter_deps="opencl"
|
overlay_opencl_filter_deps="opencl"
|
||||||
overlay_qsv_filter_deps="libmfx"
|
overlay_qsv_filter_deps="libmfx"
|
||||||
@ -6944,10 +6940,6 @@ enabled libnpp && { check_lib libnpp npp.h nppGetLibVersion -lnppig -
|
|||||||
die "ERROR: libnpp not found"; }
|
die "ERROR: libnpp not found"; }
|
||||||
enabled libopencore_amrnb && require libopencore_amrnb opencore-amrnb/interf_dec.h Decoder_Interface_init -lopencore-amrnb
|
enabled libopencore_amrnb && require libopencore_amrnb opencore-amrnb/interf_dec.h Decoder_Interface_init -lopencore-amrnb
|
||||||
enabled libopencore_amrwb && require libopencore_amrwb opencore-amrwb/dec_if.h D_IF_init -lopencore-amrwb
|
enabled libopencore_amrwb && require libopencore_amrwb opencore-amrwb/dec_if.h D_IF_init -lopencore-amrwb
|
||||||
enabled libopencv && { check_headers opencv2/core/core_c.h &&
|
|
||||||
{ check_pkg_config libopencv opencv opencv2/core/core_c.h cvCreateImageHeader ||
|
|
||||||
require libopencv opencv2/core/core_c.h cvCreateImageHeader -lopencv_core -lopencv_imgproc; } ||
|
|
||||||
require_pkg_config libopencv opencv opencv/cxcore.h cvCreateImageHeader; }
|
|
||||||
enabled libopenh264 && require_pkg_config libopenh264 "openh264 >= 1.3.0" wels/codec_api.h WelsGetCodecVersion
|
enabled libopenh264 && require_pkg_config libopenh264 "openh264 >= 1.3.0" wels/codec_api.h WelsGetCodecVersion
|
||||||
enabled libopenjpeg && { check_pkg_config libopenjpeg "libopenjp2 >= 2.1.0" openjpeg.h opj_version ||
|
enabled libopenjpeg && { check_pkg_config libopenjpeg "libopenjp2 >= 2.1.0" openjpeg.h opj_version ||
|
||||||
{ require_pkg_config libopenjpeg "libopenjp2 >= 2.1.0" openjpeg.h opj_version -DOPJ_STATIC && add_cppflags -DOPJ_STATIC; } }
|
{ require_pkg_config libopenjpeg "libopenjp2 >= 2.1.0" openjpeg.h opj_version -DOPJ_STATIC && add_cppflags -DOPJ_STATIC; } }
|
||||||
|
104
doc/filters.texi
104
doc/filters.texi
@ -18641,110 +18641,6 @@ Set character blacklist.
|
|||||||
The filter exports recognized text as the frame metadata @code{lavfi.ocr.text}.
|
The filter exports recognized text as the frame metadata @code{lavfi.ocr.text}.
|
||||||
The filter exports confidence of recognized words as the frame metadata @code{lavfi.ocr.confidence}.
|
The filter exports confidence of recognized words as the frame metadata @code{lavfi.ocr.confidence}.
|
||||||
|
|
||||||
@section ocv
|
|
||||||
|
|
||||||
Apply a video transform using libopencv.
|
|
||||||
|
|
||||||
To enable this filter, install the libopencv library and headers and
|
|
||||||
configure FFmpeg with @code{--enable-libopencv}.
|
|
||||||
|
|
||||||
It accepts the following parameters:
|
|
||||||
|
|
||||||
@table @option
|
|
||||||
|
|
||||||
@item filter_name
|
|
||||||
The name of the libopencv filter to apply.
|
|
||||||
|
|
||||||
@item filter_params
|
|
||||||
The parameters to pass to the libopencv filter. If not specified, the default
|
|
||||||
values are assumed.
|
|
||||||
|
|
||||||
@end table
|
|
||||||
|
|
||||||
Refer to the official libopencv documentation for more precise
|
|
||||||
information:
|
|
||||||
@url{http://docs.opencv.org/master/modules/imgproc/doc/filtering.html}
|
|
||||||
|
|
||||||
Several libopencv filters are supported; see the following subsections.
|
|
||||||
|
|
||||||
@anchor{dilate}
|
|
||||||
@subsection dilate
|
|
||||||
|
|
||||||
Dilate an image by using a specific structuring element.
|
|
||||||
It corresponds to the libopencv function @code{cvDilate}.
|
|
||||||
|
|
||||||
It accepts the parameters: @var{struct_el}|@var{nb_iterations}.
|
|
||||||
|
|
||||||
@var{struct_el} represents a structuring element, and has the syntax:
|
|
||||||
@var{cols}x@var{rows}+@var{anchor_x}x@var{anchor_y}/@var{shape}
|
|
||||||
|
|
||||||
@var{cols} and @var{rows} represent the number of columns and rows of
|
|
||||||
the structuring element, @var{anchor_x} and @var{anchor_y} the anchor
|
|
||||||
point, and @var{shape} the shape for the structuring element. @var{shape}
|
|
||||||
must be "rect", "cross", "ellipse", or "custom".
|
|
||||||
|
|
||||||
If the value for @var{shape} is "custom", it must be followed by a
|
|
||||||
string of the form "=@var{filename}". The file with name
|
|
||||||
@var{filename} is assumed to represent a binary image, with each
|
|
||||||
printable character corresponding to a bright pixel. When a custom
|
|
||||||
@var{shape} is used, @var{cols} and @var{rows} are ignored, the number
|
|
||||||
or columns and rows of the read file are assumed instead.
|
|
||||||
|
|
||||||
The default value for @var{struct_el} is "3x3+0x0/rect".
|
|
||||||
|
|
||||||
@var{nb_iterations} specifies the number of times the transform is
|
|
||||||
applied to the image, and defaults to 1.
|
|
||||||
|
|
||||||
Some examples:
|
|
||||||
@example
|
|
||||||
# Use the default values
|
|
||||||
ocv=dilate
|
|
||||||
|
|
||||||
# Dilate using a structuring element with a 5x5 cross, iterating two times
|
|
||||||
ocv=filter_name=dilate:filter_params=5x5+2x2/cross|2
|
|
||||||
|
|
||||||
# Read the shape from the file diamond.shape, iterating two times.
|
|
||||||
# The file diamond.shape may contain a pattern of characters like this
|
|
||||||
# *
|
|
||||||
# ***
|
|
||||||
# *****
|
|
||||||
# ***
|
|
||||||
# *
|
|
||||||
# The specified columns and rows are ignored
|
|
||||||
# but the anchor point coordinates are not
|
|
||||||
ocv=dilate:0x0+2x2/custom=diamond.shape|2
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@subsection erode
|
|
||||||
|
|
||||||
Erode an image by using a specific structuring element.
|
|
||||||
It corresponds to the libopencv function @code{cvErode}.
|
|
||||||
|
|
||||||
It accepts the parameters: @var{struct_el}:@var{nb_iterations},
|
|
||||||
with the same syntax and semantics as the @ref{dilate} filter.
|
|
||||||
|
|
||||||
@subsection smooth
|
|
||||||
|
|
||||||
Smooth the input video.
|
|
||||||
|
|
||||||
The filter takes the following parameters:
|
|
||||||
@var{type}|@var{param1}|@var{param2}|@var{param3}|@var{param4}.
|
|
||||||
|
|
||||||
@var{type} is the type of smooth filter to apply, and must be one of
|
|
||||||
the following values: "blur", "blur_no_scale", "median", "gaussian",
|
|
||||||
or "bilateral". The default value is "gaussian".
|
|
||||||
|
|
||||||
The meaning of @var{param1}, @var{param2}, @var{param3}, and @var{param4}
|
|
||||||
depends on the smooth type. @var{param1} and
|
|
||||||
@var{param2} accept integer positive values or 0. @var{param3} and
|
|
||||||
@var{param4} accept floating point values.
|
|
||||||
|
|
||||||
The default value for @var{param1} is 3. The default value for the
|
|
||||||
other parameters is 0.
|
|
||||||
|
|
||||||
These parameters correspond to the parameters assigned to the
|
|
||||||
libopencv function @code{cvSmooth}.
|
|
||||||
|
|
||||||
@section oscilloscope
|
@section oscilloscope
|
||||||
|
|
||||||
2D Video Oscilloscope.
|
2D Video Oscilloscope.
|
||||||
|
@ -427,7 +427,6 @@ OBJS-$(CONFIG_NOISE_FILTER) += vf_noise.o
|
|||||||
OBJS-$(CONFIG_NORMALIZE_FILTER) += vf_normalize.o
|
OBJS-$(CONFIG_NORMALIZE_FILTER) += vf_normalize.o
|
||||||
OBJS-$(CONFIG_NULL_FILTER) += vf_null.o
|
OBJS-$(CONFIG_NULL_FILTER) += vf_null.o
|
||||||
OBJS-$(CONFIG_OCR_FILTER) += vf_ocr.o
|
OBJS-$(CONFIG_OCR_FILTER) += vf_ocr.o
|
||||||
OBJS-$(CONFIG_OCV_FILTER) += vf_libopencv.o
|
|
||||||
OBJS-$(CONFIG_OSCILLOSCOPE_FILTER) += vf_datascope.o
|
OBJS-$(CONFIG_OSCILLOSCOPE_FILTER) += vf_datascope.o
|
||||||
OBJS-$(CONFIG_OVERLAY_FILTER) += vf_overlay.o framesync.o
|
OBJS-$(CONFIG_OVERLAY_FILTER) += vf_overlay.o framesync.o
|
||||||
OBJS-$(CONFIG_OVERLAY_CUDA_FILTER) += vf_overlay_cuda.o framesync.o vf_overlay_cuda.ptx.o \
|
OBJS-$(CONFIG_OVERLAY_CUDA_FILTER) += vf_overlay_cuda.o framesync.o vf_overlay_cuda.ptx.o \
|
||||||
|
@ -404,7 +404,6 @@ extern const AVFilter ff_vf_noise;
|
|||||||
extern const AVFilter ff_vf_normalize;
|
extern const AVFilter ff_vf_normalize;
|
||||||
extern const AVFilter ff_vf_null;
|
extern const AVFilter ff_vf_null;
|
||||||
extern const AVFilter ff_vf_ocr;
|
extern const AVFilter ff_vf_ocr;
|
||||||
extern const AVFilter ff_vf_ocv;
|
|
||||||
extern const AVFilter ff_vf_oscilloscope;
|
extern const AVFilter ff_vf_oscilloscope;
|
||||||
extern const AVFilter ff_vf_overlay;
|
extern const AVFilter ff_vf_overlay;
|
||||||
extern const AVFilter ff_vf_overlay_opencl;
|
extern const AVFilter ff_vf_overlay_opencl;
|
||||||
|
@ -1,428 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2010 Stefano Sabatini
|
|
||||||
*
|
|
||||||
* This file is part of FFmpeg.
|
|
||||||
*
|
|
||||||
* FFmpeg is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* FFmpeg is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with FFmpeg; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* libopencv wrapper functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#if HAVE_OPENCV2_CORE_CORE_C_H
|
|
||||||
#include <opencv2/core/core_c.h>
|
|
||||||
#include <opencv2/imgproc/imgproc_c.h>
|
|
||||||
#else
|
|
||||||
#include <opencv/cv.h>
|
|
||||||
#include <opencv/cxcore.h>
|
|
||||||
#endif
|
|
||||||
#include "libavutil/avstring.h"
|
|
||||||
#include "libavutil/common.h"
|
|
||||||
#include "libavutil/file.h"
|
|
||||||
#include "libavutil/mem.h"
|
|
||||||
#include "libavutil/opt.h"
|
|
||||||
#include "avfilter.h"
|
|
||||||
#include "filters.h"
|
|
||||||
#include "formats.h"
|
|
||||||
#include "video.h"
|
|
||||||
|
|
||||||
static void fill_iplimage_from_frame(IplImage *img, const AVFrame *frame, enum AVPixelFormat pixfmt)
|
|
||||||
{
|
|
||||||
IplImage *tmpimg;
|
|
||||||
int depth, channels_nb;
|
|
||||||
|
|
||||||
if (pixfmt == AV_PIX_FMT_GRAY8) { depth = IPL_DEPTH_8U; channels_nb = 1; }
|
|
||||||
else if (pixfmt == AV_PIX_FMT_BGRA) { depth = IPL_DEPTH_8U; channels_nb = 4; }
|
|
||||||
else if (pixfmt == AV_PIX_FMT_BGR24) { depth = IPL_DEPTH_8U; channels_nb = 3; }
|
|
||||||
else return;
|
|
||||||
|
|
||||||
tmpimg = cvCreateImageHeader((CvSize){frame->width, frame->height}, depth, channels_nb);
|
|
||||||
*img = *tmpimg;
|
|
||||||
img->imageData = img->imageDataOrigin = frame->data[0];
|
|
||||||
img->dataOrder = IPL_DATA_ORDER_PIXEL;
|
|
||||||
img->origin = IPL_ORIGIN_TL;
|
|
||||||
img->widthStep = frame->linesize[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
static void fill_frame_from_iplimage(AVFrame *frame, const IplImage *img, enum AVPixelFormat pixfmt)
|
|
||||||
{
|
|
||||||
frame->linesize[0] = img->widthStep;
|
|
||||||
frame->data[0] = img->imageData;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct OCVContext {
|
|
||||||
const AVClass *class;
|
|
||||||
char *name;
|
|
||||||
char *params;
|
|
||||||
int (*init)(AVFilterContext *ctx, const char *args);
|
|
||||||
void (*uninit)(AVFilterContext *ctx);
|
|
||||||
void (*end_frame_filter)(AVFilterContext *ctx, IplImage *inimg, IplImage *outimg);
|
|
||||||
void *priv;
|
|
||||||
} OCVContext;
|
|
||||||
|
|
||||||
typedef struct SmoothContext {
|
|
||||||
int type;
|
|
||||||
int param1, param2;
|
|
||||||
double param3, param4;
|
|
||||||
} SmoothContext;
|
|
||||||
|
|
||||||
static av_cold int smooth_init(AVFilterContext *ctx, const char *args)
|
|
||||||
{
|
|
||||||
OCVContext *s = ctx->priv;
|
|
||||||
SmoothContext *smooth = s->priv;
|
|
||||||
char type_str[128] = "gaussian";
|
|
||||||
|
|
||||||
smooth->param1 = 3;
|
|
||||||
smooth->param2 = 0;
|
|
||||||
smooth->param3 = 0.0;
|
|
||||||
smooth->param4 = 0.0;
|
|
||||||
|
|
||||||
if (args)
|
|
||||||
sscanf(args, "%127[^|]|%d|%d|%lf|%lf", type_str, &smooth->param1, &smooth->param2, &smooth->param3, &smooth->param4);
|
|
||||||
|
|
||||||
if (!strcmp(type_str, "blur" )) smooth->type = CV_BLUR;
|
|
||||||
else if (!strcmp(type_str, "blur_no_scale")) smooth->type = CV_BLUR_NO_SCALE;
|
|
||||||
else if (!strcmp(type_str, "median" )) smooth->type = CV_MEDIAN;
|
|
||||||
else if (!strcmp(type_str, "gaussian" )) smooth->type = CV_GAUSSIAN;
|
|
||||||
else if (!strcmp(type_str, "bilateral" )) smooth->type = CV_BILATERAL;
|
|
||||||
else {
|
|
||||||
av_log(ctx, AV_LOG_ERROR, "Smoothing type '%s' unknown.\n", type_str);
|
|
||||||
return AVERROR(EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (smooth->param1 < 0 || !(smooth->param1%2)) {
|
|
||||||
av_log(ctx, AV_LOG_ERROR,
|
|
||||||
"Invalid value '%d' for param1, it has to be a positive odd number\n",
|
|
||||||
smooth->param1);
|
|
||||||
return AVERROR(EINVAL);
|
|
||||||
}
|
|
||||||
if ((smooth->type == CV_BLUR || smooth->type == CV_BLUR_NO_SCALE || smooth->type == CV_GAUSSIAN) &&
|
|
||||||
(smooth->param2 < 0 || (smooth->param2 && !(smooth->param2%2)))) {
|
|
||||||
av_log(ctx, AV_LOG_ERROR,
|
|
||||||
"Invalid value '%d' for param2, it has to be zero or a positive odd number\n",
|
|
||||||
smooth->param2);
|
|
||||||
return AVERROR(EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
av_log(ctx, AV_LOG_VERBOSE, "type:%s param1:%d param2:%d param3:%f param4:%f\n",
|
|
||||||
type_str, smooth->param1, smooth->param2, smooth->param3, smooth->param4);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void smooth_end_frame_filter(AVFilterContext *ctx, IplImage *inimg, IplImage *outimg)
|
|
||||||
{
|
|
||||||
OCVContext *s = ctx->priv;
|
|
||||||
SmoothContext *smooth = s->priv;
|
|
||||||
cvSmooth(inimg, outimg, smooth->type, smooth->param1, smooth->param2, smooth->param3, smooth->param4);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int read_shape_from_file(int *cols, int *rows, int **values, const char *filename,
|
|
||||||
void *log_ctx)
|
|
||||||
{
|
|
||||||
uint8_t *buf, *p, *pend;
|
|
||||||
size_t size;
|
|
||||||
int ret, i, j, w;
|
|
||||||
|
|
||||||
if ((ret = av_file_map(filename, &buf, &size, 0, log_ctx)) < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/* prescan file to get the number of lines and the maximum width */
|
|
||||||
w = 0;
|
|
||||||
for (i = 0; i < size; i++) {
|
|
||||||
if (buf[i] == '\n') {
|
|
||||||
if (*rows == INT_MAX) {
|
|
||||||
av_log(log_ctx, AV_LOG_ERROR, "Overflow on the number of rows in the file\n");
|
|
||||||
ret = AVERROR_INVALIDDATA;
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
++(*rows);
|
|
||||||
*cols = FFMAX(*cols, w);
|
|
||||||
w = 0;
|
|
||||||
} else if (w == INT_MAX) {
|
|
||||||
av_log(log_ctx, AV_LOG_ERROR, "Overflow on the number of columns in the file\n");
|
|
||||||
return AVERROR_INVALIDDATA;
|
|
||||||
}
|
|
||||||
w++;
|
|
||||||
}
|
|
||||||
if (*rows > (SIZE_MAX / sizeof(int) / *cols)) {
|
|
||||||
av_log(log_ctx, AV_LOG_ERROR, "File with size %dx%d is too big\n",
|
|
||||||
*rows, *cols);
|
|
||||||
ret = AVERROR_INVALIDDATA;
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
if (!(*values = av_calloc(sizeof(int) * *rows, *cols))) {
|
|
||||||
ret = AVERROR(ENOMEM);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fill *values */
|
|
||||||
p = buf;
|
|
||||||
pend = buf + size-1;
|
|
||||||
for (i = 0; i < *rows; i++) {
|
|
||||||
for (j = 0;; j++) {
|
|
||||||
if (p > pend || *p == '\n') {
|
|
||||||
p++;
|
|
||||||
break;
|
|
||||||
} else
|
|
||||||
(*values)[*cols*i + j] = !!av_isgraph(*(p++));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
end:
|
|
||||||
av_file_unmap(buf, size);
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
{
|
|
||||||
char *line;
|
|
||||||
if (!(line = av_malloc(*cols + 1)))
|
|
||||||
return AVERROR(ENOMEM);
|
|
||||||
for (i = 0; i < *rows; i++) {
|
|
||||||
for (j = 0; j < *cols; j++)
|
|
||||||
line[j] = (*values)[i * *cols + j] ? '@' : ' ';
|
|
||||||
line[j] = 0;
|
|
||||||
av_log(log_ctx, AV_LOG_DEBUG, "%3d: %s\n", i, line);
|
|
||||||
}
|
|
||||||
av_free(line);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int parse_iplconvkernel(IplConvKernel **kernel, char *buf, void *log_ctx)
|
|
||||||
{
|
|
||||||
char shape_filename[128] = "", shape_str[32] = "rect";
|
|
||||||
int cols = 0, rows = 0, anchor_x = 0, anchor_y = 0, shape = CV_SHAPE_RECT;
|
|
||||||
int *values = NULL, ret = 0;
|
|
||||||
|
|
||||||
sscanf(buf, "%dx%d+%dx%d/%32[^=]=%127s", &cols, &rows, &anchor_x, &anchor_y, shape_str, shape_filename);
|
|
||||||
|
|
||||||
if (!strcmp(shape_str, "rect" )) shape = CV_SHAPE_RECT;
|
|
||||||
else if (!strcmp(shape_str, "cross" )) shape = CV_SHAPE_CROSS;
|
|
||||||
else if (!strcmp(shape_str, "ellipse")) shape = CV_SHAPE_ELLIPSE;
|
|
||||||
else if (!strcmp(shape_str, "custom" )) {
|
|
||||||
shape = CV_SHAPE_CUSTOM;
|
|
||||||
if ((ret = read_shape_from_file(&cols, &rows, &values, shape_filename, log_ctx)) < 0)
|
|
||||||
return ret;
|
|
||||||
} else {
|
|
||||||
av_log(log_ctx, AV_LOG_ERROR,
|
|
||||||
"Shape unspecified or type '%s' unknown.\n", shape_str);
|
|
||||||
ret = AVERROR(EINVAL);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rows <= 0 || cols <= 0) {
|
|
||||||
av_log(log_ctx, AV_LOG_ERROR,
|
|
||||||
"Invalid non-positive values for shape size %dx%d\n", cols, rows);
|
|
||||||
ret = AVERROR(EINVAL);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (anchor_x < 0 || anchor_y < 0 || anchor_x >= cols || anchor_y >= rows) {
|
|
||||||
av_log(log_ctx, AV_LOG_ERROR,
|
|
||||||
"Shape anchor %dx%d is not inside the rectangle with size %dx%d.\n",
|
|
||||||
anchor_x, anchor_y, cols, rows);
|
|
||||||
ret = AVERROR(EINVAL);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
*kernel = cvCreateStructuringElementEx(cols, rows, anchor_x, anchor_y, shape, values);
|
|
||||||
if (!*kernel) {
|
|
||||||
ret = AVERROR(ENOMEM);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
av_log(log_ctx, AV_LOG_VERBOSE, "Structuring element: w:%d h:%d x:%d y:%d shape:%s\n",
|
|
||||||
rows, cols, anchor_x, anchor_y, shape_str);
|
|
||||||
out:
|
|
||||||
av_freep(&values);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct DilateContext {
|
|
||||||
int nb_iterations;
|
|
||||||
IplConvKernel *kernel;
|
|
||||||
} DilateContext;
|
|
||||||
|
|
||||||
static av_cold int dilate_init(AVFilterContext *ctx, const char *args)
|
|
||||||
{
|
|
||||||
OCVContext *s = ctx->priv;
|
|
||||||
DilateContext *dilate = s->priv;
|
|
||||||
char default_kernel_str[] = "3x3+0x0/rect";
|
|
||||||
char *kernel_str = NULL;
|
|
||||||
const char *buf = args;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (args) {
|
|
||||||
kernel_str = av_get_token(&buf, "|");
|
|
||||||
|
|
||||||
if (!kernel_str)
|
|
||||||
return AVERROR(ENOMEM);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = parse_iplconvkernel(&dilate->kernel,
|
|
||||||
(!kernel_str || !*kernel_str) ? default_kernel_str
|
|
||||||
: kernel_str,
|
|
||||||
ctx);
|
|
||||||
av_free(kernel_str);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
if (!buf || sscanf(buf, "|%d", &dilate->nb_iterations) != 1)
|
|
||||||
dilate->nb_iterations = 1;
|
|
||||||
av_log(ctx, AV_LOG_VERBOSE, "iterations_nb:%d\n", dilate->nb_iterations);
|
|
||||||
if (dilate->nb_iterations <= 0) {
|
|
||||||
av_log(ctx, AV_LOG_ERROR, "Invalid non-positive value '%d' for nb_iterations\n",
|
|
||||||
dilate->nb_iterations);
|
|
||||||
return AVERROR(EINVAL);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static av_cold void dilate_uninit(AVFilterContext *ctx)
|
|
||||||
{
|
|
||||||
OCVContext *s = ctx->priv;
|
|
||||||
DilateContext *dilate = s->priv;
|
|
||||||
|
|
||||||
cvReleaseStructuringElement(&dilate->kernel);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dilate_end_frame_filter(AVFilterContext *ctx, IplImage *inimg, IplImage *outimg)
|
|
||||||
{
|
|
||||||
OCVContext *s = ctx->priv;
|
|
||||||
DilateContext *dilate = s->priv;
|
|
||||||
cvDilate(inimg, outimg, dilate->kernel, dilate->nb_iterations);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void erode_end_frame_filter(AVFilterContext *ctx, IplImage *inimg, IplImage *outimg)
|
|
||||||
{
|
|
||||||
OCVContext *s = ctx->priv;
|
|
||||||
DilateContext *dilate = s->priv;
|
|
||||||
cvErode(inimg, outimg, dilate->kernel, dilate->nb_iterations);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct OCVFilterEntry {
|
|
||||||
const char *name;
|
|
||||||
size_t priv_size;
|
|
||||||
int (*init)(AVFilterContext *ctx, const char *args);
|
|
||||||
void (*uninit)(AVFilterContext *ctx);
|
|
||||||
void (*end_frame_filter)(AVFilterContext *ctx, IplImage *inimg, IplImage *outimg);
|
|
||||||
} OCVFilterEntry;
|
|
||||||
|
|
||||||
static const OCVFilterEntry ocv_filter_entries[] = {
|
|
||||||
{ "dilate", sizeof(DilateContext), dilate_init, dilate_uninit, dilate_end_frame_filter },
|
|
||||||
{ "erode", sizeof(DilateContext), dilate_init, dilate_uninit, erode_end_frame_filter },
|
|
||||||
{ "smooth", sizeof(SmoothContext), smooth_init, NULL, smooth_end_frame_filter },
|
|
||||||
};
|
|
||||||
|
|
||||||
static av_cold int init(AVFilterContext *ctx)
|
|
||||||
{
|
|
||||||
OCVContext *s = ctx->priv;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!s->name) {
|
|
||||||
av_log(ctx, AV_LOG_ERROR, "No libopencv filter name specified\n");
|
|
||||||
return AVERROR(EINVAL);
|
|
||||||
}
|
|
||||||
for (i = 0; i < FF_ARRAY_ELEMS(ocv_filter_entries); i++) {
|
|
||||||
const OCVFilterEntry *entry = &ocv_filter_entries[i];
|
|
||||||
if (!strcmp(s->name, entry->name)) {
|
|
||||||
s->init = entry->init;
|
|
||||||
s->uninit = entry->uninit;
|
|
||||||
s->end_frame_filter = entry->end_frame_filter;
|
|
||||||
|
|
||||||
if (!(s->priv = av_mallocz(entry->priv_size)))
|
|
||||||
return AVERROR(ENOMEM);
|
|
||||||
return s->init(ctx, s->params);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
av_log(ctx, AV_LOG_ERROR, "No libopencv filter named '%s'\n", s->name);
|
|
||||||
return AVERROR(EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static av_cold void uninit(AVFilterContext *ctx)
|
|
||||||
{
|
|
||||||
OCVContext *s = ctx->priv;
|
|
||||||
|
|
||||||
if (s->uninit)
|
|
||||||
s->uninit(ctx);
|
|
||||||
av_freep(&s->priv);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
|
|
||||||
{
|
|
||||||
AVFilterContext *ctx = inlink->dst;
|
|
||||||
OCVContext *s = ctx->priv;
|
|
||||||
AVFilterLink *outlink= inlink->dst->outputs[0];
|
|
||||||
AVFrame *out;
|
|
||||||
IplImage inimg, outimg;
|
|
||||||
|
|
||||||
out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
|
|
||||||
if (!out) {
|
|
||||||
av_frame_free(&in);
|
|
||||||
return AVERROR(ENOMEM);
|
|
||||||
}
|
|
||||||
av_frame_copy_props(out, in);
|
|
||||||
|
|
||||||
fill_iplimage_from_frame(&inimg , in , inlink->format);
|
|
||||||
fill_iplimage_from_frame(&outimg, out, inlink->format);
|
|
||||||
s->end_frame_filter(ctx, &inimg, &outimg);
|
|
||||||
fill_frame_from_iplimage(out, &outimg, inlink->format);
|
|
||||||
|
|
||||||
av_frame_free(&in);
|
|
||||||
|
|
||||||
return ff_filter_frame(outlink, out);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define OFFSET(x) offsetof(OCVContext, x)
|
|
||||||
#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM
|
|
||||||
static const AVOption ocv_options[] = {
|
|
||||||
{ "filter_name", NULL, OFFSET(name), AV_OPT_TYPE_STRING, .flags = FLAGS },
|
|
||||||
{ "filter_params", NULL, OFFSET(params), AV_OPT_TYPE_STRING, .flags = FLAGS },
|
|
||||||
{ NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
AVFILTER_DEFINE_CLASS(ocv);
|
|
||||||
|
|
||||||
static const AVFilterPad ocv_inputs[] = {
|
|
||||||
{
|
|
||||||
.name = "default",
|
|
||||||
.type = AVMEDIA_TYPE_VIDEO,
|
|
||||||
.filter_frame = filter_frame,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
static const AVFilterPad ocv_outputs[] = {
|
|
||||||
{
|
|
||||||
.name = "default",
|
|
||||||
.type = AVMEDIA_TYPE_VIDEO,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const AVFilter ff_vf_ocv = {
|
|
||||||
.name = "ocv",
|
|
||||||
.description = NULL_IF_CONFIG_SMALL("Apply transform using libopencv."),
|
|
||||||
.priv_size = sizeof(OCVContext),
|
|
||||||
.priv_class = &ocv_class,
|
|
||||||
.init = init,
|
|
||||||
.uninit = uninit,
|
|
||||||
FILTER_INPUTS(ocv_inputs),
|
|
||||||
FILTER_OUTPUTS(ocv_outputs),
|
|
||||||
FILTER_PIXFMTS(AV_PIX_FMT_BGR24, AV_PIX_FMT_BGRA, AV_PIX_FMT_GRAY8),
|
|
||||||
};
|
|
Loading…
Reference in New Issue
Block a user