mirror of
https://github.com/WinampDesktop/winamp.git
synced 2024-12-28 22:46:06 +00:00
197 lines
5.3 KiB
C++
197 lines
5.3 KiB
C++
/* 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; |