From: Mirko Vogt Date: Tue, 8 Sep 2026 13:49:21 +0000 (+0000) Subject: ffmpeg: re-add libpostproc as a source plugin X-Git-Url: http://git.99rst.org/?a=commitdiff_plain;h=87a92bf18940b5245bb8f6ee129b9a0a19b3cad0;p=openwrt-packages.git ffmpeg: re-add libpostproc as a source plugin Upstream dropped libpostproc in 8.0; Kodi still requires it. The --enable/--disable-postproc option the patch re-introduces is set explicitly: on together with GPL in libffmpeg, off in libffmpeg-mini. Patches: 100-postproc: carried over from LibreELEC (Matthias Reichl's rebase of Michael Niedermayer's libpostproc source plugin; packages/multimedia/ffmpeg/patches/postproc/0001-postproc.patch as of LibreELEC commit 5f03a122f8): re-adds libpostproc as a source plugin Header unchanged, hunks refreshed with quilt; the patched tree is identical to the one LibreELEC's file produces. Signed-off-by: Mirko Vogt --- diff --git a/multimedia/ffmpeg/Config.in b/multimedia/ffmpeg/Config.in index 4eb6e40db..850ecf655 100644 --- a/multimedia/ffmpeg/Config.in +++ b/multimedia/ffmpeg/Config.in @@ -3,12 +3,13 @@ menu "FFmpeg configuration" comment "Licensing" config FFMPEG_GPL - bool "Include GPL components (GPL filters)" + bool "Include GPL components (libpostproc, GPL filters)" default y help - Build libffmpeg with --enable-gpl. This adds the - GPL-licensed filters, and the resulting libraries are - distributed under the GPL-2.0-or-later. + Build libffmpeg with --enable-gpl. This adds libpostproc + and the GPL-licensed filters, and the resulting libraries are + distributed under the GPL-2.0-or-later. Kodi requires + libpostproc. config FFMPEG_VERSION3 bool "Allow (L)GPL v3 components" diff --git a/multimedia/ffmpeg/Makefile b/multimedia/ffmpeg/Makefile index 26844509b..4e85d57de 100644 --- a/multimedia/ffmpeg/Makefile +++ b/multimedia/ffmpeg/Makefile @@ -487,12 +487,17 @@ FFMPEG_OPT=$(if $(CONFIG_$(1)),--enable-$(2),--disable-$(2)) ifeq ($(BUILD_VARIANT),default) + # postproc: libpostproc was removed upstream in FFmpeg 8.0 and is re-added + # by patches/100-postproc.patch (LibreELEC), which also re-introduces the + # --enable/--disable-postproc option; it is GPL-only, so it follows the GPL + # option. Kodi requires it. # vaapi/libdav1d: literal --disable until the libva / dav1d packages exist # in the feeds; then restore $(call FFMPEG_OPT,FFMPEG_VAAPI,vaapi), # $(call FFMPEG_OPT,FFMPEG_LIBDAV1D,libdav1d) and, for manual component # selection, --enable-hwaccel=*_vaapi / --enable-decoder=libdav1d. FFMPEG_CONFIGURE+= \ $(call FFMPEG_OPT,FFMPEG_GPL,gpl) \ + $(call FFMPEG_OPT,FFMPEG_GPL,postproc) \ $(call FFMPEG_OPT,FFMPEG_VERSION3,version3) \ $(call FFMPEG_OPT,FFMPEG_NONFREE,nonfree) \ $(call FFMPEG_OPT,FFMPEG_OPTIMIZE_SIZE,small) \ @@ -577,6 +582,7 @@ ifeq ($(BUILD_VARIANT),mini) --disable-programs \ --disable-avdevice \ --disable-avfilter \ + --disable-postproc \ --disable-swresample \ --disable-swscale \ --disable-everything \ diff --git a/multimedia/ffmpeg/patches/100-postproc.patch b/multimedia/ffmpeg/patches/100-postproc.patch new file mode 100644 index 000000000..a8f3bfd0b --- /dev/null +++ b/multimedia/ffmpeg/patches/100-postproc.patch @@ -0,0 +1,9728 @@ +From 983a7e16eada19bfeb423ae64e2de7dbadd45497 Mon Sep 17 00:00:00 2001 +From: Matthias Reichl +Date: Sat, 28 Mar 2026 12:25:00 +0100 +Subject: [PATCH] add sourcepluin-libpostproc from michaelni + +Rebased version of +https://github.com/michaelni/FFmpeg/tree/sourceplugin-libpostproc-8.0 + +Signed-off-by: Matthias Reichl +--- + LICENSE.md | 2 + + MAINTAINERS | 2 + + Makefile | 2 + + configure | 13 +- + doc/filters.texi | 175 ++ + fftools/ffprobe.c | 3 + + fftools/opt_common.c | 3 + + libavfilter/Makefile | 1 + + libavfilter/allfilters.c | 1 + + libavfilter/vf_pp.c | 191 ++ + libavutil/avutil.h | 1 + + libpostproc/Makefile | 23 + + libpostproc/libpostproc.v | 7 + + libpostproc/postprocess.c | 992 ++++++ + libpostproc/postprocess.h | 109 + + libpostproc/postprocess_altivec_template.c | 1214 ++++++++ + libpostproc/postprocess_internal.h | 185 ++ + libpostproc/postprocess_template.c | 3293 ++++++++++++++++++++ + libpostproc/postprocres.rc | 55 + + libpostproc/tests/.gitignore | 3 + + libpostproc/tests/blocktest.c | 113 + + libpostproc/tests/stripetest.c | 115 + + libpostproc/tests/temptest.c | 106 + + libpostproc/tests/test_utils.c | 38 + + libpostproc/tests/test_utils.h | 27 + + libpostproc/version.c | 45 + + libpostproc/version.h | 48 + + libpostproc/version_major.h | 33 + + tests/Makefile | 1 + + tests/fate/filter-video.mak | 16 + + tests/fate/libpostproc.mak | 14 + + tests/ref/fate/blocktest | 1800 +++++++++++ + tests/ref/fate/filter-pp | 10 + + tests/ref/fate/filter-pp1 | 1 + + tests/ref/fate/filter-pp2 | 1 + + tests/ref/fate/filter-pp3 | 1 + + tests/ref/fate/filter-pp4 | 1 + + tests/ref/fate/filter-pp5 | 1 + + tests/ref/fate/filter-pp6 | 1 + + tests/ref/fate/filter-qp | 1 + + tests/ref/fate/stripetest | 360 +++ + tests/ref/fate/temptest | 336 ++ + tools/gen-rc | 1 + + 43 files changed, 9344 insertions(+), 1 deletion(-) + create mode 100644 libavfilter/vf_pp.c + create mode 100644 libpostproc/Makefile + create mode 100644 libpostproc/libpostproc.v + create mode 100644 libpostproc/postprocess.c + create mode 100644 libpostproc/postprocess.h + create mode 100644 libpostproc/postprocess_altivec_template.c + create mode 100644 libpostproc/postprocess_internal.h + create mode 100644 libpostproc/postprocess_template.c + create mode 100644 libpostproc/postprocres.rc + create mode 100644 libpostproc/tests/.gitignore + create mode 100644 libpostproc/tests/blocktest.c + create mode 100644 libpostproc/tests/stripetest.c + create mode 100644 libpostproc/tests/temptest.c + create mode 100644 libpostproc/tests/test_utils.c + create mode 100644 libpostproc/tests/test_utils.h + create mode 100644 libpostproc/version.c + create mode 100644 libpostproc/version.h + create mode 100644 libpostproc/version_major.h + create mode 100644 tests/fate/libpostproc.mak + create mode 100644 tests/ref/fate/blocktest + create mode 100644 tests/ref/fate/filter-pp + create mode 100644 tests/ref/fate/filter-pp1 + create mode 100644 tests/ref/fate/filter-pp2 + create mode 100644 tests/ref/fate/filter-pp3 + create mode 100644 tests/ref/fate/filter-pp4 + create mode 100644 tests/ref/fate/filter-pp5 + create mode 100644 tests/ref/fate/filter-pp6 + create mode 100644 tests/ref/fate/filter-qp + create mode 100644 tests/ref/fate/stripetest + create mode 100644 tests/ref/fate/temptest + +--- a/LICENSE.md ++++ b/LICENSE.md +@@ -12,6 +12,7 @@ configure to activate them. In this case + + Specifically, the GPL parts of FFmpeg are: + ++- libpostproc + - optional x86 optimization in the files + - `libavcodec/x86/flac_dsp_gpl.asm` + - `libavcodec/x86/idct_mmx.c` +@@ -44,6 +45,7 @@ Specifically, the GPL parts of FFmpeg ar + - `vf_owdenoise.c` + - `vf_perspective.c` + - `vf_phase.c` ++ - `vf_pp.c` + - `vf_pp7.c` + - `vf_pullup.c` + - `vf_repeatfields.c` +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -139,6 +139,8 @@ Generic Parts: + ratecontrol.c [2] Michael Niedermayer + simple IDCT: + simple_idct.c, simple_idct.h [2] Michael Niedermayer ++ postprocessing: ++ libpostproc/* [2] Michael Niedermayer + table generation: + tableprint.c, tableprint.h Reimar Doeffinger + fixed point FFT: +--- a/Makefile ++++ b/Makefile +@@ -27,6 +27,7 @@ ALLFFLIBS = \ + avfilter \ + avformat \ + avutil \ ++ postproc \ + swscale \ + swresample \ + +@@ -35,6 +36,7 @@ FFLIBS-$(CONFIG_AVDEVICE) += avdevice + FFLIBS-$(CONFIG_AVFILTER) += avfilter + FFLIBS-$(CONFIG_AVFORMAT) += avformat + FFLIBS-$(CONFIG_AVCODEC) += avcodec ++FFLIBS-$(CONFIG_POSTPROC) += postproc + FFLIBS-$(CONFIG_SWRESAMPLE) += swresample + FFLIBS-$(CONFIG_SWSCALE) += swscale + +--- a/configure ++++ b/configure +@@ -132,6 +132,7 @@ Component options: + --disable-avformat disable libavformat build + --disable-swresample disable libswresample build + --disable-swscale disable libswscale build ++ --disable-postproc disable libpostproc build + --disable-avfilter disable libavfilter build + --disable-pthreads disable pthreads [autodetect] + --disable-w32threads disable Win32 threads [autodetect] +@@ -2229,6 +2230,7 @@ LIBRARY_LIST=" + avdevice + avfilter + swscale ++ postproc + avformat + avcodec + swresample +@@ -4242,6 +4244,7 @@ pan_filter_deps="swresample" + perspective_filter_deps="gpl" + phase_filter_deps="gpl" + pp7_filter_deps="gpl" ++pp_filter_deps="gpl postproc" + prewitt_opencl_filter_deps="opencl" + procamp_vaapi_filter_deps="vaapi" + program_opencl_filter_deps="opencl" +@@ -4363,6 +4366,8 @@ avfilter_suggest="libm stdatomic zlib" + avformat_deps="avcodec avutil" + avformat_suggest="libm network zlib stdatomic" + avutil_suggest="amf clock_gettime ffnvcodec gcrypt libm zlib libdrm libmfx opencl openssl user32 vaapi vulkan videotoolbox corefoundation corevideo coremedia bcrypt stdatomic" ++postproc_deps="avutil gpl" ++postproc_suggest="libm stdatomic" + swresample_deps="avutil" + swresample_suggest="libm libsoxr stdatomic" + swscale_deps="avutil" +@@ -7992,7 +7997,7 @@ void (^block)(void); + EOF + + # add some linker flags +-check_ldflags -Wl,-rpath-link=:libswresample:libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil ++check_ldflags -Wl,-rpath-link=:libpostproc:libswresample:libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil + enabled rpath && add_ldexeflags -Wl,-rpath,$libdir && add_ldsoflags -Wl,-rpath,$libdir + test_ldflags -Wl,-Bsymbolic && append SHFLAGS -Wl,-Bsymbolic + +@@ -8374,6 +8379,7 @@ enabled fsync_filter && prepend a + enabled mcdeint_filter && prepend avfilter_deps "avcodec" + enabled movie_filter && prepend avfilter_deps "avformat avcodec" + enabled pan_filter && prepend avfilter_deps "swresample" ++enabled pp_filter && prepend avfilter_deps "postproc" + enabled qrencode_filter && prepend avfilter_deps "swscale" + enabled qrencodesrc_filter && prepend avfilter_deps "swscale" + enabled removelogo_filter && prepend avfilter_deps "avformat avcodec swscale" +@@ -8425,6 +8431,9 @@ expand_deps(){ + reorder_by ${1}_deps LIBRARY_LIST # linking order is expected later + } + ++#we have to remove gpl from the deps here as some code assumes all lib deps are libs ++postproc_deps="$(filter_out 'gpl' $postproc_deps)" ++ + map 'expand_deps $v' $LIBRARY_LIST + + if test "$quiet" != "yes"; then +@@ -8522,6 +8531,7 @@ echo "optimize for size ${small- + echo "optimizations ${optimizations-no}" + echo "static ${static-no}" + echo "shared ${shared-no}" ++echo "postprocessing support ${postproc-no}" + echo "network support ${network-no}" + echo "threading support ${thread_type-no}" + echo "safe bitstream reader ${safe_bitstream_reader-no}" +@@ -8986,6 +8996,7 @@ extralibs_avcodec="$avcodec_extralibs" + extralibs_avformat="$avformat_extralibs" + extralibs_avdevice="$avdevice_extralibs" + extralibs_avfilter="$avfilter_extralibs" ++extralibs_postproc="$postproc_extralibs" + extralibs_swscale="$swscale_extralibs" + extralibs_swresample="$swresample_extralibs" + EOF +--- a/doc/filters.texi ++++ b/doc/filters.texi +@@ -20089,6 +20089,181 @@ Set window Y position, relative offset o + + This filter supports same @ref{commands} as options. + ++@section pp ++ ++Enable the specified chain of postprocessing subfilters using libpostproc. This ++library should be automatically selected with a GPL build (@code{--enable-gpl}). ++Subfilters must be separated by '/' and can be disabled by prepending a '-'. ++Each subfilter and some options have a short and a long name that can be used ++interchangeably, i.e. dr/dering are the same. ++ ++The filters accept the following options: ++ ++@table @option ++@item subfilters ++Set postprocessing subfilters string. ++@end table ++ ++All subfilters share common options to determine their scope: ++ ++@table @option ++@item a/autoq ++Honor the quality commands for this subfilter. ++ ++@item c/chrom ++Do chrominance filtering, too (default). ++ ++@item y/nochrom ++Do luma filtering only (no chrominance). ++ ++@item n/noluma ++Do chrominance filtering only (no luma). ++@end table ++ ++These options can be appended after the subfilter name, separated by a '|'. ++ ++Available subfilters are: ++ ++@table @option ++@item hb/hdeblock[|difference[|flatness]] ++Horizontal deblocking filter ++@table @option ++@item difference ++Difference factor where higher values mean more deblocking (default: @code{32}). ++@item flatness ++Flatness threshold where lower values mean more deblocking (default: @code{39}). ++@end table ++ ++@item vb/vdeblock[|difference[|flatness]] ++Vertical deblocking filter ++@table @option ++@item difference ++Difference factor where higher values mean more deblocking (default: @code{32}). ++@item flatness ++Flatness threshold where lower values mean more deblocking (default: @code{39}). ++@end table ++ ++@item ha/hadeblock[|difference[|flatness]] ++Accurate horizontal deblocking filter ++@table @option ++@item difference ++Difference factor where higher values mean more deblocking (default: @code{32}). ++@item flatness ++Flatness threshold where lower values mean more deblocking (default: @code{39}). ++@end table ++ ++@item va/vadeblock[|difference[|flatness]] ++Accurate vertical deblocking filter ++@table @option ++@item difference ++Difference factor where higher values mean more deblocking (default: @code{32}). ++@item flatness ++Flatness threshold where lower values mean more deblocking (default: @code{39}). ++@end table ++@end table ++ ++The horizontal and vertical deblocking filters share the difference and ++flatness values so you cannot set different horizontal and vertical ++thresholds. ++ ++@table @option ++@item h1/x1hdeblock ++Experimental horizontal deblocking filter ++ ++@item v1/x1vdeblock ++Experimental vertical deblocking filter ++ ++@item dr/dering ++Deringing filter ++ ++@item tn/tmpnoise[|threshold1[|threshold2[|threshold3]]], temporal noise reducer ++@table @option ++@item threshold1 ++larger -> stronger filtering ++@item threshold2 ++larger -> stronger filtering ++@item threshold3 ++larger -> stronger filtering ++@end table ++ ++@item al/autolevels[:f/fullyrange], automatic brightness / contrast correction ++@table @option ++@item f/fullyrange ++Stretch luma to @code{0-255}. ++@end table ++ ++@item lb/linblenddeint ++Linear blend deinterlacing filter that deinterlaces the given block by ++filtering all lines with a @code{(1 2 1)} filter. ++ ++@item li/linipoldeint ++Linear interpolating deinterlacing filter that deinterlaces the given block by ++linearly interpolating every second line. ++ ++@item ci/cubicipoldeint ++Cubic interpolating deinterlacing filter deinterlaces the given block by ++cubically interpolating every second line. ++ ++@item md/mediandeint ++Median deinterlacing filter that deinterlaces the given block by applying a ++median filter to every second line. ++ ++@item fd/ffmpegdeint ++FFmpeg deinterlacing filter that deinterlaces the given block by filtering every ++second line with a @code{(-1 4 2 4 -1)} filter. ++ ++@item l5/lowpass5 ++Vertically applied FIR lowpass deinterlacing filter that deinterlaces the given ++block by filtering all lines with a @code{(-1 2 6 2 -1)} filter. ++ ++@item fq/forceQuant[|quantizer] ++Overrides the quantizer table from the input with the constant quantizer you ++specify. ++@table @option ++@item quantizer ++Quantizer to use ++@end table ++ ++@item de/default ++Default pp filter combination (@code{hb|a,vb|a,dr|a}) ++ ++@item fa/fast ++Fast pp filter combination (@code{h1|a,v1|a,dr|a}) ++ ++@item ac ++High quality pp filter combination (@code{ha|a|128|7,va|a,dr|a}) ++@end table ++ ++@subsection Examples ++ ++@itemize ++@item ++Apply horizontal and vertical deblocking, deringing and automatic ++brightness/contrast: ++@example ++pp=hb/vb/dr/al ++@end example ++ ++@item ++Apply default filters without brightness/contrast correction: ++@example ++pp=de/-al ++@end example ++ ++@item ++Apply default filters and temporal denoiser: ++@example ++pp=default/tmpnoise|1|2|3 ++@end example ++ ++@item ++Apply deblocking on luma only, and switch vertical deblocking on or off ++automatically depending on available CPU time: ++@example ++pp=hb|y/vb|a ++@end example ++@end itemize ++ + @section pp7 + Apply Postprocessing filter 7. It is variant of the @ref{spp} filter, + similar to spp = 6 with 7 point DCT, where only the center sample is +--- a/fftools/ffprobe.c ++++ b/fftools/ffprobe.c +@@ -64,6 +64,8 @@ + #include "libswscale/version.h" + #include "libswresample/swresample.h" + #include "libswresample/version.h" ++#include "libpostproc/postprocess.h" ++#include "libpostproc/version.h" + #include "libavfilter/version.h" + #include "textformat/avtextformat.h" + #include "cmdutils.h" +@@ -2830,6 +2832,7 @@ static void ffprobe_show_library_version + SHOW_LIB_VERSION(avfilter, AVFILTER); + SHOW_LIB_VERSION(swscale, SWSCALE); + SHOW_LIB_VERSION(swresample, SWRESAMPLE); ++ SHOW_LIB_VERSION(postproc, POSTPROC); + avtext_print_section_footer(tfc); + } + +--- a/fftools/opt_common.c ++++ b/fftools/opt_common.c +@@ -61,6 +61,8 @@ + #include "libswresample/swresample.h" + #include "libswresample/version.h" + ++#include "libpostproc/postprocess.h" ++#include "libpostproc/version.h" + + enum show_muxdemuxers { + SHOW_DEFAULT, +@@ -195,6 +197,7 @@ static void print_all_libs_info(int flag + PRINT_LIB_INFO(avfilter, AVFILTER, flags, level); + PRINT_LIB_INFO(swscale, SWSCALE, flags, level); + PRINT_LIB_INFO(swresample, SWRESAMPLE, flags, level); ++ PRINT_LIB_INFO(postproc, POSTPROC, flags, level); + } + + static void print_program_info(int flags, int level) +--- a/libavfilter/Makefile ++++ b/libavfilter/Makefile +@@ -440,6 +440,7 @@ OBJS-$(CONFIG_PHOTOSENSITIVITY_FILTER) + OBJS-$(CONFIG_PIXDESCTEST_FILTER) += vf_pixdesctest.o + OBJS-$(CONFIG_PIXELIZE_FILTER) += vf_pixelize.o + OBJS-$(CONFIG_PIXSCOPE_FILTER) += vf_datascope.o ++OBJS-$(CONFIG_PP_FILTER) += vf_pp.o qp_table.o + OBJS-$(CONFIG_PP7_FILTER) += vf_pp7.o qp_table.o + OBJS-$(CONFIG_PREMULTIPLY_DYNAMIC_FILTER) += vf_premultiply.o framesync.o + OBJS-$(CONFIG_PREMULTIPLY_FILTER) += vf_premultiply.o framesync.o +--- a/libavfilter/allfilters.c ++++ b/libavfilter/allfilters.c +@@ -412,6 +412,7 @@ extern const FFFilter ff_vf_photosensiti + extern const FFFilter ff_vf_pixdesctest; + extern const FFFilter ff_vf_pixelize; + extern const FFFilter ff_vf_pixscope; ++extern const FFFilter ff_vf_pp; + extern const FFFilter ff_vf_pp7; + extern const FFFilter ff_vf_premultiply; + extern const FFFilter ff_vf_premultiply_dynamic; +--- /dev/null ++++ b/libavfilter/vf_pp.c +@@ -0,0 +1,191 @@ ++/* ++ * Copyright (c) 2002 A'rpi ++ * Copyright (C) 2012 Clément Bœsch ++ * ++ * This file is part of FFmpeg. ++ * ++ * FFmpeg is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU 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 ++ * libpostproc filter, ported from MPlayer. ++ */ ++ ++#include "libavutil/avassert.h" ++#include "libavutil/mem.h" ++#include "libavutil/opt.h" ++ ++#include "filters.h" ++#include "qp_table.h" ++#include "video.h" ++ ++#include "libpostproc/postprocess.h" ++ ++typedef struct PPFilterContext { ++ const AVClass *class; ++ char *subfilters; ++ int mode_id; ++ pp_mode *modes[PP_QUALITY_MAX + 1]; ++ void *pp_ctx; ++} PPFilterContext; ++ ++#define OFFSET(x) offsetof(PPFilterContext, x) ++#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM ++static const AVOption pp_options[] = { ++ { "subfilters", "set postprocess subfilters", OFFSET(subfilters), AV_OPT_TYPE_STRING, {.str="de"}, .flags = FLAGS }, ++ { NULL } ++}; ++ ++AVFILTER_DEFINE_CLASS(pp); ++ ++static av_cold int pp_init(AVFilterContext *ctx) ++{ ++ int i; ++ PPFilterContext *pp = ctx->priv; ++ ++ for (i = 0; i <= PP_QUALITY_MAX; i++) { ++ pp->modes[i] = pp_get_mode_by_name_and_quality(pp->subfilters, i); ++ if (!pp->modes[i]) ++ return AVERROR_EXTERNAL; ++ } ++ pp->mode_id = PP_QUALITY_MAX; ++ return 0; ++} ++ ++static int pp_process_command(AVFilterContext *ctx, const char *cmd, const char *args, ++ char *res, int res_len, int flags) ++{ ++ PPFilterContext *pp = ctx->priv; ++ ++ if (!strcmp(cmd, "quality")) { ++ pp->mode_id = av_clip(strtol(args, NULL, 10), 0, PP_QUALITY_MAX); ++ return 0; ++ } ++ return AVERROR(ENOSYS); ++} ++ ++static const enum AVPixelFormat pix_fmts[] = { ++ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVJ420P, ++ AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVJ422P, ++ AV_PIX_FMT_YUV411P, ++ AV_PIX_FMT_GBRP, ++ AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ444P, ++ AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUVJ440P, ++ AV_PIX_FMT_GRAY8, ++ AV_PIX_FMT_NONE ++}; ++ ++static int pp_config_props(AVFilterLink *inlink) ++{ ++ int flags = PP_CPU_CAPS_AUTO; ++ PPFilterContext *pp = inlink->dst->priv; ++ ++ switch (inlink->format) { ++ case AV_PIX_FMT_GRAY8: ++ case AV_PIX_FMT_YUVJ420P: ++ case AV_PIX_FMT_YUV420P: flags |= PP_FORMAT_420; break; ++ case AV_PIX_FMT_YUVJ422P: ++ case AV_PIX_FMT_YUV422P: flags |= PP_FORMAT_422; break; ++ case AV_PIX_FMT_YUV411P: flags |= PP_FORMAT_411; break; ++ case AV_PIX_FMT_GBRP: ++ case AV_PIX_FMT_YUVJ444P: ++ case AV_PIX_FMT_YUV444P: flags |= PP_FORMAT_444; break; ++ case AV_PIX_FMT_YUVJ440P: ++ case AV_PIX_FMT_YUV440P: flags |= PP_FORMAT_440; break; ++ default: av_assert0(0); ++ } ++ ++ pp->pp_ctx = pp_get_context(inlink->w, inlink->h, flags); ++ if (!pp->pp_ctx) ++ return AVERROR(ENOMEM); ++ return 0; ++} ++ ++static int pp_filter_frame(AVFilterLink *inlink, AVFrame *inbuf) ++{ ++ AVFilterContext *ctx = inlink->dst; ++ PPFilterContext *pp = ctx->priv; ++ AVFilterLink *outlink = ctx->outputs[0]; ++ const int aligned_w = FFALIGN(outlink->w, 8); ++ const int aligned_h = FFALIGN(outlink->h, 8); ++ AVFrame *outbuf; ++ int qstride = 0; ++ int8_t *qp_table = NULL; ++ int ret; ++ ++ outbuf = ff_get_video_buffer(outlink, aligned_w, aligned_h); ++ if (!outbuf) { ++ av_frame_free(&inbuf); ++ return AVERROR(ENOMEM); ++ } ++ av_frame_copy_props(outbuf, inbuf); ++ outbuf->width = inbuf->width; ++ outbuf->height = inbuf->height; ++ ++ ret = ff_qp_table_extract(inbuf, &qp_table, &qstride, NULL, NULL); ++ if (ret < 0) { ++ av_frame_free(&inbuf); ++ av_frame_free(&outbuf); ++ return ret; ++ } ++ ++ pp_postprocess((const uint8_t **)inbuf->data, inbuf->linesize, ++ outbuf->data, outbuf->linesize, ++ aligned_w, outlink->h, ++ qp_table, ++ qstride, ++ pp->modes[pp->mode_id], ++ pp->pp_ctx, ++ outbuf->pict_type | (qp_table ? PP_PICT_TYPE_QP2 : 0)); ++ ++ av_frame_free(&inbuf); ++ av_freep(&qp_table); ++ return ff_filter_frame(outlink, outbuf); ++} ++ ++static av_cold void pp_uninit(AVFilterContext *ctx) ++{ ++ int i; ++ PPFilterContext *pp = ctx->priv; ++ ++ for (i = 0; i <= PP_QUALITY_MAX; i++) ++ pp_free_mode(pp->modes[i]); ++ if (pp->pp_ctx) ++ pp_free_context(pp->pp_ctx); ++} ++ ++static const AVFilterPad pp_inputs[] = { ++ { ++ .name = "default", ++ .type = AVMEDIA_TYPE_VIDEO, ++ .config_props = pp_config_props, ++ .filter_frame = pp_filter_frame, ++ }, ++}; ++ ++const FFFilter ff_vf_pp = { ++ .p.name = "pp", ++ .p.description = NULL_IF_CONFIG_SMALL("Filter video using libpostproc."), ++ .p.priv_class = &pp_class, ++ .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, ++ .priv_size = sizeof(PPFilterContext), ++ .init = pp_init, ++ .uninit = pp_uninit, ++ FILTER_INPUTS(pp_inputs), ++ FILTER_OUTPUTS(ff_video_default_filterpad), ++ FILTER_PIXFMTS_ARRAY(pix_fmts), ++ .process_command = pp_process_command, ++}; +--- a/libavutil/avutil.h ++++ b/libavutil/avutil.h +@@ -41,6 +41,7 @@ + * @li @ref lavd "libavdevice" special devices muxing/demuxing library + * @li @ref lavu "libavutil" common utility library + * @li @ref lswr "libswresample" audio resampling, format conversion and mixing ++ * @li @ref lpp "libpostproc" post processing library + * @li @ref libsws "libswscale" color conversion and scaling library + * + * @section ffmpeg_versioning Versioning and compatibility +--- /dev/null ++++ b/libpostproc/Makefile +@@ -0,0 +1,23 @@ ++NAME = postproc ++DESC = FFmpeg postprocessing library ++FFLIBS = avutil ++ ++HEADERS = postprocess.h \ ++ version.h \ ++ version_major.h \ ++ ++OBJS = postprocess.o \ ++ version.o \ ++ ++TESTOBJS = tests/test_utils.o \ ++ ++# Windows resource file ++SHLIBOBJS-$(HAVE_GNU_WINDRES) += postprocres.o ++ ++TESTPROGS = blocktest \ ++ stripetest \ ++ temptest \ ++ ++$(SUBDIR)tests/blocktest$(EXESUF): $(SUBDIR)tests/test_utils.o ++$(SUBDIR)tests/stripetest$(EXESUF): $(SUBDIR)tests/test_utils.o ++$(SUBDIR)tests/temptest$(EXESUF): $(SUBDIR)tests/test_utils.o +--- /dev/null ++++ b/libpostproc/libpostproc.v +@@ -0,0 +1,7 @@ ++LIBPOSTPROC_MAJOR { ++ global: ++ postproc_*; ++ pp_*; ++ local: ++ *; ++}; +--- /dev/null ++++ b/libpostproc/postprocess.c +@@ -0,0 +1,992 @@ ++/* ++ * Copyright (C) 2001-2003 Michael Niedermayer (michaelni@gmx.at) ++ * ++ * AltiVec optimizations (C) 2004 Romain Dolbeau ++ * ++ * This file is part of FFmpeg. ++ * ++ * FFmpeg is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 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 General Public License for more details. ++ * ++ * You should have received a copy of the GNU 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 ++ * postprocessing. ++ */ ++ ++/* ++ C MMX MMX2 AltiVec ++isVertDC Ec Ec Ec ++isVertMinMaxOk Ec Ec Ec ++doVertLowPass E e Ec ++doVertDefFilter Ec Ec e Ec ++isHorizDC Ec Ec Ec ++isHorizMinMaxOk a E Ec ++doHorizLowPass E e Ec ++doHorizDefFilter Ec Ec e Ec ++do_a_deblock Ec E Ec ++deRing E e Ecp ++Vertical RKAlgo1 E a ++Horizontal RKAlgo1 a ++Vertical X1# a E ++Horizontal X1# a E ++LinIpolDeinterlace e E ++CubicIpolDeinterlace a e ++LinBlendDeinterlace e E ++MedianDeinterlace# E Ec Ec ++TempDeNoiser# E e Ec ++ ++# more or less selfinvented filters so the exactness is not too meaningful ++E = Exact implementation ++e = almost exact implementation (slightly different rounding,...) ++a = alternative / approximate impl ++c = checked against the other implementations (-vo md5) ++p = partially optimized, still some work to do ++*/ ++ ++/* ++TODO: ++reduce the time wasted on the mem transfer ++unroll stuff if instructions depend too much on the prior one ++move YScale thing to the end instead of fixing QP ++write a faster and higher quality deblocking filter :) ++make the mainloop more flexible (variable number of blocks at once ++ (the if/else stuff per block is slowing things down) ++compare the quality & speed of all filters ++split this huge file ++optimize c versions ++try to unroll inner for(x=0 ... loop to avoid these damn if(x ... checks ++... ++*/ ++ ++//Changelog: use git log ++ ++#include ++#include ++#include ++ ++#include "config.h" ++#include "libavutil/common.h" ++#include "libavutil/cpu.h" ++#include "libavutil/intreadwrite.h" ++#include "libavutil/mem.h" ++//#undef HAVE_MMXEXT_INLINE ++//#undef HAVE_MMX_INLINE ++//#undef ARCH_X86 ++//#define DEBUG_BRIGHTNESS ++#include "postprocess.h" ++#include "postprocess_internal.h" ++#include "libavutil/avstring.h" ++ ++#define GET_MODE_BUFFER_SIZE 500 ++#define OPTIONS_ARRAY_SIZE 10 ++#define BLOCK_SIZE 8 ++#define TEMP_STRIDE 8 ++//#define NUM_BLOCKS_AT_ONCE 16 //not used yet ++ ++#define DERING_THRESHOLD 20 ++ ++#if ARCH_X86 && HAVE_INLINE_ASM ++DECLARE_ASM_CONST(8, uint64_t, w05)= 0x0005000500050005LL; ++DECLARE_ASM_CONST(8, uint64_t, w04)= 0x0004000400040004LL; ++DECLARE_ASM_CONST(8, uint64_t, w20)= 0x0020002000200020LL; ++DECLARE_ASM_CONST(8, uint64_t, b00)= 0x0000000000000000LL; ++DECLARE_ASM_CONST(8, uint64_t, b01)= 0x0101010101010101LL; ++DECLARE_ASM_CONST(8, uint64_t, b08)= 0x0808080808080808LL; ++DECLARE_ASM_CONST(8, uint64_t, b80)= 0x8080808080808080LL; ++#endif ++ ++static const struct PPFilter filters[]= ++{ ++ {"hb", "hdeblock", 1, 1, 3, H_DEBLOCK}, ++ {"vb", "vdeblock", 1, 2, 4, V_DEBLOCK}, ++/* {"hr", "rkhdeblock", 1, 1, 3, H_RK1_FILTER}, ++ {"vr", "rkvdeblock", 1, 2, 4, V_RK1_FILTER},*/ ++ {"h1", "x1hdeblock", 1, 1, 3, H_X1_FILTER}, ++ {"v1", "x1vdeblock", 1, 2, 4, V_X1_FILTER}, ++ {"ha", "ahdeblock", 1, 1, 3, H_A_DEBLOCK}, ++ {"va", "avdeblock", 1, 2, 4, V_A_DEBLOCK}, ++ {"dr", "dering", 1, 5, 6, DERING}, ++ {"al", "autolevels", 0, 1, 2, LEVEL_FIX}, ++ {"lb", "linblenddeint", 1, 1, 4, LINEAR_BLEND_DEINT_FILTER}, ++ {"li", "linipoldeint", 1, 1, 4, LINEAR_IPOL_DEINT_FILTER}, ++ {"ci", "cubicipoldeint", 1, 1, 4, CUBIC_IPOL_DEINT_FILTER}, ++ {"md", "mediandeint", 1, 1, 4, MEDIAN_DEINT_FILTER}, ++ {"fd", "ffmpegdeint", 1, 1, 4, FFMPEG_DEINT_FILTER}, ++ {"l5", "lowpass5", 1, 1, 4, LOWPASS5_DEINT_FILTER}, ++ {"tn", "tmpnoise", 1, 7, 8, TEMP_NOISE_FILTER}, ++ {"fq", "forcequant", 1, 0, 0, FORCE_QUANT}, ++ {"be", "bitexact", 1, 0, 0, BITEXACT}, ++ {"vi", "visualize", 1, 0, 0, VISUALIZE}, ++ {NULL, NULL,0,0,0,0} //End Marker ++}; ++ ++static const char * const replaceTable[]= ++{ ++ "default", "hb:a,vb:a,dr:a", ++ "de", "hb:a,vb:a,dr:a", ++ "fast", "h1:a,v1:a,dr:a", ++ "fa", "h1:a,v1:a,dr:a", ++ "ac", "ha:a:128:7,va:a,dr:a", ++ NULL //End Marker ++}; ++ ++/* The horizontal functions exist only in C because the MMX ++ * code is faster with vertical filters and transposing. */ ++ ++/** ++ * Check if the given 8x8 Block is mostly "flat" ++ */ ++static inline int isHorizDC_C(const uint8_t src[], int stride, const PPContext *c) ++{ ++ int numEq= 0; ++ int y; ++ const int dcOffset= ((c->nonBQP*c->ppMode.baseDcDiff)>>8) + 1; ++ const int dcThreshold= dcOffset*2 + 1; ++ ++ for(y=0; y c->ppMode.flatnessThreshold; ++} ++ ++/** ++ * Check if the middle 8x8 Block in the given 8x16 block is flat ++ */ ++static inline int isVertDC_C(const uint8_t src[], int stride, const PPContext *c) ++{ ++ int numEq= 0; ++ int y; ++ const int dcOffset= ((c->nonBQP*c->ppMode.baseDcDiff)>>8) + 1; ++ const int dcThreshold= dcOffset*2 + 1; ++ ++ src+= stride*4; // src points to begin of the 8x8 Block ++ for(y=0; y c->ppMode.flatnessThreshold; ++} ++ ++static inline int isHorizMinMaxOk_C(const uint8_t src[], int stride, int QP) ++{ ++ int i; ++ for(i=0; i<2; i++){ ++ if((unsigned)(src[0] - src[5] + 2*QP) > 4*QP) return 0; ++ src += stride; ++ if((unsigned)(src[2] - src[7] + 2*QP) > 4*QP) return 0; ++ src += stride; ++ if((unsigned)(src[4] - src[1] + 2*QP) > 4*QP) return 0; ++ src += stride; ++ if((unsigned)(src[6] - src[3] + 2*QP) > 4*QP) return 0; ++ src += stride; ++ } ++ return 1; ++} ++ ++static inline int isVertMinMaxOk_C(const uint8_t src[], int stride, int QP) ++{ ++ int x; ++ src+= stride*4; ++ for(x=0; x 4*QP) return 0; ++ if((unsigned)(src[1+x + 2*stride] - src[1+x + 7*stride] + 2*QP) > 4*QP) return 0; ++ if((unsigned)(src[2+x + 4*stride] - src[2+x + 1*stride] + 2*QP) > 4*QP) return 0; ++ if((unsigned)(src[3+x + 6*stride] - src[3+x + 3*stride] + 2*QP) > 4*QP) return 0; ++ } ++ return 1; ++} ++ ++static inline int horizClassify_C(const uint8_t src[], int stride, const PPContext *c) ++{ ++ if( isHorizDC_C(src, stride, c) ){ ++ return isHorizMinMaxOk_C(src, stride, c->QP); ++ }else{ ++ return 2; ++ } ++} ++ ++static inline int vertClassify_C(const uint8_t src[], int stride, const PPContext *c) ++{ ++ if( isVertDC_C(src, stride, c) ){ ++ return isVertMinMaxOk_C(src, stride, c->QP); ++ }else{ ++ return 2; ++ } ++} ++ ++static inline void doHorizDefFilter_C(uint8_t dst[], int stride, const PPContext *c) ++{ ++ int y; ++ for(y=0; yQP){ ++ const int q=(dst[3] - dst[4])/2; ++ const int leftEnergy= 5*(dst[2] - dst[1]) + 2*(dst[0] - dst[3]); ++ const int rightEnergy= 5*(dst[6] - dst[5]) + 2*(dst[4] - dst[7]); ++ ++ int d= FFABS(middleEnergy) - FFMIN( FFABS(leftEnergy), FFABS(rightEnergy) ); ++ d= FFMAX(d, 0); ++ ++ d= (5*d + 32) >> 6; ++ d*= FFSIGN(-middleEnergy); ++ ++ if(q>0) ++ { ++ d = FFMAX(d, 0); ++ d = FFMIN(d, q); ++ } ++ else ++ { ++ d = FFMIN(d, 0); ++ d = FFMAX(d, q); ++ } ++ ++ dst[3]-= d; ++ dst[4]+= d; ++ } ++ dst+= stride; ++ } ++} ++ ++/** ++ * Do a horizontal low pass filter on the 10x8 block (dst points to middle 8x8 Block) ++ * using the 9-Tap Filter (1,1,2,2,4,2,2,1,1)/16 (C version) ++ */ ++static inline void doHorizLowPass_C(uint8_t dst[], int stride, const PPContext *c) ++{ ++ int y; ++ for(y=0; yQP ? dst[-1] : dst[0]; ++ const int last= FFABS(dst[8] - dst[7]) < c->QP ? dst[8] : dst[7]; ++ ++ int sums[10]; ++ sums[0] = 4*first + dst[0] + dst[1] + dst[2] + 4; ++ sums[1] = sums[0] - first + dst[3]; ++ sums[2] = sums[1] - first + dst[4]; ++ sums[3] = sums[2] - first + dst[5]; ++ sums[4] = sums[3] - first + dst[6]; ++ sums[5] = sums[4] - dst[0] + dst[7]; ++ sums[6] = sums[5] - dst[1] + last; ++ sums[7] = sums[6] - dst[2] + last; ++ sums[8] = sums[7] - dst[3] + last; ++ sums[9] = sums[8] - dst[4] + last; ++ ++ dst[0]= (sums[0] + sums[2] + 2*dst[0])>>4; ++ dst[1]= (sums[1] + sums[3] + 2*dst[1])>>4; ++ dst[2]= (sums[2] + sums[4] + 2*dst[2])>>4; ++ dst[3]= (sums[3] + sums[5] + 2*dst[3])>>4; ++ dst[4]= (sums[4] + sums[6] + 2*dst[4])>>4; ++ dst[5]= (sums[5] + sums[7] + 2*dst[5])>>4; ++ dst[6]= (sums[6] + sums[8] + 2*dst[6])>>4; ++ dst[7]= (sums[7] + sums[9] + 2*dst[7])>>4; ++ ++ dst+= stride; ++ } ++} ++ ++/** ++ * Experimental Filter 1 (Horizontal) ++ * will not damage linear gradients ++ * Flat blocks should look like they were passed through the (1,1,2,2,4,2,2,1,1) 9-Tap filter ++ * can only smooth blocks at the expected locations (it cannot smooth them if they did move) ++ * MMX2 version does correct clipping C version does not ++ * not identical with the vertical one ++ */ ++static inline void horizX1Filter(uint8_t *src, int stride, int QP) ++{ ++ int y; ++ static uint64_t lut[256]; ++ if(!lut[255]) ++ { ++ int i; ++ for(i=0; i<256; i++) ++ { ++ int v= i < 128 ? 2*i : 2*(i-256); ++/* ++//Simulate 112242211 9-Tap filter ++ uint64_t a= (v/16) & 0xFF; ++ uint64_t b= (v/8) & 0xFF; ++ uint64_t c= (v/4) & 0xFF; ++ uint64_t d= (3*v/8) & 0xFF; ++*/ ++//Simulate piecewise linear interpolation ++ uint64_t a= (v/16) & 0xFF; ++ uint64_t b= (v*3/16) & 0xFF; ++ uint64_t c= (v*5/16) & 0xFF; ++ uint64_t d= (7*v/16) & 0xFF; ++ uint64_t A= (0x100 - a)&0xFF; ++ uint64_t B= (0x100 - b)&0xFF; ++ uint64_t C= (0x100 - c)&0xFF; ++ uint64_t D= (0x100 - c)&0xFF; ++ ++ lut[i] = (a<<56) | (b<<48) | (c<<40) | (d<<32) | ++ (D<<24) | (C<<16) | (B<<8) | (A); ++ //lut[i] = (v<<32) | (v<<24); ++ } ++ } ++ ++ for(y=0; yQP; ++ const int dcOffset= ((c->nonBQP*c->ppMode.baseDcDiff)>>8) + 1; ++ const int dcThreshold= dcOffset*2 + 1; ++ ++ src+= step*4; // src points to begin of the 8x8 Block ++ for(y=0; y<8; y++){ ++ int numEq= 0; ++ ++ numEq += ((unsigned)(src[-1*step] - src[0*step] + dcOffset)) < dcThreshold; ++ numEq += ((unsigned)(src[ 0*step] - src[1*step] + dcOffset)) < dcThreshold; ++ numEq += ((unsigned)(src[ 1*step] - src[2*step] + dcOffset)) < dcThreshold; ++ numEq += ((unsigned)(src[ 2*step] - src[3*step] + dcOffset)) < dcThreshold; ++ numEq += ((unsigned)(src[ 3*step] - src[4*step] + dcOffset)) < dcThreshold; ++ numEq += ((unsigned)(src[ 4*step] - src[5*step] + dcOffset)) < dcThreshold; ++ numEq += ((unsigned)(src[ 5*step] - src[6*step] + dcOffset)) < dcThreshold; ++ numEq += ((unsigned)(src[ 6*step] - src[7*step] + dcOffset)) < dcThreshold; ++ numEq += ((unsigned)(src[ 7*step] - src[8*step] + dcOffset)) < dcThreshold; ++ if(numEq > c->ppMode.flatnessThreshold){ ++ int min, max, x; ++ ++ if(src[0] > src[step]){ ++ max= src[0]; ++ min= src[step]; ++ }else{ ++ max= src[step]; ++ min= src[0]; ++ } ++ for(x=2; x<8; x+=2){ ++ if(src[x*step] > src[(x+1)*step]){ ++ if(src[x *step] > max) max= src[ x *step]; ++ if(src[(x+1)*step] < min) min= src[(x+1)*step]; ++ }else{ ++ if(src[(x+1)*step] > max) max= src[(x+1)*step]; ++ if(src[ x *step] < min) min= src[ x *step]; ++ } ++ } ++ if(max-min < 2*QP){ ++ const int first= FFABS(src[-1*step] - src[0]) < QP ? src[-1*step] : src[0]; ++ const int last= FFABS(src[8*step] - src[7*step]) < QP ? src[8*step] : src[7*step]; ++ ++ int sums[10]; ++ sums[0] = 4*first + src[0*step] + src[1*step] + src[2*step] + 4; ++ sums[1] = sums[0] - first + src[3*step]; ++ sums[2] = sums[1] - first + src[4*step]; ++ sums[3] = sums[2] - first + src[5*step]; ++ sums[4] = sums[3] - first + src[6*step]; ++ sums[5] = sums[4] - src[0*step] + src[7*step]; ++ sums[6] = sums[5] - src[1*step] + last; ++ sums[7] = sums[6] - src[2*step] + last; ++ sums[8] = sums[7] - src[3*step] + last; ++ sums[9] = sums[8] - src[4*step] + last; ++ ++ if (mode & VISUALIZE) { ++ src[0*step] = ++ src[1*step] = ++ src[2*step] = ++ src[3*step] = ++ src[4*step] = ++ src[5*step] = ++ src[6*step] = ++ src[7*step] = 128; ++ } ++ src[0*step]= (sums[0] + sums[2] + 2*src[0*step])>>4; ++ src[1*step]= (sums[1] + sums[3] + 2*src[1*step])>>4; ++ src[2*step]= (sums[2] + sums[4] + 2*src[2*step])>>4; ++ src[3*step]= (sums[3] + sums[5] + 2*src[3*step])>>4; ++ src[4*step]= (sums[4] + sums[6] + 2*src[4*step])>>4; ++ src[5*step]= (sums[5] + sums[7] + 2*src[5*step])>>4; ++ src[6*step]= (sums[6] + sums[8] + 2*src[6*step])>>4; ++ src[7*step]= (sums[7] + sums[9] + 2*src[7*step])>>4; ++ } ++ }else{ ++ const int middleEnergy= 5*(src[4*step] - src[3*step]) + 2*(src[2*step] - src[5*step]); ++ ++ if(FFABS(middleEnergy) < 8*QP){ ++ const int q=(src[3*step] - src[4*step])/2; ++ const int leftEnergy= 5*(src[2*step] - src[1*step]) + 2*(src[0*step] - src[3*step]); ++ const int rightEnergy= 5*(src[6*step] - src[5*step]) + 2*(src[4*step] - src[7*step]); ++ ++ int d= FFABS(middleEnergy) - FFMIN( FFABS(leftEnergy), FFABS(rightEnergy) ); ++ d= FFMAX(d, 0); ++ ++ d= (5*d + 32) >> 6; ++ d*= FFSIGN(-middleEnergy); ++ ++ if(q>0){ ++ d = FFMAX(d, 0); ++ d = FFMIN(d, q); ++ }else{ ++ d = FFMIN(d, 0); ++ d = FFMAX(d, q); ++ } ++ ++ if ((mode & VISUALIZE) && d) { ++ d= (d < 0) ? 32 : -32; ++ src[3*step]= av_clip_uint8(src[3*step] - d); ++ src[4*step]= av_clip_uint8(src[4*step] + d); ++ d = 0; ++ } ++ ++ src[3*step]-= d; ++ src[4*step]+= d; ++ } ++ } ++ ++ src += stride; ++ } ++} ++ ++//Note: we have C and SSE2 version (which uses MMX(EXT) when advantageous) ++//Plain C versions ++//we always compile C for testing which needs bitexactness ++#define TEMPLATE_PP_C 1 ++#include "postprocess_template.c" ++ ++#if HAVE_ALTIVEC ++#include "libavutil/ppc/util_altivec.h" ++ ++# define TEMPLATE_PP_ALTIVEC 1 ++# include "postprocess_altivec_template.c" ++# include "postprocess_template.c" ++#endif ++ ++#if ARCH_X86 && HAVE_INLINE_ASM ++# if CONFIG_RUNTIME_CPUDETECT ++# define TEMPLATE_PP_SSE2 1 ++# include "postprocess_template.c" ++# else ++# if HAVE_SSE2_INLINE ++# define TEMPLATE_PP_SSE2 1 ++# include "postprocess_template.c" ++# endif ++# endif ++#endif ++ ++typedef void (*pp_fn)(const uint8_t src[], int srcStride, uint8_t dst[], int dstStride, int width, int height, ++ const int8_t QPs[], int QPStride, int isColor, PPContext *c2); ++ ++static inline void postProcess(const uint8_t src[], int srcStride, uint8_t dst[], int dstStride, int width, int height, ++ const int8_t QPs[], int QPStride, int isColor, pp_mode *vm, pp_context *vc) ++{ ++ pp_fn pp = postProcess_C; ++ PPContext *c= (PPContext *)vc; ++ PPMode *ppMode= (PPMode *)vm; ++ c->ppMode= *ppMode; //FIXME ++ ++ if (!(ppMode->lumMode & BITEXACT)) { ++#if CONFIG_RUNTIME_CPUDETECT ++#if ARCH_X86 && HAVE_INLINE_ASM ++ // ordered per speed fastest first ++ if (c->cpuCaps & AV_CPU_FLAG_SSE2) pp = postProcess_SSE2; ++#elif HAVE_ALTIVEC ++ if (c->cpuCaps & AV_CPU_FLAG_ALTIVEC) pp = postProcess_altivec; ++#endif ++#else /* CONFIG_RUNTIME_CPUDETECT */ ++#if HAVE_SSE2_INLINE ++ pp = postProcess_SSE2; ++#elif HAVE_ALTIVEC ++ pp = postProcess_altivec; ++#endif ++#endif /* !CONFIG_RUNTIME_CPUDETECT */ ++ } ++ ++ pp(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c); ++} ++ ++/* -pp Command line Help ++*/ ++const char pp_help[] = ++"Available postprocessing filters:\n" ++"Filters Options\n" ++"short long name short long option Description\n" ++"* * a autoq CPU power dependent enabler\n" ++" c chrom chrominance filtering enabled\n" ++" y nochrom chrominance filtering disabled\n" ++" n noluma luma filtering disabled\n" ++"hb hdeblock (2 threshold) horizontal deblocking filter\n" ++" 1. difference factor: default=32, higher -> more deblocking\n" ++" 2. flatness threshold: default=39, lower -> more deblocking\n" ++" the h & v deblocking filters share these\n" ++" so you can't set different thresholds for h / v\n" ++"vb vdeblock (2 threshold) vertical deblocking filter\n" ++"ha hadeblock (2 threshold) horizontal deblocking filter\n" ++"va vadeblock (2 threshold) vertical deblocking filter\n" ++"h1 x1hdeblock experimental h deblock filter 1\n" ++"v1 x1vdeblock experimental v deblock filter 1\n" ++"dr dering deringing filter\n" ++"al autolevels automatic brightness / contrast\n" ++" f fullyrange stretch luminance to (0..255)\n" ++"lb linblenddeint linear blend deinterlacer\n" ++"li linipoldeint linear interpolating deinterlace\n" ++"ci cubicipoldeint cubic interpolating deinterlacer\n" ++"md mediandeint median deinterlacer\n" ++"fd ffmpegdeint ffmpeg deinterlacer\n" ++"l5 lowpass5 FIR lowpass deinterlacer\n" ++"de default hb:a,vb:a,dr:a\n" ++"fa fast h1:a,v1:a,dr:a\n" ++"ac ha:a:128:7,va:a,dr:a\n" ++"tn tmpnoise (3 threshold) temporal noise reducer\n" ++" 1. <= 2. <= 3. larger -> stronger filtering\n" ++"fq forceQuant force quantizer\n" ++"Usage:\n" ++"[: