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