/* copyright 2006 Ben Allison */ #include "ALACMP4Decoder.h" #include "alac/ALACBitUtilities.h" #include "api__alac.h" #include "decomp.h" #include #include #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(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;