#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); }