shithub: libvpx

Download patch

ref: b4ad9b5d5052b54d74c98c2ee71d5236c39a1537
parent: 82d99257f2f2a009bd3f9cde4375e141fbf85827
author: Paul Wilkins <paulwilkins@google.com>
date: Tue Dec 6 09:48:52 EST 2011

Some further QIndex issues with extended Q

Resolved or factored out some further issues with Q index.
Put in a 3rd order polynomial instead of less accurate power function
as the best fit on gf and kf boost adjustment.
Added avg_q value to use instead of ni_av_qi.
Compute segment delta Q values based on avg_q.
Fixed bug in adjust_maxq_qrange().

The extended range Q on the derf set, using standard data rates
(which do not extend high enough to get big benefits) still show
a shortfall of between 0.5 and 1% though so there would appear to
be further issues that need to be tracked down.

Change-Id: Icfd49b9f401906ba487ef1bef7d397048295d959

--- a/vp8/encoder/firstpass.c
+++ b/vp8/encoder/firstpass.c
@@ -898,7 +898,7 @@
     double correction_factor;
 
     // Adjustment based on actual quantizer to power term.
-    power_term = (vp8_convert_qindex_to_q(Q) * 0.01) + 0.36;
+    power_term = (vp8_convert_qindex_to_q(Q) * 0.01) + pt_low;
     power_term = (power_term > pt_high) ? pt_high : power_term;
 
     // Adjustments to error term
@@ -919,29 +919,29 @@
 // PGW TODO..
 // This code removes direct dependency on QIndex to determin the range
 // (now uses the actual quantizer) but has not been tuned.
-static double adjust_maxq_qrange(VP8_COMP *cpi, int qindex )
+static double adjust_maxq_qrange(VP8_COMP *cpi)
 {
     int i;
-    double q = vp8_convert_qindex_to_q(qindex);
+    double q;
 
-    // Set the max corresponding to real q * 2.0
+    // Set the max corresponding to cpi->avg_q * 2.0
+    q = cpi->avg_q * 2.0;
     cpi->twopass.maxq_max_limit = cpi->worst_quality;
-    for ( i = qindex; i < cpi->worst_quality; i++ )
+    for ( i = cpi->best_quality; i <= cpi->worst_quality; i++ )
     {
-        if ( vp8_convert_qindex_to_q(qindex) >= (q * 2.0) )
-        {
-            cpi->twopass.maxq_max_limit = i;
-        }
+        cpi->twopass.maxq_max_limit = i;
+        if ( vp8_convert_qindex_to_q(i) >= q )
+            break;
     }
 
-    // Set the min corresponding to real q * 0.5
+    // Set the min corresponding to cpi->avg_q * 0.5
+    q = cpi->avg_q * 0.5;
     cpi->twopass.maxq_min_limit = cpi->best_quality;
-    for ( i = qindex; i > cpi->best_quality; i-- )
+    for ( i = cpi->worst_quality; i >= cpi->best_quality; i-- )
     {
-        if ( vp8_convert_qindex_to_q(qindex) <= (q * 0.5) )
-        {
-            cpi->twopass.maxq_min_limit = i;
-        }
+        cpi->twopass.maxq_min_limit = i;
+        if ( vp8_convert_qindex_to_q(i) <= q )
+            break;
     }
 }
 
@@ -1018,7 +1018,7 @@
 
         // Error per MB based correction factor
         err_correction_factor =
-            calc_correction_factor(err_per_mb, 150.0, 0.40, 0.90, Q);
+            calc_correction_factor(err_per_mb, 150.0, 0.36, 0.90, Q);
 
         bits_per_mb_at_this_q =
             vp8_bits_per_mb(INTER_FRAME, Q) + overhead_bits_per_mb;
@@ -1054,7 +1054,7 @@
                   ((unsigned int)cpi->twopass.total_stats->count >> 8)) &&
          (cpi->ni_frames > 150) )
     {
-        adjust_maxq_qrange( cpi, cpi->ni_av_qi );
+        adjust_maxq_qrange( cpi );
     }
 
     return Q;
@@ -1120,7 +1120,7 @@
 
         // Error per MB based correction factor
         err_correction_factor =
-            calc_correction_factor(err_per_mb, 100.0, 0.40, 0.90, Q);
+            calc_correction_factor(err_per_mb, 100.0, 0.36, 0.90, Q);
 
         bits_per_mb_at_this_q =
             vp8_bits_per_mb(INTER_FRAME, Q) + overhead_bits_per_mb;
@@ -1181,7 +1181,7 @@
 
         // Error per MB based correction factor
         err_correction_factor =
-            calc_correction_factor(err_per_mb, 150.0, 0.40, 0.90, Q);
+            calc_correction_factor(err_per_mb, 150.0, 0.36, 0.90, Q);
 
         bits_per_mb_at_this_q =
             (int)( .5 + ( err_correction_factor *
@@ -2329,6 +2329,46 @@
     cpi->per_frame_bandwidth = target_frame_size;                                           // Per frame bit target for this frame
 }
 
+// Make a damped adjustment to the active max q.
+int adjust_active_maxq( int old_maxqi, int new_maxqi )
+{
+    int i;
+    int ret_val = new_maxqi;
+    double old_q;
+    double new_q;
+    double target_q;
+
+    old_q = vp8_convert_qindex_to_q( old_maxqi );
+    new_q = vp8_convert_qindex_to_q( new_maxqi );
+
+    target_q = ((old_q * 7.0) + new_q) / 8.0;
+
+    if ( target_q > old_q )
+    {
+        for ( i = old_maxqi; i <= new_maxqi; i++ )
+        {
+            if ( vp8_convert_qindex_to_q( i ) >= target_q )
+            {
+                ret_val = i;
+                break;
+            }
+        }
+    }
+    else
+    {
+        for ( i = old_maxqi; i >= new_maxqi; i-- )
+        {
+            if ( vp8_convert_qindex_to_q( i ) <= target_q )
+            {
+                ret_val = i;
+                break;
+            }
+        }
+    }
+
+    return ret_val;
+}
+
 void vp8_second_pass(VP8_COMP *cpi)
 {
     int tmp_q;
@@ -2480,15 +2520,16 @@
                     (int)(cpi->twopass.bits_left / frames_left),
                     overhead_bits );
 
+        cpi->active_worst_quality         = tmp_q;
+        cpi->ni_av_qi                     = tmp_q;
+        cpi->avg_q                        = vp8_convert_qindex_to_q( tmp_q );
+
         // Limit the maxq value returned subsequently.
         // This increases the risk of overspend or underspend if the initial
         // estimate for the clip is bad, but helps prevent excessive
         // variation in Q, especially near the end of a clip
         // where for example a small overspend may cause Q to crash
-        adjust_maxq_qrange(cpi, tmp_q);
-
-        cpi->active_worst_quality         = tmp_q;
-        cpi->ni_av_qi                     = tmp_q;
+        adjust_maxq_qrange(cpi);
     }
 
     // The last few frames of a clip almost always have to few or too many
@@ -2509,14 +2550,9 @@
                     (int)(cpi->twopass.bits_left / frames_left),
                     overhead_bits );
 
-        // Move active_worst_quality but in a damped way
-        if (tmp_q > cpi->active_worst_quality)
-            cpi->active_worst_quality ++;
-        else if (tmp_q < cpi->active_worst_quality)
-            cpi->active_worst_quality --;
-
+        // Make a damped adjustment to active max Q
         cpi->active_worst_quality =
-            ((cpi->active_worst_quality * 3) + tmp_q + 2) / 4;
+            adjust_active_maxq( cpi->active_worst_quality, tmp_q );
     }
 
     cpi->twopass.frames_to_key --;
--- a/vp8/encoder/onyx_if.c
+++ b/vp8/encoder/onyx_if.c
@@ -416,6 +416,35 @@
 
 }
 
+// Computes a q delta (in "q index" terms) to get from a starting q value
+// to a target value
+// target q value
+static int compute_qdelta( VP8_COMP *cpi, double qstart, double qtarget )
+{
+    int i;
+    int start_index = cpi->worst_quality;
+    int target_index = cpi->worst_quality;
+    int retval = 0;
+
+    // Convert the average q value to an index.
+    for ( i = cpi->best_quality; i < cpi->worst_quality; i++ )
+    {
+        start_index = i;
+        if ( vp8_convert_qindex_to_q(i) >= qstart )
+            break;
+    }
+
+    // Convert the q target to an index
+    for ( i = cpi->best_quality; i < cpi->worst_quality; i++ )
+    {
+        target_index = i;
+        if ( vp8_convert_qindex_to_q(i) >= qtarget )
+            break;
+    }
+
+    return target_index - start_index;
+}
+
 //#if CONFIG_SEGFEATURES
 static void init_seg_features(VP8_COMP *cpi)
 {
@@ -422,7 +451,8 @@
     VP8_COMMON *cm = &cpi->common;
     MACROBLOCKD *xd = &cpi->mb.e_mbd;
 
-    int high_q = ((int)vp8_convert_qindex_to_q(cpi->ni_av_qi) > 32);
+    int high_q = (int)(cpi->avg_q > 32.0);
+    int qi_delta;
 
     // For now at least dont enable seg features alongside cyclic refresh.
     if ( cpi->cyclic_refresh_mode_enabled ||
@@ -471,7 +501,8 @@
             xd->update_mb_segmentation_map = 1;
             xd->update_mb_segmentation_data = 1;
 
-            set_segdata( xd, 1, SEG_LVL_ALT_Q, -(3+(cpi->ni_av_qi >> 3)) );
+            qi_delta = compute_qdelta( cpi, cpi->avg_q, (cpi->avg_q * 0.875) );
+            set_segdata( xd, 1, SEG_LVL_ALT_Q, (qi_delta - 2) );
             set_segdata( xd, 1, SEG_LVL_ALT_LF, -2 );
 
             enable_segfeature(xd, 1, SEG_LVL_ALT_Q);
@@ -495,7 +526,10 @@
                 xd->update_mb_segmentation_data = 1;
                 xd->mb_segement_abs_delta = SEGMENT_DELTADATA;
 
-                set_segdata( xd, 1, SEG_LVL_ALT_Q, 5 );
+                qi_delta = compute_qdelta( cpi, cpi->avg_q,
+                                           (cpi->avg_q * 1.125) );
+                set_segdata( xd, 1, SEG_LVL_ALT_Q, (qi_delta + 2) );
+                set_segdata( xd, 1, SEG_LVL_ALT_Q, 0 );
                 enable_segfeature(xd, 1, SEG_LVL_ALT_Q);
 
                 set_segdata( xd, 1, SEG_LVL_ALT_LF, -2 );
@@ -2242,6 +2276,8 @@
     cpi->ni_av_qi                     = cpi->oxcf.worst_allowed_q;
     cpi->ni_tot_qi                    = 0;
     cpi->ni_frames                   = 0;
+    cpi->tot_q = 0.0;
+    cpi->avg_q = vp8_convert_qindex_to_q( cpi->oxcf.worst_allowed_q );
     cpi->total_byte_count             = 0;
 
     cpi->drop_frame                  = 0;
@@ -4601,6 +4637,8 @@
     if ((cm->frame_type != KEY_FRAME) && !cm->refresh_golden_frame && !cm->refresh_alt_ref_frame)
     {
         cpi->ni_frames++;
+        cpi->tot_q += vp8_convert_qindex_to_q(Q);
+        cpi->avg_q = cpi->tot_q / (double)cpi->ni_frames;
 
         // Calculate the average Q for normal inter frames (not key or GFU
         // frames).
@@ -4732,7 +4770,7 @@
 
         if (cpi->twopass.total_left_stats->coded_error != 0.0)
             fprintf(f, "%10d %10d %10d %10d %10d %10d %10d"
-                       "%6.2f %6.2f %6.2f %6.2f %6.2f %6.2f"
+                       "%6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f"
                        "%6d %5d %5d %5d %8d %8.2f %10d %10.3f"
                        "%10.3f %8d\n",
                        cpi->common.current_video_frame, cpi->this_frame_target,
@@ -4749,6 +4787,7 @@
 #endif
                        vp8_convert_qindex_to_q(cpi->active_best_quality),
                        vp8_convert_qindex_to_q(cpi->active_worst_quality),
+                       cpi->avg_q,
                        vp8_convert_qindex_to_q(cpi->ni_av_qi),
                        vp8_convert_qindex_to_q(cpi->cq_target_quality),
                        cpi->zbin_over_quant,
@@ -4763,7 +4802,7 @@
                        cpi->tot_recode_hits);
         else
             fprintf(f, "%10d %10d %10d %10d %10d %10d %10d"
-                       "%6.2f %6.2f %6.2f %6.2f %6.2f %6.2f"
+                       "%6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f"
                        "%6d %5d %5d %5d %8d %8.2f %10d %10.3f"
                        "%8d\n",
                        cpi->common.current_video_frame,
@@ -4780,6 +4819,7 @@
 #endif
                        vp8_convert_qindex_to_q(cpi->active_best_quality),
                        vp8_convert_qindex_to_q(cpi->active_worst_quality),
+                       cpi->avg_q,
                        vp8_convert_qindex_to_q(cpi->ni_av_qi),
                        vp8_convert_qindex_to_q(cpi->cq_target_quality),
                        cpi->zbin_over_quant,
--- a/vp8/encoder/onyx_int.h
+++ b/vp8/encoder/onyx_int.h
@@ -391,6 +391,8 @@
     int ni_tot_qi;
     int ni_frames;
     int avg_frame_qindex;
+    double tot_q;
+    double avg_q;
 
     int zbin_over_quant;
     int zbin_mode_boost;
--- a/vp8/encoder/ratectrl.c
+++ b/vp8/encoder/ratectrl.c
@@ -125,12 +125,26 @@
 
 int vp8_gfboost_qadjust( int qindex )
 {
-    return (50.0 * pow(vp8_convert_qindex_to_q(qindex), 0.25) + 0.5);
+    int retval;
+    double q;
+
+    q = vp8_convert_qindex_to_q(qindex);
+    retval = (int)( ( 0.00000828 * q * q * q ) +
+                    ( -0.0055 * q * q ) +
+                    ( 1.32 * q ) + 79.3 );
+    return retval;
 }
 
 int kfboost_qadjust( int qindex )
 {
-    return (91.0 * pow(vp8_convert_qindex_to_q(qindex), 0.165) + 0.5);
+    int retval;
+    double q;
+
+    q = vp8_convert_qindex_to_q(qindex);
+    retval = (int)( ( 0.00000973 * q * q * q ) +
+                    ( -0.00613 * q * q ) +
+                    ( 1.316 * q ) + 121.2 );
+    return retval;
 }
 
 int vp8_bits_per_mb( FRAME_TYPE frame_type, int qindex  )
--- a/vp8/encoder/rdopt.c
+++ b/vp8/encoder/rdopt.c
@@ -253,7 +253,7 @@
 #if CONFIG_EXTEND_QRANGE
     q = (int)pow(vp8_dc_quant(QIndex,0)>>2, 1.25);
     q = q << 2;
-    cpi->RDMULT *= 16;
+    cpi->RDMULT = cpi->RDMULT << 4;
 #else
     q = (int)pow(vp8_dc_quant(QIndex,0), 1.25);
 #endif