diff --git a/configure b/configure index 74548c8865..111131f614 100755 --- a/configure +++ b/configure @@ -102,6 +102,7 @@ show_help(){ echo " --enable-libnut enable NUT (de)muxing via libnut," echo " native demuxer exists [default=no]" echo " --enable-libschroedinger enable Dirac support via libschroedinger [default=no]" + echo " --enable-libspeex enable Speex decoding via libspeex [default=no]" echo " --enable-libtheora enable Theora encoding via libtheora [default=no]" echo " --enable-libvorbis enable Vorbis encoding via libvorbis," echo " native implementation exists [default=no]" @@ -692,6 +693,7 @@ CONFIG_LIST=" libmp3lame libnut libschroedinger + libspeex libtheora libvorbis libx264 @@ -891,6 +893,7 @@ libgsm_ms_encoder_deps="libgsm" libmp3lame_encoder_deps="libmp3lame" libschroedinger_decoder_deps="libschroedinger" libschroedinger_encoder_deps="libschroedinger" +libspeex_decoder_deps="libspeex" libtheora_encoder_deps="libtheora" libvorbis_encoder_deps="libvorbis" libx264_encoder_deps="libx264" @@ -1730,6 +1733,7 @@ enabled libmp3lame && require LAME lame/lame.h lame_init -lmp3lame -lm enabled libnut && require libnut libnut.h nut_demuxer_init -lnut enabled libschroedinger && add_cflags $(pkg-config --cflags schroedinger-1.0) && require libschroedinger schroedinger/schro.h schro_init $(pkg-config --libs schroedinger-1.0) +enabled libspeex && require libspeex speex/speex.h speex_decoder_init -lspeex enabled libtheora && require libtheora theora/theora.h theora_info_init -ltheora -logg enabled libvorbis && require libvorbis vorbis/vorbisenc.h vorbis_info_init -lvorbisenc -lvorbis -logg enabled libx264 && require x264 x264.h x264_encoder_open -lx264 -lm && @@ -2036,6 +2040,7 @@ echo "libgsm enabled ${libgsm-no}" echo "libmp3lame enabled ${libmp3lame-no}" echo "libnut enabled ${libnut-no}" echo "libschroedinger enabled ${libschroedinger-no}" +echo "libspeex enabled ${libspeex-no}" echo "libtheora enabled ${libtheora-no}" echo "libvorbis enabled ${libvorbis-no}" echo "libx264 enabled ${libx264-no}" diff --git a/libavcodec/Makefile b/libavcodec/Makefile index e942e3e997..ece4a96982 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -334,6 +334,7 @@ OBJS-$(CONFIG_LIBGSM) += libgsm.o OBJS-$(CONFIG_LIBMP3LAME) += libmp3lame.o OBJS-$(CONFIG_LIBSCHROEDINGER_DECODER) += libschroedingerdec.o libschroedinger.o libdirac_libschro.o OBJS-$(CONFIG_LIBSCHROEDINGER_ENCODER) += libschroedingerenc.o libschroedinger.o libdirac_libschro.o +OBJS-$(CONFIG_LIBSPEEX) += libspeexdec.o OBJS-$(CONFIG_LIBTHEORA) += libtheoraenc.o OBJS-$(CONFIG_LIBVORBIS) += libvorbis.o OBJS-$(CONFIG_LIBX264) += libx264.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 074054d912..a8771dd9e9 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -293,6 +293,7 @@ void avcodec_register_all(void) REGISTER_ENCDEC (LIBGSM_MS, libgsm_ms); REGISTER_ENCODER (LIBMP3LAME, libmp3lame); REGISTER_ENCDEC (LIBSCHROEDINGER, libschroedinger); + REGISTER_DECODER (LIBSPEEX, libspeex); REGISTER_ENCODER (LIBTHEORA, libtheora); REGISTER_ENCODER (LIBVORBIS, libvorbis); REGISTER_ENCODER (LIBX264, libx264); diff --git a/libavcodec/libspeexdec.c b/libavcodec/libspeexdec.c new file mode 100644 index 0000000000..7ea348901b --- /dev/null +++ b/libavcodec/libspeexdec.c @@ -0,0 +1,144 @@ +/* + * 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 "avcodec.h" +#include +#include +#include +#include + +typedef struct { + SpeexBits bits; + SpeexStereoState stereo; + void *dec_state; + SpeexHeader *header; +} LibSpeexContext; + + +static av_cold int libspeex_decode_init(AVCodecContext *avctx) +{ + LibSpeexContext *s = avctx->priv_data; + const SpeexMode *mode; + + // defaults in the case of a missing header + if (avctx->sample_rate <= 8000) + mode = &speex_nb_mode; + else if (avctx->sample_rate <= 16000) + mode = &speex_wb_mode; + else + mode = &speex_uwb_mode; + + if (avctx->extradata_size >= 80) + s->header = speex_packet_to_header(avctx->extradata, avctx->extradata_size); + + avctx->sample_fmt = SAMPLE_FMT_S16; + if (s->header) { + avctx->sample_rate = s->header->rate; + avctx->channels = s->header->nb_channels; + avctx->frame_size = s->header->frame_size; + + mode = speex_lib_get_mode(s->header->mode); + if (!mode) { + av_log(avctx, AV_LOG_ERROR, "Unknown Speex mode %d", s->header->mode); + return -1; + } + } else + av_log(avctx, AV_LOG_INFO, "Missing speex header, assuming defaults\n"); + + if (avctx->channels > 2) { + av_log(avctx, AV_LOG_ERROR, "Only stereo and mono supported\n"); + return -1; + } + + speex_bits_init(&s->bits); + s->dec_state = speex_decoder_init(mode); + if (!s->dec_state) { + av_log(avctx, AV_LOG_ERROR, "Error initializing libspeex decoder\n"); + return -1; + } + + if (!s->header) + speex_decoder_ctl(s->dec_state, SPEEX_GET_FRAME_SIZE, &avctx->frame_size); + + 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); + } + return 0; +} + +static int libspeex_decode_frame(AVCodecContext *avctx, + void *data, int *data_size, + const uint8_t *buf, int buf_size) +{ + LibSpeexContext *s = avctx->priv_data; + int16_t *output = data, *end; + int i, num_samples; + + num_samples = avctx->frame_size * avctx->channels; + end = output + *data_size/2; + + speex_bits_read_from(&s->bits, buf, buf_size); + + for (i = 0; speex_bits_remaining(&s->bits) && output + num_samples < end; i++) { + int ret = speex_decode_int(s->dec_state, &s->bits, output); + if (ret <= -2) { + av_log(avctx, AV_LOG_ERROR, "Error decoding speex frame\n"); + return -1; + } else if (ret == -1) + // end of stream + break; + + if (avctx->channels == 2) + speex_decode_stereo_int(output, avctx->frame_size, &s->stereo); + + output += num_samples; + } + + *data_size = i * avctx->channels * avctx->frame_size * 2; + return buf_size; +} + +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); + + return 0; +} + +AVCodec libspeex_decoder = { + "libspeex", + CODEC_TYPE_AUDIO, + CODEC_ID_SPEEX, + sizeof(LibSpeexContext), + libspeex_decode_init, + NULL, + libspeex_decode_close, + libspeex_decode_frame, + .long_name = NULL_IF_CONFIG_SMALL("libspeex"), +};