Commit 4f4e1948 authored by Justin Ruggles's avatar Justin Ruggles

binkaudio: only decode one block at a time.

This prevents truncating output due to an output buffer that is too small for
all blocks. There is no limit on the number of blocks in a packet.
parent eaddd29e
...@@ -62,6 +62,7 @@ typedef struct { ...@@ -62,6 +62,7 @@ typedef struct {
DECLARE_ALIGNED(16, int16_t, current)[BINK_BLOCK_MAX_SIZE / 16]; DECLARE_ALIGNED(16, int16_t, current)[BINK_BLOCK_MAX_SIZE / 16];
float *coeffs_ptr[MAX_CHANNELS]; ///< pointers to the coeffs arrays for float_to_int16_interleave float *coeffs_ptr[MAX_CHANNELS]; ///< pointers to the coeffs arrays for float_to_int16_interleave
float *prev_ptr[MAX_CHANNELS]; ///< pointers to the overlap points in the coeffs array float *prev_ptr[MAX_CHANNELS]; ///< pointers to the overlap points in the coeffs array
uint8_t *packet_buffer;
union { union {
RDFTContext rdft; RDFTContext rdft;
DCTContext dct; DCTContext dct;
...@@ -287,6 +288,7 @@ static av_cold int decode_end(AVCodecContext *avctx) ...@@ -287,6 +288,7 @@ static av_cold int decode_end(AVCodecContext *avctx)
{ {
BinkAudioContext * s = avctx->priv_data; BinkAudioContext * s = avctx->priv_data;
av_freep(&s->bands); av_freep(&s->bands);
av_freep(&s->packet_buffer);
if (CONFIG_BINKAUDIO_RDFT_DECODER && avctx->codec->id == CODEC_ID_BINKAUDIO_RDFT) if (CONFIG_BINKAUDIO_RDFT_DECODER && avctx->codec->id == CODEC_ID_BINKAUDIO_RDFT)
ff_rdft_end(&s->trans.rdft); ff_rdft_end(&s->trans.rdft);
else if (CONFIG_BINKAUDIO_DCT_DECODER) else if (CONFIG_BINKAUDIO_DCT_DECODER)
...@@ -305,30 +307,47 @@ static int decode_frame(AVCodecContext *avctx, ...@@ -305,30 +307,47 @@ static int decode_frame(AVCodecContext *avctx,
AVPacket *avpkt) AVPacket *avpkt)
{ {
BinkAudioContext *s = avctx->priv_data; BinkAudioContext *s = avctx->priv_data;
const uint8_t *buf = avpkt->data;
int buf_size = avpkt->size;
short *samples = data; short *samples = data;
short *samples_end = (short*)((uint8_t*)data + *data_size);
int reported_size;
GetBitContext *gb = &s->gb; GetBitContext *gb = &s->gb;
int out_size, consumed = 0;
if (buf_size < 4) {
av_log(avctx, AV_LOG_ERROR, "Packet is too small\n"); if (!get_bits_left(gb)) {
return AVERROR_INVALIDDATA; uint8_t *buf;
/* handle end-of-stream */
if (!avpkt->size) {
*data_size = 0;
return 0;
}
if (avpkt->size < 4) {
av_log(avctx, AV_LOG_ERROR, "Packet is too small\n");
return AVERROR_INVALIDDATA;
}
buf = av_realloc(s->packet_buffer, avpkt->size + FF_INPUT_BUFFER_PADDING_SIZE);
if (!buf)
return AVERROR(ENOMEM);
s->packet_buffer = buf;
memcpy(s->packet_buffer, avpkt->data, avpkt->size);
init_get_bits(gb, s->packet_buffer, avpkt->size * 8);
consumed = avpkt->size;
/* skip reported size */
skip_bits_long(gb, 32);
} }
init_get_bits(gb, buf, buf_size * 8); out_size = s->block_size * av_get_bytes_per_sample(avctx->sample_fmt);
if (*data_size < out_size) {
av_log(avctx, AV_LOG_ERROR, "Output buffer is too small\n");
return AVERROR(EINVAL);
}
reported_size = get_bits_long(gb, 32); if (decode_block(s, samples, avctx->codec->id == CODEC_ID_BINKAUDIO_DCT)) {
while (samples + s->block_size <= samples_end) { av_log(avctx, AV_LOG_ERROR, "Incomplete packet\n");
if (decode_block(s, samples, avctx->codec->id == CODEC_ID_BINKAUDIO_DCT)) return AVERROR_INVALIDDATA;
break;
samples += s->block_size;
get_bits_align32(gb);
} }
get_bits_align32(gb);
*data_size = FFMIN(reported_size, (uint8_t*)samples - (uint8_t*)data); *data_size = out_size;
return buf_size; return consumed;
} }
AVCodec ff_binkaudio_rdft_decoder = { AVCodec ff_binkaudio_rdft_decoder = {
...@@ -339,6 +358,7 @@ AVCodec ff_binkaudio_rdft_decoder = { ...@@ -339,6 +358,7 @@ AVCodec ff_binkaudio_rdft_decoder = {
.init = decode_init, .init = decode_init,
.close = decode_end, .close = decode_end,
.decode = decode_frame, .decode = decode_frame,
.capabilities = CODEC_CAP_DELAY,
.long_name = NULL_IF_CONFIG_SMALL("Bink Audio (RDFT)") .long_name = NULL_IF_CONFIG_SMALL("Bink Audio (RDFT)")
}; };
...@@ -350,5 +370,6 @@ AVCodec ff_binkaudio_dct_decoder = { ...@@ -350,5 +370,6 @@ AVCodec ff_binkaudio_dct_decoder = {
.init = decode_init, .init = decode_init,
.close = decode_end, .close = decode_end,
.decode = decode_frame, .decode = decode_frame,
.capabilities = CODEC_CAP_DELAY,
.long_name = NULL_IF_CONFIG_SMALL("Bink Audio (DCT)") .long_name = NULL_IF_CONFIG_SMALL("Bink Audio (DCT)")
}; };
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment