libavcodec/libspeexdec.c
ae14f311
 /*
  * Copyright (C) 2008 David Conrad
  *
  * This file is part of FFmpeg.
  *
  * FFmpeg is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
  * FFmpeg is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with FFmpeg; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
 #include <speex/speex.h>
 #include <speex/speex_header.h>
 #include <speex/speex_stereo.h>
 #include <speex/speex_callbacks.h>
27c3f9c0
 
a903f8f0
 #include "libavutil/channel_layout.h"
1d9c2dc8
 #include "libavutil/common.h"
27c3f9c0
 #include "avcodec.h"
594d4d5d
 #include "internal.h"
ae14f311
 
 typedef struct {
     SpeexBits bits;
     SpeexStereoState stereo;
     void *dec_state;
6833385d
     int frame_size;
ae14f311
 } LibSpeexContext;
 
 
 static av_cold int libspeex_decode_init(AVCodecContext *avctx)
 {
     LibSpeexContext *s = avctx->priv_data;
     const SpeexMode *mode;
c9df4890
     SpeexHeader *header = NULL;
3b061c5e
     int spx_mode;
ae14f311
 
5d6e4c16
     avctx->sample_fmt = AV_SAMPLE_FMT_S16;
908e22b9
     if (avctx->extradata && avctx->extradata_size >= 80) {
c9df4890
         header = speex_packet_to_header(avctx->extradata,
                                         avctx->extradata_size);
         if (!header)
             av_log(avctx, AV_LOG_WARNING, "Invalid Speex header\n");
     }
e26b066c
     if (avctx->codec_tag == MKTAG('S', 'P', 'X', 'N')) {
         if (!avctx->extradata || avctx->extradata && avctx->extradata_size < 47) {
             av_log(avctx, AV_LOG_ERROR, "Missing or invalid extradata.\n");
             return AVERROR_INVALIDDATA;
         }
         if (avctx->extradata[37] != 10) {
             av_log(avctx, AV_LOG_ERROR, "Unsupported quality mode.\n");
             return AVERROR_PATCHWELCOME;
         }
         spx_mode           = 0;
     } else if (header) {
e2fc6a01
         avctx->sample_rate = header->rate;
908e22b9
         avctx->channels    = header->nb_channels;
         spx_mode           = header->mode;
         speex_header_free(header);
3b061c5e
     } else {
         switch (avctx->sample_rate) {
         case 8000:  spx_mode = 0; break;
         case 16000: spx_mode = 1; break;
         case 32000: spx_mode = 2; break;
         default:
             /* libspeex can handle any mode if initialized as ultra-wideband */
             av_log(avctx, AV_LOG_WARNING, "Invalid sample rate: %d\n"
                                           "Decoding as 32kHz ultra-wideband\n",
                                           avctx->sample_rate);
             spx_mode = 2;
ae14f311
         }
3b061c5e
     }
 
     mode = speex_lib_get_mode(spx_mode);
     if (!mode) {
         av_log(avctx, AV_LOG_ERROR, "Unknown Speex mode %d", spx_mode);
         return AVERROR_INVALIDDATA;
     }
892695c8
     s->frame_size      =  160 << spx_mode;
e2fc6a01
     if (!avctx->sample_rate)
         avctx->sample_rate = 8000 << spx_mode;
ae14f311
 
29abb04e
     if (avctx->channels < 1 || avctx->channels > 2) {
         /* libspeex can handle mono or stereo if initialized as stereo */
         av_log(avctx, AV_LOG_ERROR, "Invalid channel count: %d.\n"
                                     "Decoding as stereo.\n", avctx->channels);
         avctx->channels = 2;
ae14f311
     }
27c3f9c0
     avctx->channel_layout = avctx->channels == 2 ? AV_CH_LAYOUT_STEREO :
                                                    AV_CH_LAYOUT_MONO;
ae14f311
 
     speex_bits_init(&s->bits);
     s->dec_state = speex_decoder_init(mode);
     if (!s->dec_state) {
5bfd3147
         av_log(avctx, AV_LOG_ERROR, "Error initializing libspeex decoder.\n");
ae14f311
         return -1;
     }
 
     if (avctx->channels == 2) {
         SpeexCallback callback;
         callback.callback_id = SPEEX_INBAND_STEREO;
         callback.func = speex_std_stereo_request_handler;
         callback.data = &s->stereo;
         s->stereo = (SpeexStereoState)SPEEX_STEREO_STATE_INIT;
         speex_decoder_ctl(s->dec_state, SPEEX_SET_HANDLER, &callback);
     }
0eea2129
 
ae14f311
     return 0;
 }
 
0eea2129
 static int libspeex_decode_frame(AVCodecContext *avctx, void *data,
                                  int *got_frame_ptr, AVPacket *avpkt)
ae14f311
 {
0523dc57
     uint8_t *buf = avpkt->data;
7a00bbad
     int buf_size = avpkt->size;
ae14f311
     LibSpeexContext *s = avctx->priv_data;
bed957bb
     AVFrame *frame     = data;
0eea2129
     int16_t *output;
     int ret, consumed = 0;
 
     /* get output buffer */
bed957bb
     frame->nb_samples = s->frame_size;
1ec94b0f
     if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
0eea2129
         return ret;
bed957bb
     output = (int16_t *)frame->data[0];
ae14f311
 
45e5d0c3
     /* 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 ||
f3c9d66b
         speex_bits_peek_unsigned(&s->bits, 5) == 0xF) {
7eeaa679
         /* check for flush packet */
         if (!buf || !buf_size) {
0eea2129
             *got_frame_ptr = 0;
7eeaa679
             return buf_size;
         }
         /* set new buffer */
         speex_bits_read_from(&s->bits, buf, buf_size);
         consumed = buf_size;
     }
ae14f311
 
7eeaa679
     /* decode a single frame */
14bc60db
     ret = speex_decode_int(s->dec_state, &s->bits, output);
     if (ret <= -2) {
         av_log(avctx, AV_LOG_ERROR, "Error decoding Speex frame.\n");
a470fe80
         return AVERROR_INVALIDDATA;
ae14f311
     }
14bc60db
     if (avctx->channels == 2)
         speex_decode_stereo_int(output, s->frame_size, &s->stereo);
ae14f311
 
bed957bb
     *got_frame_ptr = 1;
0eea2129
 
7eeaa679
     return consumed;
ae14f311
 }
 
 static av_cold int libspeex_decode_close(AVCodecContext *avctx)
 {
     LibSpeexContext *s = avctx->priv_data;
 
     speex_bits_destroy(&s->bits);
     speex_decoder_destroy(s->dec_state);
 
     return 0;
 }
 
7eeaa679
 static av_cold void libspeex_decode_flush(AVCodecContext *avctx)
 {
     LibSpeexContext *s = avctx->priv_data;
     speex_bits_reset(&s->bits);
 }
 
e7e2df27
 AVCodec ff_libspeex_decoder = {
ec6402b7
     .name           = "libspeex",
b2bed932
     .long_name      = NULL_IF_CONFIG_SMALL("libspeex Speex"),
ec6402b7
     .type           = AVMEDIA_TYPE_AUDIO,
36ef5369
     .id             = AV_CODEC_ID_SPEEX,
ec6402b7
     .priv_data_size = sizeof(LibSpeexContext),
     .init           = libspeex_decode_init,
     .close          = libspeex_decode_close,
     .decode         = libspeex_decode_frame,
7eeaa679
     .flush          = libspeex_decode_flush,
0eea2129
     .capabilities   = CODEC_CAP_SUBFRAMES | CODEC_CAP_DELAY | CODEC_CAP_DR1,
ae14f311
 };