Welcome to Doom9's Forum, THE in-place to be for everyone interested in DVD conversion.

Before you start posting please read the forum rules. By posting to this forum you agree to abide by the rules.

 

Go Back   Doom9's Forum > Video Encoding > MPEG-4 AVC / H.264

Reply
 
Thread Tools Search this Thread Display Modes
Old 15th December 2007, 10:57   #1  |  Link
Dark Shikari
x264 developer
 
Dark Shikari's Avatar
 
Join Date: Sep 2005
Posts: 8,689
Variance AQ Megathread (AQ v0.48 update--defaults changed)

So, after collecting enough magic pixie dust, I've come up with an AQ algorithm that just might work. Its purpose is to avoid blocking in flat areas like regular AQ, but more importantly, avoid blurring in relatively flat textured areas, such as grass at a football game or film grain. It seems to be relatively ineffective (or worse than no AQ at all) on low-bitrate anime, but I have gotten reports that its quite useful at higher bitrates, so try it yourself and see.

Patch
Build
PthreadGC2.dll if you need it.
A 5 minute or so 1080p sample encoded with the new AQ (0.45) at 5 megabits per second
a 44 second sample of 1080p encoded at 10 megabits with AQ 0.47 (strength 0.9, sensitivity 14, qcomp=1)

How to use AQ:

1. AQ is on by default at strength 0.5. Change --aq-strength to make it stronger or weaker.
2. In 2pass, use AQ on both passes with the same settings.
3. Watch in wonder as all the blurred details come back to life and the SSIM of your video rises.

Version history:

0.48: AQ strength 0.5, sensitivity 13 made the defaults. Updated to r736. Qcomp is now scaled based on AQ strength automatically.
0.47: Rounding error fixed at low QPs. Code cleanup/optimization by Akupenguin.
0.46: Code cleanup, documentation updated, defaults changed based on testing, and RDRC removed from the main patch in preparation for putting AQ in SVN. RDRC builds and patches can still be found on Mirror05/Dark.
0.45: Fixed bug if variance=0. Additionally, when static sensitivity is used, no limit is put on the quantizers other than qpmin/qpmax; this allows one to use AQ as a form of quasi-ratecontrol to redistribute more bits to flatter frames to improve quality.
0.44: Bug in x264 CABAC encoding (mb_qp_delta) fixed. While this isn't a bug in AQ, it only showed up when using CABAC, interlaced mode, and AQ.
0.431: Crash bug fixed.
0.43: Code cleaned and re-organized. Massive speed increase of the AQ itself due to performance optimizations.
0.42: Lambda-based AQ removed due to incompatibilities with deadzone that will take some work to resolve.

0.4 (Huge overhaul):

1. Totally rewritten AQ. Same basic concept, but now uses a logarithmic scale instead of a hackneyed exponential one.
2. For B-frames, uses a tricky bit of lambda-changing instead of QP changing; this requires absolutely no bits for QP-deltas!
3. For P-frames, uses a slight bit of trickery to reduce the bit cost of QP deltas.
4. Totally rewritten, far faster automatic sensitivity. Respects bitrate in CRF mode better also.
5. Now based on r720.

0.3 (Major overhaul of automatic thresholding and options)
0.21 (Fixed overflow bug with variance function. Code now is allowed to raise quantizers. If this causes problems I may restrict it somewhat.)
0.2 (Re-introduced pre-pass for automagic thresholding)
0.11 (Heavily optimized code)
0.1 (Initial release, fixed scaling formula, removed pre-pass)
0.01 (Initial algorithm)

Results from a test of AQ 0.42:

(1-0.9769377) / (1- 0.9799512) = 15% SSIM boost
(37.751-36.792)/0.05 = 19% PSNR drop
7416.06 / 6960.12 - 1 = 6.55% bitrate drop

Last edited by Dark Shikari; 15th February 2008 at 03:06.
Dark Shikari is offline   Reply With Quote
Old 15th December 2007, 10:59   #2  |  Link
Inventive Software
Turkey Machine
 
Join Date: Jan 2005
Location: Lowestoft, UK (but visit lots of places with bribes [beer])
Posts: 1,953
Trust you to come up with this an hour before I go home for 3 weeks!

I'll have a play next week, if you're not too busy changing the innards of the algorithm.
__________________
On Discworld it is clearly recognized that million-to-one chances happen 9 times out of 10. If the hero did not overcome huge odds, what would be the point? Terry Pratchett - The Science Of Discworld
Inventive Software is offline   Reply With Quote
Old 15th December 2007, 12:23   #3  |  Link
ToS_Maverick
x264 Tester
 
Join Date: Dec 2005
Location: Austria, near Vienna
Posts: 223
OMG Dark Shikari you are a HERO

i could only do a quick test for now, but @CRF20 it was COMPLETELY transparent, at CRF22 it was VERY good...

a few questions:
- how does it work, it's very effective?
- where can i donate

more detailed test with screens coming soon
ToS_Maverick is offline   Reply With Quote
Old 15th December 2007, 12:30   #4  |  Link
Dark Shikari
x264 developer
 
Dark Shikari's Avatar
 
Join Date: Sep 2005
Posts: 8,689
Quote:
Originally Posted by ToS_Maverick View Post
OMG Dark Shikari you are a HERO

i could only do a quick test for now, but @CRF20 it was COMPLETELY transparent, at CRF22 it was VERY good...

a few questions:
- how does it work, it's very effective?
- where can i donate

more detailed test with screens coming soon
It works by using the AC energy of each macroblock as a metric. Or, in other words, it takes the average of the block's pixels, subtracts those from the original pixel data, and then takes the sum of squares of the result. This means that blocks that aren't completely flat but have a lot of texture still get hit by AQ.

There are some slight optimizations to this (like the fact that this is mathematically equivalent to SSD - SAD^2, and so forth). Also note I made a major change to the build that's up there (I reuploaded)--it now has --aq-sensitivity affect the algorithm. This affects the thresholding in the following way: lower values mean that blocks have to be "flatter" to be affected by AQ, while higher values mean blocks don't have to be as flat.

Last edited by Dark Shikari; 15th December 2007 at 12:36.
Dark Shikari is offline   Reply With Quote
Old 15th December 2007, 16:54   #5  |  Link
AGDenton
Registered User
 
AGDenton's Avatar
 
Join Date: Jan 2007
Posts: 27
Can you do an svn diff against some revision of x264 ? I'd like to test this, but I'm not under win32...
AGDenton is offline   Reply With Quote
Old 15th December 2007, 20:26   #6  |  Link
Dark Shikari
x264 developer
 
Dark Shikari's Avatar
 
Join Date: Sep 2005
Posts: 8,689
Quote:
Originally Posted by AGDenton View Post
Can you do an svn diff against some revision of x264 ? I'd like to test this, but I'm not under win32...
Code:
Index: encoder/encoder.c
===================================================================
--- encoder/encoder.c	(revision 712)
+++ encoder/encoder.c	(working copy)
@@ -472,6 +472,8 @@
     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 );
+    if( h->param.analyse.b_aq && h->param.analyse.f_aq_strength <= 0 )
+        h->param.analyse.b_aq = 0;
     h->param.analyse.i_noise_reduction = x264_clip3( h->param.analyse.i_noise_reduction, 0, 1<<16 );
 
     {
Index: encoder/analyse.c
===================================================================
--- encoder/analyse.c	(revision 712)
+++ encoder/analyse.c	(working copy)
@@ -29,6 +29,7 @@
 #endif
 
 #include "common/common.h"
+#include "common/cpu.h"
 #include "macroblock.h"
 #include "me.h"
 #include "ratecontrol.h"
@@ -2031,8 +2032,61 @@
     }
 }
 
+//Finds the total AC energy of the block in all planes.
+static int ac_energy_mb(x264_t *h)
+{
+    DECLARE_ALIGNED( static uint8_t, zero[FDEC_STRIDE*16], 16 );
+    int avg[3];
+    int x,y;
+    for(y = 0; y < 16; y++)
+        for(x = 0; x < 16; x++)
+            zero[FDEC_STRIDE*y+x]=0;
+    avg[0] = h->pixf.sad[PIXEL_16x16](zero,FDEC_STRIDE,h->mb.pic.p_fenc[0],FENC_STRIDE) >> 8;
+    avg[1] = h->pixf.sad[PIXEL_8x8](zero,FDEC_STRIDE,h->mb.pic.p_fenc[1],FENC_STRIDE) >> 6;
+    avg[2] = h->pixf.sad[PIXEL_8x8](zero,FDEC_STRIDE,h->mb.pic.p_fenc[2],FENC_STRIDE) >> 6;
+    int totalSSD = 0;
+    for(y = 0; y < 16; y++)
+        for(x = 0; x < 16; x++)
+            zero[FDEC_STRIDE*y+x]=avg[0];
+    totalSSD += h->pixf.ssd[PIXEL_16x16](zero,FDEC_STRIDE,h->mb.pic.p_fenc[0],FENC_STRIDE);
+    for(y = 0; y < 8; y++)
+        for(x = 0; x < 8; x++)
+            zero[FDEC_STRIDE*y+x]=avg[1];
+    totalSSD += h->pixf.ssd[PIXEL_8x8](zero,FDEC_STRIDE,h->mb.pic.p_fenc[1],FENC_STRIDE);
+    for(y = 0; y < 8; y++)
+        for(x = 0; x < 8; x++)
+            zero[FDEC_STRIDE*y+x]=avg[2];
+    totalSSD += h->pixf.ssd[PIXEL_8x8](zero,FDEC_STRIDE,h->mb.pic.p_fenc[2],FENC_STRIDE);
+    return totalSSD;
+}
 
 /*****************************************************************************
+ * x264_adaptive_quant:
+ * check if mb is "flat", i.e. has most energy in low frequency components, and
+ * adjust qp down if it is
+ *****************************************************************************/
+void x264_adaptive_quant( x264_t *h, x264_mb_analysis_t *a )
+{
+    int qp = h->mb.i_qp;
+    int ac_energy = ac_energy_mb(h);
+    x264_cpu_restore(h->param.cpu);
+    float result = ac_energy;
+    const float expconst = 0.367879441;
+    float threshold = powf(h->param.analyse.f_aq_sensitivity,4)/2;
+    if(result < threshold)
+    {
+        if(result == 0) result = 1;
+        else
+            result = (expconst-expf(-powf(threshold/result,0.2))) * 2.71828183;
+    }
+    else result = 0;
+    int qp_adj = (qp * result * h->param.analyse.f_aq_strength) / 2;
+    qp_adj = x264_clip3(qp_adj, 0, qp/2);
+    h->mb.i_qp = a->i_qp = qp - qp_adj;
+    h->mb.i_chroma_qp = i_chroma_qp_table[x264_clip3( h->mb.i_qp + h->pps->i_chroma_qp_index_offset, 0, 51 )];
+}
+
+/*****************************************************************************
  * x264_macroblock_analyse:
  *****************************************************************************/
 void x264_macroblock_analyse( x264_t *h )
@@ -2040,9 +2094,14 @@
     x264_mb_analysis_t analysis;
     int i_cost = COST_MAX;
     int i;
+    
+    h->mb.i_qp = x264_ratecontrol_qp( h );
 
+    if( h->param.analyse.b_aq )
+        x264_adaptive_quant( h, &analysis );
+
     /* init analysis */
-    x264_mb_analyse_init( h, &analysis, x264_ratecontrol_qp( h ) );
+    x264_mb_analyse_init( h, &analysis, h->mb.i_qp );
 
     /*--------------------------- Do the analysis ---------------------------*/
     if( h->sh.i_type == SLICE_TYPE_I )
Index: x264.c
===================================================================
--- x264.c	(revision 712)
+++ x264.c	(working copy)
@@ -243,6 +243,12 @@
         "                                  - 2: enabled on all mode decisions\n", defaults->analyse.i_trellis );
     H0( "      --no-fast-pskip         Disables early SKIP detection on P-frames\n" );
     H0( "      --no-dct-decimate       Disables coefficient thresholding on P-frames\n" );
+    H0( "      --aq-strength <float>   Amount to adjust QP per MB [%.1f]\n"
+        "                                  0.0: no AQ\n"
+        "                                  1.1: strong AQ\n", defaults->analyse.f_aq_strength );
+    H0( "      --aq-sensitivity <float> \"Flatness\" threshold to trigger AQ [%.1f]\n"
+        "                                    5: applies to almost no blocks\n"
+        "                                   35: applies to almost all blocks\n", defaults->analyse.f_aq_sensitivity );
     H0( "      --nr <integer>          Noise reduction [%d]\n", defaults->analyse.i_noise_reduction );
     H1( "\n" );
     H1( "      --deadzone-inter <int>  Set the size of the inter luma quantization deadzone [%d]\n", defaults->analyse.i_luma_deadzone[0] );
@@ -406,6 +412,8 @@
             { "trellis", required_argument, NULL, 't' },
             { "no-fast-pskip", no_argument, NULL, 0 },
             { "no-dct-decimate", no_argument, NULL, 0 },
+            { "aq-strength", required_argument, NULL, 0 },
+            { "aq-sensitivity", required_argument, NULL, 0 },
             { "deadzone-inter", required_argument, NULL, '0' },
             { "deadzone-intra", required_argument, NULL, '0' },
             { "level",   required_argument, NULL, 0 },
Index: common/pixel.c
===================================================================
--- common/pixel.c	(revision 712)
+++ common/pixel.c	(working copy)
@@ -213,6 +213,14 @@
 PIXEL_SATD_C( x264_pixel_satd_4x8,   4, 8 )
 PIXEL_SATD_C( x264_pixel_satd_4x4,   4, 4 )
 
+static int x264_pixel_count_8x8( uint8_t *pix, int i_pix, uint32_t threshold )
+{
+    int x, y, sum = 0;
+    for( y=0; y<8; y++, pix += i_pix )
+        for( x=0; x<8; x++ )
+            sum += pix[x] > (uint8_t)threshold;
+    return sum;
+}
 
 /****************************************************************************
  * pixel_sa8d_WxH: sum of 8x8 Hadamard transformed differences
@@ -473,6 +481,8 @@
     pixf->ads[PIXEL_16x8] = pixel_ads2;
     pixf->ads[PIXEL_8x8] = pixel_ads1;
 
+    pixf->count_8x8 = x264_pixel_count_8x8;
+
 #ifdef HAVE_MMX
     if( cpu&X264_CPU_MMX )
     {
Index: common/pixel.h
===================================================================
--- common/pixel.h	(revision 712)
+++ common/pixel.h	(working copy)
@@ -84,6 +84,8 @@
     void (*ads[7])( int enc_dc[4], uint16_t *sums, int delta,
                     uint16_t *res, int width );
 
+    int (*count_8x8)( uint8_t *pix, int i_pix, uint32_t threshold );
+
     /* calculate satd of V, H, and DC modes.
      * may be NULL, in which case just use pred+satd instead. */
     void (*intra_satd_x3_16x16)( uint8_t *fenc, uint8_t *fdec, int res[3] );
Index: common/common.c
===================================================================
--- common/common.c	(revision 712)
+++ common/common.c	(working copy)
@@ -123,6 +123,9 @@
     param->analyse.i_chroma_qp_offset = 0;
     param->analyse.b_fast_pskip = 1;
     param->analyse.b_dct_decimate = 1;
+    param->analyse.b_aq = 0;
+    param->analyse.f_aq_strength = 0.0;
+    param->analyse.f_aq_sensitivity = 15;
     param->analyse.i_luma_deadzone[0] = 21;
     param->analyse.i_luma_deadzone[1] = 11;
     param->analyse.b_psnr = 1;
@@ -455,6 +458,13 @@
         p->analyse.b_fast_pskip = atobool(value);
     OPT("dct-decimate")
         p->analyse.b_dct_decimate = atobool(value);
+    OPT("aq-strength")
+    {
+        p->analyse.f_aq_strength = atof(value);
+        p->analyse.b_aq = (p->analyse.f_aq_strength > 0.0);
+    }
+    OPT("aq-sensitivity")
+        p->analyse.f_aq_sensitivity = atof(value);
     OPT("deadzone-inter")
         p->analyse.i_luma_deadzone[0] = atoi(value);
     OPT("deadzone-intra")
@@ -939,6 +949,9 @@
             s += sprintf( s, " zones" );
     }
 
+    if( p->analyse.b_aq )
+        s += sprintf( s, " aq=1:%.1f:%.1f", p->analyse.f_aq_strength, p->analyse.f_aq_sensitivity );
+
     return buf;
 }
 
Index: x264.h
===================================================================
--- x264.h	(revision 712)
+++ x264.h	(working copy)
@@ -230,6 +230,9 @@
         int          i_trellis;  /* trellis RD quantization */
         int          b_fast_pskip; /* early SKIP detection on P-frames */
         int          b_dct_decimate; /* transform coefficient thresholding on P-frames */
+        int          b_aq; /* psy adaptive QP */
+        float        f_aq_strength;
+        float        f_aq_sensitivity;
         int          i_noise_reduction; /* adaptive pseudo-deadzone */
 
         /* the deadzone size that will be used in luma quantization */
Dark Shikari is offline   Reply With Quote
Old 15th December 2007, 20:43   #7  |  Link
akupenguin
x264 developer
 
akupenguin's Avatar
 
Join Date: Sep 2004
Posts: 2,393
In addition to being unnecessary as discussed before, your zero array is not thread safe. And if you did for whatever reason need a dc array, its stride should be 0 to reduce the amount of data to initialize.
akupenguin is offline   Reply With Quote
Old 15th December 2007, 20:50   #8  |  Link
Dark Shikari
x264 developer
 
Dark Shikari's Avatar
 
Join Date: Sep 2005
Posts: 8,689
Quote:
Originally Posted by akupenguin View Post
In addition to being unnecessary as discussed before, your zero array is not thread safe. And if you did for whatever reason need a dc array, its stride should be 0 to reduce the amount of data to initialize.
Yup, yup, I will fix the code. Wait, the zero array isn't threadsafe though? Isn't that what ordinary AQ uses?
Dark Shikari is offline   Reply With Quote
Old 15th December 2007, 20:52   #9  |  Link
akupenguin
x264 developer
 
akupenguin's Avatar
 
Join Date: Sep 2004
Posts: 2,393
That zero array contains zeros. Yours gets modified. In short: there shouldn't be any non-const static variables.
akupenguin is offline   Reply With Quote
Old 15th December 2007, 21:10   #10  |  Link
Dark Shikari
x264 developer
 
Dark Shikari's Avatar
 
Join Date: Sep 2005
Posts: 8,689
Quote:
Originally Posted by akupenguin View Post
That zero array contains zeros. Yours gets modified. In short: there shouldn't be any non-const static variables.
Bleh, fixed code.

Not bit-equivalent to the old one, but close enough, and faster.

Code:
Index: encoder/encoder.c
===================================================================
--- encoder/encoder.c	(revision 712)
+++ encoder/encoder.c	(working copy)
@@ -472,6 +472,8 @@
     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 );
+    if( h->param.analyse.b_aq && h->param.analyse.f_aq_strength <= 0 )
+        h->param.analyse.b_aq = 0;
     h->param.analyse.i_noise_reduction = x264_clip3( h->param.analyse.i_noise_reduction, 0, 1<<16 );
 
     {
Index: encoder/analyse.c
===================================================================
--- encoder/analyse.c	(revision 712)
+++ encoder/analyse.c	(working copy)
@@ -29,6 +29,7 @@
 #endif
 
 #include "common/common.h"
+#include "common/cpu.h"
 #include "macroblock.h"
 #include "me.h"
 #include "ratecontrol.h"
@@ -2031,8 +2032,51 @@
     }
 }
 
+//Finds the total AC energy of the block in all planes.
+static int ac_energy_mb(x264_t *h)
+{
+    DECLARE_ALIGNED( static uint8_t, zero[16], 16 );
+    int sad,ssd;
+    int totalSSD = 0;
+    sad = h->pixf.sad[PIXEL_16x16](zero,0,h->mb.pic.p_fenc[0],FENC_STRIDE);
+    ssd = h->pixf.ssd[PIXEL_16x16](zero,0,h->mb.pic.p_fenc[0],FENC_STRIDE);
+    totalSSD += ssd - ((sad * sad) >> 8);
+    sad = h->pixf.sad[PIXEL_8x8](zero,0,h->mb.pic.p_fenc[1],FENC_STRIDE);
+    ssd = h->pixf.ssd[PIXEL_8x8](zero,0,h->mb.pic.p_fenc[1],FENC_STRIDE);
+    totalSSD += ssd - ((sad * sad) >> 6);
+    sad = h->pixf.sad[PIXEL_8x8](zero,0,h->mb.pic.p_fenc[2],FENC_STRIDE);
+    ssd = h->pixf.ssd[PIXEL_8x8](zero,0,h->mb.pic.p_fenc[2],FENC_STRIDE);
+    totalSSD += ssd - ((sad * sad) >> 6);
+    return totalSSD;
+}
 
 /*****************************************************************************
+ * x264_adaptive_quant:
+ * check if mb is "flat", i.e. has most energy in low frequency components, and
+ * adjust qp down if it is
+ *****************************************************************************/
+void x264_adaptive_quant( x264_t *h, x264_mb_analysis_t *a )
+{
+    int qp = h->mb.i_qp;
+    int ac_energy = ac_energy_mb(h);
+    x264_cpu_restore(h->param.cpu);
+    float result = ac_energy;
+    const float expconst = 0.367879441;
+    float threshold = powf(h->param.analyse.f_aq_sensitivity,4)/2;
+    if(result < threshold)
+    {
+        if(result == 0) result = 1;
+        else
+            result = (expconst-expf(-powf(threshold/result,0.2))) * 2.71828183;
+    }
+    else result = 0;
+    int qp_adj = (qp * result * h->param.analyse.f_aq_strength) / 2;
+    qp_adj = x264_clip3(qp_adj, 0, qp/2);
+    h->mb.i_qp = a->i_qp = qp - qp_adj;
+    h->mb.i_chroma_qp = i_chroma_qp_table[x264_clip3( h->mb.i_qp + h->pps->i_chroma_qp_index_offset, 0, 51 )];
+}
+
+/*****************************************************************************
  * x264_macroblock_analyse:
  *****************************************************************************/
 void x264_macroblock_analyse( x264_t *h )
@@ -2040,9 +2084,14 @@
     x264_mb_analysis_t analysis;
     int i_cost = COST_MAX;
     int i;
+    
+    h->mb.i_qp = x264_ratecontrol_qp( h );
 
+    if( h->param.analyse.b_aq )
+        x264_adaptive_quant( h, &analysis );
+
     /* init analysis */
-    x264_mb_analyse_init( h, &analysis, x264_ratecontrol_qp( h ) );
+    x264_mb_analyse_init( h, &analysis, h->mb.i_qp );
 
     /*--------------------------- Do the analysis ---------------------------*/
     if( h->sh.i_type == SLICE_TYPE_I )
Index: x264.c
===================================================================
--- x264.c	(revision 712)
+++ x264.c	(working copy)
@@ -243,6 +243,12 @@
         "                                  - 2: enabled on all mode decisions\n", defaults->analyse.i_trellis );
     H0( "      --no-fast-pskip         Disables early SKIP detection on P-frames\n" );
     H0( "      --no-dct-decimate       Disables coefficient thresholding on P-frames\n" );
+    H0( "      --aq-strength <float>   Amount to adjust QP per MB [%.1f]\n"
+        "                                  0.0: no AQ\n"
+        "                                  1.1: strong AQ\n", defaults->analyse.f_aq_strength );
+    H0( "      --aq-sensitivity <float> \"Flatness\" threshold to trigger AQ [%.1f]\n"
+        "                                    5: applies to almost no blocks\n"
+        "                                   35: applies to almost all blocks\n", defaults->analyse.f_aq_sensitivity );
     H0( "      --nr <integer>          Noise reduction [%d]\n", defaults->analyse.i_noise_reduction );
     H1( "\n" );
     H1( "      --deadzone-inter <int>  Set the size of the inter luma quantization deadzone [%d]\n", defaults->analyse.i_luma_deadzone[0] );
@@ -406,6 +412,8 @@
             { "trellis", required_argument, NULL, 't' },
             { "no-fast-pskip", no_argument, NULL, 0 },
             { "no-dct-decimate", no_argument, NULL, 0 },
+            { "aq-strength", required_argument, NULL, 0 },
+            { "aq-sensitivity", required_argument, NULL, 0 },
             { "deadzone-inter", required_argument, NULL, '0' },
             { "deadzone-intra", required_argument, NULL, '0' },
             { "level",   required_argument, NULL, 0 },
Index: common/pixel.c
===================================================================
--- common/pixel.c	(revision 712)
+++ common/pixel.c	(working copy)
@@ -213,6 +213,14 @@
 PIXEL_SATD_C( x264_pixel_satd_4x8,   4, 8 )
 PIXEL_SATD_C( x264_pixel_satd_4x4,   4, 4 )
 
+static int x264_pixel_count_8x8( uint8_t *pix, int i_pix, uint32_t threshold )
+{
+    int x, y, sum = 0;
+    for( y=0; y<8; y++, pix += i_pix )
+        for( x=0; x<8; x++ )
+            sum += pix[x] > (uint8_t)threshold;
+    return sum;
+}
 
 /****************************************************************************
  * pixel_sa8d_WxH: sum of 8x8 Hadamard transformed differences
@@ -473,6 +481,8 @@
     pixf->ads[PIXEL_16x8] = pixel_ads2;
     pixf->ads[PIXEL_8x8] = pixel_ads1;
 
+    pixf->count_8x8 = x264_pixel_count_8x8;
+
 #ifdef HAVE_MMX
     if( cpu&X264_CPU_MMX )
     {
Index: common/pixel.h
===================================================================
--- common/pixel.h	(revision 712)
+++ common/pixel.h	(working copy)
@@ -84,6 +84,8 @@
     void (*ads[7])( int enc_dc[4], uint16_t *sums, int delta,
                     uint16_t *res, int width );
 
+    int (*count_8x8)( uint8_t *pix, int i_pix, uint32_t threshold );
+
     /* calculate satd of V, H, and DC modes.
      * may be NULL, in which case just use pred+satd instead. */
     void (*intra_satd_x3_16x16)( uint8_t *fenc, uint8_t *fdec, int res[3] );
Index: common/common.c
===================================================================
--- common/common.c	(revision 712)
+++ common/common.c	(working copy)
@@ -123,6 +123,9 @@
     param->analyse.i_chroma_qp_offset = 0;
     param->analyse.b_fast_pskip = 1;
     param->analyse.b_dct_decimate = 1;
+    param->analyse.b_aq = 0;
+    param->analyse.f_aq_strength = 0.0;
+    param->analyse.f_aq_sensitivity = 15;
     param->analyse.i_luma_deadzone[0] = 21;
     param->analyse.i_luma_deadzone[1] = 11;
     param->analyse.b_psnr = 1;
@@ -455,6 +458,13 @@
         p->analyse.b_fast_pskip = atobool(value);
     OPT("dct-decimate")
         p->analyse.b_dct_decimate = atobool(value);
+    OPT("aq-strength")
+    {
+        p->analyse.f_aq_strength = atof(value);
+        p->analyse.b_aq = (p->analyse.f_aq_strength > 0.0);
+    }
+    OPT("aq-sensitivity")
+        p->analyse.f_aq_sensitivity = atof(value);
     OPT("deadzone-inter")
         p->analyse.i_luma_deadzone[0] = atoi(value);
     OPT("deadzone-intra")
@@ -939,6 +949,9 @@
             s += sprintf( s, " zones" );
     }
 
+    if( p->analyse.b_aq )
+        s += sprintf( s, " aq=1:%.1f:%.1f", p->analyse.f_aq_strength, p->analyse.f_aq_sensitivity );
+
     return buf;
 }
 
Index: x264.h
===================================================================
--- x264.h	(revision 712)
+++ x264.h	(working copy)
@@ -230,6 +230,9 @@
         int          i_trellis;  /* trellis RD quantization */
         int          b_fast_pskip; /* early SKIP detection on P-frames */
         int          b_dct_decimate; /* transform coefficient thresholding on P-frames */
+        int          b_aq; /* psy adaptive QP */
+        float        f_aq_strength;
+        float        f_aq_sensitivity;
         int          i_noise_reduction; /* adaptive pseudo-deadzone */
 
         /* the deadzone size that will be used in luma quantization */
EXE updated.

Last edited by Dark Shikari; 15th December 2007 at 21:12.
Dark Shikari is offline   Reply With Quote
Old 15th December 2007, 21:41   #11  |  Link
LigH
German doom9/Gleitz SuMo
 
LigH's Avatar
 
Join Date: Oct 2001
Location: Germany, rural Altmark
Posts: 5,667
Hooray!

Thanks for this patch. I bet some friends in the german board will test it too.
LigH is offline   Reply With Quote
Old 16th December 2007, 00:39   #12  |  Link
Sagekilla
x264aholic
 
Join Date: Jul 2007
Location: New York
Posts: 1,752
So now the general starting point for using AQ-strength would be 1.0 and now 0.5 as before? If so that would be quite nice, since I'd imagine it'd give me some more leeway with only using tiny amounts of AQ in those pesky movies where theres relatively few dark scenes.
Sagekilla is offline   Reply With Quote
Old 16th December 2007, 01:47   #13  |  Link
Dark Shikari
x264 developer
 
Dark Shikari's Avatar
 
Join Date: Sep 2005
Posts: 8,689
I found a bug with my energy function where I get an integer overflow in some extremely bright blocks, resulting in AQ not being activated even if the block is flat. A fix will come in a bit.

I'm also working on a magical algorithm to automatically find a good threshold value for each frame.

Last edited by Dark Shikari; 16th December 2007 at 02:02.
Dark Shikari is offline   Reply With Quote
Old 16th December 2007, 02:10   #14  |  Link
Sagekilla
x264aholic
 
Join Date: Jul 2007
Location: New York
Posts: 1,752
Quote:
Originally Posted by Dark Shikari View Post
I found a bug with my energy function where I get an integer overflow in some extremely bright blocks, resulting in AQ not being activated even if the block is flat. A fix will come in a bit.

I'm also working on a magical algorithm to automatically find a good threshold value for each frame.
Could this be magically added to a multi-patched x264 with all your other wonderful patches too?
Sagekilla is offline   Reply With Quote
Old 16th December 2007, 02:15   #15  |  Link
Dark Shikari
x264 developer
 
Dark Shikari's Avatar
 
Join Date: Sep 2005
Posts: 8,689
Quote:
Originally Posted by Sagekilla View Post
Could this be magically added to a multi-patched x264 with all your other wonderful patches too?
Soon. In the meantime, a teaser of the latest algorithm:

(1-pass ABR, 1000 kbit, a comparison of two I-frames)

Original:



AQ:



Note most of the ringing is from the original source, which was not a very well-encoded DVD (and so blurring obscures the ringing when AQ isn't used).

If you want a huge contrast between the two, look at the wheel in the background on the first image. Or the bricks in the background on the second image.

Last edited by Dark Shikari; 16th December 2007 at 02:19.
Dark Shikari is offline   Reply With Quote
Old 16th December 2007, 02:16   #16  |  Link
Sagekilla
x264aholic
 
Join Date: Jul 2007
Location: New York
Posts: 1,752
Very nice, some good detail retention in areas that I'd imagine would otherwise be killed off..
Sagekilla is offline   Reply With Quote
Old 16th December 2007, 04:38   #17  |  Link
kumi
Straight to video
 
kumi's Avatar
 
Join Date: Jun 2005
Posts: 637
I see a huge difference in CRF output size with --aq-sensitivity 0. Normal?

--crf 21.5
Size: 9.99 MB
Bitrate (Avg): 1.169

--crf 21.5 --aq-str 1.0
Size: 8.12 MB
Bitrate (Avg): 0.950

--crf 21.5 --aq-str 1.0 --aq-sens 0
Size: 36.8 MB
Bitrate (Avg): 4.309
__________________
.
kumi is offline   Reply With Quote
Old 16th December 2007, 04:41   #18  |  Link
Sagekilla
x264aholic
 
Join Date: Jul 2007
Location: New York
Posts: 1,752
Quote:
Originally Posted by kumi View Post
I see a huge difference in CRF output size with --aq-sensitivity 0. Normal?

--crf 21.5
Size: 9.99 MB
Bitrate (Avg): 1.169

--crf 21.5 --aq-str 1.0
Size: 8.12 MB
Bitrate (Avg): 0.950

--crf 21.5 --aq-str 1.0 --aq-sens 0
Size: 36.8 MB
Bitrate (Avg): 4.309
Perhaps it may be borked with 0, like one of those divide by zero errors.
Sagekilla is offline   Reply With Quote
Old 16th December 2007, 04:56   #19  |  Link
kumi
Straight to video
 
kumi's Avatar
 
Join Date: Jun 2005
Posts: 637
Yes, but
"2. For the automagic thresholding algorithm, use --aq-sensitivity 0."
__________________
.
kumi is offline   Reply With Quote
Old 16th December 2007, 05:11   #20  |  Link
Dark Shikari
x264 developer
 
Dark Shikari's Avatar
 
Join Date: Sep 2005
Posts: 8,689
Quote:
Originally Posted by kumi View Post
I see a huge difference in CRF output size with --aq-sensitivity 0. Normal?

--crf 21.5
Size: 9.99 MB
Bitrate (Avg): 1.169

--crf 21.5 --aq-str 1.0
Size: 8.12 MB
Bitrate (Avg): 0.950

--crf 21.5 --aq-str 1.0 --aq-sens 0
Size: 36.8 MB
Bitrate (Avg): 4.309
Try with bitrate mode to make the results more comparable. Its likely screwing up ratecontrol--I will try to see what I can do to make it avoid blowing up the filesize.

That is natural though--AQ does drastically raise filesize with CRF. Its just in this case its raised it a bit more than usual.
Dark Shikari is offline   Reply With Quote
Reply

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +1. The time now is 01:35.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2018, vBulletin Solutions Inc.