[FFmpeg-devel] [PATCH 6/7] vc2enc: redistribute leftover bytes

Rostislav Pehlivanov atomnuker at gmail.com
Sat Feb 27 20:29:07 CET 2016


This commit redistributes the leftover bytes amongst the top 150 slices
in terms of size (in the hopes that they'll be the ones bitrate starved).

A more perceptual method would probably need to cut bits off from slices
which don't need much, but that'll be implemented later.

The cached quantizer bit cost helped to keep this search from barely
taking CPU time.

Signed-off-by: Rostislav Pehlivanov <atomnuker at gmail.com>
---
 libavcodec/vc2enc.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 51 insertions(+), 1 deletion(-)

diff --git a/libavcodec/vc2enc.c b/libavcodec/vc2enc.c
index 600a8ac..df71953 100644
--- a/libavcodec/vc2enc.c
+++ b/libavcodec/vc2enc.c
@@ -39,6 +39,9 @@
 /* Per slice quantization bit cost cache */
 #define SLICE_CACHED_QUANTIZERS 30
 
+/* Decides the cutoff point in # of slices to distribute the leftover bytes */
+#define SLICE_REDIST_TOTAL 150
+
 enum VC2_QM {
     VC2_QM_DEF = 0,
     VC2_QM_COL,
@@ -780,9 +783,13 @@ static int encode_hq_slice(AVCodecContext *avctx, void *arg)
 static int encode_slices(VC2EncContext *s)
 {
     uint8_t *buf;
-    int slice_x, slice_y, skip = 0;
+    int i, slice_x, slice_y, skip = 0;
+    int bytes_left = 0;
     SliceArgs *enc_args = s->slice_args;
 
+    int bytes_top[SLICE_REDIST_TOTAL] = {0};
+    SliceArgs *top_loc[SLICE_REDIST_TOTAL] = {NULL};
+
     avpriv_align_put_bits(&s->pb);
     flush_put_bits(&s->pb);
     buf = put_bits_ptr(&s->pb);
@@ -790,6 +797,47 @@ static int encode_slices(VC2EncContext *s)
     for (slice_y = 0; slice_y < s->num_y; slice_y++) {
         for (slice_x = 0; slice_x < s->num_x; slice_x++) {
             SliceArgs *args = &enc_args[s->num_x*slice_y + slice_x];
+            bytes_left += args->bytes_left;
+            for (i = 0; i < FFMIN(SLICE_REDIST_TOTAL, s->num_x*s->num_y); i++) {
+                if (args->bytes > bytes_top[i]) {
+                    bytes_top[i] = args->bytes;
+                    top_loc[i] = args;
+                    break;
+                }
+            }
+        }
+    }
+
+    while (1) {
+        int distributed = 0;
+        for (i = 0; i < FFMIN(SLICE_REDIST_TOTAL, s->num_x*s->num_y); i++) {
+            SliceArgs *args;
+            int bits, bytes, diff, prev_bytes, new_idx;
+            if (bytes_left <= 0)
+                break;
+            if (!top_loc[i] || !top_loc[i]->quant_idx)
+                break;
+            args = top_loc[i];
+            prev_bytes = args->bytes;
+            new_idx = av_clip(args->quant_idx - 1, 0, s->q_ceil);
+            bits = count_hq_slice(s, args->cache, &args->cached_results,
+                                  args->x, args->y, new_idx);
+            bytes = FFALIGN((bits >> 3), s->size_scaler) + 4 + s->prefix_bytes;
+            diff = bytes - prev_bytes;
+            if ((bytes_left - diff) >= 0) {
+                args->quant_idx = new_idx;
+                args->bytes = bytes;
+                bytes_left -= diff;
+                distributed++;
+            }
+        }
+        if (!distributed)
+            break;
+    }
+
+    for (slice_y = 0; slice_y < s->num_y; slice_y++) {
+        for (slice_x = 0; slice_x < s->num_x; slice_x++) {
+            SliceArgs *args = &enc_args[s->num_x*slice_y + slice_x];
             init_put_bits(&args->pb, buf + skip, args->bytes);
             s->q_avg = (s->q_avg + args->quant_idx)/2;
             skip += args->bytes;
@@ -1042,6 +1090,8 @@ static av_cold int vc2_encode_init(AVCodecContext *avctx)
     s->strict_compliance = 1;
 
     s->q_avg = 0;
+    s->slice_max_bytes = 0;
+    s->slice_min_bytes = 0;
 
     /* Mark unknown as progressive */
     s->interlaced = !((avctx->field_order == AV_FIELD_UNKNOWN) ||
-- 
2.7.0



More information about the ffmpeg-devel mailing list