diff options
Diffstat (limited to 'Src/alac/ALACMP4Decoder.cpp')
-rw-r--r-- | Src/alac/ALACMP4Decoder.cpp | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/Src/alac/ALACMP4Decoder.cpp b/Src/alac/ALACMP4Decoder.cpp new file mode 100644 index 00000000..13ed2ec5 --- /dev/null +++ b/Src/alac/ALACMP4Decoder.cpp @@ -0,0 +1,197 @@ +/* copyright 2006 Ben Allison */ +#include "ALACMP4Decoder.h" +#include "alac/ALACBitUtilities.h" +#include "api__alac.h" +#include "decomp.h" +#include <math.h> +#include <string.h> +#include "../external_dependencies/libmp4v2/mp4.h" +#include "../Plugins/Input/in_mp4/mpeg4audio.h" + + +// {B6CB4A7C-A8D0-4c55-8E60-9F7A7A23DA0F} +static const GUID playbackConfigGroupGUID = +{ 0xb6cb4a7c, 0xa8d0, 0x4c55, { 0x8e, 0x60, 0x9f, 0x7a, 0x7a, 0x23, 0xda, 0xf } }; + +int ALACMP4Decoder::OpenMP4(MP4FileHandle mp4_file, MP4TrackId mp4_track, size_t output_bits, size_t maxChannels, bool useFloat) +{ + if (useFloat) + return MP4_FAILURE; + // get requested output bits + this->output_bits = (int)output_bits; + + use_rg = false; + rg = 1.0f; + uint64_t val; + if (MP4GetTrackIntegerProperty(mp4_file, mp4_track, "mdia.minf.stbl.stsd.*[0].channels", &val)) + channels = (int)val; + else + channels=2; + + if (MP4GetTrackIntegerProperty(mp4_file, mp4_track, "mdia.minf.stbl.stsd.*[0].sampleSize", &val)) + bps= (int)val; + else + bps=16; + + return MP4_SUCCESS; +} + +int ALACMP4Decoder::GetCurrentBitrate(unsigned int *bitrate) +{ + if (mpAlacDecoder->mConfig.avgBitRate) + { + *bitrate = mpAlacDecoder->mConfig.avgBitRate; + return MP4_SUCCESS; + } + return MP4_GETCURRENTBITRATE_UNKNOWN; // TODO +} + + /* + * 32 bits atom size + * 32 bits tag ("alac") + * + * Following data is passed to the function, ALACSpecificConfig structure (24 Bytes) does not contain + * "tag version", check and skip if data contains it + * + * 32 bits tag version (0) + * 32 bits samples per frame (used when not set explicitly in the frames) --> frameLength + * 8 bits compatible version (0) + * 8 bits sample size --> bitDepth + * 8 bits history mult (40) + * 8 bits initial history (10) + * 8 bits rice param limit (14) + * 8 bits channels --> numChannels + * 16 bits maxRun (255) + * 32 bits max coded frame size (0 means unknown) --> maxFrameBytes + * 32 bits average bitrate (0 means unknown) + * 32 bits samplerate + */ +int ALACMP4Decoder::AudioSpecificConfiguration(void *buffer, size_t buffer_size) +{ + mpAlacDecoder = new ALACDecoder(); + if (buffer_size > sizeof(ALACSpecificConfig)) + { + // we have the "tag version" embedded; + // just skip + size_t skip = sizeof(uint32_t); + mpAlacDecoder->Init((void*)((char*)buffer + skip), sizeof(ALACSpecificConfig)); + } + else + { + mpAlacDecoder->Init(buffer, buffer_size); + } + + /*alac = create_alac(bps, channels); + alac_set_info(alac, reinterpret_cast<char *>(buffer));*/ + return MP4_SUCCESS; +} + +void ALACMP4Decoder::Flush() +{ + // TODO +} + +void ALACMP4Decoder::Close() +{ + if (mpAlacDecoder) + { + delete mpAlacDecoder; + mpAlacDecoder = 0; + } +} + +int ALACMP4Decoder::GetOutputProperties(unsigned int *sampleRate, unsigned int *channels, unsigned int *bitsPerSample) +{ + *sampleRate = mpAlacDecoder->mConfig.sampleRate; // TODO: verify + *channels = mpAlacDecoder->mConfig.numChannels; + *bitsPerSample = mpAlacDecoder->mConfig.bitDepth; + return MP4_SUCCESS; +} + +int ALACMP4Decoder::OutputFrameSize(size_t *frameSize) +{ + *frameSize = mpAlacDecoder->mConfig.frameLength; // TODO: verify + return MP4_SUCCESS; +} + + +#define PA_CLIP_( val, min, max )\ +{ val = ((val) < (min)) ? (min) : (((val) > (max)) ? (max) : (val)); } + +inline static void clip(double &x, double a, double b) +{ + double x1 = fabs (x - a); + double x2 = fabs (x - b); + x = x1 + (a + b); + x -= x2; + x *= 0.5; +} + + +int ALACMP4Decoder::DecodeSample(void *inputBuffer, size_t inputBufferBytes, void *outputBuffer, size_t *outputBufferBytes) +{ + struct BitBuffer inputChunk; + BitBufferInit(&inputChunk, (uint8_t*)(inputBuffer), inputBufferBytes); + uint32_t numFrames = 0; + mpAlacDecoder->Decode(&inputChunk, (uint8_t*)(outputBuffer), mpAlacDecoder->mConfig.frameLength , mpAlacDecoder->mConfig.numChannels, &numFrames); + + size_t bytesPerSample = (mpAlacDecoder->mConfig.bitDepth / 8) * mpAlacDecoder->mConfig.numChannels; + *outputBufferBytes = mpAlacDecoder->mConfig.frameLength * bytesPerSample; + + if (use_rg && mpAlacDecoder->mConfig.bitDepth == 16) + { + size_t numSamples = *outputBufferBytes / (mpAlacDecoder->mConfig.bitDepth / 8); + //if (bitsPerSample == 16) + { + // TODO: this algorithm assumes ALAC bps is 16!! + int16_t* audioBuffer = (int16_t*)outputBuffer; + for (size_t i = 0; i != numSamples; i++) + { + float sample = (float)audioBuffer[i]; + int32_t temp = (int32_t)(sample * rg); + PA_CLIP_(temp, -0x8000, 0x7FFF); + audioBuffer[i] = (uint16_t)temp; + } + } + } + return MP4_SUCCESS; +} + +const char *ALACMP4Decoder::GetCodecInfoString() +{ + return "mdia.minf.stbl.stsd.alac.alac.decoderConfig"; +} + +int ALACMP4Decoder::CanHandleCodec(const char *codecName) +{ + return !strcmp(codecName, "alac"); +} + +int ALACMP4Decoder::SetGain(float gain) +{ + if (gain != 1.0f) + { + use_rg = true; + rg = gain; + } + return MP4_SUCCESS; +} + +#ifdef CBCLASS +#undef CBCLASS +#endif + +#define CBCLASS ALACMP4Decoder +START_DISPATCH; +CB(MPEG4_AUDIO_OPENMP4, OpenMP4) +CB(MPEG4_AUDIO_ASC, AudioSpecificConfiguration) +CB(MPEG4_AUDIO_BITRATE, GetCurrentBitrate) +CB(MPEG4_AUDIO_FRAMESIZE, OutputFrameSize) +CB(MPEG4_AUDIO_OUTPUTINFO, GetOutputProperties) +CB(MPEG4_AUDIO_DECODE, DecodeSample) +VCB(MPEG4_AUDIO_FLUSH, Flush) +VCB(MPEG4_AUDIO_CLOSE, Close) +CB(MPEG4_AUDIO_CODEC_INFO_STRING, GetCodecInfoString) +CB(MPEG4_AUDIO_HANDLES_CODEC, CanHandleCodec) +CB(MPEG4_AUDIO_SET_GAIN, SetGain) +END_DISPATCH;
\ No newline at end of file |