diff --git a/libavcodec/ffv1.h b/libavcodec/ffv1.h index 2c3e6e4c98..9d8329f00f 100644 --- a/libavcodec/ffv1.h +++ b/libavcodec/ffv1.h @@ -130,7 +130,8 @@ typedef struct FFV1Context { int slice_y; int slice_reset_contexts; int slice_coding_mode; - int slice_rct_y_coef; + int slice_rct_by_coef; + int slice_rct_ry_coef; } FFV1Context; int ffv1_common_init(AVCodecContext *avctx); diff --git a/libavcodec/ffv1dec.c b/libavcodec/ffv1dec.c index 6c01ebf15f..d7dd110545 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) * s->slice_rct_y_coef) >> 2; + g -= (b * s->slice_rct_by_coef + r * s->slice_rct_ry_coef) >> 2; b += 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_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) { + fs->slice_rct_by_coef = get_symbol(c, state, 0); + 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"); 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 (ffv1_init_slice_state(f, fs) < 0) diff --git a/libavcodec/ffv1enc.c b/libavcodec/ffv1enc.c index a518146625..7f9f203447 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) * s->slice_rct_y_coef) >> 2; + g += (b * s->slice_rct_by_coef + r * s->slice_rct_ry_coef) >> 2; b += offset; r += offset; } @@ -560,7 +560,7 @@ static int write_extradata(FFV1Context *f) if (f->version == 3) { f->micro_version = 4; } else if (f->version == 4) - f->micro_version = 1; + f->micro_version = 2; 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) 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); + if (fs->slice_coding_mode != 1) { + 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) { - 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; int16_t *sample[3]; 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; bb -= bg; - stat[0] += FFABS(bg); - stat[1] += FFABS(bg + ((br+bb)>>2)); - stat[2] += FFABS(bg + ((br+bb)>>1)); + for (i = 0; i>2)); + } } sample[0][x] = ag; @@ -1057,12 +1079,13 @@ static void choose_rct_params(FFV1Context *fs, uint8_t *src[3], const int stride } best = 0; - for (i=1; i<=2; i++) { + for (i=1; islice_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) @@ -1085,7 +1108,8 @@ static int encode_slice(AVCodecContext *c, void *arg) if (f->version > 3) { choose_rct_params(fs, planes, p->linesize, width, height); } else { - fs->slice_rct_y_coef = 1; + fs->slice_rct_by_coef = 1; + fs->slice_rct_ry_coef = 1; } retry: