Signed-off-by: Paul B Mahol <one...@gmail.com> --- doc/filters.texi | 22 +++++++++++ libavfilter/Makefile | 1 + libavfilter/allfilters.c | 1 + libavfilter/vf_convolve.c | 99 ++++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 113 insertions(+), 10 deletions(-)
diff --git a/doc/filters.texi b/doc/filters.texi index 45515966e8..0220b7786a 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -6937,6 +6937,28 @@ Set whether or not chroma is considered in the metric calculations. Default is @code{1}. @end table +@section deconvolve + +Apply 2D deconvolution of video stream in frequency domain using second stream +as impulse. + +The filter accepts the following options: + +@table @option +@item planes +Set which planes to process. + +@item impulse +Set which impulse video frames will be processed, can be @var{first} +or @var{all}. Default is @var{all}. + +@item noise +Set noise when doing divisions. Default is @var{0}. Useful when width and height +are not same and not power of 2. +@end table + +The @code{deconvolve} filter also supports the @ref{framesync} options. + @section deflate Apply deflate effect to the video. diff --git a/libavfilter/Makefile b/libavfilter/Makefile index 6b06d57234..8bde542163 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -165,6 +165,7 @@ OBJS-$(CONFIG_DATASCOPE_FILTER) += vf_datascope.o OBJS-$(CONFIG_DCTDNOIZ_FILTER) += vf_dctdnoiz.o OBJS-$(CONFIG_DEBAND_FILTER) += vf_deband.o OBJS-$(CONFIG_DECIMATE_FILTER) += vf_decimate.o +OBJS-$(CONFIG_DECONVOLVE_FILTER) += vf_convolve.o framesync.o OBJS-$(CONFIG_DEFLATE_FILTER) += vf_neighbor.o OBJS-$(CONFIG_DEFLICKER_FILTER) += vf_deflicker.o OBJS-$(CONFIG_DEINTERLACE_QSV_FILTER) += vf_deinterlace_qsv.o diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index 707faad777..67c073091f 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -175,6 +175,7 @@ static void register_all(void) REGISTER_FILTER(DCTDNOIZ, dctdnoiz, vf); REGISTER_FILTER(DEBAND, deband, vf); REGISTER_FILTER(DECIMATE, decimate, vf); + REGISTER_FILTER(DECONVOLVE, deconvolve, vf); REGISTER_FILTER(DEFLATE, deflate, vf); REGISTER_FILTER(DEFLICKER, deflicker, vf); REGISTER_FILTER(DEINTERLACE_QSV,deinterlace_qsv,vf); diff --git a/libavfilter/vf_convolve.c b/libavfilter/vf_convolve.c index 88ae884a19..1b96848b87 100644 --- a/libavfilter/vf_convolve.c +++ b/libavfilter/vf_convolve.c @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <float.h> + #include "libavutil/imgutils.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" @@ -51,8 +53,11 @@ typedef struct ConvolveContext { int depth; int planes; int impulse; + float noise; int nb_planes; int got_impulse[4]; + + int (*filter)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs); } ConvolveContext; #define OFFSET(x) offsetof(ConvolveContext, x) @@ -121,16 +126,16 @@ static int config_input_main(AVFilterLink *inlink) s->fft_bits[i] = fft_bits; s->fft_len[i] = 1 << s->fft_bits[i]; - if (!(s->fft_hdata[i] = av_calloc(s->fft_len[i] + 1, s->fft_len[i] * sizeof(FFTComplex)))) + if (!(s->fft_hdata[i] = av_calloc(s->fft_len[i], s->fft_len[i] * sizeof(FFTComplex)))) return AVERROR(ENOMEM); - if (!(s->fft_vdata[i] = av_calloc(s->fft_len[i] + 1, s->fft_len[i] * sizeof(FFTComplex)))) + if (!(s->fft_vdata[i] = av_calloc(s->fft_len[i], s->fft_len[i] * sizeof(FFTComplex)))) return AVERROR(ENOMEM); - if (!(s->fft_hdata_impulse[i] = av_calloc(s->fft_len[i] + 1, s->fft_len[i] * sizeof(FFTComplex)))) + if (!(s->fft_hdata_impulse[i] = av_calloc(s->fft_len[i], s->fft_len[i] * sizeof(FFTComplex)))) return AVERROR(ENOMEM); - if (!(s->fft_vdata_impulse[i] = av_calloc(s->fft_len[i] + 1, s->fft_len[i] * sizeof(FFTComplex)))) + if (!(s->fft_vdata_impulse[i] = av_calloc(s->fft_len[i], s->fft_len[i] * sizeof(FFTComplex)))) return AVERROR(ENOMEM); } @@ -166,7 +171,7 @@ static int fft_horizontal(AVFilterContext *ctx, void *arg, int jobnr, int nb_job FFTComplex *hdata = td->hdata; const int plane = td->plane; const int n = td->n; - int start = (n * jobnr ) / nb_jobs; + int start = (n * jobnr) / nb_jobs; int end = (n * (jobnr+1)) / nb_jobs; int y; @@ -261,7 +266,7 @@ static int fft_vertical(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) FFTComplex *vdata = td->vdata; const int plane = td->plane; const int n = td->n; - int start = (n * jobnr ) / nb_jobs; + int start = (n * jobnr) / nb_jobs; int end = (n * (jobnr+1)) / nb_jobs; int y, x; @@ -286,7 +291,7 @@ static int ifft_vertical(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs FFTComplex *vdata = td->vdata; const int plane = td->plane; const int n = td->n; - int start = (n * jobnr ) / nb_jobs; + int start = (n * jobnr) / nb_jobs; int end = (n * (jobnr+1)) / nb_jobs; int y, x; @@ -310,7 +315,7 @@ static int ifft_horizontal(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo FFTComplex *hdata = td->hdata; const int plane = td->plane; const int n = td->n; - int start = (n * jobnr ) / nb_jobs; + int start = (n * jobnr) / nb_jobs; int end = (n * (jobnr+1)) / nb_jobs; int y; @@ -383,7 +388,7 @@ static int complex_multiply(AVFilterContext *ctx, void *arg, int jobnr, int nb_j FFTComplex *input = td->hdata; FFTComplex *filter = td->vdata; const int n = td->n; - int start = (n * jobnr ) / nb_jobs; + int start = (n * jobnr) / nb_jobs; int end = (n * (jobnr+1)) / nb_jobs; int y, x; @@ -406,6 +411,38 @@ static int complex_multiply(AVFilterContext *ctx, void *arg, int jobnr, int nb_j return 0; } +static int complex_divide(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + ConvolveContext *s = ctx->priv; + ThreadData *td = arg; + FFTComplex *input = td->hdata; + FFTComplex *filter = td->vdata; + const float noise = s->noise; + const int n = td->n; + int start = (n * jobnr) / nb_jobs; + int end = (n * (jobnr+1)) / nb_jobs; + int y, x; + + for (y = start; y < end; y++) { + int yn = y * n; + + for (x = 0; x < n; x++) { + FFTSample re, im, ire, iim, div; + + re = input[yn + x].re; + im = input[yn + x].im; + ire = filter[yn + x].re; + iim = filter[yn + x].im; + div = ire * ire + iim * iim + noise; + + input[yn + x].re = (ire * re + iim * im) / div; + input[yn + x].im = (ire * im - iim * re) / div; + } + } + + return 0; +} + static int do_convolve(FFFrameSync *fs) { AVFilterContext *ctx = fs->parent; @@ -474,7 +511,7 @@ static int do_convolve(FFFrameSync *fs) td.hdata = input; td.vdata = filter; - ctx->internal->execute(ctx, complex_multiply, &td, NULL, FFMIN3(MAX_THREADS, n, ff_filter_get_nb_threads(ctx))); + ctx->internal->execute(ctx, s->filter, &td, NULL, FFMIN3(MAX_THREADS, n, ff_filter_get_nb_threads(ctx))); td.hdata = s->fft_hdata[plane]; td.vdata = s->fft_vdata[plane]; @@ -525,6 +562,21 @@ static int activate(AVFilterContext *ctx) return ff_framesync_activate(&s->fs); } +static av_cold int init(AVFilterContext *ctx) +{ + ConvolveContext *s = ctx->priv; + + if (!strcmp(ctx->filter->name, "convolve")) { + s->filter = complex_multiply; + } else if (!strcmp(ctx->filter->name, "deconvolve")) { + s->filter = complex_divide; + } else { + return AVERROR_BUG; + } + + return 0; +} + static av_cold void uninit(AVFilterContext *ctx) { ConvolveContext *s = ctx->priv; @@ -571,6 +623,7 @@ AVFilter ff_vf_convolve = { .name = "convolve", .description = NULL_IF_CONFIG_SMALL("Convolve first video stream with second video stream."), .preinit = convolve_framesync_preinit, + .init = init, .uninit = uninit, .query_formats = query_formats, .activate = activate, @@ -580,3 +633,29 @@ AVFilter ff_vf_convolve = { .outputs = convolve_outputs, .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS, }; + +static const AVOption deconvolve_options[] = { + { "planes", "set planes to deconvolve", OFFSET(planes), AV_OPT_TYPE_INT, {.i64=7}, 0, 15, FLAGS }, + { "impulse", "when to process impulses", OFFSET(impulse), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS, "impulse" }, + { "first", "process only first impulse, ignore rest", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "impulse" }, + { "all", "process all impulses", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "impulse" }, + { "noise", "set noise", OFFSET(noise), AV_OPT_TYPE_FLOAT, {.dbl=0}, 0, 1, FLAGS }, + { NULL }, +}; + +FRAMESYNC_DEFINE_CLASS(deconvolve, ConvolveContext, fs); + +AVFilter ff_vf_deconvolve = { + .name = "deconvolve", + .description = NULL_IF_CONFIG_SMALL("Deconvolve first video stream with second video stream."), + .preinit = deconvolve_framesync_preinit, + .init = init, + .uninit = uninit, + .query_formats = query_formats, + .activate = activate, + .priv_size = sizeof(ConvolveContext), + .priv_class = &deconvolve_class, + .inputs = convolve_inputs, + .outputs = convolve_outputs, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS, +}; -- 2.11.0 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel