mirror of https://github.com/FFmpeg/FFmpeg.git
Originally committed as revision 15676 to svn://svn.ffmpeg.org/ffmpeg/trunkpull/126/head
parent
60ce2f9cae
commit
ae14f311f8
4 changed files with 151 additions and 0 deletions
@ -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 <speex/speex.h> |
||||
#include <speex/speex_header.h> |
||||
#include <speex/speex_stereo.h> |
||||
#include <speex/speex_callbacks.h> |
||||
|
||||
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"), |
||||
}; |
Loading…
Reference in new issue