]> git.sesse.net Git - ffmpeg/blobdiff - libavfilter/vf_hqdn3d.c
dcadec: use float planar sample format
[ffmpeg] / libavfilter / vf_hqdn3d.c
index 3a81f37ae152d929424b3b939196faaddb784f85..71b670d3f1296a7e4439d9cf3400a5515ed646c8 100644 (file)
 #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 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
     };
 
@@ -267,6 +295,7 @@ static int query_formats(AVFilterContext *ctx)
 static int config_input(AVFilterLink *inlink)
 {
     HQDN3DContext *hqdn3d = inlink->dst->priv;
+    int i;
 
     hqdn3d->hsub = av_pix_fmt_descriptors[inlink->format].log2_chroma_w;
     hqdn3d->vsub = av_pix_fmt_descriptors[inlink->format].log2_chroma_h;
@@ -276,6 +305,19 @@ static int config_input(AVFilterLink *inlink)
     if (!hqdn3d->line)
         return AVERROR(ENOMEM);
 
+    for (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 +335,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),