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/NSVAACDecoder.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/aacdec/NSVAACDecoder.cpp')
-rw-r--r-- | Src/aacdec/NSVAACDecoder.cpp | 229 |
1 files changed, 229 insertions, 0 deletions
diff --git a/Src/aacdec/NSVAACDecoder.cpp b/Src/aacdec/NSVAACDecoder.cpp new file mode 100644 index 00000000..94a6efd7 --- /dev/null +++ b/Src/aacdec/NSVAACDecoder.cpp @@ -0,0 +1,229 @@ +#include "NSVAACDecoder.h" + +#include <assert.h> +#include "api.h" +#include "../nsv/nsvlib.h" +#include "api.h" +#include "../nsv/nsvlib.h" +#include "../nsv/dec_if.h" +#include <string.h> +#include <bfc/platform/export.h> +#include "NSVAACDecoder.h" +#include <bfc/error.h> +#ifndef MIN +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +NSVAACDecoder *NSVAACDecoder::CreateDecoder() +{ + CAccessUnitPtr access_unit = CAccessUnit_Create(0, 0); + if (!access_unit) + return 0; + + NSVAACDecoder *decoder=0; + WASABI_API_MEMMGR->New(&decoder); + if (!decoder) + { + CAccessUnit_Destroy(&access_unit); + return 0; + } + decoder->Initialize(access_unit); + return decoder; +} + +NSVAACDecoder::NSVAACDecoder() +{ + access_unit = 0; + composition_unit = 0; + decoder = 0; + source_position=0; + out_left=0; + in_position=0; +} + +NSVAACDecoder::~NSVAACDecoder() +{ + mp4AudioDecoder_Destroy(&decoder); + CAccessUnit_Destroy(&access_unit); + CCompositionUnit_Destroy(&composition_unit); +} + +void NSVAACDecoder::Initialize(CAccessUnitPtr _access_unit) +{ + access_unit = _access_unit; +} + +void NSVAACDecoder::flush() +{ + if (decoder) + mp4AudioDecoder_Reset(decoder, MP4AUDIODECPARAM_DEFAULT, 0); +} + + +static void ConfigureADTS(CSAudioSpecificConfig* asc, nsaac_adts_header_t header) +{ + asc->m_aot = (AUDIO_OBJECT_TYPE)(header->profile + 1); + asc->m_channelConfiguration = header->channel_configuration; + asc->m_channels = nsaac_adts_get_channel_count(header); + asc->m_nrOfStreams = 1; + asc->m_samplesPerFrame = 1024; + asc->m_samplingFrequencyIndex = header->sample_rate_index; + asc->m_samplingFrequency = nsaac_adts_get_samplerate(header); + asc->m_avgBitRate = 0; /* only needed for tvq */ + asc->m_mpsPresentFlag = -1; + asc->m_saocPresentFlag = -1; + asc->m_ldmpsPresentFlag = -1; +} + +// returns -1 on error, 0 on success (done with data in 'in'), 1 on success +// but to pass 'in' again next time around. +int NSVAACDecoder::decode(void *in, int in_len, void *out, int *out_len, unsigned int out_fmt[8]) +{ + if (out_left) + { + unsigned int channels; + unsigned int sample_rate; + if (CCompositionUnit_GetChannels(composition_unit, &channels) != MP4AUDIODEC_OK + || CCompositionUnit_GetSamplingRate(composition_unit, &sample_rate) != MP4AUDIODEC_OK) + return -1; + + + out_fmt[0] = NSV_MAKETYPE('P', 'C', 'M', ' '); + out_fmt[1] = sample_rate; + out_fmt[2] = channels; + out_fmt[3] = 16; + + const uint8_t *audio_output=0; + CCompositionUnit_GetPcmPtr(composition_unit, &audio_output); + size_t copy_size = min(out_left, *out_len); + memcpy(out, audio_output + source_position, copy_size); + *out_len = copy_size; + out_left -= copy_size; + source_position += copy_size; + return 1; +; + } + + in = (uint8_t *)in + in_position; + in_len -= in_position; + + if (in_len > 7) + { + ADTSHeader header; + if (nsaac_adts_parse(&header, (const uint8_t *)in) == NErr_Success) + { + if (!decoder) + { + CSAudioSpecificConfig asc; + memset(&asc, 0, sizeof(asc)); + ConfigureADTS(&asc, &header); + + CSAudioSpecificConfig *asc_array = &asc; + decoder = mp4AudioDecoder_Create(&asc_array, 1); + if (decoder) + { + mp4AudioDecoder_SetParam(decoder, TDL_MODE, SWITCH_ON); + 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_INT16); + } + if (!decoder || !composition_unit) + { + in_position=0; + return -1; + } + } + if (header.frame_length > in_len) + { + in_position=0; + return -1; + } + if (header.frame_length != in_len) + { + in_position+=header.frame_length; + } + else + { + in_position=0; + } + + CAccessUnit_Reset(access_unit); + CAccessUnit_Assign(access_unit, (const uint8_t *)in + 7, header.frame_length-7); + 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; + unsigned int sample_rate; + if (CCompositionUnit_GetSamplesPerChannel(composition_unit, &samples_per_channel) != MP4AUDIODEC_OK + || CCompositionUnit_GetChannels(composition_unit, &channels) != MP4AUDIODEC_OK + || CCompositionUnit_GetSamplingRate(composition_unit, &sample_rate) != MP4AUDIODEC_OK) + return -1; + + size_t num_samples = samples_per_channel * channels; + size_t output_size = num_samples * 2 /* 16 bits */; + + const uint16_t *audio_output=0; + CCompositionUnit_GetPcmPtr(composition_unit, &audio_output); + size_t copy_size = min(output_size, *out_len); + memcpy(out, audio_output, copy_size); + *out_len = copy_size; + out_left = output_size - copy_size; + source_position = copy_size; + + out_fmt[0] = NSV_MAKETYPE('P', 'C', 'M', ' '); + out_fmt[1] = sample_rate; + out_fmt[2] = channels; + out_fmt[3] = 16; + + int br; + CCompositionUnit_GetProperty(composition_unit, CUBUFFER_AVGBITRATE, &br); + out_fmt[4] =br/1000; + if (in_position) + return 1; + return 0; + } + else + { + return -1; + } + + } + else + { + in_position=0; + return -1; + } + } + *out_len = 0; + in_position=0; + return 0; + +} + + + +IAudioDecoder *NSVDecoder::CreateAudioDecoder(FOURCC format, IAudioOutput **output) +{ + switch (format) + { + case NSV_MAKETYPE('A', 'A', 'C', ' ') : + case NSV_MAKETYPE('A', 'A', 'C', 'P'): + case NSV_MAKETYPE('A', 'P', 'L', ' '): + { + NSVAACDecoder *dec = NSVAACDecoder::CreateDecoder(); + return dec; + } + + default: + return 0; + } +} + + +#define CBCLASS NSVDecoder +START_DISPATCH; +CB(SVC_NSVFACTORY_CREATEAUDIODECODER, CreateAudioDecoder) +END_DISPATCH; +#undef CBCLASS |