diff options
Diffstat (limited to 'Src/mp3-mpg123/adts_mpg123.cpp')
-rw-r--r-- | Src/mp3-mpg123/adts_mpg123.cpp | 279 |
1 files changed, 279 insertions, 0 deletions
diff --git a/Src/mp3-mpg123/adts_mpg123.cpp b/Src/mp3-mpg123/adts_mpg123.cpp new file mode 100644 index 00000000..272291bd --- /dev/null +++ b/Src/mp3-mpg123/adts_mpg123.cpp @@ -0,0 +1,279 @@ +#include "ADTS_MPG123.h" +#include "../winamp/wa_ipc.h" +#include <math.h> +#include "../nsutil/pcm.h" +#include <assert.h> + +ADTS_MPG123::ADTS_MPG123() : decoder(0), gain(1.f) +{ + decoderDelay = 529; + + bitsPerSample = 0; + allowRG = false; + useFloat = false; + channels = 0; + sampleRate = 0; + decode_buffer = 0; + decode_buffer_length = 0; +} + +ADTS_MPG123::~ADTS_MPG123() +{ + if (decoder) { + mpg123_delete(decoder); + decoder = 0; + } + free(decode_buffer); +} + +int ADTS_MPG123::Initialize(bool forceMono, bool reverseStereo, bool allowSurround, int maxBits, bool _allowRG, bool _useFloat, bool _useCRC) +{ + allowRG = _allowRG; + useFloat = _useFloat; + int downmix = 0; + if (reverseStereo) + downmix = 2; + else + downmix = forceMono ? 1 : 0; + bitsPerSample = maxBits; + + decoder = mpg123_new(NULL, NULL); + long flags = MPG123_QUIET|MPG123_FORCE_FLOAT|MPG123_SKIP_ID3V2|MPG123_IGNORE_STREAMLENGTH|MPG123_IGNORE_INFOFRAME; + if (forceMono) { + flags |= MPG123_FORCE_MONO; + } + mpg123_param(decoder, MPG123_FLAGS, flags, 0); + mpg123_param(decoder, MPG123_RVA, MPG123_RVA_OFF, 0); + + return 0; +} + +bool ADTS_MPG123::Open(ifc_mpeg_stream_reader *file) +{ + mpg123_open_feed(decoder); + if (allowRG) { + gain = file->MPEGStream_Gain(); + } + return true; +} + +void ADTS_MPG123::Close() +{ + if (decoder) { + mpg123_delete(decoder); + decoder = 0; + } +} + +bool ADTS_MPG123::_UpdateProperties() +{ + if (decoder && (!channels || !sampleRate)) { + long sample_rate = 44100; + int channels = 2; + int encoding = 0; + if (mpg123_getformat(decoder, &sample_rate, &channels, &encoding) == MPG123_OK) { + this->channels = channels; + this->sampleRate = sample_rate; + } + } + + return channels && sampleRate; +} + +void ADTS_MPG123::GetOutputParameters(size_t *numBits, int *numChannels, int *sampleRate) +{ + _UpdateProperties(); + *sampleRate = this->sampleRate; + *numChannels = this->channels; + *numBits = bitsPerSample; +} + +void ADTS_MPG123::CalculateFrameSize(int *frameSize) +{ + _UpdateProperties(); + *frameSize = (int)(bitsPerSample/8) * channels * mpg123_spf(decoder); +#if 0 // TODO? + if (decoder->GetStreamInfo()->GetLayer() == 1) + *frameSize *= 3; +#endif +} + +void ADTS_MPG123::Flush(ifc_mpeg_stream_reader *file) +{ + mpg123_open_feed(decoder); +} + +size_t ADTS_MPG123::GetCurrentBitrate() +{ + mpg123_frameinfo frameInfo; + if (mpg123_info(decoder, &frameInfo) == MPG123_OK) { + return frameInfo.bitrate; + } else { + return 0; + } +} + +size_t ADTS_MPG123::GetDecoderDelay() +{ + return decoderDelay; +} + +static void Decimate(const float *input, void *output, size_t numSamples, size_t *outputWritten, int bitsPerSample, bool useFloat, float gain) +{ + if (!useFloat) + { + // TODO seen a few crashes reported where 'output' is 0 + nsutil_pcm_FloatToInt_Interleaved_Gain(output, input, bitsPerSample, numSamples, gain); + } + else if (gain != 1.f) + { + float *data = (float *)output; + for (size_t i=0;i<numSamples;i++) + data[i]*=gain; + //data[i]=input[i]*gain; + } + + *outputWritten = numSamples * (bitsPerSample / 8); +} + +int ADTS_MPG123::_Read(ifc_mpeg_stream_reader *_file) +{ + int err; + do { + unsigned char buffer[4096]; + size_t bytes = 0; + _file->MPEGStream_Read(buffer, sizeof(buffer), &bytes); + err = mpg123_feed(decoder, buffer, bytes); + } while (err == MPG123_NEED_MORE); + switch(err) { + case MPG123_OK: + return adts::SUCCESS; + case MPG123_NEED_MORE: + if (_file->MPEGStream_EOF()) { + return adts::ENDOFFILE; + } else { + return adts::NEEDMOREDATA; + } + default: + return adts::FAILURE; + } +} + +/* +notes for mp3 surround implementations +need to check the first two frames for ancillary data +store first valid in temp +store second valid frame in delay line +decimate first valid into output buffer +ancillary data is stored one frame behind, so PCM data decoded from mp3 frame n combines with anc data from frame n+1 +*/ +int ADTS_MPG123::Sync(ifc_mpeg_stream_reader *_file, unsigned __int8 *output, size_t outputSize, size_t *outputWritten, size_t *bitrate) +{ + if (outputWritten) { + *outputWritten = 0; + } + + int err = _Read(_file); + if (err == adts::SUCCESS) { + err = mpg123_read(decoder, 0, 0, 0); + if (err == MPG123_NEED_MORE) { + return adts::NEEDMOREDATA; + } + if (err != MPG123_NEW_FORMAT + && err != MPG123_OK) { + return adts::FAILURE; + } + _UpdateProperties(); + mpg123_frameinfo frameInfo; + err = mpg123_info(decoder, &frameInfo); + if (err == MPG123_OK) { + *bitrate = frameInfo.bitrate; + return adts::SUCCESS; + } else { + return adts::NEEDMOREDATA; + } + } else { + return err; + } +} + +int ADTS_MPG123::Decode(ifc_mpeg_stream_reader *_file, unsigned __int8 *output, size_t outputSize, size_t *outputWritten, size_t *bitrate, size_t *endCut) +{ + bool retried=false; + for (;;) { + if (!decode_buffer) { + int channels = 2; + long sample_rate; + int encoding; + if (mpg123_getformat(decoder, &sample_rate, &channels, &encoding) == MPG123_OK) { + this->channels = channels; + decode_buffer_length = sizeof(float) * channels * mpg123_spf(decoder); + decode_buffer = (float *)malloc(decode_buffer_length); + if (!decode_buffer) { + return adts::FAILURE; + } + } + } + + float *flData=useFloat?(float *)output:decode_buffer; + size_t flDataSize=useFloat?outputSize:decode_buffer_length; + size_t done=0; + int err = mpg123_read(decoder, (unsigned char *)flData, flDataSize, &done); + switch(err) { + case MPG123_OK: + { + Decimate(flData, output, done / sizeof(float), outputWritten, (int)bitsPerSample, useFloat, (float)gain); + mpg123_frameinfo frameInfo; + if (mpg123_info(decoder, &frameInfo) == MPG123_OK) { + *bitrate = frameInfo.bitrate; + } + } + return adts::SUCCESS; + case MPG123_NEW_FORMAT: + assert(done == 0); + return adts::SUCCESS; + case MPG123_NEED_MORE: + if (done) { + Decimate(flData, output, done / sizeof(float), outputWritten, (int)bitsPerSample, useFloat, (float)gain); + mpg123_frameinfo frameInfo; + if (mpg123_info(decoder, &frameInfo) == MPG123_OK) { + *bitrate = frameInfo.bitrate; + } + return adts::SUCCESS; + } else if (_file->MPEGStream_EOF()) { + return adts::ENDOFFILE; + } else { + if (retried) { + return adts::NEEDMOREDATA; + } else { + retried=true; + err = _Read(_file); + if (err != adts::SUCCESS) { + return err; + } else { + break; + } + } + } + default: + assert(done == 0); + return adts::FAILURE; + } + } +} + +int ADTS_MPG123::GetLayer() +{ + if (decoder) { + mpg123_frameinfo frameInfo; + mpg123_info(decoder, &frameInfo); + return frameInfo.layer; + } else { + return 0; + } +} + +void ADTS_MPG123::Release() +{ + delete this; +}
\ No newline at end of file |