Commit 566858a7 authored by Loren Merritt's avatar Loren Merritt Committed by Loren Merritt

vf_hqdn3d: support 16bit colordepth

parent 44b0b85f
...@@ -35,21 +35,24 @@ ...@@ -35,21 +35,24 @@
#include "video.h" #include "video.h"
typedef struct { typedef struct {
int16_t coefs[4][512*16]; int16_t *coefs[4];
uint16_t *line; uint16_t *line;
uint16_t *frame_prev[3]; uint16_t *frame_prev[3];
double strength[4];
int hsub, vsub; int hsub, vsub;
int depth; int depth;
} HQDN3DContext; } HQDN3DContext;
#define LUT_BITS (depth==16 ? 8 : 4)
#define RIGHTSHIFT(a,b) (((a)+(((1<<(b))-1)>>1))>>(b)) #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 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)\ #define STORE(x,val) (depth==8 ? dst[x] = RIGHTSHIFT(val, 16-depth)\
: AV_WN16A(dst+(x)*2, 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]; return cur + coef[d];
} }
...@@ -62,11 +65,11 @@ static void denoise_temporal(uint8_t *src, uint8_t *dst, ...@@ -62,11 +65,11 @@ static void denoise_temporal(uint8_t *src, uint8_t *dst,
long x, y; long x, y;
uint32_t tmp; uint32_t tmp;
temporal += 0x1000; temporal += 256 << LUT_BITS;
for (y = 0; y < h; y++) { for (y = 0; y < h; y++) {
for (x = 0; x < w; x++) { 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); STORE(x, tmp);
} }
src += sstride; src += sstride;
...@@ -85,15 +88,15 @@ static void denoise_spatial(uint8_t *src, uint8_t *dst, ...@@ -85,15 +88,15 @@ static void denoise_spatial(uint8_t *src, uint8_t *dst,
uint32_t pixel_ant; uint32_t pixel_ant;
uint32_t tmp; uint32_t tmp;
spatial += 0x1000; spatial += 256 << LUT_BITS;
temporal += 0x1000; temporal += 256 << LUT_BITS;
/* First line has no top neighbor. Only left one for each tmp and /* First line has no top neighbor. Only left one for each tmp and
* last frame */ * last frame */
pixel_ant = LOAD(0); pixel_ant = LOAD(0);
for (x = 0; x < w; x++) { for (x = 0; x < w; x++) {
line_ant[x] = tmp = pixel_ant = lowpass(pixel_ant, LOAD(x), spatial); line_ant[x] = tmp = pixel_ant = lowpass(pixel_ant, LOAD(x), spatial, depth);
frame_ant[x] = tmp = lowpass(frame_ant[x], tmp, temporal); frame_ant[x] = tmp = lowpass(frame_ant[x], tmp, temporal, depth);
STORE(x, tmp); STORE(x, tmp);
} }
...@@ -103,13 +106,13 @@ static void denoise_spatial(uint8_t *src, uint8_t *dst, ...@@ -103,13 +106,13 @@ static void denoise_spatial(uint8_t *src, uint8_t *dst,
frame_ant += w; frame_ant += w;
pixel_ant = LOAD(0); pixel_ant = LOAD(0);
for (x = 0; x < w-1; x++) { for (x = 0; x < w-1; x++) {
line_ant[x] = tmp = lowpass(line_ant[x], pixel_ant, spatial); line_ant[x] = tmp = lowpass(line_ant[x], pixel_ant, spatial, depth);
pixel_ant = lowpass(pixel_ant, LOAD(x+1), spatial); pixel_ant = lowpass(pixel_ant, LOAD(x+1), spatial, depth);
frame_ant[x] = tmp = lowpass(frame_ant[x], tmp, temporal); frame_ant[x] = tmp = lowpass(frame_ant[x], tmp, temporal, depth);
STORE(x, tmp); STORE(x, tmp);
} }
line_ant[x] = tmp = lowpass(line_ant[x], pixel_ant, spatial); line_ant[x] = tmp = lowpass(line_ant[x], pixel_ant, spatial, depth);
frame_ant[x] = tmp = lowpass(frame_ant[x], tmp, temporal); frame_ant[x] = tmp = lowpass(frame_ant[x], tmp, temporal, depth);
STORE(x, tmp); STORE(x, tmp);
} }
} }
...@@ -120,6 +123,8 @@ static void denoise_depth(uint8_t *src, uint8_t *dst, ...@@ -120,6 +123,8 @@ static void denoise_depth(uint8_t *src, uint8_t *dst,
int w, int h, int sstride, int dstride, int w, int h, int sstride, int dstride,
int16_t *spatial, int16_t *temporal, int depth) 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; long x, y;
uint16_t *frame_ant = *frame_ant_ptr; uint16_t *frame_ant = *frame_ant_ptr;
if (!frame_ant) { if (!frame_ant) {
...@@ -145,24 +150,28 @@ static void denoise_depth(uint8_t *src, uint8_t *dst, ...@@ -145,24 +150,28 @@ static void denoise_depth(uint8_t *src, uint8_t *dst,
case 8: denoise_depth(__VA_ARGS__, 8); break;\ case 8: denoise_depth(__VA_ARGS__, 8); break;\
case 9: denoise_depth(__VA_ARGS__, 9); break;\ case 9: denoise_depth(__VA_ARGS__, 9); break;\
case 10: denoise_depth(__VA_ARGS__, 10); 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; int i;
double gamma, simil, C; 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); gamma = log(0.25) / log(1.0 - FFMIN(dist25,252.0)/255.0 - 0.00001);
for (i = -255*16; i <= 255*16; i++) { for (i = -255<<LUT_BITS; i <= 255<<LUT_BITS; i++) {
// lowpass() truncates (not rounds) the diff, so +15/32 for the midpoint of the bin. double f = ((i<<(9-LUT_BITS)) + (1<<(8-LUT_BITS)) - 1) / 512.0; // midpoint of the bin
double f = (i + 15.0/32.0) / 16.0;
simil = 1.0 - FFABS(f) / 255.0; simil = 1.0 - FFABS(f) / 255.0;
C = pow(simil, gamma) * 256.0 * f; C = pow(simil, gamma) * 256.0 * f;
ct[16*256+i] = lrint(C); ct[(256<<LUT_BITS)+i] = lrint(C);
} }
ct[0] = !!dist25; ct[0] = !!dist25;
return ct;
} }
#define PARAM1_DEFAULT 4.0 #define PARAM1_DEFAULT 4.0
...@@ -210,6 +219,11 @@ static int init(AVFilterContext *ctx, const char *args) ...@@ -210,6 +219,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", av_log(ctx, AV_LOG_VERBOSE, "ls:%lf cs:%lf lt:%lf ct:%lf\n",
lum_spac, chrom_spac, lum_tmp, chrom_tmp); lum_spac, chrom_spac, lum_tmp, chrom_tmp);
if (lum_spac < 0 || chrom_spac < 0 || isnan(chrom_tmp)) { if (lum_spac < 0 || chrom_spac < 0 || isnan(chrom_tmp)) {
...@@ -219,11 +233,6 @@ static int init(AVFilterContext *ctx, const char *args) ...@@ -219,11 +233,6 @@ static int init(AVFilterContext *ctx, const char *args)
return AVERROR(EINVAL); 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; return 0;
} }
...@@ -231,6 +240,10 @@ static void uninit(AVFilterContext *ctx) ...@@ -231,6 +240,10 @@ static void uninit(AVFilterContext *ctx)
{ {
HQDN3DContext *hqdn3d = ctx->priv; 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->line);
av_freep(&hqdn3d->frame_prev[0]); av_freep(&hqdn3d->frame_prev[0]);
av_freep(&hqdn3d->frame_prev[1]); av_freep(&hqdn3d->frame_prev[1]);
...@@ -256,6 +269,9 @@ static int query_formats(AVFilterContext *ctx) ...@@ -256,6 +269,9 @@ static int query_formats(AVFilterContext *ctx)
AV_NE( PIX_FMT_YUV420P10BE, PIX_FMT_YUV420P10LE ), AV_NE( PIX_FMT_YUV420P10BE, PIX_FMT_YUV420P10LE ),
AV_NE( PIX_FMT_YUV422P10BE, PIX_FMT_YUV422P10LE ), AV_NE( PIX_FMT_YUV422P10BE, PIX_FMT_YUV422P10LE ),
AV_NE( PIX_FMT_YUV444P10BE, PIX_FMT_YUV444P10LE ), 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 PIX_FMT_NONE
}; };
...@@ -276,6 +292,12 @@ static int config_input(AVFilterLink *inlink) ...@@ -276,6 +292,12 @@ static int config_input(AVFilterLink *inlink)
if (!hqdn3d->line) if (!hqdn3d->line)
return AVERROR(ENOMEM); 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);
}
return 0; return 0;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment