vf_hqdn3d: support 9 and 10bit colordepth

Signed-off-by: Ronald S. Bultje <rsbultje@gmail.com>
This commit is contained in:
Loren Merritt 2012-07-27 01:42:05 +00:00 committed by Ronald S. Bultje
parent 0f583e6cc5
commit 1ad715dbf3
1 changed files with 53 additions and 19 deletions

View File

@ -27,6 +27,7 @@
*/
#include "libavutil/pixdesc.h"
#include "libavutil/intreadwrite.h"
#include "avfilter.h"
#include "formats.h"
#include "internal.h"
@ -37,18 +38,25 @@ typedef struct {
uint16_t *line;
uint16_t *frame_prev[3];
int hsub, vsub;
int depth;
} HQDN3DContext;
#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)
{
int d = (prev-cur)>>4;
return cur + coef[d];
}
av_always_inline
static void denoise_temporal(uint8_t *src, uint8_t *dst,
uint16_t *frame_ant,
int w, int h, int sstride, int dstride,
int16_t *temporal)
int16_t *temporal, int depth)
{
long x, y;
uint32_t tmp;
@ -57,8 +65,8 @@ static void denoise_temporal(uint8_t *src, uint8_t *dst,
for (y = 0; y < h; y++) {
for (x = 0; x < w; x++) {
frame_ant[x] = tmp = lowpass(frame_ant[x], src[x]<<8, temporal);
dst[x] = (tmp+0x7F)>>8;
frame_ant[x] = tmp = lowpass(frame_ant[x], LOAD(x), temporal);
STORE(x, tmp);
}
src += sstride;
dst += dstride;
@ -66,10 +74,11 @@ static void denoise_temporal(uint8_t *src, uint8_t *dst,
}
}
av_always_inline
static void denoise_spatial(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)
int16_t *spatial, int16_t *temporal, int depth)
{
long x, y;
uint32_t pixel_ant;
@ -80,34 +89,35 @@ static void denoise_spatial(uint8_t *src, uint8_t *dst,
/* First line has no top neighbor. Only left one for each tmp and
* last frame */
pixel_ant = src[0]<<8;
pixel_ant = LOAD(0);
for (x = 0; x < w; x++) {
line_ant[x] = tmp = pixel_ant = lowpass(pixel_ant, src[x]<<8, spatial);
line_ant[x] = tmp = pixel_ant = lowpass(pixel_ant, LOAD(x), spatial);
frame_ant[x] = tmp = lowpass(frame_ant[x], tmp, temporal);
dst[x] = (tmp+0x7F)>>8;
STORE(x, tmp);
}
for (y = 1; y < h; y++) {
src += sstride;
dst += dstride;
frame_ant += w;
pixel_ant = src[0]<<8;
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, src[x+1]<<8, spatial);
pixel_ant = lowpass(pixel_ant, LOAD(x+1), spatial);
frame_ant[x] = tmp = lowpass(frame_ant[x], tmp, temporal);
dst[x] = (tmp+0x7F)>>8;
STORE(x, tmp);
}
line_ant[x] = tmp = lowpass(line_ant[x], pixel_ant, spatial);
frame_ant[x] = tmp = lowpass(frame_ant[x], tmp, temporal);
dst[x] = (tmp+0x7F)>>8;
STORE(x, tmp);
}
}
static void denoise(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)
av_always_inline
static void denoise_depth(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)
{
long x, y;
uint16_t *frame_ant = *frame_ant_ptr;
@ -116,19 +126,26 @@ static void denoise(uint8_t *src, uint8_t *dst,
*frame_ant_ptr = frame_ant = av_malloc(w*h*sizeof(uint16_t));
for (y = 0; y < h; y++, src += sstride, frame_ant += w)
for (x = 0; x < w; x++)
frame_ant[x] = src[x]<<8;
frame_ant[x] = LOAD(x);
src = frame_src;
frame_ant = *frame_ant_ptr;
}
if (spatial[0])
denoise_spatial(src, dst, line_ant, frame_ant,
w, h, sstride, dstride, spatial, temporal);
w, h, sstride, dstride, spatial, temporal, depth);
else
denoise_temporal(src, dst, frame_ant,
w, h, sstride, dstride, temporal);
w, h, sstride, dstride, temporal, depth);
}
#define denoise(...) \
switch (hqdn3d->depth) {\
case 8: denoise_depth(__VA_ARGS__, 8); break;\
case 9: denoise_depth(__VA_ARGS__, 9); break;\
case 10: denoise_depth(__VA_ARGS__, 10); break;\
}
static void precalc_coefs(int16_t *ct, double dist25)
{
int i;
@ -222,7 +239,23 @@ static void uninit(AVFilterContext *ctx)
static int query_formats(AVFilterContext *ctx)
{
static const enum PixelFormat pix_fmts[] = {
PIX_FMT_YUV420P, PIX_FMT_YUV422P, PIX_FMT_YUV411P, PIX_FMT_NONE
PIX_FMT_YUV420P,
PIX_FMT_YUV422P,
PIX_FMT_YUV444P,
PIX_FMT_YUV410P,
PIX_FMT_YUV411P,
PIX_FMT_YUV440P,
PIX_FMT_YUVJ420P,
PIX_FMT_YUVJ422P,
PIX_FMT_YUVJ444P,
PIX_FMT_YUVJ440P,
AV_NE( PIX_FMT_YUV420P9BE, PIX_FMT_YUV420P9LE ),
AV_NE( PIX_FMT_YUV422P9BE, PIX_FMT_YUV422P9LE ),
AV_NE( PIX_FMT_YUV444P9BE, PIX_FMT_YUV444P9LE ),
AV_NE( PIX_FMT_YUV420P10BE, PIX_FMT_YUV420P10LE ),
AV_NE( PIX_FMT_YUV422P10BE, PIX_FMT_YUV422P10LE ),
AV_NE( PIX_FMT_YUV444P10BE, PIX_FMT_YUV444P10LE ),
PIX_FMT_NONE
};
ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
@ -236,6 +269,7 @@ static int config_input(AVFilterLink *inlink)
hqdn3d->hsub = av_pix_fmt_descriptors[inlink->format].log2_chroma_w;
hqdn3d->vsub = av_pix_fmt_descriptors[inlink->format].log2_chroma_h;
hqdn3d->depth = av_pix_fmt_descriptors[inlink->format].comp[0].depth_minus1+1;
hqdn3d->line = av_malloc(inlink->w * sizeof(*hqdn3d->line));
if (!hqdn3d->line)