Commit 7eeaa679 authored by Justin Ruggles's avatar Justin Ruggles

libspeexdec: decode one frame at a time.

This allows for knowing the output size before decoding even when there is no
header (e.g. FLV). Otherwise we would have to do a preliminary full frame
decode to determine the number of frames-per-packet.
parent 41ac093f
...@@ -99,32 +99,42 @@ static int libspeex_decode_frame(AVCodecContext *avctx, ...@@ -99,32 +99,42 @@ static int libspeex_decode_frame(AVCodecContext *avctx,
uint8_t *buf = avpkt->data; uint8_t *buf = avpkt->data;
int buf_size = avpkt->size; int buf_size = avpkt->size;
LibSpeexContext *s = avctx->priv_data; LibSpeexContext *s = avctx->priv_data;
int16_t *output = data, *end; int16_t *output = data;
int i, num_samples; int out_size, ret, consumed = 0;
num_samples = s->frame_size * avctx->channels; /* check output buffer size */
end = output + *data_size / sizeof(*output); out_size = s->frame_size * avctx->channels *
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);
}
speex_bits_read_from(&s->bits, buf, buf_size); /* if there is not enough data left for the smallest possible frame,
reset the libspeex buffer using the current packet, otherwise ignore
the current packet and keep decoding frames from the libspeex buffer. */
if (speex_bits_remaining(&s->bits) < 43) {
/* check for flush packet */
if (!buf || !buf_size) {
*data_size = 0;
return buf_size;
}
/* set new buffer */
speex_bits_read_from(&s->bits, buf, buf_size);
consumed = buf_size;
}
for (i = 0; speex_bits_remaining(&s->bits) && output + num_samples < end; i++) { /* decode a single frame */
int ret = speex_decode_int(s->dec_state, &s->bits, output); ret = speex_decode_int(s->dec_state, &s->bits, output);
if (ret <= -2) { if (ret <= -2) {
av_log(avctx, AV_LOG_ERROR, "Error decoding Speex frame.\n"); av_log(avctx, AV_LOG_ERROR, "Error decoding Speex frame.\n");
return -1; return -1;
} else if (ret == -1) }
// end of stream
break;
if (avctx->channels == 2) if (avctx->channels == 2)
speex_decode_stereo_int(output, s->frame_size, &s->stereo); speex_decode_stereo_int(output, s->frame_size, &s->stereo);
output += num_samples; *data_size = out_size;
} return consumed;
avctx->frame_size = s->frame_size * i;
*data_size = avctx->channels * avctx->frame_size * sizeof(*output);
return buf_size;
} }
static av_cold int libspeex_decode_close(AVCodecContext *avctx) static av_cold int libspeex_decode_close(AVCodecContext *avctx)
...@@ -138,6 +148,12 @@ static av_cold int libspeex_decode_close(AVCodecContext *avctx) ...@@ -138,6 +148,12 @@ static av_cold int libspeex_decode_close(AVCodecContext *avctx)
return 0; return 0;
} }
static av_cold void libspeex_decode_flush(AVCodecContext *avctx)
{
LibSpeexContext *s = avctx->priv_data;
speex_bits_reset(&s->bits);
}
AVCodec ff_libspeex_decoder = { AVCodec ff_libspeex_decoder = {
.name = "libspeex", .name = "libspeex",
.type = AVMEDIA_TYPE_AUDIO, .type = AVMEDIA_TYPE_AUDIO,
...@@ -146,5 +162,7 @@ AVCodec ff_libspeex_decoder = { ...@@ -146,5 +162,7 @@ AVCodec ff_libspeex_decoder = {
.init = libspeex_decode_init, .init = libspeex_decode_init,
.close = libspeex_decode_close, .close = libspeex_decode_close,
.decode = libspeex_decode_frame, .decode = libspeex_decode_frame,
.flush = libspeex_decode_flush,
.capabilities = CODEC_CAP_SUBFRAMES | CODEC_CAP_DELAY,
.long_name = NULL_IF_CONFIG_SMALL("libspeex Speex"), .long_name = NULL_IF_CONFIG_SMALL("libspeex Speex"),
}; };
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