]> granicus.if.org Git - libvpx/commitdiff
Some further QIndex issues with extended Q
authorPaul Wilkins <paulwilkins@google.com>
Tue, 6 Dec 2011 14:48:52 +0000 (14:48 +0000)
committerPaul Wilkins <paulwilkins@google.com>
Tue, 6 Dec 2011 15:43:17 +0000 (15:43 +0000)
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

vp8/encoder/firstpass.c
vp8/encoder/onyx_if.c
vp8/encoder/onyx_int.h
vp8/encoder/ratectrl.c
vp8/encoder/rdopt.c

index bdddc2219498f29d39e85be5ff2b2196f05a04f0..3295cea228a2671773c28a7fcda6443d519615f5 100644 (file)
@@ -898,7 +898,7 @@ static double calc_correction_factor( double err_per_mb,
     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 @@ static double calc_correction_factor( double err_per_mb,
 // 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 @@ static int estimate_max_q(VP8_COMP *cpi,
 
         // 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 @@ static int estimate_max_q(VP8_COMP *cpi,
                   ((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 @@ static int estimate_cq( VP8_COMP *cpi,
 
         // 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 @@ static int estimate_q(VP8_COMP *cpi, double section_err, int section_target_band
 
         // 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 @@ static void assign_std_frame_bits(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame)
     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 @@ void vp8_second_pass(VP8_COMP *cpi)
                     (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 @@ void vp8_second_pass(VP8_COMP *cpi)
                     (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 --;
index 4a6b7617dd3384127293ca05e7e33f8fc64f5d63..126a2db5e3746a82db0769ec2c94ce8db96cef03 100644 (file)
@@ -416,13 +416,43 @@ static void segmentation_test_function(VP8_PTR ptr)
 
 }
 
+// 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)
 {
     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 @@ static void init_seg_features(VP8_COMP *cpi)
             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 @@ static void init_seg_features(VP8_COMP *cpi)
                 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 @@ VP8_PTR vp8_create_compressor(VP8_CONFIG *oxcf)
     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 @@ static void encode_frame_to_data_rate
     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 @@ static void encode_frame_to_data_rate
 
         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 @@ static void encode_frame_to_data_rate
 #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 @@ static void encode_frame_to_data_rate
                        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 @@ static void encode_frame_to_data_rate
 #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,
index 160f22d05c0552455583f4739fd8c9b184b293ae..38025cad5c83d7b73f1c7d1bba5a2f633d9e9605 100644 (file)
@@ -391,6 +391,8 @@ typedef struct VP8_COMP
     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;
index de6ccaf0f7a010fbbea0192c681990cdb596fc20..2ab16ed11475e173708a935e6c8864e07505b99c 100644 (file)
@@ -125,12 +125,26 @@ double vp8_convert_qindex_to_q( int qindex )
 
 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  )
index 00a39584572e6d7a41ec73d5135217db13f7f6fd..8be284965f9930a75980b5b2b9fd7b77c1d43c05 100644 (file)
@@ -253,7 +253,7 @@ void vp8_initialize_rd_consts(VP8_COMP *cpi, int QIndex)
 #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