Added time and position seeking support to the mp3 decoder plugin.

This commit is contained in:
Joshua Jones 2010-02-13 00:37:10 +00:00
parent e5fa03d1d6
commit f644990896
1 changed files with 102 additions and 53 deletions

View File

@ -36,7 +36,7 @@ cMP3Decoder::cMP3Decoder(IDataSource* stream) : IAudioDecoder(stream), Context(0
size |= (idv3Header[8] & 0x7f) << (1*7);
size |= (idv3Header[9] & 0x7f) ;
size += 10; // header size
size += 10;
DataOffset = size;
Stream->seek(DataOffset, false);
@ -108,7 +108,7 @@ int cMP3Decoder::getFrequency()
bool cMP3Decoder::isSeekingSupported()
{
return false;
return true;
}
bool cMP3Decoder::isValid()
@ -118,60 +118,63 @@ bool cMP3Decoder::isValid()
int cMP3Decoder::readAudioData(void* output, int amount)
{
//Check to see if we have an empty packet and fill it
if(CurrentPacket.size <= CurrentPacket.read)
if(Valid)
{
//Empty packet, grab a new one.
CurrentPacket.reset();
memset(CurrentPacket.data, 0, MPAUDEC_MAX_AUDIO_FRAME_SIZE);
unsigned char inputBuffer[4096];
int oldPos = Stream->getCurrentPos();
int inputSize = Stream->read(inputBuffer, Context->frame_size);
if(inputSize == 0)
return 0;
int rv = mpaudec_decode_frame( Context, CurrentPacket.data, &CurrentPacket.size, inputBuffer, inputSize);
Stream->seek(oldPos + rv, false);
//Oops, error...
if(rv < 0)
return -1;
//OpenAL really hates it if you try to change format in the middle
if(NumChannels != Context->channels)
return -1;
if(Frequency != Context->sample_rate)
return -1;
//Error from reading, but we need to try to move ahead to avoid stopping the feed since it may be recoverable
if(CurrentPacket.size < 0)
//Check to see if we have an empty packet and fill it
if(CurrentPacket.size <= CurrentPacket.read)
{
CurrentPacket.size = Context->frame_size;
memset(CurrentPacket.data, 0, CurrentPacket.size);
//Empty packet, grab a new one.
CurrentPacket.reset();
memset(CurrentPacket.data, 0, MPAUDEC_MAX_AUDIO_FRAME_SIZE);
unsigned char inputBuffer[MPAUDEC_MAX_AUDIO_FRAME_SIZE];
int oldPos = Stream->getCurrentPos();
int inputSize = Stream->read(inputBuffer, Context->frame_size > MPAUDEC_MAX_AUDIO_FRAME_SIZE ? MPAUDEC_MAX_AUDIO_FRAME_SIZE : Context->frame_size);
if(inputSize == 0)
return 0;
int rv = mpaudec_decode_frame( Context, CurrentPacket.data, &CurrentPacket.size, inputBuffer, inputSize);
Stream->seek(oldPos + rv, false);
//Oops, error...
if(rv < 0)
return -1;
//OpenAL really hates it if you try to change format in the middle
if(NumChannels != Context->channels)
return -1;
if(Frequency != Context->sample_rate)
return -1;
//Error from reading, but we need to try to move ahead to avoid stopping the feed since it may be recoverable
if(CurrentPacket.size < 0)
{
CurrentPacket.size = Context->frame_size;
memset(CurrentPacket.data, 0, CurrentPacket.size);
}
}
}
//If we have data left since last time, put it in if we have space
if( CurrentPacket.size > CurrentPacket.read )
{
int amountLeft = CurrentPacket.size - CurrentPacket.read;
if(amountLeft < amount)
//If we have data left since last time, put it in if we have space
if( CurrentPacket.size > CurrentPacket.read )
{
//Dump in all our data
memcpy(output, CurrentPacket.data + CurrentPacket.read, amountLeft);
CurrentPacket.read += amountLeft;
return amountLeft;
}
else
{
//Not enough space for all our data, put in a little bit
memcpy(output, CurrentPacket.data + CurrentPacket.read, amount);
CurrentPacket.read += amount;
return amount;
int amountLeft = CurrentPacket.size - CurrentPacket.read;
if(amountLeft < amount)
{
//Dump in all our data
memcpy(output, CurrentPacket.data + CurrentPacket.read, amountLeft);
CurrentPacket.read += amountLeft;
return amountLeft;
}
else
{
//Not enough space for all our data, put in a little bit
memcpy(output, CurrentPacket.data + CurrentPacket.read, amount);
CurrentPacket.read += amount;
return amount;
}
}
}
@ -180,8 +183,14 @@ int cMP3Decoder::readAudioData(void* output, int amount)
bool cMP3Decoder::setPosition(int position, bool relative)
{
if(position == 0 && !relative)
if(Valid)
{
if(relative)
position = Stream->getCurrentPos() + position;
if(position < DataOffset)
position = DataOffset;
//Just reload from scratch
Stream->seek(DataOffset, false);
@ -195,12 +204,52 @@ bool cMP3Decoder::setPosition(int position, bool relative)
Context->frame_size = oldContext.frame_size;
Context->sample_rate = oldContext.sample_rate;
Context->parse_only = 1;
int lastFrameSize = 0;
while(Stream->getCurrentPos() < position)
{
//Eat up frames till we reach about the right spot
unsigned char inputBuffer[MPAUDEC_MAX_AUDIO_FRAME_SIZE];
int oldPos = Stream->getCurrentPos();
int inputSize = Stream->read(inputBuffer, Context->frame_size > MPAUDEC_MAX_AUDIO_FRAME_SIZE ? MPAUDEC_MAX_AUDIO_FRAME_SIZE : Context->frame_size);
if(inputSize == 0)
{
Stream->seek(DataOffset, false);
return false;
}
unsigned char tempBuffer[MPAUDEC_MAX_AUDIO_FRAME_SIZE];
int outputSize = 0;
int rv = mpaudec_decode_frame( Context, tempBuffer, &outputSize, inputBuffer, inputSize);
Stream->seek(oldPos + rv, false);
//Oops, error...
if(rv < 0)
{
Stream->seek(DataOffset, false);
return false;
}
lastFrameSize = rv;
}
Context->parse_only = 0;
Stream->seek(-lastFrameSize, true);
return true;
}
return false;
}
bool cMP3Decoder::seek(float seconds, bool relative)
{
{
if(Valid)
{
int amountToSeek = seconds * (float)(Context->bit_rate / 8);
return setPosition(amountToSeek, relative);
}
return false;
}