summaryrefslogtreecommitdiffstats
path: root/libavfilter
diff options
context:
space:
mode:
authorMichael Niedermayer <michaelni@gmx.at>2012-08-26 22:36:13 +0200
committerMichael Niedermayer <michaelni@gmx.at>2012-08-26 22:40:02 +0200
commit17106a7c90902c7cddc5ad516234bd0e37d27732 (patch)
tree674b2b4bf6bba67f441c925511fc1cabe5bda74a /libavfilter
parent3a621c9d9929bcad3ae042c4c33308b4544c7cb1 (diff)
parentd7f9786cbcd3fede7c751f1c1f481e55ee2380bd (diff)
downloadffmpeg-streaming-17106a7c90902c7cddc5ad516234bd0e37d27732.zip
ffmpeg-streaming-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.c97
-rw-r--r--libavfilter/x86/Makefile1
-rw-r--r--libavfilter/x86/hqdn3d.asm106
3 files changed, 176 insertions, 28 deletions
diff --git a/libavfilter/vf_hqdn3d.c b/libavfilter/vf_hqdn3d.c
index c7cef44..515af3c 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 e98693d..46fc84f 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 0000000..88b9b0d
--- /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
OpenPOWER on IntegriCloud