ffv1.4: use 2 coefficients for calculating the Y plane in the RCT

0-0.7% improved compression

Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
pull/51/head
Michael Niedermayer 11 years ago
parent 2bdda9a15c
commit 0e575c24d6
  1. 3
      libavcodec/ffv1.h
  2. 10
      libavcodec/ffv1dec.c
  3. 46
      libavcodec/ffv1enc.c

@ -130,7 +130,8 @@ typedef struct FFV1Context {
int slice_y; int slice_y;
int slice_reset_contexts; int slice_reset_contexts;
int slice_coding_mode; int slice_coding_mode;
int slice_rct_y_coef; int slice_rct_by_coef;
int slice_rct_ry_coef;
} FFV1Context; } FFV1Context;
int ffv1_common_init(AVCodecContext *avctx); int ffv1_common_init(AVCodecContext *avctx);

@ -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) { if (s->slice_coding_mode != 1) {
b -= offset; b -= offset;
r -= offset; r -= offset;
g -= ((b + r) * s->slice_rct_y_coef) >> 2; g -= (b * s->slice_rct_by_coef + r * s->slice_rct_ry_coef) >> 2;
b += g; b += g;
r += g; r += g;
} }
@ -334,8 +334,9 @@ static int decode_slice_header(FFV1Context *f, FFV1Context *fs)
fs->slice_reset_contexts = get_rac(c, state); fs->slice_reset_contexts = get_rac(c, state);
fs->slice_coding_mode = get_symbol(c, state, 0); fs->slice_coding_mode = get_symbol(c, state, 0);
if (fs->slice_coding_mode != 1) { if (fs->slice_coding_mode != 1) {
fs->slice_rct_y_coef = get_symbol(c, state, 0); fs->slice_rct_by_coef = get_symbol(c, state, 0);
if (fs->slice_rct_y_coef > 2U) { fs->slice_rct_ry_coef = get_symbol(c, state, 0);
if ((uint64_t)fs->slice_rct_by_coef + (uint64_t)fs->slice_rct_ry_coef > 4) {
av_log(f->avctx, AV_LOG_ERROR, "slice_rct_y_coef out of range\n"); av_log(f->avctx, AV_LOG_ERROR, "slice_rct_y_coef out of range\n");
return AVERROR_INVALIDDATA; return AVERROR_INVALIDDATA;
} }
@ -388,7 +389,8 @@ static int decode_slice(AVCodecContext *c, void *arg)
} }
} }
fs->slice_rct_y_coef = 1; fs->slice_rct_by_coef = 1;
fs->slice_rct_ry_coef = 1;
if (f->version > 2) { if (f->version > 2) {
if (ffv1_init_slice_state(f, fs) < 0) if (ffv1_init_slice_state(f, fs) < 0)

@ -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) { if (s->slice_coding_mode != 1) {
b -= g; b -= g;
r -= g; r -= g;
g += ((b + r) * s->slice_rct_y_coef) >> 2; g += (b * s->slice_rct_by_coef + r * s->slice_rct_ry_coef) >> 2;
b += offset; b += offset;
r += offset; r += offset;
} }
@ -560,7 +560,7 @@ static int write_extradata(FFV1Context *f)
if (f->version == 3) { if (f->version == 3) {
f->micro_version = 4; f->micro_version = 4;
} else if (f->version == 4) } else if (f->version == 4)
f->micro_version = 1; f->micro_version = 2;
put_symbol(c, state, f->micro_version, 0); put_symbol(c, state, f->micro_version, 0);
} }
@ -999,14 +999,36 @@ static void encode_slice_header(FFV1Context *f, FFV1Context *fs)
if (fs->slice_coding_mode == 1) if (fs->slice_coding_mode == 1)
ffv1_clear_slice_state(f, fs); ffv1_clear_slice_state(f, fs);
put_symbol(c, state, fs->slice_coding_mode, 0); put_symbol(c, state, fs->slice_coding_mode, 0);
if (fs->slice_coding_mode != 1) if (fs->slice_coding_mode != 1) {
put_symbol(c, state, fs->slice_rct_y_coef, 0); put_symbol(c, state, fs->slice_rct_by_coef, 0);
put_symbol(c, state, fs->slice_rct_ry_coef, 0);
}
} }
} }
static void choose_rct_params(FFV1Context *fs, uint8_t *src[3], const int stride[3], int w, int h) static void choose_rct_params(FFV1Context *fs, uint8_t *src[3], const int stride[3], int w, int h)
{ {
int stat[3] = {0}; #define NB_Y_COEFF 15
static const int rct_y_coeff[15][2] = {
{0, 0}, // 4G
{1, 1}, // R + 2G + B
{2, 2}, // 2R + 2B
{0, 2}, // 2G + 2B
{2, 0}, // 2R + 2G
{4, 0}, // 4R
{0, 4}, // 4B
{0, 3}, // 1G + 3B
{3, 0}, // 3R + 1G
{3, 1}, // 3R + B
{1, 3}, // R + 3B
{1, 2}, // R + G + 2B
{2, 1}, // 2R + G + B
{0, 1}, // 3G + B
{1, 0}, // R + 3G
};
int stat[NB_Y_COEFF] = {0};
int x, y, i, p, best; int x, y, i, p, best;
int16_t *sample[3]; int16_t *sample[3];
int lbd = fs->bits_per_raw_sample <= 8; int lbd = fs->bits_per_raw_sample <= 8;
@ -1041,9 +1063,9 @@ static void choose_rct_params(FFV1Context *fs, uint8_t *src[3], const int stride
br -= bg; br -= bg;
bb -= bg; bb -= bg;
stat[0] += FFABS(bg); for (i = 0; i<NB_Y_COEFF; i++) {
stat[1] += FFABS(bg + ((br+bb)>>2)); stat[i] += FFABS(bg + ((br*rct_y_coeff[i][0] + bb*rct_y_coeff[i][1])>>2));
stat[2] += FFABS(bg + ((br+bb)>>1)); }
} }
sample[0][x] = ag; sample[0][x] = ag;
@ -1057,12 +1079,13 @@ static void choose_rct_params(FFV1Context *fs, uint8_t *src[3], const int stride
} }
best = 0; best = 0;
for (i=1; i<=2; i++) { for (i=1; i<NB_Y_COEFF; i++) {
if (stat[i] < stat[best]) if (stat[i] < stat[best])
best = i; best = i;
} }
fs->slice_rct_y_coef = best; fs->slice_rct_by_coef = rct_y_coeff[best][1];
fs->slice_rct_ry_coef = rct_y_coeff[best][0];
} }
static int encode_slice(AVCodecContext *c, void *arg) static int encode_slice(AVCodecContext *c, void *arg)
@ -1085,7 +1108,8 @@ static int encode_slice(AVCodecContext *c, void *arg)
if (f->version > 3) { if (f->version > 3) {
choose_rct_params(fs, planes, p->linesize, width, height); choose_rct_params(fs, planes, p->linesize, width, height);
} else { } else {
fs->slice_rct_y_coef = 1; fs->slice_rct_by_coef = 1;
fs->slice_rct_ry_coef = 1;
} }
retry: retry:

Loading…
Cancel
Save