dct-domain noise reduction (ported from lavc)
authorLoren Merritt <pengvado@videolan.org>
Tue, 10 Jan 2006 07:31:29 +0000 (07:31 +0000)
committerLoren Merritt <pengvado@videolan.org>
Tue, 10 Jan 2006 07:31:29 +0000 (07:31 +0000)
git-svn-id: svn://svn.videolan.org/x264/trunk@398 df754926-b1dd-0310-bc7b-ec298dee348c

common/common.h
common/dct.h
encoder/analyse.c
encoder/encoder.c
encoder/macroblock.c
encoder/macroblock.h
x264.c
x264.h

index 7681c01..f5ab1d6 100644 (file)
@@ -261,6 +261,10 @@ struct x264_t
     int             unquant4_mf[4][52][16];
     int             unquant8_mf[2][52][64];
 
+    uint32_t        nr_residual_sum[4][64];
+    uint32_t        nr_offset[4][64];
+    uint32_t        nr_count[4];
+
     /* Slice header */
     x264_slice_header_t sh;
 
@@ -343,6 +347,8 @@ struct x264_t
         int     i_subpel_refine;
         int     b_chroma_me;
         int     b_trellis;
+        int     b_noise_reduction;
+
         /* Allowed qpel MV range to stay within the picture + emulated edge pixels */
         int     mv_min[2];
         int     mv_max[2];
index aae3262..c492951 100644 (file)
@@ -48,6 +48,12 @@ static const int x264_dct8_weight_tab[64] = {
 #define W(i) (i==0 ? FIX8(3.125) :\
               i==1 ? FIX8(1.25) :\
               i==2 ? FIX8(0.5) :0)
+static const int x264_dct4_weight2_tab[16] = {
+    W(0), W(1), W(0), W(1),
+    W(1), W(2), W(1), W(2),
+    W(0), W(1), W(0), W(1),
+    W(1), W(2), W(1), W(2)
+};
 static const int x264_dct4_weight2_zigzag[16] = {
     W(0), W(1), W(1), W(0), W(2), W(0), W(1), W(1),
     W(1), W(1), W(2), W(0), W(2), W(1), W(1), W(2)
@@ -60,6 +66,17 @@ static const int x264_dct4_weight2_zigzag[16] = {
               i==3 ? FIX8(0.88637) :\
               i==4 ? FIX8(1.60040) :\
               i==5 ? FIX8(1.41850) :0)
+static const int x264_dct8_weight2_tab[64] = {
+    W(0), W(3), W(4), W(3),  W(0), W(3), W(4), W(3),
+    W(3), W(1), W(5), W(1),  W(3), W(1), W(5), W(1),
+    W(4), W(5), W(2), W(5),  W(4), W(5), W(2), W(5),
+    W(3), W(1), W(5), W(1),  W(3), W(1), W(5), W(1),
+
+    W(0), W(3), W(4), W(3),  W(0), W(3), W(4), W(3),
+    W(3), W(1), W(5), W(1),  W(3), W(1), W(5), W(1),
+    W(4), W(5), W(2), W(5),  W(4), W(5), W(2), W(5),
+    W(3), W(1), W(5), W(1),  W(3), W(1), W(5), W(1)
+};
 static const int x264_dct8_weight2_zigzag[64] = {
     W(0), W(3), W(3), W(4), W(1), W(4), W(3), W(5),
     W(5), W(3), W(0), W(1), W(2), W(1), W(0), W(3),
index 2381a2e..bb2035d 100644 (file)
@@ -198,6 +198,7 @@ static void x264_mb_analyse_init( x264_t *h, x264_mb_analysis_t *a, int i_qp )
                         && h->mb.i_subpel_refine >= 5;
     h->mb.b_trellis = h->param.analyse.i_trellis > 1;
     h->mb.b_transform_8x8 = 0;
+    h->mb.b_noise_reduction = 0;
 
     /* I: Intra part */
     a->i_sad_i16x16 =
@@ -2271,6 +2272,7 @@ void x264_macroblock_analyse( x264_t *h )
         x264_mb_analyse_transform( h );
 
     h->mb.b_trellis = h->param.analyse.i_trellis;
+    h->mb.b_noise_reduction = h->param.analyse.i_noise_reduction;
 }
 
 /*-------------------- Update MB from the analysis ----------------------*/
index 030d152..32d06c2 100644 (file)
@@ -370,6 +370,7 @@ static int x264_validate_parameters( x264_t *h )
         h->param.analyse.i_chroma_qp_offset = 0;
         h->param.analyse.i_trellis = 0;
         h->param.analyse.b_fast_pskip = 0;
+        h->param.analyse.i_noise_reduction = 0;
     }
 
     if( ( h->param.i_width % 16 || h->param.i_height % 16 ) && !h->mb.b_lossless )
@@ -421,6 +422,7 @@ static int x264_validate_parameters( x264_t *h )
     if( !h->param.b_cabac )
         h->param.analyse.i_trellis = 0;
     h->param.analyse.i_trellis = x264_clip3( h->param.analyse.i_trellis, 0, 2 );
+    h->param.analyse.i_noise_reduction = x264_clip3( h->param.analyse.i_noise_reduction, 0, 1<<16 );
 
     {
         const x264_level_t *l = x264_levels;
@@ -1508,6 +1510,8 @@ do_encode:
 
     x264_frame_put( h->frames.unused, h->fenc );
 
+    x264_noise_reduction_update( h );
+
     TIMER_STOP( i_mtime_encode_frame );
 
     /* ---------------------- Compute/Print statistics --------------------- */
index 6a84607..b6541fa 100644 (file)
@@ -207,6 +207,8 @@ void x264_mb_encode_i4x4( x264_t *h, int idx, int i_qscale )
 
     h->dctf.sub4x4_dct( dct4x4, p_src, i_stride, p_dst, i_stride );
 
+    if( h->mb.b_noise_reduction )
+        x264_denoise_dct( h, (int16_t*)dct4x4 );
     if( h->mb.b_trellis )
         x264_quant_4x4_trellis( h, dct4x4, CQM_4IY, i_qscale, DCT_LUMA_4x4, 1 );
     else
@@ -229,6 +231,8 @@ void x264_mb_encode_i8x8( x264_t *h, int idx, int i_qscale )
 
     h->dctf.sub8x8_dct8( dct8x8, p_src, i_stride, p_dst, i_stride );
 
+    if( h->mb.b_noise_reduction )
+        x264_denoise_dct( h, (int16_t*)dct8x8 );
     if( h->mb.b_trellis )
         x264_quant_8x8_trellis( h, dct8x8, CQM_8IY, i_qscale, 1 );
     else 
@@ -269,6 +273,8 @@ static void x264_mb_encode_i16x16( x264_t *h, int i_qscale )
         dct4x4[0][block_idx_y[i]][block_idx_x[i]] = dct4x4[1+i][0][0];
 
         /* quant/scan/dequant */
+        if( h->mb.b_noise_reduction )
+            x264_denoise_dct( h, (int16_t*)dct4x4[i] );
         if( h->mb.b_trellis )
             x264_quant_4x4_trellis( h, dct4x4[1+i], CQM_4IY, i_qscale, DCT_LUMA_AC, 1 );
         else
@@ -501,6 +507,8 @@ void x264_macroblock_encode( x264_t *h )
 
             for( idx = 0; idx < 4; idx++ )
             {
+                if( h->mb.b_noise_reduction )
+                    x264_denoise_dct( h, (int16_t*)dct8x8[idx] );
                 if( h->mb.b_trellis )
                     x264_quant_8x8_trellis( h, dct8x8[idx], CQM_8PY, i_qp, 0 );
                 else
@@ -552,6 +560,8 @@ void x264_macroblock_encode( x264_t *h )
                 {
                     idx = i8x8 * 4 + i4x4;
 
+                    if( h->mb.b_noise_reduction )
+                        x264_denoise_dct( h, (int16_t*)dct4x4[idx] );
                     if( h->mb.b_trellis )
                         x264_quant_4x4_trellis( h, dct4x4[idx], CQM_4PY, i_qp, DCT_LUMA_4x4, 0 );
                     else
@@ -790,3 +800,63 @@ int x264_macroblock_probe_skip( x264_t *h, int b_bidir )
 
     return 1;
 }
+
+/****************************************************************************
+ * DCT-domain noise reduction / adaptive deadzone
+ * from libavcodec
+ ****************************************************************************/
+
+void x264_noise_reduction_update( x264_t *h )
+{
+    int cat, i;
+    for( cat = 0; cat < 4; cat++ )
+    {
+        int b_8x8 = cat >= 2;
+        int size = b_8x8 ? 64 : 16;
+        const int *weight = b_8x8 ? x264_dct8_weight2_tab : x264_dct4_weight2_tab;
+
+        if( h->nr_count[cat] > (b_8x8 ? (1<<16) : (1<<18)) )
+        {
+            for( i = 0; i < size; i++ )
+                h->nr_residual_sum[cat][i] >>= 1;
+            h->nr_count[cat] >>= 1;
+        }
+
+        for( i = 0; i < size; i++ )
+            h->nr_offset[cat][i] =
+                ((uint64_t)h->param.analyse.i_noise_reduction * h->nr_count[cat]
+                 + h->nr_residual_sum[cat][i]/2)
+              / ((uint64_t)h->nr_residual_sum[cat][i] * weight[i]/256 + 1);
+    }
+}
+
+void x264_denoise_dct( x264_t *h, int16_t *dct )
+{
+    const int cat = !IS_INTRA(h->mb.i_type) + 2*h->mb.b_transform_8x8;
+    int i;
+
+    h->nr_count[cat]++;
+
+    for( i = (cat >= 2 ? 63 : 15); i >= 1; i-- )
+    {
+        int level = dct[i];
+        if( level )
+        {
+            if( level > 0 )
+            {
+                h->nr_residual_sum[cat][i] += level;
+                level -= h->nr_offset[cat][i];
+                if( level < 0 )
+                    level = 0;
+            }
+            else
+            {
+                h->nr_residual_sum[cat][i] -= level;
+                level += h->nr_offset[cat][i];
+                if( level > 0 )
+                    level = 0;
+            }
+            dct[i] = level;
+        }
+    }
+}
index 3c848bc..f856fd3 100644 (file)
@@ -46,6 +46,9 @@ void x264_quant_4x4_trellis( x264_t *h, int16_t dct[4][4], int i_quant_cat,
 void x264_quant_8x8_trellis( x264_t *h, int16_t dct[8][8], int i_quant_cat,
                              int i_qp, int b_intra );
 
+void x264_noise_reduction_update( x264_t *h );
+void x264_denoise_dct( x264_t *h, int16_t *dct );
+
 static inline int array_non_zero( int *v, int i_count )
 {
     int i;
diff --git a/x264.c b/x264.c
index cc403d3..cf0055c 100644 (file)
--- a/x264.c
+++ b/x264.c
@@ -263,6 +263,7 @@ static void Help( x264_param_t *defaults )
              "                                  - 1: enabled only on the final encode of a MB\n"
              "                                  - 2: enabled on all mode decisions\n"
              "      --no-fast-pskip         Disables early SKIP detection on P-frames\n"
+             "      --nr <integer>          Noise reduction [%d]\n"
              "\n"
              "      --cqm <string>          Preset quant matrices [\"flat\"]\n"
              "                                  - jvt, flat\n"
@@ -356,6 +357,7 @@ static void Help( x264_param_t *defaults )
             defaults->analyse.i_me_range,
             defaults->analyse.i_subpel_refine,
             defaults->analyse.i_trellis,
+            defaults->analyse.i_noise_reduction,
             strtable_lookup( overscan_str, defaults->vui.i_overscan ),
             strtable_lookup( vidformat_str, defaults->vui.i_vidformat ),
             strtable_lookup( fullrange_str, defaults->vui.b_fullrange ),
@@ -482,6 +484,7 @@ static int  Parse( int argc, char **argv,
 #define OPT_B_RDO 316
 #define OPT_NO_FAST_PSKIP 317
 #define OPT_BIME 318
+#define OPT_NR 319
 
         static struct option long_options[] =
         {
@@ -544,6 +547,7 @@ static int  Parse( int argc, char **argv,
             { "progress",no_argument,       NULL, OPT_PROGRESS },
             { "visualize",no_argument,      NULL, OPT_VISUALIZE },
             { "aud",     no_argument,       NULL, OPT_AUD },
+            { "nr",      required_argument, NULL, OPT_NR },
             { "cqm",     required_argument, NULL, OPT_CQM },
             { "cqmfile", required_argument, NULL, OPT_CQMFILE },
             { "cqm4",    required_argument, NULL, OPT_CQM4 },
@@ -844,6 +848,9 @@ static int  Parse( int argc, char **argv,
                 fprintf( stderr, "not compiled with visualization support\n" );
 #endif
                 break;
+            case OPT_NR:
+                param->analyse.i_noise_reduction = atoi(optarg);
+                break;
             case OPT_CQM:
                 if( strstr( optarg, "flat" ) )
                     param->i_cqm_preset = X264_CQM_FLAT;
diff --git a/x264.h b/x264.h
index 993b8e3..86abc97 100644 (file)
--- a/x264.h
+++ b/x264.h
@@ -202,6 +202,7 @@ typedef struct
         int          b_mixed_references; /* allow each mb partition in P-frames to have it's own reference number */
         int          i_trellis;  /* trellis RD quantization */
         int          b_fast_pskip; /* early SKIP detection on P-frames */
+        int          i_noise_reduction; /* adaptive pseudo-deadzone */
 
         int          b_psnr;    /* Do we compute PSNR stats (save a few % of cpu) */
     } analyse;