mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-01-08 13:22:53 +02:00
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>
This commit is contained in:
parent
1b26460788
commit
7854d2d251
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user