[FFmpeg-cvslog] avcodec/ffv1: support adjusting the g vs r + b coefficient in the RCT

Michael Niedermayer git at videolan.org
Mon Dec 9 00:52:15 CET 2013


ffmpeg | branch: master | Michael Niedermayer <michaelni at gmx.at> | Sun Dec  8 22:09:50 2013 +0100| [7854d2d2515dc2a54c5f309100aeecf83cd14e97] | committer: Michael Niedermayer

avcodec/ffv1: support adjusting the g vs r + b coefficient in the RCT

about 1% better compression

Signed-off-by: Michael Niedermayer <michaelni at gmx.at>

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=7854d2d2515dc2a54c5f309100aeecf83cd14e97
---

 libavcodec/ffv1.h    |    1 +
 libavcodec/ffv1dec.c |   11 ++++++-
 libavcodec/ffv1enc.c |   79 ++++++++++++++++++++++++++++++++++++++++++++++----
 3 files changed, 85 insertions(+), 6 deletions(-)

diff --git a/libavcodec/ffv1.h b/libavcodec/ffv1.h
index bdc7b86..2c3e6e4 100644
--- a/libavcodec/ffv1.h
+++ b/libavcodec/ffv1.h
@@ -130,6 +130,7 @@ typedef struct FFV1Context {
     int slice_y;
     int slice_reset_contexts;
     int slice_coding_mode;
+    int slice_rct_y_coef;
 } FFV1Context;
 
 int ffv1_common_init(AVCodecContext *avctx);
diff --git a/libavcodec/ffv1dec.c b/libavcodec/ffv1dec.c
index 166bc25..6c01ebf 100644
--- a/libavcodec/ffv1dec.c
+++ b/libavcodec/ffv1dec.c
@@ -260,7 +260,7 @@ static void decode_rgb_frame(FFV1Context *s, uint8_t *src[3], int w, int h, int
             if (s->slice_coding_mode != 1) {
                 b -= offset;
                 r -= offset;
-                g -= (b + r) >> 2;
+                g -= ((b + r) * s->slice_rct_y_coef) >> 2;
                 b += g;
                 r += g;
             }
@@ -333,6 +333,13 @@ static int decode_slice_header(FFV1Context *f, FFV1Context *fs)
     if (fs->version > 3) {
         fs->slice_reset_contexts = get_rac(c, state);
         fs->slice_coding_mode = get_symbol(c, state, 0);
+        if (fs->slice_coding_mode != 1) {
+            fs->slice_rct_y_coef = get_symbol(c, state, 0);
+            if (fs->slice_rct_y_coef > 2U) {
+                av_log(f->avctx, AV_LOG_ERROR, "slice_rct_y_coef out of range\n");
+                return AVERROR_INVALIDDATA;
+            }
+        }
     }
     return 0;
 }
@@ -381,6 +388,8 @@ static int decode_slice(AVCodecContext *c, void *arg)
         }
     }
 
+    fs->slice_rct_y_coef = 1;
+
     if (f->version > 2) {
         if (ffv1_init_slice_state(f, fs) < 0)
             return AVERROR(ENOMEM);
diff --git a/libavcodec/ffv1enc.c b/libavcodec/ffv1enc.c
index 2c87d7a..4e2e0b3 100644
--- a/libavcodec/ffv1enc.c
+++ b/libavcodec/ffv1enc.c
@@ -441,7 +441,7 @@ static int encode_rgb_frame(FFV1Context *s, uint8_t *src[3], int w, int h, int s
             if (s->slice_coding_mode != 1) {
                 b -= g;
                 r -= g;
-                g += (b + r) >> 2;
+                g += ((b + r) * s->slice_rct_y_coef) >> 2;
                 b += offset;
                 r += offset;
             }
@@ -557,8 +557,10 @@ static int write_extradata(FFV1Context *f)
 
     put_symbol(c, state, f->version, 0);
     if (f->version > 2) {
-        if (f->version == 3)
+        if (f->version == 3) {
             f->micro_version = 4;
+        } else if (f->version == 4)
+            f->micro_version = 1;
         put_symbol(c, state, f->micro_version, 0);
     }
 
@@ -995,9 +997,71 @@ static void encode_slice_header(FFV1Context *f, FFV1Context *fs)
         if (fs->slice_coding_mode == 1)
             ffv1_clear_slice_state(f, fs);
         put_symbol(c, state, fs->slice_coding_mode, 0);
+        if (fs->slice_coding_mode != 1)
+            put_symbol(c, state, fs->slice_rct_y_coef, 0);
     }
 }
 
+static void choose_rct_params(FFV1Context *fs, uint8_t *src[3], const int stride[3], int w, int h)
+{
+    int stat[3] = {0};
+    int x, y, i, p, best;
+    int16_t *sample[3];
+    int lbd = fs->bits_per_raw_sample <= 8;
+
+    for (y = 0; y < h; y++) {
+        int lastr=0, lastg=0, lastb=0;
+        for (p = 0; p < 3; p++)
+            sample[p] = fs->sample_buffer + p*w;
+
+        for (x = 0; x < w; x++) {
+            int b, g, r;
+            if (lbd) {
+                unsigned v = *((uint32_t*)(src[0] + x*4 + stride[0]*y));
+                b =  v        & 0xFF;
+                g = (v >>  8) & 0xFF;
+                r = (v >> 16) & 0xFF;
+            } else {
+                b = *((uint16_t*)(src[0] + x*2 + stride[0]*y));
+                g = *((uint16_t*)(src[1] + x*2 + stride[1]*y));
+                r = *((uint16_t*)(src[2] + x*2 + stride[2]*y));
+            }
+
+            if (x && y) {
+                int ar = r - lastr;
+                int ag = g - lastg;
+                int ab = b - lastb;
+                int bg = ag - sample[0][x];
+                int bb = ab - sample[1][x];
+                int br = ar - sample[2][x];
+
+                br -= bg;
+                bb -= bg;
+
+                stat[0] += FFABS(bg);
+                stat[1] += FFABS(bg + ((br+bb)>>2));
+                stat[2] += FFABS(bg + ((br+bb)>>1));
+
+                sample[0][x] = ag;
+                sample[1][x] = ab;
+                sample[2][x] = ar;
+            }
+
+            lastr = r;
+            lastg = g;
+            lastb = b;
+        }
+    }
+
+    best = 0;
+    for (i=1; i<=2; i++) {
+        if (stat[i] < stat[best])
+            best = i;
+    }
+
+    fs->slice_rct_y_coef = best;
+}
+
 static int encode_slice(AVCodecContext *c, void *arg)
 {
     FFV1Context *fs  = *(void **)arg;
@@ -1010,8 +1074,16 @@ static int encode_slice(AVCodecContext *c, void *arg)
     const int ps     = av_pix_fmt_desc_get(c->pix_fmt)->comp[0].step_minus1 + 1;
     int ret;
     RangeCoder c_bak = fs->c;
+    uint8_t *planes[3] = {p->data[0] + ps*x + y*p->linesize[0],
+                          p->data[1] + ps*x + y*p->linesize[1],
+                          p->data[2] + ps*x + y*p->linesize[2]};
 
     fs->slice_coding_mode = 0;
+    if (f->version > 3) {
+        choose_rct_params(fs, planes, p->linesize, width, height);
+    } else {
+        fs->slice_rct_y_coef = 1;
+    }
 
 retry:
     if (c->coded_frame->key_frame)
@@ -1043,9 +1115,6 @@ retry:
         if (fs->transparency)
             ret |= encode_plane(fs, p->data[3] + ps*x + y*p->linesize[3], width, height, p->linesize[3], 2);
     } else {
-        uint8_t *planes[3] = {p->data[0] + ps*x + y*p->linesize[0],
-                              p->data[1] + ps*x + y*p->linesize[1],
-                              p->data[2] + ps*x + y*p->linesize[2]};
         ret = encode_rgb_frame(fs, planes, width, height, p->linesize);
     }
     emms_c();



More information about the ffmpeg-cvslog mailing list