X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;ds=sidebyside;f=libavcodec%2Flibspeexdec.c;h=a26b763688da23423351f26c1c2146bb5afc9c26;hb=295e05a762332c5edcc84c325e94457815a51b5c;hp=b9d9149ee2db9e705171c6e60b8998477020f049;hpb=29abb04e73b0580ebe38703cadb988d26df6a76a;p=ffmpeg diff --git a/libavcodec/libspeexdec.c b/libavcodec/libspeexdec.c index b9d9149ee2d..a26b763688d 100644 --- a/libavcodec/libspeexdec.c +++ b/libavcodec/libspeexdec.c @@ -22,15 +22,16 @@ #include #include #include -#include "avcodec.h" + +#include "libavutil/channel_layout.h" #include "libavutil/common.h" +#include "avcodec.h" +#include "internal.h" -typedef struct { - AVFrame frame; +typedef struct LibSpeexContext { SpeexBits bits; SpeexStereoState stereo; void *dec_state; - SpeexHeader *header; int frame_size; } LibSpeexContext; @@ -39,16 +40,20 @@ static av_cold int libspeex_decode_init(AVCodecContext *avctx) { LibSpeexContext *s = avctx->priv_data; const SpeexMode *mode; + SpeexHeader *header = NULL; int spx_mode; - if (avctx->extradata_size >= 80) - s->header = speex_packet_to_header(avctx->extradata, avctx->extradata_size); - avctx->sample_fmt = AV_SAMPLE_FMT_S16; - if (s->header) { - avctx->channels = s->header->nb_channels; - s->frame_size = s->header->frame_size; - spx_mode = s->header->mode; + if (avctx->extradata && avctx->extradata_size >= 80) { + header = speex_packet_to_header(avctx->extradata, + avctx->extradata_size); + if (!header) + av_log(avctx, AV_LOG_WARNING, "Invalid Speex header\n"); + } + if (header) { + avctx->channels = header->nb_channels; + spx_mode = header->mode; + speex_header_free(header); } else { switch (avctx->sample_rate) { case 8000: spx_mode = 0; break; @@ -69,6 +74,7 @@ static av_cold int libspeex_decode_init(AVCodecContext *avctx) return AVERROR_INVALIDDATA; } avctx->sample_rate = 8000 << spx_mode; + s->frame_size = 160 << spx_mode; if (avctx->channels < 1 || avctx->channels > 2) { /* libspeex can handle mono or stereo if initialized as stereo */ @@ -76,6 +82,8 @@ static av_cold int libspeex_decode_init(AVCodecContext *avctx) "Decoding as stereo.\n", avctx->channels); avctx->channels = 2; } + avctx->channel_layout = avctx->channels == 2 ? AV_CH_LAYOUT_STEREO : + AV_CH_LAYOUT_MONO; speex_bits_init(&s->bits); s->dec_state = speex_decoder_init(mode); @@ -84,10 +92,6 @@ static av_cold int libspeex_decode_init(AVCodecContext *avctx) return -1; } - if (!s->header) { - speex_decoder_ctl(s->dec_state, SPEEX_GET_FRAME_SIZE, &s->frame_size); - } - if (avctx->channels == 2) { SpeexCallback callback; callback.callback_id = SPEEX_INBAND_STEREO; @@ -97,9 +101,6 @@ static av_cold int libspeex_decode_init(AVCodecContext *avctx) speex_decoder_ctl(s->dec_state, SPEEX_SET_HANDLER, &callback); } - avcodec_get_frame_defaults(&s->frame); - avctx->coded_frame = &s->frame; - return 0; } @@ -109,21 +110,24 @@ static int libspeex_decode_frame(AVCodecContext *avctx, void *data, uint8_t *buf = avpkt->data; int buf_size = avpkt->size; LibSpeexContext *s = avctx->priv_data; + AVFrame *frame = data; int16_t *output; int ret, consumed = 0; /* get output buffer */ - s->frame.nb_samples = s->frame_size; - if ((ret = avctx->get_buffer(avctx, &s->frame)) < 0) { + frame->nb_samples = s->frame_size; + if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) { av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); return ret; } - output = (int16_t *)s->frame.data[0]; - - /* 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) { + output = (int16_t *)frame->data[0]; + + /* if there is not enough data left for the smallest possible frame or the + next 5 bits are a terminator code, 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) < 5 || + speex_bits_peek_unsigned(&s->bits, 5) == 0xF) { /* check for flush packet */ if (!buf || !buf_size) { *got_frame_ptr = 0; @@ -143,8 +147,7 @@ static int libspeex_decode_frame(AVCodecContext *avctx, void *data, if (avctx->channels == 2) speex_decode_stereo_int(output, s->frame_size, &s->stereo); - *got_frame_ptr = 1; - *(AVFrame *)data = s->frame; + *got_frame_ptr = 1; return consumed; } @@ -153,7 +156,6 @@ static av_cold int libspeex_decode_close(AVCodecContext *avctx) { LibSpeexContext *s = avctx->priv_data; - speex_header_free(s->header); speex_bits_destroy(&s->bits); speex_decoder_destroy(s->dec_state); @@ -168,6 +170,7 @@ static av_cold void libspeex_decode_flush(AVCodecContext *avctx) AVCodec ff_libspeex_decoder = { .name = "libspeex", + .long_name = NULL_IF_CONFIG_SMALL("libspeex Speex"), .type = AVMEDIA_TYPE_AUDIO, .id = AV_CODEC_ID_SPEEX, .priv_data_size = sizeof(LibSpeexContext), @@ -176,5 +179,4 @@ AVCodec ff_libspeex_decoder = { .decode = libspeex_decode_frame, .flush = libspeex_decode_flush, .capabilities = CODEC_CAP_SUBFRAMES | CODEC_CAP_DELAY | CODEC_CAP_DR1, - .long_name = NULL_IF_CONFIG_SMALL("libspeex Speex"), };