aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Niedermayer <michaelni@gmx.at>2013-12-08 22:09:50 +0100
committerMichael Niedermayer <michaelni@gmx.at>2013-12-09 00:37:38 +0100
commit7854d2d2515dc2a54c5f309100aeecf83cd14e97 (patch)
tree5c5b403b90264c20b117e321e9cbaf390b263f3b
parent1b264607883e7d52a3941cd9c192e3045096acc9 (diff)
downloadffmpeg-7854d2d2515dc2a54c5f309100aeecf83cd14e97.tar.gz
avcodec/ffv1: support adjusting the g vs r + b coefficient in the RCT
about 1% better compression Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
-rw-r--r--libavcodec/ffv1.h1
-rw-r--r--libavcodec/ffv1dec.c11
-rw-r--r--libavcodec/ffv1enc.c79
3 files changed, 85 insertions, 6 deletions
diff --git a/libavcodec/ffv1.h b/libavcodec/ffv1.h
index bdc7b862d0..2c3e6e4c98 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 166bc259f0..6c01ebf15f 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 2c87d7ae86..4e2e0b3da9 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();