]> granicus.if.org Git - libvpx/commitdiff
Rate control on static scenes plus Y2dc delta Q fix.
authorPaul Wilkins <paulwilkins@google.com>
Wed, 11 Jan 2012 14:05:57 +0000 (14:05 +0000)
committerPaul Wilkins <paulwilkins@google.com>
Tue, 17 Jan 2012 17:42:46 +0000 (17:42 +0000)
A problem can arise on static clips with force key frames where
attempts to avoid popping lead to a progressive reduction in key
frame Q that ultimately may lead to unexpected overspend against
the  rate target.

The changes in this patch help to insure that in such clips the
quality of the key frames across the clip is more uniform (rather
than starting bad and getting better - especially at low target rates).

This patch also includes a fix that removes a delta on the Y2DC
when the baseline q index < 4 as this is no longer needed.

There is also a fix to try and prevent repeat single step Q adjustment in
the recode loop leading to lots of recodes, especially where the use
of forced skips as part of segmentation has made the impact of Q on
the number of bits generated much smaller.

Patch 2: Amend "last_boosted_qindex" calculation for arf overlay frames.

Change-Id: Ia1feeb79ed8ed014e4239994fcf5e58e68fd9459

vp8/encoder/firstpass.c
vp8/encoder/mbgraph.c
vp8/encoder/onyx_if.c
vp8/encoder/onyx_int.h
vp8/encoder/quantize.c
vp8/encoder/ratectrl.c

index 901404617edd886be83461bf2c20352958c45b61..19ae70684f9cc5444aa1a22389f99961e73c670f 100644 (file)
@@ -3032,10 +3032,26 @@ static void find_next_key_frame(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame)
 
         // We do three calculations for kf size.
         // The first is based on the error score for the whole kf group.
-        // The second (optionaly) on the key frames own error if this is smaller than the average for the group.
-        // The final one insures that the frame receives at least the allocation it would have received based on its own error score vs the error score remaining
-
-        allocation_chunks = ((cpi->twopass.frames_to_key - 1) * 100) + kf_boost;           // cpi->twopass.frames_to_key-1 because key frame itself is taken care of by kf_boost
+        // The second (optionaly) on the key frames own error if this is
+        // smaller than the average for the group.
+        // The final one insures that the frame receives at least the
+        // allocation it would have received based on its own error score vs
+        // the error score remaining
+        // Special case if the sequence appears almost totaly static
+        // as measured by the decay accumulator. In this case we want to
+        // spend almost all of the bits on the key frame.
+        // cpi->twopass.frames_to_key-1 because key frame itself is taken
+        // care of by kf_boost.
+        if ( decay_accumulator >= 0.99 )
+        {
+            allocation_chunks =
+                ((cpi->twopass.frames_to_key - 1) * 10) + kf_boost;
+        }
+        else
+        {
+            allocation_chunks =
+                ((cpi->twopass.frames_to_key - 1) * 100) + kf_boost;
+        }
 
         // Normalize Altboost and allocations chunck down to prevent overflow
         while (kf_boost > 1000)
index ad40c9e33b20666a25c84be677720022ffd543bc..4f9ba125bf8d2510adb723be8b13c59a25cd5b37 100644 (file)
@@ -477,12 +477,16 @@ void separate_arf_mbs
     //if ( ncnt[1] && (ncnt[0] / ncnt[1] < 10) )
     if ( 1 )
     {
-        cpi->mbgraph_use_arf_segmentation = ncnt[1];
+        // Note % of blocks that are marked as static
+        cpi->static_mb_pct =
+            (ncnt[1] * 100) / cm->MBs;
+
         vp8_enable_segmentation((VP8_PTR) cpi);
     }
     else
     {
-        cpi->mbgraph_use_arf_segmentation = 0;
+        cpi->static_mb_pct = 0;
+
         vp8_disable_segmentation((VP8_PTR) cpi);
     }
 
index b60d996a8dbfca714d7f7881596f78137eac25ee..25b56691d5fd14724743566bb72850a1e9886c89 100644 (file)
@@ -492,6 +492,7 @@ static void init_seg_features(VP8_COMP *cpi)
         vpx_memset( cpi->segmentation_map, 0, (cm->mb_rows * cm->mb_cols));
         xd->update_mb_segmentation_map = 0;
         xd->update_mb_segmentation_data = 0;
+        cpi->static_mb_pct = 0;
 
         // Disable segmentation
         vp8_disable_segmentation((VP8_PTR)cpi);
@@ -507,6 +508,7 @@ static void init_seg_features(VP8_COMP *cpi)
         vpx_memset( cpi->segmentation_map, 0, (cm->mb_rows * cm->mb_cols));
         xd->update_mb_segmentation_map = 0;
         xd->update_mb_segmentation_data = 0;
+        cpi->static_mb_pct = 0;
 
         // Disable segmentation and individual segment features by default
         vp8_disable_segmentation((VP8_PTR)cpi);
@@ -557,7 +559,7 @@ static void init_seg_features(VP8_COMP *cpi)
                 set_segdata( xd, 1, SEG_LVL_ALT_LF, -2 );
                 enable_segfeature(xd, 1, SEG_LVL_ALT_LF);
 
-                if ( high_q )
+                if ( high_q || (cpi->static_mb_pct == 100) )
                 {
                     set_segref(xd, 1, ALTREF_FRAME);
                     enable_segfeature(xd, 1, SEG_LVL_REF_FRAME);
@@ -1973,6 +1975,8 @@ static void init_config(VP8_PTR ptr, VP8_CONFIG *oxcf)
     cpi->total_actual_bits            = 0;
     cpi->total_target_vs_actual       = 0;
 
+    cpi->static_mb_pct = 0;
+
 #if VP8_TEMPORAL_ALT_REF
     {
         int i;
@@ -2233,6 +2237,7 @@ void vp8_change_config(VP8_PTR ptr, VP8_CONFIG *oxcf)
     {
         cpi->last_q[0] = cpi->oxcf.fixed_q;
         cpi->last_q[1] = cpi->oxcf.fixed_q;
+        cpi->last_boosted_qindex = cpi->oxcf.fixed_q;
     }
 
     cpi->Speed = cpi->oxcf.cpu_used;
@@ -2694,6 +2699,9 @@ void vp8_remove_compressor(VP8_PTR *ptr)
                 fprintf(f, "%7.3f\t%7.3f\t%7.3f\t%7.3f\t%7.3f\t%7.3f\t%8.0f\n",
                         dr, cpi->total / cpi->count, total_psnr, cpi->totalp / cpi->count, total_psnr2, total_ssim,
                         total_encode_time);
+//                fprintf(f, "%7.3f\t%7.3f\t%7.3f\t%7.3f\t%7.3f\t%7.3f\t%8.0f %10ld\n",
+//                        dr, cpi->total / cpi->count, total_psnr, cpi->totalp / cpi->count, total_psnr2, total_ssim,
+//                        total_encode_time, cpi->tot_recode_hits);
             }
 
             if (cpi->b_calculate_ssimg)
@@ -2702,6 +2710,9 @@ void vp8_remove_compressor(VP8_PTR *ptr)
                 fprintf(f, "%7.3f\t%6.4f\t%6.4f\t%6.4f\t%6.4f\t%8.0f\n", dr,
                         cpi->total_ssimg_y / cpi->count, cpi->total_ssimg_u / cpi->count,
                         cpi->total_ssimg_v / cpi->count, cpi->total_ssimg_all / cpi->count, total_encode_time);
+//                fprintf(f, "%7.3f\t%6.4f\t%6.4f\t%6.4f\t%6.4f\t%8.0f  %10ld\n", dr,
+//                        cpi->total_ssimg_y / cpi->count, cpi->total_ssimg_u / cpi->count,
+//                        cpi->total_ssimg_v / cpi->count, cpi->total_ssimg_all / cpi->count, total_encode_time, cpi->tot_recode_hits);
             }
 
             fclose(f);
@@ -4134,10 +4145,15 @@ static void encode_frame_to_data_rate
                 // based on the ambient Q to reduce the risk of popping
                 if ( cpi->this_key_frame_forced )
                 {
-                    if ( cpi->active_best_quality > cpi->avg_frame_qindex * 7/8)
-                        cpi->active_best_quality = cpi->avg_frame_qindex * 7/8;
-                    else if ( cpi->active_best_quality < cpi->avg_frame_qindex >> 2 )
-                        cpi->active_best_quality = cpi->avg_frame_qindex >> 2;
+                    int delta_qindex;
+                    int qindex = cpi->last_boosted_qindex;
+
+                    delta_qindex = compute_qdelta( cpi, qindex,
+                                                   (qindex * 0.75) );
+
+                    cpi->active_best_quality = qindex + delta_qindex;
+                    if (cpi->active_best_quality < cpi->best_quality)
+                        cpi->active_best_quality = cpi->best_quality;
                 }
             }
             // One pass more conservative
@@ -4248,8 +4264,16 @@ static void encode_frame_to_data_rate
     if ( cpi->active_worst_quality < cpi->active_best_quality )
         cpi->active_worst_quality = cpi->active_best_quality;
 
-    // Determine initial Q to try
-    Q = vp8_regulate_q(cpi, cpi->this_frame_target);
+    // Specuial case code to try and match quality with forced key frames
+    if ( (cm->frame_type == KEY_FRAME) && cpi->this_key_frame_forced )
+    {
+        Q = cpi->last_boosted_qindex;
+    }
+    else
+    {
+        // Determine initial Q to try
+        Q = vp8_regulate_q(cpi, cpi->this_frame_target);
+    }
     last_zbin_oq = cpi->zbin_over_quant;
 
     // Set highest allowed value for Zbin over quant
@@ -4527,23 +4551,32 @@ static void encode_frame_to_data_rate
                                          &cm->yv12_fb[cm->new_fb_idx],
                                          IF_RTCD(&cpi->rtcd.variance));
 
+            int high_err_target = cpi->ambient_err;
+            int low_err_target = ((cpi->ambient_err * 3) >> 2);
+
             // The key frame is not good enough
-            if ( kf_err > ((cpi->ambient_err * 7) >> 3) )
+            if ( (kf_err > high_err_target) &&
+                 (cpi->projected_frame_size <= frame_over_shoot_limit) )
             {
                 // Lower q_high
                 q_high = (Q > q_low) ? (Q - 1) : q_low;
 
                 // Adjust Q
-                Q = (q_high + q_low) >> 1;
+                Q = (Q * high_err_target) / kf_err;
+                if ( Q < ((q_high + q_low) >> 1))
+                    Q = (q_high + q_low) >> 1;
             }
             // The key frame is much better than the previous frame
-            else if ( kf_err < (cpi->ambient_err >> 1) )
+            else if ( (kf_err < low_err_target) &&
+                      (cpi->projected_frame_size >= frame_under_shoot_limit) )
             {
                 // Raise q_low
                 q_low = (Q < q_high) ? (Q + 1) : q_high;
 
                 // Adjust Q
-                Q = (q_high + q_low + 1) >> 1;
+                Q = (Q * low_err_target) / kf_err;
+                if ( Q > ((q_high + q_low + 1) >> 1))
+                    Q = (q_high + q_low + 1) >> 1;
             }
 
             // Clamp Q to upper and lower limits:
@@ -4569,14 +4602,12 @@ static void encode_frame_to_data_rate
             // Frame is too large
             if (cpi->projected_frame_size > cpi->this_frame_target)
             {
-                //if ( cpi->zbin_over_quant == 0 )
                 q_low = (Q < q_high) ? (Q + 1) : q_high; // Raise Qlow as to at least the current value
 
                 if (cpi->zbin_over_quant > 0)            // If we are using over quant do the same for zbin_oq_low
                     zbin_oq_low = (cpi->zbin_over_quant < zbin_oq_high) ? (cpi->zbin_over_quant + 1) : zbin_oq_high;
 
-                //if ( undershoot_seen || (Q == MAXQ) )
-                if (undershoot_seen)
+                if ( undershoot_seen || (loop_count > 1) )
                 {
                     // Update rate_correction_factor unless cpi->active_worst_quality has changed.
                     if (!active_worst_qchanged)
@@ -4619,7 +4650,7 @@ static void encode_frame_to_data_rate
                 else                                    // else lower zbin_oq_high
                     zbin_oq_high = (cpi->zbin_over_quant > zbin_oq_low) ? (cpi->zbin_over_quant - 1) : zbin_oq_low;
 
-                if (overshoot_seen)
+                if ( overshoot_seen || (loop_count > 1) )
                 {
                     // Update rate_correction_factor unless cpi->active_worst_quality has changed.
                     if (!active_worst_qchanged)
@@ -4845,6 +4876,20 @@ static void encode_frame_to_data_rate
 
     cpi->last_q[cm->frame_type] = cm->base_qindex;
 
+    // Keep record of last boosted (KF/KF/ARF) Q value.
+    // If the current frame is coded at a lower Q then we also update it.
+    // If all mbs in this group are skipped only update if the Q value is
+    // better than that already stored.
+    // This is used to help set quality in forced key frames to reduce popping
+    if ( (cm->base_qindex < cpi->last_boosted_qindex) ||
+         ( (cpi->static_mb_pct < 100) &&
+           ( (cm->frame_type == KEY_FRAME) ||
+             cm->refresh_alt_ref_frame ||
+             (cm->refresh_golden_frame && !cpi->is_src_frame_alt_ref) ) ) )
+    {
+        cpi->last_boosted_qindex = cm->base_qindex;
+    }
+
     if (cm->frame_type == KEY_FRAME)
     {
         vp8_adjust_key_frame_context(cpi);
@@ -4991,7 +5036,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"
+                       "%7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f"
                        "%6d %5d %5d %5d %8d %8.2f %10d %10.3f"
                        "%10.3f %8d\n",
                        cpi->common.current_video_frame, cpi->this_frame_target,
@@ -5023,7 +5068,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"
+                       "%7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f"
                        "%6d %5d %5d %5d %8d %8.2f %10d %10.3f"
                        "%8d\n",
                        cpi->common.current_video_frame,
index f47a4640803797b3cbf000fd43d78e5490acc53e..002f30a9788480b19053cf82632aac1a8d5390ec 100644 (file)
@@ -383,6 +383,7 @@ typedef struct VP8_COMP
     int this_frame_target;
     int projected_frame_size;
     int last_q[2];                   // Separate values for Intra/Inter
+    int last_boosted_qindex;         // Last boosted GF/KF/ARF q
 
     double rate_correction_factor;
     double key_frame_rate_correction_factor;
@@ -483,11 +484,7 @@ typedef struct VP8_COMP
 #endif
     MBGRAPH_FRAME_STATS mbgraph_stats[MAX_LAG_BUFFERS];
     int mbgraph_n_frames;             // number of frames filled in the above
-    int mbgraph_use_arf_segmentation; // set if part of an ARF is considered to be a
-                                      // poor predictor, and thus coeffs are skipped
-                                      // or coded at a higher Q using MB-segmentation
-                                      // this value is the number of MBs that are
-                                      // poor predictors (> 0 and < common.MBs)
+    int static_mb_pct;                // % forced skip mbs by segmentation
 
     int decimation_factor;
     int decimation_count;
index 68b10cc4c2fa41a0bff5e540827f8eaf7b4337a9..d7316f74e086bdfa5a2c80bf671ac3352a203d7d 100644 (file)
@@ -1271,30 +1271,18 @@ void vp8cx_frame_init_quantizer(VP8_COMP *cpi)
 void vp8_set_quantizer(struct VP8_COMP *cpi, int Q)
 {
     VP8_COMMON *cm = &cpi->common;
-    int update = 0;
-    int new_delta_q;
-    cm->base_qindex = Q;
-
-    /* if any of the delta_q values are changing update flag has to be set */
-    /* currently only y2dc_delta_q may change */
 
+    // if any of the delta_q values are changing update flag will
+    // have to be set.
     cm->y1dc_delta_q = 0;
     cm->y2ac_delta_q = 0;
     cm->uvdc_delta_q = 0;
     cm->uvac_delta_q = 0;
+    cm->y2dc_delta_q = 0;
 
-    if (Q < 4)
-    {
-        new_delta_q = 4-Q;
-    }
-    else
-        new_delta_q = 0;
-
-    update |= cm->y2dc_delta_q != new_delta_q;
-    cm->y2dc_delta_q = new_delta_q;
-
-    /* quantizer has to be reinitialized for any delta_q changes */
-    if(update)
-        vp8cx_init_quantizer(cpi);
+    // quantizer has to be reinitialized if any delta_q changes.
+    // As there are not any here for now this is inactive code.
+    //if(update)
+    //    vp8cx_init_quantizer(cpi);
 }
 
index d2e680f89dfe353f359a2dd059e7f97c6c36fd4f..fd3f8d7b2fe23bf7d9af4b0ce7e1d50da1c9bf41 100644 (file)
@@ -24,7 +24,7 @@
 #include "encodemv.h"
 
 
-#define MIN_BPB_FACTOR          0.01
+#define MIN_BPB_FACTOR          0.005
 #define MAX_BPB_FACTOR          50
 
 extern const MB_PREDICTION_MODE vp8_mode_order[MAX_MODES];
@@ -1477,6 +1477,14 @@ void vp8_compute_frame_size_bounds(VP8_COMP *cpi, int *frame_under_shoot_limit,
                 }
             }
         }
+
+        // For very small rate targets where the fractional adjustment
+        // (eg * 7/8) may be tiny make sure there is at least a minimum
+        // range.
+        *frame_over_shoot_limit += 200;
+        *frame_under_shoot_limit -= 200;
+        if ( *frame_under_shoot_limit < 0 )
+            *frame_under_shoot_limit = 0;
     }
 }