mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-04-14 00:58:38 +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_y;
|
||||||
int slice_reset_contexts;
|
int slice_reset_contexts;
|
||||||
int slice_coding_mode;
|
int slice_coding_mode;
|
||||||
|
int slice_rct_y_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) >> 2;
|
g -= ((b + r) * s->slice_rct_y_coef) >> 2;
|
||||||
b += g;
|
b += g;
|
||||||
r += g;
|
r += g;
|
||||||
}
|
}
|
||||||
@ -333,6 +333,13 @@ static int decode_slice_header(FFV1Context *f, FFV1Context *fs)
|
|||||||
if (fs->version > 3) {
|
if (fs->version > 3) {
|
||||||
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) {
|
||||||
|
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;
|
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 (f->version > 2) {
|
||||||
if (ffv1_init_slice_state(f, fs) < 0)
|
if (ffv1_init_slice_state(f, fs) < 0)
|
||||||
return AVERROR(ENOMEM);
|
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) {
|
if (s->slice_coding_mode != 1) {
|
||||||
b -= g;
|
b -= g;
|
||||||
r -= g;
|
r -= g;
|
||||||
g += (b + r) >> 2;
|
g += ((b + r) * s->slice_rct_y_coef) >> 2;
|
||||||
b += offset;
|
b += offset;
|
||||||
r += offset;
|
r += offset;
|
||||||
}
|
}
|
||||||
@ -557,8 +557,10 @@ static int write_extradata(FFV1Context *f)
|
|||||||
|
|
||||||
put_symbol(c, state, f->version, 0);
|
put_symbol(c, state, f->version, 0);
|
||||||
if (f->version > 2) {
|
if (f->version > 2) {
|
||||||
if (f->version == 3)
|
if (f->version == 3) {
|
||||||
f->micro_version = 4;
|
f->micro_version = 4;
|
||||||
|
} else if (f->version == 4)
|
||||||
|
f->micro_version = 1;
|
||||||
put_symbol(c, state, f->micro_version, 0);
|
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)
|
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)
|
||||||
|
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)
|
static int encode_slice(AVCodecContext *c, void *arg)
|
||||||
{
|
{
|
||||||
FFV1Context *fs = *(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;
|
const int ps = av_pix_fmt_desc_get(c->pix_fmt)->comp[0].step_minus1 + 1;
|
||||||
int ret;
|
int ret;
|
||||||
RangeCoder c_bak = fs->c;
|
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;
|
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:
|
retry:
|
||||||
if (c->coded_frame->key_frame)
|
if (c->coded_frame->key_frame)
|
||||||
@ -1043,9 +1115,6 @@ retry:
|
|||||||
if (fs->transparency)
|
if (fs->transparency)
|
||||||
ret |= encode_plane(fs, p->data[3] + ps*x + y*p->linesize[3], width, height, p->linesize[3], 2);
|
ret |= encode_plane(fs, p->data[3] + ps*x + y*p->linesize[3], width, height, p->linesize[3], 2);
|
||||||
} else {
|
} 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);
|
ret = encode_rgb_frame(fs, planes, width, height, p->linesize);
|
||||||
}
|
}
|
||||||
emms_c();
|
emms_c();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user