You've already forked FFmpeg
mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-06-14 22:15:12 +02:00
compat
doc
ffbuild
fftools
libavcodec
libavdevice
libavfilter
aarch64
cuda
dnn
metal
opencl
riscv
tests
vulkan
x86
.gitignore
Makefile
aap_template.c
adynamicequalizer_template.c
aeval.c
af_aap.c
af_acontrast.c
af_acopy.c
af_acrossover.c
af_acrusher.c
af_adeclick.c
af_adecorrelate.c
af_adelay.c
af_adenorm.c
af_aderivative.c
af_adrc.c
af_adynamicequalizer.c
af_adynamicsmooth.c
af_aecho.c
af_aemphasis.c
af_aexciter.c
af_afade.c
af_afftdn.c
af_afftfilt.c
af_afir.c
af_afir.h
af_afirdsp.h
af_aformat.c
af_afreqshift.c
af_afwtdn.c
af_agate.c
af_aiir.c
af_alimiter.c
af_amerge.c
af_amix.c
af_amultiply.c
af_anequalizer.c
af_anlmdn.c
af_anlmdndsp.h
af_anlms.c
af_anull.c
af_apad.c
af_aphaser.c
af_apsyclip.c
af_apulsator.c
af_aresample.c
af_arls.c
af_arnndn.c
af_asdr.c
af_asetnsamples.c
af_asetrate.c
af_ashowinfo.c
af_asoftclip.c
af_aspectralstats.c
af_asr.c
af_astats.c
af_asubboost.c
af_asupercut.c
af_atempo.c
af_atilt.c
af_axcorrelate.c
af_biquads.c
af_bs2b.c
af_channelmap.c
af_channelsplit.c
af_chorus.c
af_compand.c
af_compensationdelay.c
af_crossfeed.c
af_crystalizer.c
af_dcshift.c
af_deesser.c
af_dialoguenhance.c
af_drmeter.c
af_dynaudnorm.c
af_earwax.c
af_extrastereo.c
af_firequalizer.c
af_flanger.c
af_haas.c
af_hdcd.c
af_headphone.c
af_join.c
af_ladspa.c
af_loudnorm.c
af_lv2.c
af_mcompand.c
af_pan.c
af_replaygain.c
af_rubberband.c
af_sidechaincompress.c
af_silencedetect.c
af_silenceremove.c
af_sofalizer.c
af_speechnorm.c
af_stereotools.c
af_stereowiden.c
af_superequalizer.c
af_surround.c
af_tremolo.c
af_vibrato.c
af_virtualbass.c
af_volume.c
af_volume.h
af_volumedetect.c
afir_template.c
allfilters.c
anlms_template.c
arls_template.c
asink_anullsink.c
asrc_afdelaysrc.c
asrc_afirsrc.c
asrc_anoisesrc.c
asrc_anullsrc.c
asrc_flite.c
asrc_hilbert.c
asrc_sinc.c
asrc_sine.c
atadenoise.h
audio.c
audio.h
avf_a3dscope.c
avf_abitscope.c
avf_ahistogram.c
avf_aphasemeter.c
avf_avectorscope.c
avf_concat.c
avf_showcqt.c
avf_showcqt.h
avf_showcwt.c
avf_showfreqs.c
avf_showspatial.c
avf_showspectrum.c
avf_showvolume.c
avf_showwaves.c
avfilter.c
avfilter.h
avfilter_internal.h
avfiltergraph.c
avfilterres.rc
bbox.c
bbox.h
blend.h
blend_modes.c
boxblur.c
boxblur.h
bufferqueue.h
buffersink.c
buffersink.h
buffersrc.c
buffersrc.h
bwdifdsp.c
bwdifdsp.h
ccfifo.c
ccfifo.h
colorchannelmixer_template.c
colorspace.c
colorspace.h
colorspacedsp.c
colorspacedsp.h
colorspacedsp_template.c
colorspacedsp_yuv2yuv_template.c
convolution.h
dialoguenhance_template.c
dnn_filter_common.c
dnn_filter_common.h
dnn_interface.h
drawutils.c
drawutils.h
ebur128.c
ebur128.h
edge_common.c
edge_common.h
edge_template.c
f_bench.c
f_cue.c
f_drawgraph.c
f_ebur128.c
f_graphmonitor.c
f_interleave.c
f_latency.c
f_loop.c
f_metadata.c
f_perms.c
f_realtime.c
f_reverse.c
f_segment.c
f_select.c
f_sendcmd.c
f_sidedata.c
f_streamselect.c
f_zmq.c
fflcms2.c
fflcms2.h
file_open.c
filters.h
formats.c
formats.h
framepool.c
framepool.h
framequeue.c
framequeue.h
framerate.h
framesync.c
framesync.h
gblur.h
generate_wave_table.c
generate_wave_table.h
gradfun.h
graphdump.c
graphparser.c
hermite.h
hflip.h
internal.h
lavfutils.c
lavfutils.h
libavfilter.v
limiter.h
log2_tab.c
lswsutils.c
lswsutils.h
lut3d.h
maskedclamp.h
maskedmerge.h
median.h
median_template.c
motion_estimation.c
motion_estimation.h
opencl.c
opencl.h
opencl_source.h
palette.c
palette.h
phase_template.c
preserve_color.h
psnr.h
pthread.c
qp_table.c
qp_table.h
qrencode.c
qsvvpp.c
qsvvpp.h
removegrain.h
scale_eval.c
scale_eval.h
scene_sad.c
scene_sad.h
setpts.c
settb.c
signature.h
signature_lookup.c
silenceremove_template.c
split.c
src_avsynctest.c
src_movie.c
ssim.h
stack_internal.c
stack_internal.h
stereo3d.h
textutils.c
textutils.h
threshold.h
tinterlace.h
transform.c
transform.h
transpose.h
trim.c
unsharp.h
v360.h
vaapi_vpp.c
vaapi_vpp.h
vaf_spectrumsynth.c
version.c
version.h
version_major.h
vf_addroi.c
vf_alphamerge.c
vf_amplify.c
vf_aspect.c
vf_atadenoise.c
vf_avgblur.c
vf_avgblur_opencl.c
vf_avgblur_vulkan.c
vf_backgroundkey.c
vf_bbox.c
vf_bilateral.c
vf_bilateral_cuda.c
vf_bilateral_cuda.cu
vf_bitplanenoise.c
vf_blackdetect.c
vf_blackframe.c
vf_blend.c
vf_blend_init.h
vf_blend_vulkan.c
vf_blockdetect.c
vf_blurdetect.c
vf_bm3d.c
vf_boxblur.c
vf_bwdif.c
vf_bwdif_cuda.c
vf_bwdif_cuda.cu
vf_bwdif_vulkan.c
vf_cas.c
vf_ccrepack.c
vf_chromaber_vulkan.c
vf_chromakey.c
vf_chromakey_cuda.c
vf_chromakey_cuda.cu
vf_chromanr.c
vf_chromashift.c
vf_ciescope.c
vf_codecview.c
vf_colorbalance.c
vf_colorchannelmixer.c
vf_colorconstancy.c
vf_colorcontrast.c
vf_colorcorrect.c
vf_colorize.c
vf_colorkey.c
vf_colorkey_opencl.c
vf_colorlevels.c
vf_colormap.c
vf_colormatrix.c
vf_colorspace.c
vf_colorspace_cuda.c
vf_colorspace_cuda.cu
vf_colortemperature.c
vf_convolution.c
vf_convolution_opencl.c
vf_convolve.c
vf_copy.c
vf_coreimage.m
vf_corr.c
vf_cover_rect.c
vf_crop.c
vf_cropdetect.c
vf_curves.c
vf_datascope.c
vf_dblur.c
vf_dctdnoiz.c
vf_deband.c
vf_deblock.c
vf_decimate.c
vf_dedot.c
vf_deflicker.c
vf_deinterlace_vaapi.c
vf_dejudder.c
vf_delogo.c
vf_derain.c
vf_deshake.c
vf_deshake_opencl.c
vf_despill.c
vf_detelecine.c
vf_displace.c
vf_dnn_classify.c
vf_dnn_detect.c
vf_dnn_processing.c
vf_drawbox.c
vf_drawtext.c
vf_edgedetect.c
vf_elbg.c
vf_entropy.c
vf_epx.c
vf_eq.c
vf_eq.h
vf_estdif.c
vf_exposure.c
vf_extractplanes.c
vf_fade.c
vf_feedback.c
vf_fftdnoiz.c
vf_fftfilt.c
vf_field.c
vf_fieldhint.c
vf_fieldmatch.c
vf_fieldorder.c
vf_fillborders.c
vf_find_rect.c
vf_flip_vulkan.c
vf_floodfill.c
vf_format.c
vf_fps.c
vf_framepack.c
vf_framerate.c
vf_framestep.c
vf_freezedetect.c
vf_freezeframes.c
vf_frei0r.c
vf_fspp.c
vf_fspp.h
vf_fsync.c
vf_gblur.c
vf_gblur_init.h
vf_gblur_vulkan.c
vf_geq.c
vf_gradfun.c
vf_grayworld.c
vf_guided.c
vf_hflip.c
vf_hflip_init.h
vf_histeq.c
vf_histogram.c
vf_hqdn3d.c
vf_hqdn3d.h
vf_hqx.c
vf_hsvkey.c
vf_hue.c
vf_huesaturation.c
vf_hwdownload.c
vf_hwmap.c
vf_hwupload.c
vf_hwupload_cuda.c
vf_hysteresis.c
vf_iccdetect.c
vf_iccgen.c
vf_identity.c
vf_idet.c
vf_idet.h
vf_il.c
vf_kerndeint.c
vf_lagfun.c
vf_lenscorrection.c
vf_lensfun.c
vf_libopencv.c
vf_libplacebo.c
vf_libvmaf.c
vf_limitdiff.c
vf_limiter.c
vf_lumakey.c
vf_lut.c
vf_lut2.c
vf_lut3d.c
vf_maskedclamp.c
vf_maskedmerge.c
vf_maskedminmax.c
vf_maskedthreshold.c
vf_maskfun.c
vf_mcdeint.c
vf_median.c
vf_mergeplanes.c
vf_mestimate.c
vf_midequalizer.c
vf_minterpolate.c
vf_misc_vaapi.c
vf_mix.c
vf_monochrome.c
vf_morpho.c
vf_mpdecimate.c
vf_multiply.c
vf_negate.c
vf_neighbor.c
vf_neighbor_opencl.c
vf_nlmeans.c
vf_nlmeans.h
vf_nlmeans_init.h
vf_nlmeans_opencl.c
vf_nlmeans_vulkan.c
vf_nnedi.c
vf_noise.c
vf_noise.h
vf_normalize.c
vf_null.c
vf_ocr.c
vf_overlay.c
vf_overlay.h
vf_overlay_cuda.c
vf_overlay_cuda.cu
vf_overlay_opencl.c
vf_overlay_qsv.c
vf_overlay_vaapi.c
vf_overlay_vulkan.c
vf_owdenoise.c
vf_pad.c
vf_pad_opencl.c
vf_palettegen.c
vf_paletteuse.c
vf_perspective.c
vf_phase.c
vf_photosensitivity.c
vf_pixdesctest.c
vf_pixelize.c
vf_pp.c
vf_pp7.c
vf_pp7.h
vf_premultiply.c
vf_procamp_vaapi.c
vf_program_opencl.c
vf_pseudocolor.c
vf_psnr.c
vf_pullup.c
vf_pullup.h
vf_qp.c
vf_quirc.c
vf_random.c
vf_readeia608.c
vf_readvitc.c
vf_remap.c
vf_remap_opencl.c
vf_removegrain.c
vf_removelogo.c
vf_repeatfields.c
vf_rotate.c
vf_sab.c
vf_scale.c
vf_scale_cuda.c
vf_scale_cuda.cu
vf_scale_cuda.h
vf_scale_npp.c
vf_scale_vaapi.c
vf_scale_vt.c
vf_scale_vulkan.c
vf_scdet.c
vf_scroll.c
vf_selectivecolor.c
vf_separatefields.c
vf_setparams.c
vf_sharpen_npp.c
vf_shear.c
vf_showinfo.c
vf_showpalette.c
vf_shuffleframes.c
vf_shufflepixels.c
vf_shuffleplanes.c
vf_signalstats.c
vf_signature.c
vf_siti.c
vf_smartblur.c
vf_spp.c
vf_spp.h
vf_sr.c
vf_ssim.c
vf_ssim360.c
vf_stack.c
vf_stack_qsv.c
vf_stack_vaapi.c
vf_stereo3d.c
vf_subtitles.c
vf_super2xsai.c
vf_swaprect.c
vf_swapuv.c
vf_telecine.c
vf_threshold.c
vf_threshold_init.h
vf_thumbnail.c
vf_thumbnail_cuda.c
vf_thumbnail_cuda.cu
vf_tile.c
vf_tiltandshift.c
vf_tinterlace.c
vf_tmidequalizer.c
vf_tonemap.c
vf_tonemap_opencl.c
vf_tonemap_vaapi.c
vf_tpad.c
vf_transpose.c
vf_transpose_npp.c
vf_transpose_opencl.c
vf_transpose_vaapi.c
vf_transpose_vt.c
vf_transpose_vulkan.c
vf_unsharp.c
vf_unsharp_opencl.c
vf_untile.c
vf_uspp.c
vf_v360.c
vf_vaguedenoiser.c
vf_varblur.c
vf_vectorscope.c
vf_vflip.c
vf_vfrdet.c
vf_vibrance.c
vf_vidstabdetect.c
vf_vidstabtransform.c
vf_vif.c
vf_vignette.c
vf_vmafmotion.c
vf_vpp_qsv.c
vf_w3fdif.c
vf_waveform.c
vf_weave.c
vf_xbr.c
vf_xfade.c
vf_xfade_opencl.c
vf_xfade_vulkan.c
vf_xmedian.c
vf_yadif.c
vf_yadif_cuda.c
vf_yadif_cuda.cu
vf_yadif_videotoolbox.m
vf_yaepblur.c
vf_zoompan.c
vf_zscale.c
video.c
video.h
vidstabutils.c
vidstabutils.h
vmaf_motion.h
vsink_nullsink.c
vsrc_cellauto.c
vsrc_ddagrab.c
vsrc_ddagrab_shaders.h
vsrc_gradients.c
vsrc_life.c
vsrc_mandelbrot.c
vsrc_mptestsrc.c
vsrc_sierpinski.c
vsrc_testsrc.c
vsrc_testsrc_vulkan.c
vulkan.c
vulkan.h
vulkan_filter.c
vulkan_filter.h
vulkan_glslang.c
vulkan_shaderc.c
vulkan_spirv.h
w3fdif.h
window_func.h
yadif.h
yadif_common.c
libavformat
libavutil
libpostproc
libswresample
libswscale
presets
tests
tools
.gitattributes
.gitignore
.mailmap
.travis.yml
CONTRIBUTING.md
COPYING.GPLv2
COPYING.GPLv3
COPYING.LGPLv2.1
COPYING.LGPLv3
CREDITS
Changelog
INSTALL.md
LICENSE.md
MAINTAINERS
Makefile
README.md
RELEASE
configure
A filter needs formats.h iff it uses FILTER_QUERY_FUNC(); since lots of filters have been switched to use something else than FILTER_QUERY_FUNC, they don't need it any more, but removing this header has been forgotten. This commit does this; files with formats.h inclusion went down from 304 to 139 here (it were 449 before the preceding commit). While just at it, also improve the other headers a bit. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
380 lines
20 KiB
C
380 lines
20 KiB
C
/*
|
|
* Original copyright (c) 2002 Remi Guyomarch <rguyom@pobox.com>
|
|
* Port copyright (c) 2010 Daniel G. Taylor <dan@programmer-art.org>
|
|
* Relicensed to the LGPL with permission from Remi Guyomarch.
|
|
*
|
|
* 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
|
|
* blur / sharpen filter, ported to FFmpeg from MPlayer
|
|
* libmpcodecs/unsharp.c.
|
|
*
|
|
* This code is based on:
|
|
*
|
|
* An Efficient algorithm for Gaussian blur using finite-state machines
|
|
* Frederick M. Waltz and John W. V. Miller
|
|
*
|
|
* SPIE Conf. on Machine Vision Systems for Inspection and Metrology VII
|
|
* Originally published Boston, Nov 98
|
|
*
|
|
* http://www.engin.umd.umich.edu/~jwvm/ece581/21_GBlur.pdf
|
|
*/
|
|
|
|
#include "avfilter.h"
|
|
#include "internal.h"
|
|
#include "video.h"
|
|
#include "libavutil/common.h"
|
|
#include "libavutil/imgutils.h"
|
|
#include "libavutil/mem.h"
|
|
#include "libavutil/opt.h"
|
|
#include "libavutil/pixdesc.h"
|
|
#include "unsharp.h"
|
|
|
|
typedef struct TheadData {
|
|
UnsharpFilterParam *fp;
|
|
uint8_t *dst;
|
|
const uint8_t *src;
|
|
int dst_stride;
|
|
int src_stride;
|
|
int width;
|
|
int height;
|
|
} ThreadData;
|
|
|
|
#define DEF_UNSHARP_SLICE_FUNC(name, nbits) \
|
|
static int name##_##nbits(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \
|
|
{ \
|
|
ThreadData *td = arg; \
|
|
UnsharpFilterParam *fp = td->fp; \
|
|
UnsharpContext *s = ctx->priv; \
|
|
uint32_t **sc = fp->sc; \
|
|
uint32_t *sr = fp->sr; \
|
|
const uint##nbits##_t *src2 = NULL; \
|
|
const int amount = fp->amount; \
|
|
const int steps_x = fp->steps_x; \
|
|
const int steps_y = fp->steps_y; \
|
|
const int scalebits = fp->scalebits; \
|
|
const int32_t halfscale = fp->halfscale; \
|
|
\
|
|
uint##nbits##_t *dst = (uint##nbits##_t*)td->dst; \
|
|
const uint##nbits##_t *src = (const uint##nbits##_t *)td->src; \
|
|
int dst_stride = td->dst_stride; \
|
|
int src_stride = td->src_stride; \
|
|
const int width = td->width; \
|
|
const int height = td->height; \
|
|
const int sc_offset = jobnr * 2 * steps_y; \
|
|
const int sr_offset = jobnr * (MAX_MATRIX_SIZE - 1); \
|
|
const int slice_start = (height * jobnr) / nb_jobs; \
|
|
const int slice_end = (height * (jobnr+1)) / nb_jobs; \
|
|
\
|
|
int32_t res; \
|
|
int x, y, z; \
|
|
uint32_t tmp1, tmp2; \
|
|
\
|
|
if (!amount) { \
|
|
av_image_copy_plane(td->dst + slice_start * dst_stride, dst_stride, \
|
|
td->src + slice_start * src_stride, src_stride, \
|
|
width * s->bps, slice_end - slice_start); \
|
|
return 0; \
|
|
} \
|
|
\
|
|
for (y = 0; y < 2 * steps_y; y++) \
|
|
memset(sc[sc_offset + y], 0, sizeof(sc[y][0]) * (width + 2 * steps_x)); \
|
|
\
|
|
dst_stride = dst_stride / s->bps; \
|
|
src_stride = src_stride / s->bps; \
|
|
/* if this is not the first tile, we start from (slice_start - steps_y) */ \
|
|
/* so we can get smooth result at slice boundary */ \
|
|
if (slice_start > steps_y) { \
|
|
src += (slice_start - steps_y) * src_stride; \
|
|
dst += (slice_start - steps_y) * dst_stride; \
|
|
} \
|
|
\
|
|
for (y = -steps_y + slice_start; y < steps_y + slice_end; y++) { \
|
|
if (y < height) \
|
|
src2 = src; \
|
|
\
|
|
memset(sr + sr_offset, 0, sizeof(sr[0]) * (2 * steps_x - 1)); \
|
|
for (x = -steps_x; x < width + steps_x; x++) { \
|
|
tmp1 = x <= 0 ? src2[0] : x >= width ? src2[width-1] : src2[x]; \
|
|
for (z = 0; z < steps_x * 2; z += 2) { \
|
|
tmp2 = sr[sr_offset + z + 0] + tmp1; sr[sr_offset + z + 0] = tmp1; \
|
|
tmp1 = sr[sr_offset + z + 1] + tmp2; sr[sr_offset + z + 1] = tmp2; \
|
|
} \
|
|
for (z = 0; z < steps_y * 2; z += 2) { \
|
|
tmp2 = sc[sc_offset + z + 0][x + steps_x] + tmp1; \
|
|
sc[sc_offset + z + 0][x + steps_x] = tmp1; \
|
|
tmp1 = sc[sc_offset + z + 1][x + steps_x] + tmp2; \
|
|
sc[sc_offset + z + 1][x + steps_x] = tmp2; \
|
|
} \
|
|
if (x >= steps_x && y >= (steps_y + slice_start)) { \
|
|
const uint##nbits##_t *srx = src - steps_y * src_stride + x - steps_x; \
|
|
uint##nbits##_t *dsx = dst - steps_y * dst_stride + x - steps_x; \
|
|
\
|
|
res = (int32_t)*srx + ((((int32_t) * srx - \
|
|
(int32_t)((tmp1 + halfscale) >> scalebits)) * amount) >> (8+nbits)); \
|
|
*dsx = av_clip_uint##nbits(res); \
|
|
} \
|
|
} \
|
|
if (y >= 0) { \
|
|
dst += dst_stride; \
|
|
src += src_stride; \
|
|
} \
|
|
} \
|
|
return 0; \
|
|
}
|
|
DEF_UNSHARP_SLICE_FUNC(unsharp_slice, 16)
|
|
DEF_UNSHARP_SLICE_FUNC(unsharp_slice, 8)
|
|
|
|
static int apply_unsharp_c(AVFilterContext *ctx, AVFrame *in, AVFrame *out)
|
|
{
|
|
AVFilterLink *inlink = ctx->inputs[0];
|
|
UnsharpContext *s = ctx->priv;
|
|
int i, plane_w[4], plane_h[4];
|
|
UnsharpFilterParam *fp[4];
|
|
ThreadData td;
|
|
|
|
plane_w[0] = plane_w[3] = inlink->w;
|
|
plane_w[1] = plane_w[2] = AV_CEIL_RSHIFT(inlink->w, s->hsub);
|
|
plane_h[0] = plane_h[3] = inlink->h;
|
|
plane_h[1] = plane_h[2] = AV_CEIL_RSHIFT(inlink->h, s->vsub);
|
|
fp[0] = &s->luma;
|
|
fp[1] = fp[2] = &s->chroma;
|
|
fp[3] = &s->alpha;
|
|
for (i = 0; i < s->nb_planes; i++) {
|
|
td.fp = fp[i];
|
|
td.dst = out->data[i];
|
|
td.src = in->data[i];
|
|
td.width = plane_w[i];
|
|
td.height = plane_h[i];
|
|
td.dst_stride = out->linesize[i];
|
|
td.src_stride = in->linesize[i];
|
|
ff_filter_execute(ctx, s->unsharp_slice, &td, NULL,
|
|
FFMIN(plane_h[i], s->nb_threads));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#define MAX_SCALEBITS 25
|
|
|
|
static int set_filter_param(AVFilterContext *ctx, const char *name, const char *short_name,
|
|
UnsharpFilterParam *fp, int msize_x, int msize_y, float amount)
|
|
{
|
|
fp->msize_x = msize_x;
|
|
fp->msize_y = msize_y;
|
|
fp->amount = amount * 65536.0;
|
|
|
|
fp->steps_x = msize_x / 2;
|
|
fp->steps_y = msize_y / 2;
|
|
fp->scalebits = (fp->steps_x + fp->steps_y) * 2;
|
|
fp->halfscale = 1 << (fp->scalebits - 1);
|
|
|
|
if (fp->scalebits > MAX_SCALEBITS) {
|
|
av_log(ctx, AV_LOG_ERROR, "%s matrix size (%sx/2+%sy/2)*2=%d greater than maximum value %d\n",
|
|
name, short_name, short_name, fp->scalebits, MAX_SCALEBITS);
|
|
return AVERROR(EINVAL);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static av_cold int init(AVFilterContext *ctx)
|
|
{
|
|
UnsharpContext *s = ctx->priv;
|
|
int ret;
|
|
|
|
#define SET_FILTER_PARAM(name_, short_) \
|
|
ret = set_filter_param(ctx, #name_, #short_, &s->name_, \
|
|
s->short_##msize_x, s->short_##msize_y, s->short_##amount); \
|
|
if (ret < 0) \
|
|
return ret; \
|
|
|
|
SET_FILTER_PARAM(luma, l);
|
|
SET_FILTER_PARAM(chroma, c);
|
|
SET_FILTER_PARAM(alpha, a);
|
|
|
|
s->apply_unsharp = apply_unsharp_c;
|
|
return 0;
|
|
}
|
|
|
|
static const enum AVPixelFormat pix_fmts[] = {
|
|
AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA444P,
|
|
AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA444P12, AV_PIX_FMT_YUVA444P16,
|
|
AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA422P12, AV_PIX_FMT_YUVA422P16,
|
|
AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA420P16,
|
|
AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV410P,
|
|
AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P,
|
|
AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9,
|
|
AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV440P10,
|
|
AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV440P12,
|
|
AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16,
|
|
AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_NONE
|
|
};
|
|
|
|
static int init_filter_param(AVFilterContext *ctx, UnsharpFilterParam *fp, const char *effect_type, int width)
|
|
{
|
|
int z;
|
|
UnsharpContext *s = ctx->priv;
|
|
const char *effect = fp->amount == 0 ? "none" : fp->amount < 0 ? "blur" : "sharpen";
|
|
|
|
if (!(fp->msize_x & fp->msize_y & 1)) {
|
|
av_log(ctx, AV_LOG_ERROR,
|
|
"Invalid even size for %s matrix size %dx%d\n",
|
|
effect_type, fp->msize_x, fp->msize_y);
|
|
return AVERROR(EINVAL);
|
|
}
|
|
|
|
av_log(ctx, AV_LOG_VERBOSE, "effect:%s type:%s msize_x:%d msize_y:%d amount:%0.2f\n",
|
|
effect, effect_type, fp->msize_x, fp->msize_y, fp->amount / 65535.0);
|
|
|
|
fp->sr = av_malloc_array((MAX_MATRIX_SIZE - 1) * s->nb_threads, sizeof(uint32_t));
|
|
fp->sc = av_calloc(fp->steps_y * s->nb_threads, 2 * sizeof(*fp->sc));
|
|
if (!fp->sr || !fp->sc)
|
|
return AVERROR(ENOMEM);
|
|
|
|
for (z = 0; z < 2 * fp->steps_y * s->nb_threads; z++)
|
|
if (!(fp->sc[z] = av_malloc_array(width + 2 * fp->steps_x,
|
|
sizeof(*(fp->sc[z])))))
|
|
return AVERROR(ENOMEM);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int config_input(AVFilterLink *inlink)
|
|
{
|
|
UnsharpContext *s = inlink->dst->priv;
|
|
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
|
|
int ret;
|
|
|
|
s->nb_planes = desc->nb_components;
|
|
s->hsub = desc->log2_chroma_w;
|
|
s->vsub = desc->log2_chroma_h;
|
|
s->bitdepth = desc->comp[0].depth;
|
|
s->bps = s->bitdepth > 8 ? 2 : 1;
|
|
s->unsharp_slice = s->bitdepth > 8 ? unsharp_slice_16 : unsharp_slice_8;
|
|
|
|
// ensure (height / nb_threads) > 4 * steps_y,
|
|
// so that we don't have too much overlap between two threads
|
|
s->nb_threads = FFMIN(ff_filter_get_nb_threads(inlink->dst),
|
|
inlink->h / (4 * s->luma.steps_y));
|
|
|
|
ret = init_filter_param(inlink->dst, &s->luma, "luma", inlink->w);
|
|
if (ret < 0)
|
|
return ret;
|
|
ret = init_filter_param(inlink->dst, &s->chroma, "chroma", AV_CEIL_RSHIFT(inlink->w, s->hsub));
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void free_filter_param(UnsharpFilterParam *fp, int nb_threads)
|
|
{
|
|
int z;
|
|
|
|
if (fp->sc) {
|
|
for (z = 0; z < 2 * fp->steps_y * nb_threads; z++)
|
|
av_freep(&fp->sc[z]);
|
|
av_freep(&fp->sc);
|
|
}
|
|
av_freep(&fp->sr);
|
|
}
|
|
|
|
static av_cold void uninit(AVFilterContext *ctx)
|
|
{
|
|
UnsharpContext *s = ctx->priv;
|
|
|
|
free_filter_param(&s->luma, s->nb_threads);
|
|
free_filter_param(&s->chroma, s->nb_threads);
|
|
}
|
|
|
|
static int filter_frame(AVFilterLink *link, AVFrame *in)
|
|
{
|
|
UnsharpContext *s = link->dst->priv;
|
|
AVFilterLink *outlink = link->dst->outputs[0];
|
|
AVFrame *out;
|
|
int ret = 0;
|
|
|
|
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);
|
|
|
|
ret = s->apply_unsharp(link->dst, in, out);
|
|
|
|
av_frame_free(&in);
|
|
|
|
if (ret < 0) {
|
|
av_frame_free(&out);
|
|
return ret;
|
|
}
|
|
return ff_filter_frame(outlink, out);
|
|
}
|
|
|
|
#define OFFSET(x) offsetof(UnsharpContext, x)
|
|
#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
|
|
#define MIN_SIZE 3
|
|
#define MAX_SIZE 23
|
|
static const AVOption unsharp_options[] = {
|
|
{ "luma_msize_x", "set luma matrix horizontal size", OFFSET(lmsize_x), AV_OPT_TYPE_INT, { .i64 = 5 }, MIN_SIZE, MAX_SIZE, FLAGS },
|
|
{ "lx", "set luma matrix horizontal size", OFFSET(lmsize_x), AV_OPT_TYPE_INT, { .i64 = 5 }, MIN_SIZE, MAX_SIZE, FLAGS },
|
|
{ "luma_msize_y", "set luma matrix vertical size", OFFSET(lmsize_y), AV_OPT_TYPE_INT, { .i64 = 5 }, MIN_SIZE, MAX_SIZE, FLAGS },
|
|
{ "ly", "set luma matrix vertical size", OFFSET(lmsize_y), AV_OPT_TYPE_INT, { .i64 = 5 }, MIN_SIZE, MAX_SIZE, FLAGS },
|
|
{ "luma_amount", "set luma effect strength", OFFSET(lamount), AV_OPT_TYPE_FLOAT, { .dbl = 1 }, -2, 5, FLAGS },
|
|
{ "la", "set luma effect strength", OFFSET(lamount), AV_OPT_TYPE_FLOAT, { .dbl = 1 }, -2, 5, FLAGS },
|
|
{ "chroma_msize_x", "set chroma matrix horizontal size", OFFSET(cmsize_x), AV_OPT_TYPE_INT, { .i64 = 5 }, MIN_SIZE, MAX_SIZE, FLAGS },
|
|
{ "cx", "set chroma matrix horizontal size", OFFSET(cmsize_x), AV_OPT_TYPE_INT, { .i64 = 5 }, MIN_SIZE, MAX_SIZE, FLAGS },
|
|
{ "chroma_msize_y", "set chroma matrix vertical size", OFFSET(cmsize_y), AV_OPT_TYPE_INT, { .i64 = 5 }, MIN_SIZE, MAX_SIZE, FLAGS },
|
|
{ "cy", "set chroma matrix vertical size", OFFSET(cmsize_y), AV_OPT_TYPE_INT, { .i64 = 5 }, MIN_SIZE, MAX_SIZE, FLAGS },
|
|
{ "chroma_amount", "set chroma effect strength", OFFSET(camount), AV_OPT_TYPE_FLOAT, { .dbl = 0 }, -2, 5, FLAGS },
|
|
{ "ca", "set chroma effect strength", OFFSET(camount), AV_OPT_TYPE_FLOAT, { .dbl = 0 }, -2, 5, FLAGS },
|
|
{ "alpha_msize_x", "set alpha matrix horizontal size", OFFSET(amsize_x), AV_OPT_TYPE_INT, { .i64 = 5 }, MIN_SIZE, MAX_SIZE, FLAGS },
|
|
{ "ax", "set alpha matrix horizontal size", OFFSET(amsize_x), AV_OPT_TYPE_INT, { .i64 = 5 }, MIN_SIZE, MAX_SIZE, FLAGS },
|
|
{ "alpha_msize_y", "set alpha matrix vertical size", OFFSET(amsize_y), AV_OPT_TYPE_INT, { .i64 = 5 }, MIN_SIZE, MAX_SIZE, FLAGS },
|
|
{ "ay", "set alpha matrix vertical size", OFFSET(amsize_y), AV_OPT_TYPE_INT, { .i64 = 5 }, MIN_SIZE, MAX_SIZE, FLAGS },
|
|
{ "alpha_amount", "set alpha effect strength", OFFSET(aamount), AV_OPT_TYPE_FLOAT, { .dbl = 0 }, -2, 5, FLAGS },
|
|
{ "aa", "set alpha effect strength", OFFSET(aamount), AV_OPT_TYPE_FLOAT, { .dbl = 0 }, -2, 5, FLAGS },
|
|
{ NULL }
|
|
};
|
|
|
|
AVFILTER_DEFINE_CLASS(unsharp);
|
|
|
|
static const AVFilterPad avfilter_vf_unsharp_inputs[] = {
|
|
{
|
|
.name = "default",
|
|
.type = AVMEDIA_TYPE_VIDEO,
|
|
.filter_frame = filter_frame,
|
|
.config_props = config_input,
|
|
},
|
|
};
|
|
|
|
const AVFilter ff_vf_unsharp = {
|
|
.name = "unsharp",
|
|
.description = NULL_IF_CONFIG_SMALL("Sharpen or blur the input video."),
|
|
.priv_size = sizeof(UnsharpContext),
|
|
.priv_class = &unsharp_class,
|
|
.init = init,
|
|
.uninit = uninit,
|
|
FILTER_INPUTS(avfilter_vf_unsharp_inputs),
|
|
FILTER_OUTPUTS(ff_video_default_filterpad),
|
|
FILTER_PIXFMTS_ARRAY(pix_fmts),
|
|
.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
|
|
};
|