1+ #pragma once
2+ #include " AudioTools/CoreAudio/AudioBasic/StrView.h"
3+
4+ namespace audio_tools {
5+
6+ /* *
7+ * @brief AAC header parser to check if the data is a valid ADTS aac which
8+ * can extract some relevant audio information.
9+ * @ingroup codecs
10+ * @ingroup decoder
11+ * @author Phil Schatzmann
12+ * @copyright GPLv3
13+ */
14+
15+ class HeaderParserAAC {
16+ class AACHeader {
17+ public:
18+ uint8_t id;
19+ uint8_t layer;
20+ bool protection_absent;
21+ uint8_t profile;
22+ uint8_t sampling_freq_idx;
23+ bool private_bit;
24+ uint8_t channel_cfg;
25+ bool original_copy;
26+ // uint8_t home; // not used
27+ uint8_t copyright_id_bit;
28+ uint8_t copyright_id_start;
29+ int frame_length;
30+ uint8_t adts_buf_fullness; // Used for bit reservoir, 0x7FF = VBR
31+ int num_rawdata_blocks; // Usually 00 (1 AAC frame per ADTS frame)
32+ };
33+
34+ public:
35+ // / parses the header string and returns true if this is a valid mp3 file
36+ bool isValid (const uint8_t * data, int len) {
37+ if (findSyncWord (data, len) == -1 ) {
38+ LOGE (" Could not find FrameSync" );
39+ return false ;
40+ }
41+
42+ header.id = (data[1 ] >> 3 ) & 0b1 ;
43+ header.layer = (data[1 ] >> 1 ) & 0b11 ;
44+ header.protection_absent = (data[1 ]) & 0b1 ;
45+ header.profile = (data[2 ] >> 6 ) & 0b11 ;
46+ header.sampling_freq_idx = (data[2 ] >> 2 ) & 0b1111 ;
47+ header.private_bit = (data[2 ] >> 1 ) & 0b1 ;
48+ header.channel_cfg = ((data[2 ] & 0b1 ) << 2 ) | (data[3 ] >> 6 );
49+ header.original_copy = (data[3 ] >> 5 ) & 0b1 ;
50+ // header.home = (data[3] >> 4) & 0b1; // unused
51+ // parse adts_variable_header()
52+ header.copyright_id_bit = (data[3 ] >> 3 ) & 0b1 ;
53+ header.copyright_id_start = (data[3 ] >> 2 ) & 0b1 ;
54+ header.frame_length =
55+ ((data[3 ] & 0b11 ) << 11 ) | (data[4 ] << 3 ) | (data[5 ] >> 5 );
56+ header.adts_buf_fullness = ((data[5 ] & 0b11111 ) << 6 ) | (data[6 ] >> 2 );
57+ header.num_rawdata_blocks =
58+ (data[6 ]) & 0b11 ; // Usually 00 (1 AAC frame per ADTS frame)
59+
60+ bool is_valid = true ;
61+
62+ is_valid = is_valid && header.sampling_freq_idx < 12 ;
63+ is_valid = is_valid && header.channel_cfg < 8 && header.channel_cfg > 0 ;
64+ is_valid = is_valid && header.profile < 3 ; // 0: Main, 1: LC, 2: SSR
65+ is_valid = is_valid && header.layer == 0 ; // 0: ADTS
66+ is_valid = is_valid && header.id <= 1 ; // 0: MPEG-4, 1: MPEG-2
67+
68+ if (len >= header.frame_length + 11 ) {
69+ is_valid = is_valid && findSyncWord (data + header.frame_length ,
70+ len - header.frame_length ) != 0 ;
71+ }
72+ return is_valid;
73+ }
74+
75+ uint16_t getSampleRate () const {
76+ return sample_rates[header.sampling_freq_idx ];
77+ }
78+
79+ uint8_t getChannels () const { return header.channel_cfg ; }
80+
81+ // / Determines the frame length
82+ int getFrameLength () { return header.frame_length ; }
83+
84+ // / Finds the mp3/aac sync word
85+ int findSyncWord (const uint8_t * buf, size_t nBytes, uint8_t synch = 0xFF ,
86+ uint8_t syncl = 0xF0 ) {
87+ for (int i = 0 ; i < nBytes - 1 ; i++) {
88+ if ((buf[i + 0 ] & synch) == synch && (buf[i + 1 ] & syncl) == syncl)
89+ return i;
90+ }
91+ return -1 ;
92+ }
93+ int getRawDataBlocks () { return header.num_rawdata_blocks ; }
94+
95+ AACHeader getHeader () { return header; }
96+
97+ protected:
98+ const int sample_rates[13 ] = {96000 , 88200 , 64000 , 48000 , 44100 , 32000 , 24000 ,
99+ 22050 , 16000 , 12000 , 11025 , 8000 , 7350 };
100+
101+ AACHeader header{0 };
102+ };
103+
104+ } // namespace audio_tools
0 commit comments