makes noise in nplay, MediaPlayer will not use it, nothing sounds good

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@6198 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
shatty
2004-01-20 10:51:41 +00:00
parent 0c6beeacb4
commit 955c0efddc
5 changed files with 201 additions and 69 deletions
+1
View File
@@ -7,6 +7,7 @@ SubDirHdrs $(SUBDIR) libspeex ;
Addon speex : media plugins : Addon speex : media plugins :
speexCodecPlugin.cpp speexCodecPlugin.cpp
speexCodecDefaults.cpp
: false : libspeex.a libogg.a : false : libspeex.a libogg.a
; ;
@@ -0,0 +1,35 @@
#include "speexCodecDefaults.h"
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;
SpeexSettings::SpeexSettings()
{
}
/* static */ bool
SpeexSettings::PerceptualPostFilter(void)
{
return perceptual_post_filter;
}
/* static */ speex_mode
SpeexSettings::PreferredBand(void)
{
return preferred_band;
}
/* static */ speex_channels
SpeexSettings::PreferredChannels(void)
{
return preferred_channels;
}
// if non-zero, specifies a sampling rate in Hertz
/* static */ float
SpeexSettings::SamplingRate(void)
{
return sampling_rate;
}
@@ -0,0 +1,30 @@
enum speex_mode {
automatic_band = -1,
narrow_band,
wide_band,
ultra_wide_band,
};
enum speex_channels {
automatic_channels = -1,
mono_channels,
stereo_channels,
};
class SpeexSettings {
private:
SpeexSettings();
public:
static bool PerceptualPostFilter(void);
static speex_mode PreferredBand(void);
static speex_channels PreferredChannels(void);
// if non-zero, specifies a sampling rate in Hertz
static float SamplingRate(void);
private:
static bool perceptual_post_filter;
static speex_mode preferred_band;
static speex_channels preferred_channels;
static float sampling_rate;
};
@@ -7,6 +7,7 @@
#include <vector> #include <vector>
#include "ogg/ogg.h" #include "ogg/ogg.h"
#include "speexCodecPlugin.h" #include "speexCodecPlugin.h"
#include "speexCodecDefaults.h"
#define TRACE_THIS 1 #define TRACE_THIS 1
#if TRACE_THIS #if TRACE_THIS
@@ -18,15 +19,20 @@
#define DECODE_BUFFER_SIZE (32 * 1024) #define DECODE_BUFFER_SIZE (32 * 1024)
inline size_t inline size_t
AudioBufferSize(int32 channel_count, uint32 sample_format, float frame_rate, bigtime_t buffer_duration = 50000 /* 50 ms */) AudioBufferSize(media_raw_audio_format * raf, bigtime_t buffer_duration = 50000 /* 50 ms */)
{ {
return (sample_format & 0xf) * channel_count * (size_t)((frame_rate * buffer_duration) / 1000000.0); return (raf->format & 0xf) * (raf->channel_count)
* (size_t)((raf->frame_rate * buffer_duration) / 1000000.0);
} }
speexDecoder::speexDecoder() speexDecoder::speexDecoder()
{ {
TRACE("speexDecoder::speexDecoder\n"); TRACE("speexDecoder::speexDecoder\n");
speex_bits_init(&fBits);
fDecoderState = 0;
fHeader = 0;
fSpeexFrameSize = 0;
fSpeexBytesRemaining = 0;
fStartTime = 0; fStartTime = 0;
fFrameSize = 0; fFrameSize = 0;
fOutputBufferSize = 0; fOutputBufferSize = 0;
@@ -36,6 +42,8 @@ speexDecoder::speexDecoder()
speexDecoder::~speexDecoder() speexDecoder::~speexDecoder()
{ {
TRACE("speexDecoder::~speexDecoder\n"); TRACE("speexDecoder::~speexDecoder\n");
speex_bits_destroy(&fBits);
speex_decoder_destroy(fDecoderState);
} }
@@ -48,7 +56,7 @@ speexDecoder::Setup(media_format *inputFormat,
return B_ERROR; return B_ERROR;
} }
if (inputFormat->u.encoded_audio.encoding != 'Spee') { if (inputFormat->u.encoded_audio.encoding != 'Spee') {
TRACE("speexDecoder::Setup not called with 'vorb' stream: not speex\n"); TRACE("speexDecoder::Setup not called with 'Spee' stream: not speex\n");
return B_ERROR; return B_ERROR;
} }
if (inputFormat->MetaDataSize() != sizeof(std::vector<ogg_packet> *)) { if (inputFormat->MetaDataSize() != sizeof(std::vector<ogg_packet> *)) {
@@ -56,11 +64,66 @@ speexDecoder::Setup(media_format *inputFormat,
return B_ERROR; return B_ERROR;
} }
std::vector<ogg_packet> * packets = (std::vector<ogg_packet> *)inputFormat->MetaData(); std::vector<ogg_packet> * packets = (std::vector<ogg_packet> *)inputFormat->MetaData();
if (packets->size() != 2) { if (packets->size() < 2) {
TRACE("speexDecoder::Setup not called with two ogg_packets: not speex\n"); TRACE("speexDecoder::Setup not called with at least two ogg_packets: not speex\n");
return B_ERROR; return B_ERROR;
} }
debugger("speexDecoder::Setup"); // parse header packet
ogg_packet * packet = &(*packets)[0];
fHeader = speex_packet_to_header((char*)packet->packet, packet->bytes);
if (fHeader == NULL) {
TRACE("speexDecoder::Setup failed in ogg_packet to speex_header conversion\n");
return B_ERROR;
}
if (packets->size() != 2 + (unsigned)fHeader->extra_headers) {
TRACE("speexDecoder::Setup not called with all the extra headers\n");
delete fHeader;
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;
switch (SpeexSettings::PreferredBand()) {
case narrow_band:
mode = &speex_nb_mode;
break;
case wide_band:
mode = &speex_wb_mode;
break;
case ultra_wide_band:
mode = &speex_uwb_mode;
break;
case automatic_band:
default:
mode = speex_mode_list[fHeader->mode];
break;
}
#ifdef STRICT_SPEEX
if (header->speex_version_id > 1) {
TRACE("speexDecoder::Setup failed: version id too new");
return B_ERROR;
}
if (mode->bitstream_version != fHeader->mode_bitstream_version) {
TRACE("speexDecoder::Setup failed: bitstream version mismatch");
return B_ERROR;
}
#endif // STRICT_SPEEX
fDecoderState = speex_decoder_init(mode);
if (fDecoderState == NULL) {
TRACE("speexDecoder::Setup failed to initialize the decoder state");
return B_ERROR;
}
if (SpeexSettings::PerceptualPostFilter()) {
int enabled = 1;
speex_decoder_ctl(fDecoderState,SPEEX_SET_ENH,&enabled);
}
speex_decoder_ctl(fDecoderState,SPEEX_GET_FRAME_SIZE,&fSpeexFrameSize);
fSpeexBuffer = new float[fSpeexFrameSize];
// fill out the encoding format // fill out the encoding format
CopyInfoToEncodedFormat(inputFormat); CopyInfoToEncodedFormat(inputFormat);
return B_OK; return B_OK;
@@ -68,33 +131,32 @@ speexDecoder::Setup(media_format *inputFormat,
void speexDecoder::CopyInfoToEncodedFormat(media_format * format) { void speexDecoder::CopyInfoToEncodedFormat(media_format * format) {
format->type = B_MEDIA_ENCODED_AUDIO; format->type = B_MEDIA_ENCODED_AUDIO;
format->user_data_type = B_CODEC_TYPE_INFO;
strncpy((char*)format->user_data,"Spee",4);
format->u.encoded_audio.encoding format->u.encoded_audio.encoding
= (media_encoded_audio_format::audio_encoding)'Spee'; = (media_encoded_audio_format::audio_encoding)'Spee';
/* if (fInfo.bitrate_nominal > 0) { if (fHeader->bitrate > 0) {
format->u.encoded_audio.bit_rate = fInfo.bitrate_nominal; format->u.encoded_audio.bit_rate = fHeader->bitrate;
} else if (fInfo.bitrate_upper > 0) { }
format->u.encoded_audio.bit_rate = fInfo.bitrate_upper; if (fHeader->nb_channels == 1) {
} else if (fInfo.bitrate_lower > 0) { format->u.encoded_audio.multi_info.channel_mask = B_CHANNEL_LEFT;
format->u.encoded_audio.bit_rate = fInfo.bitrate_lower; } else {
format->u.encoded_audio.multi_info.channel_mask = B_CHANNEL_LEFT | B_CHANNEL_RIGHT;
} }
*/
CopyInfoToDecodedFormat(&format->u.encoded_audio.output); CopyInfoToDecodedFormat(&format->u.encoded_audio.output);
format->u.encoded_audio.frame_size = sizeof(ogg_packet); format->u.encoded_audio.frame_size = sizeof(ogg_packet);
} }
void speexDecoder::CopyInfoToDecodedFormat(media_raw_audio_format * raf) { void speexDecoder::CopyInfoToDecodedFormat(media_raw_audio_format * raf) {
/* raf->frame_rate = (float)fHeader->rate; // XXX int32->float ??
raf->frame_rate = (float)fInfo.rate; // XXX long->float ?? raf->channel_count = fHeader->nb_channels;
raf->channel_count = fInfo.channels;
raf->format = media_raw_audio_format::B_AUDIO_FLOAT; // XXX verify: support others? raf->format = media_raw_audio_format::B_AUDIO_FLOAT; // XXX verify: support others?
raf->byte_order = B_MEDIA_HOST_ENDIAN; // XXX should support other endain, too raf->byte_order = B_MEDIA_HOST_ENDIAN; // XXX should support other endain, too
if (raf->buffer_size < 512 || raf->buffer_size > 65536) { if (raf->buffer_size < 512 || raf->buffer_size > 65536) {
raf->buffer_size = AudioBufferSize(raf->channel_count,raf->format,raf->frame_rate); raf->buffer_size = AudioBufferSize(raf);
} }
// setup output variables // setup output variables
fFrameSize = (raf->format & 0xf) * fInfo.channels; fFrameSize = (raf->format & 0xf) * raf->channel_count;
*/
fOutputBufferSize = raf->buffer_size; fOutputBufferSize = raf->buffer_size;
} }
@@ -109,12 +171,11 @@ speexDecoder::NegotiateOutputFormat(media_format *ioDecodedFormat)
CopyInfoToDecodedFormat(&ioDecodedFormat->u.raw_audio); CopyInfoToDecodedFormat(&ioDecodedFormat->u.raw_audio);
// add the media_mult_audio_format fields // add the media_mult_audio_format fields
if (ioDecodedFormat->u.raw_audio.channel_mask == 0) { if (ioDecodedFormat->u.raw_audio.channel_mask == 0) {
/* if (fInfo.channels == 1) { if (fHeader->nb_channels == 1) {
ioDecodedFormat->u.raw_audio.channel_mask = B_CHANNEL_LEFT; ioDecodedFormat->u.raw_audio.channel_mask = B_CHANNEL_LEFT;
} else { } else {
ioDecodedFormat->u.raw_audio.channel_mask = B_CHANNEL_LEFT | B_CHANNEL_RIGHT; ioDecodedFormat->u.raw_audio.channel_mask = B_CHANNEL_LEFT | B_CHANNEL_RIGHT;
} }
*/
} }
return B_OK; return B_OK;
} }
@@ -126,12 +187,8 @@ speexDecoder::Seek(uint32 seekTo,
bigtime_t seekTime, bigtime_t *time) bigtime_t seekTime, bigtime_t *time)
{ {
TRACE("speexDecoder::Seek\n"); TRACE("speexDecoder::Seek\n");
/* int ignore = 0;
float **pcm; speex_decoder_ctl(fDecoderState,SPEEX_RESET_STATE,&ignore);
// throw the old samples away!
int samples = speex_synthesis_pcmout(&fDspState,&pcm);
speex_synthesis_read(&fDspState,samples);
*/
return B_OK; return B_OK;
} }
@@ -147,50 +204,48 @@ speexDecoder::Decode(void *buffer, int64 *frameCount,
mediaHeader->start_time = fStartTime; mediaHeader->start_time = fStartTime;
//TRACE("speexDecoder: Decoding start time %.6f\n", fStartTime / 1000000.0); //TRACE("speexDecoder: Decoding start time %.6f\n", fStartTime / 1000000.0);
debugger("speexDecoder::Decode"); // debugger("speexDecoder::Decode");
while (out_bytes_needed > 0) { while (out_bytes_needed > 0) {
/* int samples; if (fSpeexBytesRemaining > 0) {
float **pcm; if (fSpeexBytesRemaining < out_bytes_needed) {
while ((samples = speex_synthesis_pcmout(&fDspState,&pcm)) == 0) { memcpy(out_buffer,fSpeexBuffer,fSpeexBytesRemaining);
// get a new packet out_buffer += fSpeexBytesRemaining;
void *chunkBuffer; out_bytes_needed -= fSpeexBytesRemaining;
int32 chunkSize; } else {
media_header mh; memcpy(out_buffer,fSpeexBuffer,out_bytes_needed);
status_t status = GetNextChunk(&chunkBuffer, &chunkSize, &mh); memcpy(fSpeexBuffer,&fSpeexBuffer[fSpeexBytesRemaining],
if (status == B_LAST_BUFFER_ERROR) { fSpeexBytesRemaining-out_bytes_needed);
goto done; out_buffer += out_bytes_needed;
} out_bytes_needed = 0;
if (status != B_OK) { break;
TRACE("speexDecoder::Decode: GetNextChunk failed\n");
return status;
}
if (chunkSize != sizeof(ogg_packet)) {
TRACE("speexDecoder::Decode: chunk not ogg_packet-sized\n");
return B_ERROR;
}
ogg_packet * packet = static_cast<ogg_packet*>(chunkBuffer);
if (speex_synthesis(&fBlock,packet)==0) {
speex_synthesis_blockin(&fDspState,&fBlock);
} }
} }
// reduce samples to the amount of samples we will actually consume // get a new packet
samples = min_c(samples,out_bytes_needed/fFrameSize); void *chunkBuffer;
for (int sample = 0; sample < samples ; sample++) { int32 chunkSize;
for (int channel = 0; channel < fInfo.channels; channel++) { media_header mh;
*((float*)out_buffer) = pcm[channel][sample]; status_t status = GetNextChunk(&chunkBuffer, &chunkSize, &mh);
out_buffer += sizeof(float); if (status == B_LAST_BUFFER_ERROR) {
} goto done;
}
if (status != B_OK) {
TRACE("speexDecoder::Decode: GetNextChunk failed\n");
return status;
} }
out_bytes_needed -= samples * fInfo.channels * sizeof(float); if (chunkSize != sizeof(ogg_packet)) {
// report back how many samples we consumed TRACE("speexDecoder::Decode: chunk not ogg_packet-sized\n");
speex_synthesis_read(&fDspState,samples); return B_ERROR;
}
fStartTime += (1000000LL * samples) / fInfo.rate; ogg_packet * packet = static_cast<ogg_packet*>(chunkBuffer);
*/ speex_bits_read_from(&fBits, (char*)packet->packet, packet->bytes);
//TRACE("speexDecoder: fStartTime inc'd to %.6f\n", fStartTime / 1000000.0); speex_decode(fDecoderState, &fBits, fSpeexBuffer);
fSpeexBytesRemaining = fSpeexFrameSize;
} }
done: done:
uint samples = (out_buffer - (uint8*)buffer) / fFrameSize;
fStartTime += (1000000LL * samples) / fHeader->rate;
//TRACE("speexDecoder: fStartTime inc'd to %.6f\n", fStartTime / 1000000.0);
*frameCount = (fOutputBufferSize - out_bytes_needed) / fFrameSize; *frameCount = (fOutputBufferSize - out_bytes_needed) / fFrameSize;
if (out_buffer != buffer) { if (out_buffer != buffer) {
@@ -1,4 +1,7 @@
#include "DecoderPlugin.h" #include "DecoderPlugin.h"
#include "speex.h"
#include "speex_header.h"
#include "speex_callbacks.h"
class speexDecoder : public Decoder class speexDecoder : public Decoder
{ {
@@ -23,6 +26,14 @@ private:
void CopyInfoToEncodedFormat(media_format * format); void CopyInfoToEncodedFormat(media_format * format);
void CopyInfoToDecodedFormat(media_raw_audio_format * raf); void CopyInfoToDecodedFormat(media_raw_audio_format * raf);
SpeexBits fBits;
void * fDecoderState;
SpeexHeader * fHeader;
int fSpeexFrameSize;
float * fSpeexBuffer;
int fSpeexBytesRemaining;
bigtime_t fStartTime; bigtime_t fStartTime;
int fFrameSize; int fFrameSize;
int fOutputBufferSize; int fOutputBufferSize;