avcodec/svq1dec: detect buggy FFmpeg encoder and apply correction to interframe mean symbols

The FFmpeg encoder does not increment the temporal reference field, so use
that knowledge plus the extradata field to detect buggy versions of the encoder.
This commit is contained in:
Peter Ross 2022-11-01 09:24:29 +11:00
parent 6fe8556a19
commit 16af424bf9
1 changed files with 23 additions and 9 deletions

View File

@ -73,6 +73,8 @@ typedef struct SVQ1Context {
int height;
int frame_code;
int nonref; // 1 if the current frame won't be referenced
int last_tempref;
} SVQ1Context;
static const uint8_t string_table[256] = {
@ -229,7 +231,7 @@ static int svq1_decode_block_intra(GetBitContext *bitbuf, uint8_t *pixels,
}
static int svq1_decode_block_non_intra(GetBitContext *bitbuf, uint8_t *pixels,
ptrdiff_t pitch)
ptrdiff_t pitch, int buggy)
{
uint32_t bit_cache;
uint8_t *list[63];
@ -270,6 +272,13 @@ static int svq1_decode_block_non_intra(GetBitContext *bitbuf, uint8_t *pixels,
mean = get_vlc2(bitbuf, svq1_inter_mean.table, 9, 3) - 256;
if (buggy) {
if (mean == -128)
mean = 128;
else if (mean == 128)
mean = -128;
}
SVQ1_CALC_CODEBOOK_ENTRIES(ff_svq1_inter_codebooks);
for (y = 0; y < height; y++) {
@ -455,7 +464,7 @@ static int svq1_decode_delta_block(AVCodecContext *avctx, HpelDSPContext *hdsp,
GetBitContext *bitbuf,
uint8_t *current, uint8_t *previous,
ptrdiff_t pitch, svq1_pmv *motion, int x, int y,
int width, int height)
int width, int height, int buggy)
{
uint32_t block_type;
int result = 0;
@ -487,7 +496,7 @@ static int svq1_decode_delta_block(AVCodecContext *avctx, HpelDSPContext *hdsp,
ff_dlog(avctx, "Error in svq1_motion_inter_block %i\n", result);
break;
}
result = svq1_decode_block_non_intra(bitbuf, current, pitch);
result = svq1_decode_block_non_intra(bitbuf, current, pitch, buggy);
break;
case SVQ1_BLOCK_INTER_4V:
@ -498,7 +507,7 @@ static int svq1_decode_delta_block(AVCodecContext *avctx, HpelDSPContext *hdsp,
ff_dlog(avctx, "Error in svq1_motion_inter_4v_block %i\n", result);
break;
}
result = svq1_decode_block_non_intra(bitbuf, current, pitch);
result = svq1_decode_block_non_intra(bitbuf, current, pitch, buggy);
break;
case SVQ1_BLOCK_INTRA:
@ -524,15 +533,18 @@ static void svq1_parse_string(GetBitContext *bitbuf, uint8_t out[257])
out[i] = 0;
}
static int svq1_decode_frame_header(AVCodecContext *avctx, AVFrame *frame)
static int svq1_decode_frame_header(AVCodecContext *avctx, AVFrame *frame, int * buggy)
{
SVQ1Context *s = avctx->priv_data;
GetBitContext *bitbuf = &s->gb;
int frame_size_code;
int width = s->width;
int height = s->height;
int tempref;
skip_bits(bitbuf, 8); /* temporal_reference */
tempref = get_bits(bitbuf, 8); /* temporal_reference */
*buggy = tempref == 0 && s->last_tempref == 0 && avctx->extradata_size == 0;
s->last_tempref = tempref;
/* frame type */
s->nonref = 0;
@ -624,7 +636,7 @@ static int svq1_decode_frame(AVCodecContext *avctx, AVFrame *cur,
int buf_size = avpkt->size;
SVQ1Context *s = avctx->priv_data;
uint8_t *current;
int result, i, x, y, width, height;
int result, i, x, y, width, height, buggy;
int ret;
/* initialize bit buffer */
@ -664,7 +676,7 @@ static int svq1_decode_frame(AVCodecContext *avctx, AVFrame *cur,
src[i] = ((src[i] << 16) | (src[i] >> 16)) ^ src[7 - i];
}
result = svq1_decode_frame_header(avctx, cur);
result = svq1_decode_frame_header(avctx, cur, &buggy);
if (result != 0) {
ff_dlog(avctx, "Error in svq1_decode_frame_header %i\n", result);
return result;
@ -734,7 +746,7 @@ static int svq1_decode_frame(AVCodecContext *avctx, AVFrame *cur,
result = svq1_decode_delta_block(avctx, &s->hdsp,
&s->gb, &current[x],
previous, linesize,
s->pmv, x, y, width, height);
s->pmv, x, y, width, height, buggy);
if (result != 0) {
ff_dlog(avctx,
"Error in svq1_decode_delta_block %i\n",
@ -820,6 +832,8 @@ static av_cold int svq1_decode_init(AVCodecContext *avctx)
ff_thread_once(&init_static_once, svq1_static_init);
s->last_tempref = 0xFF;
return 0;
}