libavcodec/libspeexdec.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008 David Conrad
00003  *
00004  * This file is part of Libav.
00005  *
00006  * Libav is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  *
00011  * Libav is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with Libav; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00019  */
00020 
00021 #include <speex/speex.h>
00022 #include <speex/speex_header.h>
00023 #include <speex/speex_stereo.h>
00024 #include <speex/speex_callbacks.h>
00025 #include "avcodec.h"
00026 #include "internal.h"
00027 
00028 typedef struct {
00029     AVFrame frame;
00030     SpeexBits bits;
00031     SpeexStereoState stereo;
00032     void *dec_state;
00033     SpeexHeader *header;
00034     int frame_size;
00035 } LibSpeexContext;
00036 
00037 
00038 static av_cold int libspeex_decode_init(AVCodecContext *avctx)
00039 {
00040     LibSpeexContext *s = avctx->priv_data;
00041     const SpeexMode *mode;
00042 
00043     // defaults in the case of a missing header
00044     if (avctx->sample_rate <= 8000)
00045         mode = &speex_nb_mode;
00046     else if (avctx->sample_rate <= 16000)
00047         mode = &speex_wb_mode;
00048     else
00049         mode = &speex_uwb_mode;
00050 
00051     if (avctx->extradata_size >= 80)
00052         s->header = speex_packet_to_header(avctx->extradata, avctx->extradata_size);
00053 
00054     avctx->sample_fmt = AV_SAMPLE_FMT_S16;
00055     if (s->header) {
00056         avctx->sample_rate = s->header->rate;
00057         avctx->channels    = s->header->nb_channels;
00058         avctx->frame_size  = s->frame_size = s->header->frame_size;
00059         if (s->header->frames_per_packet)
00060             avctx->frame_size *= s->header->frames_per_packet;
00061 
00062         mode = speex_lib_get_mode(s->header->mode);
00063         if (!mode) {
00064             av_log(avctx, AV_LOG_ERROR, "Unknown Speex mode %d", s->header->mode);
00065             return AVERROR_INVALIDDATA;
00066         }
00067     } else
00068         av_log(avctx, AV_LOG_INFO, "Missing Speex header, assuming defaults.\n");
00069 
00070     if (avctx->channels > 2) {
00071         av_log(avctx, AV_LOG_ERROR, "Only stereo and mono are supported.\n");
00072         return AVERROR(EINVAL);
00073     }
00074 
00075     speex_bits_init(&s->bits);
00076     s->dec_state = speex_decoder_init(mode);
00077     if (!s->dec_state) {
00078         av_log(avctx, AV_LOG_ERROR, "Error initializing libspeex decoder.\n");
00079         return -1;
00080     }
00081 
00082     if (!s->header) {
00083         speex_decoder_ctl(s->dec_state, SPEEX_GET_FRAME_SIZE, &s->frame_size);
00084     }
00085 
00086     if (avctx->channels == 2) {
00087         SpeexCallback callback;
00088         callback.callback_id = SPEEX_INBAND_STEREO;
00089         callback.func = speex_std_stereo_request_handler;
00090         callback.data = &s->stereo;
00091         s->stereo = (SpeexStereoState)SPEEX_STEREO_STATE_INIT;
00092         speex_decoder_ctl(s->dec_state, SPEEX_SET_HANDLER, &callback);
00093     }
00094 
00095     avcodec_get_frame_defaults(&s->frame);
00096     avctx->coded_frame = &s->frame;
00097 
00098     return 0;
00099 }
00100 
00101 static int libspeex_decode_frame(AVCodecContext *avctx, void *data,
00102                                  int *got_frame_ptr, AVPacket *avpkt)
00103 {
00104     uint8_t *buf = avpkt->data;
00105     int buf_size = avpkt->size;
00106     LibSpeexContext *s = avctx->priv_data;
00107     int16_t *output;
00108     int ret, consumed = 0;
00109 
00110     /* get output buffer */
00111     s->frame.nb_samples = s->frame_size;
00112     if ((ret = ff_get_buffer(avctx, &s->frame)) < 0) {
00113         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00114         return ret;
00115     }
00116     output = (int16_t *)s->frame.data[0];
00117 
00118     /* if there is not enough data left for the smallest possible frame,
00119        reset the libspeex buffer using the current packet, otherwise ignore
00120        the current packet and keep decoding frames from the libspeex buffer. */
00121     if (speex_bits_remaining(&s->bits) < 43) {
00122         /* check for flush packet */
00123         if (!buf || !buf_size) {
00124             *got_frame_ptr = 0;
00125             return buf_size;
00126         }
00127         /* set new buffer */
00128         speex_bits_read_from(&s->bits, buf, buf_size);
00129         consumed = buf_size;
00130     }
00131 
00132     /* decode a single frame */
00133     ret = speex_decode_int(s->dec_state, &s->bits, output);
00134     if (ret <= -2) {
00135         av_log(avctx, AV_LOG_ERROR, "Error decoding Speex frame.\n");
00136         return AVERROR_INVALIDDATA;
00137     }
00138     if (avctx->channels == 2)
00139         speex_decode_stereo_int(output, s->frame_size, &s->stereo);
00140 
00141     *got_frame_ptr   = 1;
00142     *(AVFrame *)data = s->frame;
00143 
00144     return consumed;
00145 }
00146 
00147 static av_cold int libspeex_decode_close(AVCodecContext *avctx)
00148 {
00149     LibSpeexContext *s = avctx->priv_data;
00150 
00151     speex_header_free(s->header);
00152     speex_bits_destroy(&s->bits);
00153     speex_decoder_destroy(s->dec_state);
00154 
00155     return 0;
00156 }
00157 
00158 static av_cold void libspeex_decode_flush(AVCodecContext *avctx)
00159 {
00160     LibSpeexContext *s = avctx->priv_data;
00161     speex_bits_reset(&s->bits);
00162 }
00163 
00164 AVCodec ff_libspeex_decoder = {
00165     .name           = "libspeex",
00166     .type           = AVMEDIA_TYPE_AUDIO,
00167     .id             = CODEC_ID_SPEEX,
00168     .priv_data_size = sizeof(LibSpeexContext),
00169     .init           = libspeex_decode_init,
00170     .close          = libspeex_decode_close,
00171     .decode         = libspeex_decode_frame,
00172     .flush          = libspeex_decode_flush,
00173     .capabilities   = CODEC_CAP_SUBFRAMES | CODEC_CAP_DELAY | CODEC_CAP_DR1,
00174     .long_name = NULL_IF_CONFIG_SMALL("libspeex Speex"),
00175 };