diff --git a/src/add-ons/media/plugins/speex/speexCodecDefaults.cpp b/src/add-ons/media/plugins/speex/speexCodecDefaults.cpp index 569369bf74..5897a43625 100644 --- a/src/add-ons/media/plugins/speex/speexCodecDefaults.cpp +++ b/src/add-ons/media/plugins/speex/speexCodecDefaults.cpp @@ -3,7 +3,7 @@ bool SpeexSettings::perceptual_post_filter = true; speex_mode SpeexSettings::preferred_band = automatic_band; speex_channels SpeexSettings::preferred_channels = automatic_channels; -float SpeexSettings::sampling_rate = 0; +int SpeexSettings::sampling_rate = 0; SpeexSettings::SpeexSettings() { @@ -28,7 +28,7 @@ SpeexSettings::PreferredChannels(void) } // if non-zero, specifies a sampling rate in Hertz -/* static */ float +/* static */ int SpeexSettings::SamplingRate(void) { return sampling_rate; diff --git a/src/add-ons/media/plugins/speex/speexCodecDefaults.h b/src/add-ons/media/plugins/speex/speexCodecDefaults.h index 2faaf7da70..d714b7bf96 100644 --- a/src/add-ons/media/plugins/speex/speexCodecDefaults.h +++ b/src/add-ons/media/plugins/speex/speexCodecDefaults.h @@ -20,11 +20,11 @@ public: static speex_mode PreferredBand(void); static speex_channels PreferredChannels(void); // if non-zero, specifies a sampling rate in Hertz - static float SamplingRate(void); + static int SamplingRate(void); private: static bool perceptual_post_filter; static speex_mode preferred_band; static speex_channels preferred_channels; - static float sampling_rate; + static int sampling_rate; }; diff --git a/src/add-ons/media/plugins/speex/speexCodecPlugin.cpp b/src/add-ons/media/plugins/speex/speexCodecPlugin.cpp index b06a5efbff..d418d8bcb8 100644 --- a/src/add-ons/media/plugins/speex/speexCodecPlugin.cpp +++ b/src/add-ons/media/plugins/speex/speexCodecPlugin.cpp @@ -31,8 +31,9 @@ speexDecoder::speexDecoder() speex_bits_init(&fBits); fDecoderState = 0; fHeader = 0; + fStereoState = 0; fSpeexFrameSize = 0; - fSpeexBytesRemaining = 0; + fSpeexBuffer = 0; fStartTime = 0; fFrameSize = 0; fOutputBufferSize = 0; @@ -42,6 +43,8 @@ speexDecoder::speexDecoder() speexDecoder::~speexDecoder() { TRACE("speexDecoder::~speexDecoder\n"); + delete fStereoState; + delete fSpeexBuffer; speex_bits_destroy(&fBits); speex_decoder_destroy(fDecoderState); } @@ -51,6 +54,7 @@ status_t speexDecoder::Setup(media_format *inputFormat, const void *infoBuffer, int32 infoSize) { + debugger("speexDecoder::Setup"); if (inputFormat->type != B_MEDIA_ENCODED_AUDIO) { TRACE("speexDecoder::Setup not called with audio stream: not speex\n"); return B_ERROR; @@ -81,37 +85,54 @@ speexDecoder::Setup(media_format *inputFormat, fHeader = 0; return B_ERROR; } - if (fHeader->mode >= SPEEX_NB_MODES) { - TRACE("speexDecoder::Setup failed: unknown speex mode\n"); - return B_ERROR; - } - // setup mode - SpeexMode * mode; + // modify header to reflect settings switch (SpeexSettings::PreferredBand()) { case narrow_band: - mode = &speex_nb_mode; + fHeader->mode = 0; break; case wide_band: - mode = &speex_wb_mode; + fHeader->mode = 1; break; case ultra_wide_band: - mode = &speex_uwb_mode; + fHeader->mode = 2; break; case automatic_band: default: - mode = speex_mode_list[fHeader->mode]; break; } + switch (SpeexSettings::PreferredChannels()) { + case mono_channels: + fHeader->nb_channels = 1; + break; + case stereo_channels: + fHeader->nb_channels = 2; + break; + case automatic_channels: + default: + break; + } + if (SpeexSettings::SamplingRate() != 0) { + fHeader->rate = SpeexSettings::SamplingRate(); + } + // sanity checks #ifdef STRICT_SPEEX if (header->speex_version_id > 1) { TRACE("speexDecoder::Setup failed: version id too new"); return B_ERROR; } +#endif + if (fHeader->mode >= SPEEX_NB_MODES) { + TRACE("speexDecoder::Setup failed: unknown speex mode\n"); + return B_ERROR; + } + // setup from header + SpeexMode * mode = speex_mode_list[fHeader->mode]; +#ifdef STRICT_SPEEX if (mode->bitstream_version != fHeader->mode_bitstream_version) { TRACE("speexDecoder::Setup failed: bitstream version mismatch"); return B_ERROR; } -#endif // STRICT_SPEEX +#endif fDecoderState = speex_decoder_init(mode); if (fDecoderState == NULL) { TRACE("speexDecoder::Setup failed to initialize the decoder state"); @@ -119,11 +140,22 @@ speexDecoder::Setup(media_format *inputFormat, } if (SpeexSettings::PerceptualPostFilter()) { int enabled = 1; - speex_decoder_ctl(fDecoderState,SPEEX_SET_ENH,&enabled); + speex_decoder_ctl(fDecoderState, SPEEX_SET_ENH, &enabled); } - speex_decoder_ctl(fDecoderState,SPEEX_GET_FRAME_SIZE,&fSpeexFrameSize); + speex_decoder_ctl(fDecoderState, SPEEX_GET_FRAME_SIZE, &fSpeexFrameSize); + if (fHeader->nb_channels == 2) { + SpeexCallback callback; + SpeexStereoState stereo = SPEEX_STEREO_STATE_INIT; + callback.callback_id = SPEEX_INBAND_STEREO; + callback.func = speex_std_stereo_request_handler; + fStereoState = new SpeexStereoState(stereo); + callback.data = fStereoState; + speex_decoder_ctl(fDecoderState, SPEEX_SET_HANDLER, &callback); + fSpeexFrameSize *= 2; + } + delete fSpeexBuffer; fSpeexBuffer = new float[fSpeexFrameSize]; - + speex_decoder_ctl(fDecoderState, SPEEX_SET_SAMPLING_RATE, &fHeader->rate); // fill out the encoding format CopyInfoToEncodedFormat(inputFormat); return B_OK; @@ -137,6 +169,9 @@ void speexDecoder::CopyInfoToEncodedFormat(media_format * format) { = (media_encoded_audio_format::audio_encoding)'Spee'; if (fHeader->bitrate > 0) { format->u.encoded_audio.bit_rate = fHeader->bitrate; + } else { + speex_decoder_ctl(fDecoderState, SPEEX_GET_BITRATE, &fHeader->bitrate); + format->u.encoded_audio.bit_rate = fHeader->bitrate; } if (fHeader->nb_channels == 1) { format->u.encoded_audio.multi_info.channel_mask = B_CHANNEL_LEFT; @@ -154,6 +189,7 @@ void speexDecoder::CopyInfoToDecodedFormat(media_raw_audio_format * raf) { raf->byte_order = B_MEDIA_HOST_ENDIAN; // XXX should support other endain, too if (raf->buffer_size < 512 || raf->buffer_size > 65536) { raf->buffer_size = AudioBufferSize(raf); + raf->buffer_size = (1 + raf->buffer_size / fSpeexFrameSize) * fSpeexFrameSize; } // setup output variables fFrameSize = (raf->format & 0xf) * raf->channel_count; @@ -205,21 +241,7 @@ speexDecoder::Decode(void *buffer, int64 *frameCount, //TRACE("speexDecoder: Decoding start time %.6f\n", fStartTime / 1000000.0); // debugger("speexDecoder::Decode"); - while (out_bytes_needed > 0) { - if (fSpeexBytesRemaining > 0) { - if (fSpeexBytesRemaining < out_bytes_needed) { - memcpy(out_buffer,fSpeexBuffer,fSpeexBytesRemaining); - out_buffer += fSpeexBytesRemaining; - out_bytes_needed -= fSpeexBytesRemaining; - } else { - memcpy(out_buffer,fSpeexBuffer,out_bytes_needed); - memcpy(fSpeexBuffer,&fSpeexBuffer[fSpeexBytesRemaining], - fSpeexBytesRemaining-out_bytes_needed); - out_buffer += out_bytes_needed; - out_bytes_needed = 0; - break; - } - } + while (out_bytes_needed >= fSpeexFrameSize) { // get a new packet void *chunkBuffer; int32 chunkSize; @@ -238,8 +260,12 @@ speexDecoder::Decode(void *buffer, int64 *frameCount, } ogg_packet * packet = static_cast(chunkBuffer); speex_bits_read_from(&fBits, (char*)packet->packet, packet->bytes); - speex_decode(fDecoderState, &fBits, fSpeexBuffer); - fSpeexBytesRemaining = fSpeexFrameSize; + speex_decode(fDecoderState, &fBits, (float*)out_buffer); + if (fHeader->nb_channels == 2) { + speex_decode_stereo((float*)out_buffer, fSpeexFrameSize, fStereoState); + } + out_buffer += fSpeexFrameSize; + out_bytes_needed -= fSpeexFrameSize; } done: diff --git a/src/add-ons/media/plugins/speex/speexCodecPlugin.h b/src/add-ons/media/plugins/speex/speexCodecPlugin.h index 74d4c9f50f..1e67e7eb30 100644 --- a/src/add-ons/media/plugins/speex/speexCodecPlugin.h +++ b/src/add-ons/media/plugins/speex/speexCodecPlugin.h @@ -1,6 +1,7 @@ #include "DecoderPlugin.h" #include "speex.h" #include "speex_header.h" +#include "speex_stereo.h" #include "speex_callbacks.h" class speexDecoder : public Decoder @@ -29,10 +30,10 @@ private: SpeexBits fBits; void * fDecoderState; SpeexHeader * fHeader; + SpeexStereoState * fStereoState; int fSpeexFrameSize; float * fSpeexBuffer; - int fSpeexBytesRemaining; bigtime_t fStartTime; int fFrameSize;