diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/aacdec/MP4AACDecoder.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/aacdec/MP4AACDecoder.cpp')
-rw-r--r-- | Src/aacdec/MP4AACDecoder.cpp | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/Src/aacdec/MP4AACDecoder.cpp b/Src/aacdec/MP4AACDecoder.cpp new file mode 100644 index 00000000..c8f00003 --- /dev/null +++ b/Src/aacdec/MP4AACDecoder.cpp @@ -0,0 +1,236 @@ +#include "MP4AACDecoder.h" +#include "api.h" +#include <math.h> +#include <bfc/platform/minmax.h> +#include "../nsutil/pcm.h" + + + +// {B6CB4A7C-A8D0-4c55-8E60-9F7A7A23DA0F} +static const GUID playbackConfigGroupGUID = + { 0xb6cb4a7c, 0xa8d0, 0x4c55, { 0x8e, 0x60, 0x9f, 0x7a, 0x7a, 0x23, 0xda, 0xf } }; + +MP4AACDecoder::MP4AACDecoder() +{ + preDelay = 0; + decoder = 0; + access_unit = 0; + composition_unit = 0; + isFloat = false; + gain=1.0f; + // get bps + bitsPerSample = AGAVE_API_CONFIG->GetUnsigned(playbackConfigGroupGUID, L"bits", 16); + if (bitsPerSample >= 24) bitsPerSample = 24; + else bitsPerSample = 16; + + // get max channels + if (AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"surround", true)) + maxChannels = 6; + else if (AGAVE_API_CONFIG->GetBool(playbackConfigGroupGUID, L"mono", false)) + maxChannels = 1; + else + maxChannels = 2; +} + +int MP4AACDecoder::Open() +{ + /* with FhG's API, we can't actually create a decoder until we have the ASC. + best we can do right now is create the access unit object */ + access_unit = CAccessUnit_Create(0, 0); + if (access_unit) + return MP4_SUCCESS; + else + return MP4_FAILURE; +} + +int MP4AACDecoder::OpenEx(size_t _bits, size_t _maxChannels, bool useFloat) +{ + isFloat = useFloat; + if (isFloat) + { + bitsPerSample = 32; + } + else + { + if (_bits) + bitsPerSample = _bits; + if (bitsPerSample >= 24) bitsPerSample = 24; + else bitsPerSample = 16; + } + if (_maxChannels) + maxChannels = _maxChannels; + return Open(); +} + +int MP4AACDecoder::GetOutputProperties(unsigned int *sampleRate, unsigned int *channels, unsigned int *_bitsPerSample) +{ + bool dummy; + return GetOutputPropertiesEx(sampleRate, channels, _bitsPerSample, &dummy); +} + +int MP4AACDecoder::GetOutputPropertiesEx(unsigned int *sampleRate, unsigned int *channels, unsigned int *_bitsPerSample, bool *useFloat) +{ + /* TODO: verify that it's safe to call these, e.g. one frame has been decoded successfully, otherwise call MKV_NEED_MORE_INPUT */ + CCompositionUnit_GetSamplingRate(composition_unit, sampleRate); + CCompositionUnit_GetChannels(composition_unit, channels); + + *_bitsPerSample = bitsPerSample; + *useFloat = isFloat; + return MP4_SUCCESS; +} + +void MP4AACDecoder::Flush() +{ + mp4AudioDecoder_Reset(decoder, MP4AUDIODECPARAM_DEFAULT, 0); +} + +int MP4AACDecoder::GetCurrentBitrate(unsigned int *bitrate) +{ + int current_bitrate; + if (CCompositionUnit_GetProperty(composition_unit, CUBUFFER_CURRENTBITRATE, ¤t_bitrate) == MP4AUDIODEC_OK) + { + *bitrate = current_bitrate/1000; + return MP4_SUCCESS; + } + else + return MP4_GETCURRENTBITRATE_UNKNOWN; +} + +int MP4AACDecoder::DecodeSample(void *inputBuffer, size_t inputBufferBytes, void *outputBuffer, size_t *outputBufferBytes) +{ + CAccessUnit_Reset(access_unit); + CAccessUnit_Assign(access_unit, (const unsigned char *)inputBuffer, inputBufferBytes); + CCompositionUnit_Reset(composition_unit); + MP4_RESULT result = mp4AudioDecoder_DecodeFrame(decoder, &access_unit, composition_unit); + + if (result == MP4AUDIODEC_OK) + { + unsigned int channels; + unsigned int samples_per_channel; + if (CCompositionUnit_GetSamplesPerChannel(composition_unit, &samples_per_channel) != MP4AUDIODEC_OK + || CCompositionUnit_GetChannels(composition_unit, &channels) != MP4AUDIODEC_OK) + return MP4_FAILURE; + const float *audio_output = 0; + + size_t num_samples = samples_per_channel * channels; + size_t output_size = num_samples * (bitsPerSample/8); + if (output_size > *outputBufferBytes) + return MP4_FAILURE; + + *outputBufferBytes = output_size; + CCompositionUnit_GetPcmPtr(composition_unit, &audio_output); + if (!isFloat) + { + nsutil_pcm_FloatToInt_Interleaved_Gain(outputBuffer, audio_output, bitsPerSample, num_samples, gain/32768.0f); + } + else + { + for (size_t i = 0;i != num_samples;i++) + ((float *)outputBuffer)[i] = audio_output[i] * gain / 32768.0f; + } + + return MP4_SUCCESS; + } + else + return MP4_FAILURE; +} + +int MP4AACDecoder::OutputFrameSize(size_t *frameSize) +{ + if (!decoder) + return MP4_FAILURE; + + unsigned int samples_per_channel; + unsigned int channels; + if (CCompositionUnit_GetSamplesPerChannel(composition_unit, &samples_per_channel) != MP4AUDIODEC_OK + || CCompositionUnit_GetChannels(composition_unit, &channels) != MP4AUDIODEC_OK) + return MP4_FAILURE; + + *frameSize = samples_per_channel*channels; + return MP4_SUCCESS; +} + + +int MP4AACDecoder::AudioSpecificConfiguration(void *buffer, size_t buffer_size) // reads ASC block from mp4 file +{ + // TODO: error check + if (buffer && buffer_size) + { + CSAudioSpecificConfig asc; + memset(&asc, 0, sizeof(asc)); + if (mp4AudioDecoder_ascParse((const unsigned char *)buffer, buffer_size, &asc) == MP4AUDIODEC_OK) + { + CSAudioSpecificConfig *asc_array = &asc;; + decoder = mp4AudioDecoder_Create(&asc_array, 1); + if (decoder) + { + mp4AudioDecoder_SetParam(decoder, TDL_MODE, SWITCH_OFF); + mp4AudioDecoder_SetParam(decoder, CONCEALMENT_ENERGYINTERPOLATION, SWITCH_OFF); + composition_unit = CCompositionUnit_Create(max(asc.m_channels, 8), asc.m_samplesPerFrame * 2, asc.m_samplingFrequency, 6144, CUBUFFER_PCMTYPE_FLOAT); + return MP4_SUCCESS; + } + } + } + + return MP4_FAILURE; +} + +void MP4AACDecoder::Close() +{ + mp4AudioDecoder_Destroy(&decoder); + CAccessUnit_Destroy(&access_unit); + CCompositionUnit_Destroy(&composition_unit); +} + +int MP4AACDecoder::CanHandleCodec(const char *codecName) +{ + return !strcmp(codecName, "mp4a"); +} + +int MP4AACDecoder::CanHandleType(uint8_t type) +{ + switch (type) + { + case MP4_TYPE_MPEG4_AUDIO: + return 1; + case MP4_TYPE_MPEG2_AAC_LC_AUDIO: + return 1; + default: + return 0; + } +} + +int MP4AACDecoder::CanHandleMPEG4Type(uint8_t type) +{ + switch (type) + { + case MP4_MPEG4_TYPE_AAC_LC_AUDIO: + case MP4_MPEG4_TYPE_AAC_HE_AUDIO: + case MP4_MPEG4_TYPE_PARAMETRIC_STEREO: + return 1; + default: + return 0; + } +} + +#ifdef CBCLASS +#undef CBCLASS +#endif + +#define CBCLASS MP4AACDecoder +START_DISPATCH; +CB(MPEG4_AUDIO_OPEN, Open) +CB(MPEG4_AUDIO_OPEN_EX, OpenEx) +CB(MPEG4_AUDIO_ASC, AudioSpecificConfiguration) +CB(MPEG4_AUDIO_BITRATE, GetCurrentBitrate) +CB(MPEG4_AUDIO_FRAMESIZE, OutputFrameSize) +CB(MPEG4_AUDIO_OUTPUTINFO, GetOutputProperties) +CB(MPEG4_AUDIO_OUTPUTINFO_EX, GetOutputPropertiesEx) +CB(MPEG4_AUDIO_DECODE, DecodeSample) +VCB(MPEG4_AUDIO_FLUSH, Flush) +VCB(MPEG4_AUDIO_CLOSE, Close) +CB(MPEG4_AUDIO_HANDLES_CODEC, CanHandleCodec) +CB(MPEG4_AUDIO_HANDLES_TYPE, CanHandleType) +CB(MPEG4_AUDIO_HANDLES_MPEG4_TYPE, CanHandleMPEG4Type) +CB(MPEG4_AUDIO_SET_GAIN, SetGain) +END_DISPATCH; |