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

View File

@ -73,6 +73,8 @@ typedef struct SVQ1Context {
int height; int height;
int frame_code; int frame_code;
int nonref; // 1 if the current frame won't be referenced int nonref; // 1 if the current frame won't be referenced
int last_tempref;
} SVQ1Context; } SVQ1Context;
static const uint8_t string_table[256] = { 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, static int svq1_decode_block_non_intra(GetBitContext *bitbuf, uint8_t *pixels,
ptrdiff_t pitch) ptrdiff_t pitch, int buggy)
{ {
uint32_t bit_cache; uint32_t bit_cache;
uint8_t *list[63]; 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; 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); SVQ1_CALC_CODEBOOK_ENTRIES(ff_svq1_inter_codebooks);
for (y = 0; y < height; y++) { for (y = 0; y < height; y++) {
@ -455,7 +464,7 @@ static int svq1_decode_delta_block(AVCodecContext *avctx, HpelDSPContext *hdsp,
GetBitContext *bitbuf, GetBitContext *bitbuf,
uint8_t *current, uint8_t *previous, uint8_t *current, uint8_t *previous,
ptrdiff_t pitch, svq1_pmv *motion, int x, int y, ptrdiff_t pitch, svq1_pmv *motion, int x, int y,
int width, int height) int width, int height, int buggy)
{ {
uint32_t block_type; uint32_t block_type;
int result = 0; 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); ff_dlog(avctx, "Error in svq1_motion_inter_block %i\n", result);
break; break;
} }
result = svq1_decode_block_non_intra(bitbuf, current, pitch); result = svq1_decode_block_non_intra(bitbuf, current, pitch, buggy);
break; break;
case SVQ1_BLOCK_INTER_4V: 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); ff_dlog(avctx, "Error in svq1_motion_inter_4v_block %i\n", result);
break; break;
} }
result = svq1_decode_block_non_intra(bitbuf, current, pitch); result = svq1_decode_block_non_intra(bitbuf, current, pitch, buggy);
break; break;
case SVQ1_BLOCK_INTRA: case SVQ1_BLOCK_INTRA:
@ -524,15 +533,18 @@ static void svq1_parse_string(GetBitContext *bitbuf, uint8_t out[257])
out[i] = 0; 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; SVQ1Context *s = avctx->priv_data;
GetBitContext *bitbuf = &s->gb; GetBitContext *bitbuf = &s->gb;
int frame_size_code; int frame_size_code;
int width = s->width; int width = s->width;
int height = s->height; 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 */ /* frame type */
s->nonref = 0; s->nonref = 0;
@ -624,7 +636,7 @@ static int svq1_decode_frame(AVCodecContext *avctx, AVFrame *cur,
int buf_size = avpkt->size; int buf_size = avpkt->size;
SVQ1Context *s = avctx->priv_data; SVQ1Context *s = avctx->priv_data;
uint8_t *current; uint8_t *current;
int result, i, x, y, width, height; int result, i, x, y, width, height, buggy;
int ret; int ret;
/* initialize bit buffer */ /* 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]; 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) { if (result != 0) {
ff_dlog(avctx, "Error in svq1_decode_frame_header %i\n", result); ff_dlog(avctx, "Error in svq1_decode_frame_header %i\n", result);
return result; return result;
@ -734,7 +746,7 @@ static int svq1_decode_frame(AVCodecContext *avctx, AVFrame *cur,
result = svq1_decode_delta_block(avctx, &s->hdsp, result = svq1_decode_delta_block(avctx, &s->hdsp,
&s->gb, &current[x], &s->gb, &current[x],
previous, linesize, previous, linesize,
s->pmv, x, y, width, height); s->pmv, x, y, width, height, buggy);
if (result != 0) { if (result != 0) {
ff_dlog(avctx, ff_dlog(avctx,
"Error in svq1_decode_delta_block %i\n", "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); ff_thread_once(&init_static_once, svq1_static_init);
s->last_tempref = 0xFF;
return 0; return 0;
} }