mirror of
https://github.com/WinampDesktop/winamp.git
synced 2024-09-24 15:54:12 +00:00
225 lines
5 KiB
C++
225 lines
5 KiB
C++
#include "ADTSHeader.h"
|
|
#include "nmrCommon/services/stdServiceImpl.h"
|
|
|
|
|
|
enum
|
|
{
|
|
ADTS_NOT_PROTECTED = 1,
|
|
ADTS_PROTECTED = 0,
|
|
ADTS_SYNC = 0xFFF,
|
|
ADTS_MAIN = 0x00,
|
|
ADTS_LC = 0x01,
|
|
ADTS_SSR = 0x10,
|
|
ADTS_LTP = 0x11
|
|
};
|
|
|
|
const int aac_adts_parse(const aac_adts_header_t header, const __uint8 *buffer)
|
|
{
|
|
header->syncword = ((buffer[0] << 4) | (buffer[1] >> 4));
|
|
|
|
if (header->syncword != ADTS_SYNC)
|
|
{
|
|
return NErr_LostSynchronization;
|
|
}
|
|
|
|
header->id = ((buffer[1] >> 3) & 1);
|
|
header->layer = ((buffer[1] >> 1) & 3);
|
|
if (header->layer != 0)
|
|
{
|
|
return NErr_WrongFormat;
|
|
}
|
|
|
|
header->protection = ((buffer[1]) & 1);
|
|
header->profile = ((buffer[2] >> 6) & 3);
|
|
header->sample_rate_index = ((buffer[2] >> 2) & 0xF);
|
|
if (header->sample_rate_index == 15)
|
|
{
|
|
return NErr_UnsupportedFormat; // might actually be OK if we can separately signal the sample rate
|
|
}
|
|
|
|
if (header->sample_rate_index > 13)
|
|
{
|
|
return NErr_Reserved;
|
|
}
|
|
|
|
header->private_bit = ((buffer[2] >> 1) & 1);
|
|
header->channel_configuration = ((buffer[2] & 1) << 2) | ((buffer[3] >> 6) & 3);
|
|
header->original = ((buffer[3] >> 5) & 1);
|
|
header->home = ((buffer[3] >> 4) & 1);
|
|
|
|
header->frame_length = ((buffer[3] & 3) << 11) | (buffer[4]<<3) | ((buffer[5] >> 5) & 7);
|
|
header->buffer_fullness = ((buffer[5] & 0x1F) << 6) | (buffer[6] >> 2);
|
|
header->num_data_blocks = (buffer[6] & 3);
|
|
return NErr_Success;
|
|
}
|
|
|
|
static const unsigned int aac_sratetab[] =
|
|
{
|
|
96000,
|
|
88200,
|
|
64000,
|
|
48000,
|
|
44100,
|
|
32000,
|
|
24000,
|
|
22050,
|
|
16000,
|
|
12000,
|
|
11025,
|
|
8000,
|
|
7350,
|
|
};
|
|
#if 0
|
|
const int aac_adts_match(const aac_adts_header_t header1, const aac_adts_header_t header2)
|
|
{
|
|
if (header1->id != header2->id)
|
|
{
|
|
return NErr_False;
|
|
}
|
|
|
|
if (header1->profile != header2->profile)
|
|
{
|
|
return NErr_False;
|
|
}
|
|
|
|
if (header1->sample_rate_index != header2->sample_rate_index)
|
|
{
|
|
return NErr_False;
|
|
}
|
|
|
|
if (header1->channel_configuration != header2->channel_configuration)
|
|
{
|
|
return NErr_False;
|
|
}
|
|
|
|
return NErr_True;
|
|
}
|
|
#endif
|
|
const int aac_adts_get_channel_count(const aac_adts_header_t header)
|
|
{
|
|
switch (header->channel_configuration)
|
|
{
|
|
case 7:
|
|
{
|
|
return 8;
|
|
}
|
|
default:
|
|
{
|
|
return header->channel_configuration;
|
|
}
|
|
}
|
|
}
|
|
|
|
const __uint16 getADTSFrameInfo(const char *hdr, unsigned int *samplerate, __uint8 *asc_header)
|
|
{
|
|
ADTSHeader header = {0};
|
|
if (aac_adts_parse(&header, (const __uint8 *)hdr) == NErr_Success)
|
|
{
|
|
*samplerate = aac_sratetab[header.sample_rate_index];
|
|
|
|
// we need this when generating flv frames
|
|
// as it creates the AudioSpecificConfig
|
|
// from the existing ADTS header details
|
|
// (is like a mini-ADTS header to create)
|
|
if (asc_header)
|
|
{
|
|
asc_header[0] |= (((header.profile + 1) & 31) << 3) + (header.sample_rate_index >> 1);
|
|
asc_header[1] |= ((header.sample_rate_index & 0x1) << 7) + (header.channel_configuration << 3);
|
|
}
|
|
|
|
//*bitrate = (int)(((header.frame_length / 1/*frames*/) * (aac_sratetab[header.sample_rate_index] / 1024.0)) + 0.5) * 8;
|
|
return (__uint16)header.frame_length;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
const char *AAC_FrameInfo::getVersionName() const
|
|
{
|
|
if (m_version)
|
|
return "v2";
|
|
return "v4";
|
|
}
|
|
|
|
const char *AAC_FrameInfo::getAOT() const
|
|
{
|
|
switch (m_aot)
|
|
{
|
|
case 2: return "LC";
|
|
case 5: return "SBR";
|
|
case 29: return "PS";
|
|
default: return "unknown profile";
|
|
}
|
|
}
|
|
|
|
|
|
int getAACFrameLength (const unsigned char *p, unsigned int len)
|
|
{
|
|
if (len < 6)
|
|
return -1;
|
|
return ((p[3] & 0x3) << 11) + (p[4] << 3) + ((p[5] & 0xE0) >> 5);
|
|
}
|
|
|
|
int getAACFrameInfo (const unsigned char *p, unsigned int len, AAC_FrameInfo &info)
|
|
{
|
|
if (len < 6)
|
|
return -1;
|
|
if ((((long)p[0])<<4 | (p[1]>>4)) != 0xfff)
|
|
return -1;
|
|
|
|
int layer = ((p[1] >> 1) & 3);
|
|
if (layer != 0)
|
|
return -1;
|
|
int sample_rate_index = ((p[2] >> 2) & 0xF);
|
|
|
|
if (sample_rate_index > 13)
|
|
return -1;
|
|
int samplerate = aac_sratetab [sample_rate_index];
|
|
if (info.m_samplerate)
|
|
{
|
|
if (info.m_samplerate != samplerate)
|
|
return -1;
|
|
}
|
|
else
|
|
info.m_samplerate = samplerate;
|
|
info.m_blocks = (p[6] & 0x3) + 1;
|
|
info.m_pattern = (((unsigned long)(p[0])<<24) | (p[1]<<16) | (p[2]<<8) | p[0]) & info.m_mask;
|
|
|
|
return getAACFrameLength (p, len);
|
|
}
|
|
|
|
|
|
int AAC_FrameInfo::verifyFrame (const unsigned char *buf, unsigned int len)
|
|
{
|
|
if (len > 6)
|
|
{
|
|
unsigned long v = (unsigned long)(buf[0])<<24 | (buf[1]<<16) | (buf[2]<<8) | buf[0];
|
|
|
|
if ((v & m_mask) == m_pattern)
|
|
{
|
|
m_blocks = (buf[6] & 0x3) + 1;
|
|
m_version = (buf[1] >> 3) & 1; // 1 mpeg2, 0 mpeg4
|
|
m_aot = ((buf[2] >> 6) & 3) + 1;
|
|
return getAACFrameLength (buf, len);
|
|
}
|
|
// DLOG ("AAC failed sync, retry..");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
AAC_FrameInfo::AAC_FrameInfo (unsigned long value) : parserInfo (0xFFFEFDC0, value)
|
|
{
|
|
m_description = "AAC";
|
|
m_blocks = 0;
|
|
m_aot = 0;
|
|
}
|
|
|
|
AAC_FrameInfo::AAC_FrameInfo(const unsigned char *p, unsigned int len) : parserInfo()
|
|
{
|
|
m_mask = 0xFFFEFDC0;
|
|
m_description = "AAC";
|
|
m_blocks = 0;
|
|
getAACFrameInfo (p, len, *this);
|
|
}
|
|
|