mirror of
https://github.com/WinampDesktop/winamp.git
synced 2024-09-24 15:54:12 +00:00
230 lines
5.5 KiB
C++
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
|