diff options
author | Michael Niedermayer <michaelni@gmx.at> | 2012-08-26 22:36:13 +0200 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2012-08-26 22:40:02 +0200 |
commit | 17106a7c90902c7cddc5ad516234bd0e37d27732 (patch) | |
tree | 674b2b4bf6bba67f441c925511fc1cabe5bda74a /libavfilter | |
parent | 3a621c9d9929bcad3ae042c4c33308b4544c7cb1 (diff) | |
parent | d7f9786cbcd3fede7c751f1c1f481e55ee2380bd (diff) | |
download | ffmpeg-17106a7c90902c7cddc5ad516234bd0e37d27732.tar.gz |
Merge remote-tracking branch 'qatar/master'
* qatar/master:
audio_frame_queue: Clean up ff_af_queue_log_state debug function
dwt: Remove unused code.
cavs: convert cavsdata.h to a .c file
cavs: Move inline functions only used in one file out of the header
cavs: Move data tables used in only one place to that file
fate: Add a single symbol Ut Video decoder test
vf_hqdn3d: x86 asm
vf_hqdn3d: support 16bit colordepth
avconv: prefer user-forced input framerate when choosing output framerate
Conflicts:
ffmpeg.c
libavcodec/audio_frame_queue.c
libavcodec/dwt.c
Merged-by: Michael Niedermayer <michaelni@gmx.at>
Diffstat (limited to 'libavfilter')
-rw-r--r-- | libavfilter/vf_hqdn3d.c | 97 | ||||
-rw-r--r-- | libavfilter/x86/Makefile | 1 | ||||
-rw-r--r-- | libavfilter/x86/hqdn3d.asm | 106 |
3 files changed, 176 insertions, 28 deletions
diff --git a/libavfilter/vf_hqdn3d.c b/libavfilter/vf_hqdn3d.c index c7cef44860..515af3c624 100644 --- a/libavfilter/vf_hqdn3d.c +++ b/libavfilter/vf_hqdn3d.c @@ -35,21 +35,30 @@ #include "video.h" typedef struct { - int16_t coefs[4][512*16]; + int16_t *coefs[4]; uint16_t *line; uint16_t *frame_prev[3]; + double strength[4]; int hsub, vsub; int depth; + void (*denoise_row[17])(uint8_t *src, uint8_t *dst, uint16_t *line_ant, uint16_t *frame_ant, ptrdiff_t w, int16_t *spatial, int16_t *temporal); } HQDN3DContext; +void ff_hqdn3d_row_8_x86(uint8_t *src, uint8_t *dst, uint16_t *line_ant, uint16_t *frame_ant, ptrdiff_t w, int16_t *spatial, int16_t *temporal); +void ff_hqdn3d_row_9_x86(uint8_t *src, uint8_t *dst, uint16_t *line_ant, uint16_t *frame_ant, ptrdiff_t w, int16_t *spatial, int16_t *temporal); +void ff_hqdn3d_row_10_x86(uint8_t *src, uint8_t *dst, uint16_t *line_ant, uint16_t *frame_ant, ptrdiff_t w, int16_t *spatial, int16_t *temporal); +void ff_hqdn3d_row_16_x86(uint8_t *src, uint8_t *dst, uint16_t *line_ant, uint16_t *frame_ant, ptrdiff_t w, int16_t *spatial, int16_t *temporal); + +#define LUT_BITS (depth==16 ? 8 : 4) #define RIGHTSHIFT(a,b) (((a)+(((1<<(b))-1)>>1))>>(b)) #define LOAD(x) ((depth==8 ? src[x] : AV_RN16A(src+(x)*2)) << (16-depth)) #define STORE(x,val) (depth==8 ? dst[x] = RIGHTSHIFT(val, 16-depth)\ : AV_WN16A(dst+(x)*2, RIGHTSHIFT(val, 16-depth))) -static inline uint32_t lowpass(int prev, int cur, int16_t *coef) +av_always_inline +static inline uint32_t lowpass(int prev, int cur, int16_t *coef, int depth) { - int d = (prev-cur)>>4; + int d = (prev - cur) >> (8 - LUT_BITS); return cur + coef[d]; } @@ -62,11 +71,11 @@ static void denoise_temporal(uint8_t *src, uint8_t *dst, long x, y; uint32_t tmp; - temporal += 0x1000; + temporal += 256 << LUT_BITS; for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { - frame_ant[x] = tmp = lowpass(frame_ant[x], LOAD(x), temporal); + frame_ant[x] = tmp = lowpass(frame_ant[x], LOAD(x), temporal, depth); STORE(x, tmp); } src += sstride; @@ -76,7 +85,8 @@ static void denoise_temporal(uint8_t *src, uint8_t *dst, } av_always_inline -static void denoise_spatial(uint8_t *src, uint8_t *dst, +static void denoise_spatial(HQDN3DContext *hqdn3d, + uint8_t *src, uint8_t *dst, uint16_t *line_ant, uint16_t *frame_ant, int w, int h, int sstride, int dstride, int16_t *spatial, int16_t *temporal, int depth) @@ -85,15 +95,15 @@ static void denoise_spatial(uint8_t *src, uint8_t *dst, uint32_t pixel_ant; uint32_t tmp; - spatial += 0x1000; - temporal += 0x1000; + spatial += 256 << LUT_BITS; + temporal += 256 << LUT_BITS; /* First line has no top neighbor. Only left one for each tmp and * last frame */ pixel_ant = LOAD(0); for (x = 0; x < w; x++) { - line_ant[x] = tmp = pixel_ant = lowpass(pixel_ant, LOAD(x), spatial); - frame_ant[x] = tmp = lowpass(frame_ant[x], tmp, temporal); + line_ant[x] = tmp = pixel_ant = lowpass(pixel_ant, LOAD(x), spatial, depth); + frame_ant[x] = tmp = lowpass(frame_ant[x], tmp, temporal, depth); STORE(x, tmp); } @@ -101,25 +111,32 @@ static void denoise_spatial(uint8_t *src, uint8_t *dst, src += sstride; dst += dstride; frame_ant += w; + if (hqdn3d->denoise_row[depth]) { + hqdn3d->denoise_row[depth](src, dst, line_ant, frame_ant, w, spatial, temporal); + continue; + } pixel_ant = LOAD(0); for (x = 0; x < w-1; x++) { - line_ant[x] = tmp = lowpass(line_ant[x], pixel_ant, spatial); - pixel_ant = lowpass(pixel_ant, LOAD(x+1), spatial); - frame_ant[x] = tmp = lowpass(frame_ant[x], tmp, temporal); + line_ant[x] = tmp = lowpass(line_ant[x], pixel_ant, spatial, depth); + pixel_ant = lowpass(pixel_ant, LOAD(x+1), spatial, depth); + frame_ant[x] = tmp = lowpass(frame_ant[x], tmp, temporal, depth); STORE(x, tmp); } - line_ant[x] = tmp = lowpass(line_ant[x], pixel_ant, spatial); - frame_ant[x] = tmp = lowpass(frame_ant[x], tmp, temporal); + line_ant[x] = tmp = lowpass(line_ant[x], pixel_ant, spatial, depth); + frame_ant[x] = tmp = lowpass(frame_ant[x], tmp, temporal, depth); STORE(x, tmp); } } av_always_inline -static void denoise_depth(uint8_t *src, uint8_t *dst, +static void denoise_depth(HQDN3DContext *hqdn3d, + uint8_t *src, uint8_t *dst, uint16_t *line_ant, uint16_t **frame_ant_ptr, int w, int h, int sstride, int dstride, int16_t *spatial, int16_t *temporal, int depth) { + // FIXME: For 16bit depth, frame_ant could be a pointer to the previous + // filtered frame rather than a separate buffer. long x, y; uint16_t *frame_ant = *frame_ant_ptr; if (!frame_ant) { @@ -133,7 +150,7 @@ static void denoise_depth(uint8_t *src, uint8_t *dst, } if (spatial[0]) - denoise_spatial(src, dst, line_ant, frame_ant, + denoise_spatial(hqdn3d, src, dst, line_ant, frame_ant, w, h, sstride, dstride, spatial, temporal, depth); else denoise_temporal(src, dst, frame_ant, @@ -145,24 +162,28 @@ static void denoise_depth(uint8_t *src, uint8_t *dst, case 8: denoise_depth(__VA_ARGS__, 8); break;\ case 9: denoise_depth(__VA_ARGS__, 9); break;\ case 10: denoise_depth(__VA_ARGS__, 10); break;\ + case 16: denoise_depth(__VA_ARGS__, 16); break;\ } -static void precalc_coefs(int16_t *ct, double dist25) +static int16_t *precalc_coefs(double dist25, int depth) { int i; double gamma, simil, C; + int16_t *ct = av_malloc((512<<LUT_BITS)*sizeof(int16_t)); + if (!ct) + return NULL; gamma = log(0.25) / log(1.0 - FFMIN(dist25,252.0)/255.0 - 0.00001); - for (i = -255*16; i <= 255*16; i++) { - // lowpass() truncates (not rounds) the diff, so +15/32 for the midpoint of the bin. - double f = (i + 15.0/32.0) / 16.0; + for (i = -255<<LUT_BITS; i <= 255<<LUT_BITS; i++) { + double f = ((i<<(9-LUT_BITS)) + (1<<(8-LUT_BITS)) - 1) / 512.0; // midpoint of the bin simil = 1.0 - FFABS(f) / 255.0; C = pow(simil, gamma) * 256.0 * f; - ct[16*256+i] = lrint(C); + ct[(256<<LUT_BITS)+i] = lrint(C); } ct[0] = !!dist25; + return ct; } #define PARAM1_DEFAULT 4.0 @@ -210,6 +231,11 @@ static int init(AVFilterContext *ctx, const char *args) } } + hqdn3d->strength[0] = lum_spac; + hqdn3d->strength[1] = lum_tmp; + hqdn3d->strength[2] = chrom_spac; + hqdn3d->strength[3] = chrom_tmp; + av_log(ctx, AV_LOG_VERBOSE, "ls:%lf cs:%lf lt:%lf ct:%lf\n", lum_spac, chrom_spac, lum_tmp, chrom_tmp); if (lum_spac < 0 || chrom_spac < 0 || isnan(chrom_tmp)) { @@ -219,11 +245,6 @@ static int init(AVFilterContext *ctx, const char *args) return AVERROR(EINVAL); } - precalc_coefs(hqdn3d->coefs[0], lum_spac); - precalc_coefs(hqdn3d->coefs[1], lum_tmp); - precalc_coefs(hqdn3d->coefs[2], chrom_spac); - precalc_coefs(hqdn3d->coefs[3], chrom_tmp); - return 0; } @@ -231,6 +252,10 @@ static void uninit(AVFilterContext *ctx) { HQDN3DContext *hqdn3d = ctx->priv; + av_freep(&hqdn3d->coefs[0]); + av_freep(&hqdn3d->coefs[1]); + av_freep(&hqdn3d->coefs[2]); + av_freep(&hqdn3d->coefs[3]); av_freep(&hqdn3d->line); av_freep(&hqdn3d->frame_prev[0]); av_freep(&hqdn3d->frame_prev[1]); @@ -256,6 +281,9 @@ static int query_formats(AVFilterContext *ctx) AV_NE( PIX_FMT_YUV420P10BE, PIX_FMT_YUV420P10LE ), AV_NE( PIX_FMT_YUV422P10BE, PIX_FMT_YUV422P10LE ), AV_NE( PIX_FMT_YUV444P10BE, PIX_FMT_YUV444P10LE ), + AV_NE( PIX_FMT_YUV420P16BE, PIX_FMT_YUV420P16LE ), + AV_NE( PIX_FMT_YUV422P16BE, PIX_FMT_YUV422P16LE ), + AV_NE( PIX_FMT_YUV444P16BE, PIX_FMT_YUV444P16LE ), PIX_FMT_NONE }; @@ -276,6 +304,19 @@ static int config_input(AVFilterLink *inlink) if (!hqdn3d->line) return AVERROR(ENOMEM); + for (int i=0; i<4; i++) { + hqdn3d->coefs[i] = precalc_coefs(hqdn3d->strength[i], hqdn3d->depth); + if (!hqdn3d->coefs[i]) + return AVERROR(ENOMEM); + } + +#if HAVE_YASM + hqdn3d->denoise_row[ 8] = ff_hqdn3d_row_8_x86; + hqdn3d->denoise_row[ 9] = ff_hqdn3d_row_9_x86; + hqdn3d->denoise_row[10] = ff_hqdn3d_row_10_x86; + hqdn3d->denoise_row[16] = ff_hqdn3d_row_16_x86; +#endif + return 0; } @@ -293,7 +334,7 @@ static int end_frame(AVFilterLink *inlink) int ret, c; for (c = 0; c < 3; c++) { - denoise(inpic->data[c], outpic->data[c], + denoise(hqdn3d, inpic->data[c], outpic->data[c], hqdn3d->line, &hqdn3d->frame_prev[c], inpic->video->w >> (!!c * hqdn3d->hsub), inpic->video->h >> (!!c * hqdn3d->vsub), diff --git a/libavfilter/x86/Makefile b/libavfilter/x86/Makefile index e98693d654..46fc84f3ec 100644 --- a/libavfilter/x86/Makefile +++ b/libavfilter/x86/Makefile @@ -1,2 +1,3 @@ MMX-OBJS-$(CONFIG_YADIF_FILTER) += x86/yadif.o MMX-OBJS-$(CONFIG_GRADFUN_FILTER) += x86/gradfun.o +YASM-OBJS-$(CONFIG_HQDN3D_FILTER) += x86/hqdn3d.o diff --git a/libavfilter/x86/hqdn3d.asm b/libavfilter/x86/hqdn3d.asm new file mode 100644 index 0000000000..88b9b0d034 --- /dev/null +++ b/libavfilter/x86/hqdn3d.asm @@ -0,0 +1,106 @@ +;****************************************************************************** +;* Copyright (c) 2012 Loren Merritt +;* +;* 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 +;****************************************************************************** + +%include "x86inc.asm" + +SECTION .text + +%macro LOWPASS 3 ; prevsample, cursample, lut + sub %1q, %2q +%if lut_bits != 8 + sar %1q, 8-lut_bits +%endif + movsx %1d, word [%3q+%1q*2] + add %1d, %2d +%endmacro + +%macro LOAD 3 ; dstreg, x, bitdepth +%if %3 == 8 + movzx %1, byte [srcq+%2] +%else + movzx %1, word [srcq+(%2)*2] +%endif +%if %3 != 16 + shl %1, 16-%3 +%endif +%endmacro + +%macro HQDN3D_ROW 1 ; bitdepth +%if ARCH_X86_64 +cglobal hqdn3d_row_%1_x86, 7,10,0, src, dst, lineant, frameant, width, spatial, temporal, pixelant, t0, t1 +%else +cglobal hqdn3d_row_%1_x86, 7,7,0, src, dst, lineant, frameant, width, spatial, temporal +%endif + %assign bytedepth (%1+7)>>3 + %assign lut_bits 4+4*(%1/16) + dec widthq + lea srcq, [srcq+widthq*bytedepth] + lea dstq, [dstq+widthq*bytedepth] + lea frameantq, [frameantq+widthq*2] + lea lineantq, [lineantq+widthq*2] + neg widthq + %define xq widthq +%if ARCH_X86_32 + mov dstmp, dstq + mov srcmp, srcq + mov frameantmp, frameantq + mov lineantmp, lineantq + %define dstq r0 + %define frameantq r0 + %define lineantq r0 + %define pixelantq r1 + %define pixelantd r1d + DECLARE_REG_TMP 2,3 +%endif + LOAD pixelantd, xq, %1 +ALIGN 16 +.loop: + movifnidn srcq, srcmp + LOAD t0d, xq+1, %1 ; skip on the last iteration to avoid overread +.loop2: + movifnidn lineantq, lineantmp + movzx t1d, word [lineantq+xq*2] + LOWPASS t1, pixelant, spatial + mov [lineantq+xq*2], t1w + LOWPASS pixelant, t0, spatial + movifnidn frameantq, frameantmp + movzx t0d, word [frameantq+xq*2] + LOWPASS t0, t1, temporal + mov [frameantq+xq*2], t0w + movifnidn dstq, dstmp +%if %1 != 16 + add t0d, (1<<(15-%1))-1 + shr t0d, 16-%1 ; could eliminate this by storing from t0h, but only with some contraints on register allocation +%endif +%if %1 == 8 + mov [dstq+xq], t0b +%else + mov [dstq+xq*2], t0w +%endif + inc xq + jl .loop + je .loop2 + REP_RET +%endmacro ; HQDN3D_ROW + +HQDN3D_ROW 8 +HQDN3D_ROW 9 +HQDN3D_ROW 10 +HQDN3D_ROW 16 |