#include "NSVAACDecoder.h" #include #include "api.h" #include "../nsv/nsvlib.h" #include "api.h" #include "../nsv/nsvlib.h" #include "../nsv/dec_if.h" #include #include #include "NSVAACDecoder.h" #include #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