winamp/Src/aacdec/NSVAACDecoder.cpp
2024-09-24 14:54:57 +02:00

230 lines
5.5 KiB
C++

#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