Half ready, not working mp3 streaming code.

This commit is contained in:
johns 2002-12-17 14:42:01 +00:00
parent a10c8c61ac
commit 65041d9073

View file

@ -23,6 +23,8 @@
//
// $Id$
// FIXME: JOHNS: MP3 streaming did not yet work.
//@{
/*----------------------------------------------------------------------------
@ -55,6 +57,17 @@ typedef struct _mad_user_ {
unsigned char Buffer[4096]; // Decoded buffer
} MyUser;
/**
** Private mp3 data structure to handle mp3 streaming.
*/
typedef struct _mp3_data_ {
char* PointerInBuffer; /// Pointer into buffer
struct mad_decoder Decoder[1]; /// Mad decoder handle
MyUser User[1]; /// Decoder user data
} Mp3Data;
#define MP3_BUFFER_SIZE (12 * 1024) /// Buffer size to fill
/*----------------------------------------------------------------------------
-- Functions
----------------------------------------------------------------------------*/
@ -181,39 +194,113 @@ local enum mad_flow MAD_error(void *user __attribute__((unused)),
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/**
** Read one frame from mad decoder.
**
** @param decoder Decoder
** @param buf Buffer to write data to
** @param len Length of the buffer
**
** @return Number of bytes read
*/
local int MadRead(struct mad_decoder* decoder, unsigned char* buf, int len)
{
struct mad_stream *stream;
struct mad_frame *frame;
struct mad_synth *synth;
DebugLevel0Fn("%p %p %d\n" _C_ decoder _C_ buf _C_ len);
stream = &decoder->sync->stream;
frame = &decoder->sync->frame;
synth = &decoder->sync->synth;
DebugLevel0Fn("Error: %d\n" _C_ stream->error);
do {
DebugLevel0Fn("Read stream\n");
switch (MAD_read(decoder->cb_data, stream)) {
case MAD_FLOW_STOP:
return 0;
case MAD_FLOW_BREAK:
return -1;
case MAD_FLOW_IGNORE:
continue;
case MAD_FLOW_CONTINUE:
break;
}
while (1) {
if (mad_frame_decode(frame, stream) == -1) {
if (!MAD_RECOVERABLE(stream->error)) {
break;
}
switch (MAD_error(decoder->cb_data, stream, frame)) {
case MAD_FLOW_STOP:
return 0;
case MAD_FLOW_BREAK:
return -1;
case MAD_FLOW_IGNORE:
break;
case MAD_FLOW_CONTINUE:
default:
continue;
}
}
mad_synth_frame(synth, frame);
#if 0
// FIXME: write out the frame buffer!
switch (decoder->output_func(decoder->cb_data, &frame->header,
&synth->pcm)) {
case MAD_FLOW_STOP:
return 0;
case MAD_FLOW_BREAK:
return -1;
case MAD_FLOW_IGNORE:
case MAD_FLOW_CONTINUE:
break;
}
#endif
}
// Should stop here!
} while (stream->error == MAD_ERROR_BUFLEN);
return -1;
}
/**
** Type member function to read from the Mp3 file
** Type member function to read from the mp3 file
**
** @param sample Sample reading from
** @param buf Buffer to write data to
** @param len Length of the buffer
** @param sample Sample reading from
** @param buf Buffer to write data to
** @param len Length of the buffer
**
** @return Number of bytes read
** @return Number of bytes read
*/
local int Mp3ReadStream(Sample* sample, void* buf, int len)
{
Mp3Data* data;
int i;
int n;
int bitstream;
data = (Mp3Data*) sample->User;
DebugLevel0Fn("%p %d\n" _C_ buf _C_ len);
data = sample->User;
// see if we have enough read already
if (data->PointerInBuffer + len - sample->Data > sample->Length) {
if (data->PointerInBuffer - sample->Data + len > sample->Length) {
// not enough in buffer, read more
n = sample->Length - (data->PointerInBuffer - sample->Data);
memcpy(sample->Data, data->PointerInBuffer, n);
sample->Length = n;
data->PointerInBuffer = sample->Data;
n = OGG_BUFFER_SIZE - n;
n = MP3_BUFFER_SIZE - n;
for (;;) {
i = ov_read(data->VorbisFile,
data->PointerInBuffer + sample->Length, n, 0, 2, 1,
&bitstream);
i = MadRead(data->Decoder, data->PointerInBuffer + sample->Length,
n);
if (i <= 0) {
break;
}
@ -234,18 +321,30 @@ local int Mp3ReadStream(Sample* sample, void* buf, int len)
}
/**
** Type member function to free an Mp3 file
** Type member function to free an mp3 file
**
** @param sample Sample to free
** @param sample Sample to free
*/
local void Mp3FreeStream(Sample* sample)
{
Mp3Data* data;
IfDebug( AllocatedSoundMemory -= sizeof(*sample) + OGG_BUFFER_SIZE);
IfDebug( AllocatedSoundMemory -= sizeof(*sample) + MP3_BUFFER_SIZE);
data = sample->User;
// release the decoder
mad_synth_finish(data->Decoder->sync->synth);
mad_frame_finish(&data->Decoder->sync->frame);
mad_stream_finish(&data->Decoder->sync->stream);
free(data->Decoder->sync);
data->Decoder->sync = NULL;
mad_decoder_finish(data->Decoder);
CLclose(data->User->File);
data = (Mp3Data*)sample->User;
ov_clear(data->VorbisFile);
free(data);
free(sample);
}
@ -257,16 +356,15 @@ local const SampleType Mp3StreamSampleType = {
Mp3ReadStream,
Mp3FreeStream,
};
#endif
/**
** Type member function to read from the Mp3 file
** Type member function to read from the mp3 file
**
** @param sample Sample reading from
** @param buf Buffer to write data to
** @param len Length of the buffer
** @param sample Sample reading from
** @param buf Buffer to write data to
** @param len Length of the buffer
**
** @return Number of bytes read
** @return Number of bytes read
*/
local int Mp3Read(Sample* sample, void* buf, int len)
{
@ -284,9 +382,9 @@ local int Mp3Read(Sample* sample, void* buf, int len)
}
/**
** Type member function to free an Mp3 file
** Type member function to free an mp3 file
**
** @param sample Sample to free
** @param sample Sample to free
*/
local void Mp3Free(Sample* sample)
{
@ -303,121 +401,6 @@ local const SampleType Mp3SampleType = {
Mp3Free,
};
/**
** Test code.
*/
static int run_sync(struct mad_decoder *decoder)
{
enum mad_flow (*error_func) (void *, struct mad_stream *,
struct mad_frame *);
void *error_data;
int bad_last_frame = 0;
struct mad_stream *stream;
struct mad_frame *frame;
struct mad_synth *synth;
int result = 0;
error_func = decoder->error_func;
error_data = decoder->cb_data;
stream = &decoder->sync->stream;
frame = &decoder->sync->frame;
synth = &decoder->sync->synth;
mad_stream_init(stream);
mad_frame_init(frame);
mad_synth_init(synth);
mad_stream_options(stream, decoder->options);
do {
switch (decoder->input_func(decoder->cb_data, stream)) {
case MAD_FLOW_STOP:
goto done;
case MAD_FLOW_BREAK:
goto fail;
case MAD_FLOW_IGNORE:
continue;
case MAD_FLOW_CONTINUE:
break;
}
while (1) {
if (decoder->header_func) {
if (mad_header_decode(&frame->header, stream) == -1) {
if (!MAD_RECOVERABLE(stream->error))
break;
switch (error_func(error_data, stream, frame)) {
case MAD_FLOW_STOP:
goto done;
case MAD_FLOW_BREAK:
goto fail;
case MAD_FLOW_IGNORE:
case MAD_FLOW_CONTINUE:
default:
continue;
}
}
switch (decoder->header_func(decoder->cb_data, &frame->header)) {
case MAD_FLOW_STOP:
goto done;
case MAD_FLOW_BREAK:
goto fail;
case MAD_FLOW_IGNORE:
continue;
case MAD_FLOW_CONTINUE:
break;
}
}
if (mad_frame_decode(frame, stream) == -1) {
if (!MAD_RECOVERABLE(stream->error))
break;
switch (error_func(error_data, stream, frame)) {
case MAD_FLOW_STOP:
goto done;
case MAD_FLOW_BREAK:
goto fail;
case MAD_FLOW_IGNORE:
break;
case MAD_FLOW_CONTINUE:
default:
continue;
}
} else
bad_last_frame = 0;
mad_synth_frame(synth, frame);
if (decoder->output_func) {
switch (decoder->output_func(decoder->cb_data, &frame->header,
&synth->pcm)) {
case MAD_FLOW_STOP:
goto done;
case MAD_FLOW_BREAK:
goto fail;
case MAD_FLOW_IGNORE:
case MAD_FLOW_CONTINUE:
break;
}
}
}
} while (stream->error == MAD_ERROR_BUFLEN);
fail:
result = -1;
done:
mad_synth_finish(synth);
mad_frame_finish(frame);
mad_stream_finish(stream);
return result;
}
/**
** Load mp3.
**
@ -425,13 +408,13 @@ done:
** @param flags Load flags.
**
** @return Returns the loaded sample.
**
** @todo Support more flags, LoadOnDemand.
*/
global Sample *LoadMp3(const char* name, int flags __attribute__((unused)))
global Sample *LoadMp3(const char* name, int flags)
{
MyUser user;
CLFile* f;
unsigned char magic[2];
struct mad_decoder decoder;
Sample* sample;
if (!(f = CLopen(name))) {
@ -454,47 +437,95 @@ global Sample *LoadMp3(const char* name, int flags __attribute__((unused)))
DebugLevel2Fn("Have mp3 file %s\n" _C_ name);
sample = malloc(sizeof(*sample));
sample->Channels = 0;
sample->SampleSize = 0;
sample->Frequency = 0;
sample->Length = 0;
#ifdef MP3_STREAM_WORKS
if (flags & PlayAudioStream)
#else
if (0 && (flags & PlayAudioStream))
#endif
{
Mp3Data* data;
// configure input, output, and error functions
user.File = f;
user.Sample = sample;
sample = malloc(sizeof(*sample) + MP3_BUFFER_SIZE);
if (!sample) {
fprintf(stderr, "Out of memory\n");
CLclose(f);
return NULL;
}
data = malloc(sizeof(*data));
if (!data) {
fprintf(stderr, "Out of memory\n");
free(sample);
CLclose(f);
return NULL;
}
sample->User = data;
sample->Channels = 0;
sample->SampleSize = 0;
sample->Frequency = 0;
sample->Length = 0;
sample->Type = &Mp3StreamSampleType;
mad_decoder_init(&decoder, &user,
MAD_read, 0 /* header */, 0 /* filter */, MAD_write,
MAD_error, 0 /* message */);
data->User->File = f;
data->User->Sample = sample;
// start decoding
// mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);
// configure input, output, and error functions
decoder.sync = malloc(sizeof(*decoder.sync));
if (!decoder.sync) {
mad_decoder_init(data->Decoder, data->User,
MAD_read, NULL /* header */, NULL /* filter */, MAD_write,
MAD_error, NULL /* message */);
data->Decoder->sync = malloc(sizeof(*data->Decoder->sync));
if (!data->Decoder->sync) {
fprintf(stderr, "Out of memory\n");
mad_decoder_finish(data->Decoder);
free(data);
free(sample);
CLclose(f);
return NULL;
}
mad_stream_init(&data->Decoder->sync->stream);
mad_frame_init(&data->Decoder->sync->frame);
mad_synth_init(&data->Decoder->sync->synth);
mad_stream_options(&data->Decoder->sync->stream,
data->Decoder->options);
// Read first frame for channels, ...
data->PointerInBuffer = sample->Data;
sample->Length = MadRead(data->Decoder, sample->Data, MP3_BUFFER_SIZE);
DebugLevel0Fn(" %d\n" _C_ sizeof(*sample) + MP3_BUFFER_SIZE);
IfDebug( AllocatedSoundMemory += sizeof(*sample) + MP3_BUFFER_SIZE);
return sample;
} else {
MyUser user;
struct mad_decoder decoder;
sample = calloc(1, sizeof(*sample));
user.File = f;
user.Sample = sample;
// configure input, output, and error functions
mad_decoder_init(&decoder, &user,
MAD_read, NULL /* header */, NULL /* filter */, MAD_write,
MAD_error, NULL /* message */);
mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);
// release the decoder
mad_decoder_finish(&decoder);
CLclose(f);
return NULL;
user.Sample->Type = &Mp3SampleType;
user.Sample->User = 0;
DebugLevel0Fn(" %d\n" _C_ user.Sample->Length);
IfDebug( AllocatedSoundMemory += user.Sample->Length; );
return user.Sample;
}
run_sync(&decoder);
free(decoder.sync);
decoder.sync = 0;
// release the decoder
mad_decoder_finish(&decoder);
CLclose(f);
user.Sample->Type = &Mp3SampleType;
user.Sample->User = 0;
DebugLevel0Fn(" %d\n" _C_ user.Sample->Length);
IfDebug( AllocatedSoundMemory += user.Sample->Length; );
return user.Sample;
}
#endif // } WITH_SOUND && USE_MAD