access_unit/
aac.rs

1use bytes::{Bytes, BytesMut};
2
3pub fn is_aac(input: &[u8]) -> bool {
4    // Check if we have at least 7 bytes (minimum ADTS header size)
5    if input.len() < 7 {
6        return false;
7    }
8
9    // Check for the ADTS sync word (12 bits)
10    if input[0] != 0xFF || (input[1] & 0xF0) != 0xF0 {
11        return false;
12    }
13
14    let layer = (input[1] & 0x06) >> 1;
15    if layer != 0 {
16        // Layer must be '00' for AAC
17        return false;
18    }
19
20    // Check profile (2 bits)
21    let profile = (input[2] & 0xC0) >> 6;
22    if profile == 3 {
23        // '11' is reserved
24        return false;
25    }
26
27    // Check sampling frequency index (4 bits)
28    let sampling_freq_index = (input[2] & 0x3C) >> 2;
29    if sampling_freq_index > 11 {
30        // Valid range is 0-11
31        return false;
32    }
33
34    // All checks passed
35    true
36}
37
38pub fn extract_aac_data(sound_data: &Bytes) -> Option<Bytes> {
39    if sound_data.len() < 7 {
40        return None;
41    }
42
43    // Check for the ADTS sync word
44    if sound_data[0] != 0xFF || (sound_data[1] & 0xF0) != 0xF0 {
45        return None;
46    }
47
48    // Parse the ADTS header
49    let protection_absent: bool = (sound_data[1] & 0x01) == 0x01;
50    let header_size: usize = if protection_absent { 7 } else { 9 };
51
52    if sound_data.len() < header_size {
53        return None;
54    }
55
56    let frame_length: usize = (((sound_data[3] as usize & 0x03) << 11)
57        | ((sound_data[4] as usize) << 3)
58        | ((sound_data[5] as usize) >> 5)) as usize;
59
60    if sound_data.len() < frame_length {
61        return None;
62    }
63
64    Some(sound_data.slice(header_size..frame_length))
65}
66
67pub fn ensure_adts_header(data: Bytes, channels: u8, sample_rate: u32) -> Bytes {
68    // Assume that the first byte might contain the ASC if `extract_aac_data` finds no ADTS header
69    if extract_aac_data(&data).is_none() {
70        // Assuming data[0] is present and is the first byte of ASC
71        // Parse the profile from the ASC
72        let audio_object_type = data[0] >> 3; // First 5 bits contain the audio object type
73        let profile = match audio_object_type {
74            1 => 0x66, // AAC-LC
75            2 => 0x67, // HE-AAC v1
76            5 => 0x68, // HE-AAC v2
77            _ => 0x66, // Default to AAC-LC if unknown
78        };
79
80        let header = create_adts_header(profile, channels, sample_rate, data.len() - 2, false);
81        let mut payload = BytesMut::from(&header[..]);
82        payload.extend_from_slice(&data[2..]); // Skip the first two bytes if they are part of ASC
83
84        return payload.freeze();
85    }
86
87    return data;
88}
89
90pub fn create_adts_header(
91    codec_id: u8,
92    channels: u8,
93    sample_rate: u32,
94    aac_frame_length: usize,
95    has_crc: bool,
96) -> Vec<u8> {
97    let profile_object_type = match codec_id {
98        0x66 => 1, // AAC LC (internally set as `1`, should directly be `01` in bits)
99        0x67 => 2, // AAC HEV1
100        0x68 => 3, // AAC HEV2
101        _ => 1,    // Default to AAC LC
102    };
103
104    let sample_rate_index = sample_rate_index(sample_rate);
105    let channel_config = channels.min(7);
106    let header_length = if has_crc { 9 } else { 7 };
107    let frame_length = aac_frame_length + header_length;
108
109    let mut header = Vec::with_capacity(header_length);
110    let protection_absent = if has_crc { 0 } else { 1 };
111
112    header.push(0xFF);
113    header.push(0xF0 | protection_absent);
114
115    let profile_and_sampling =
116        (profile_object_type << 6) | (sample_rate_index << 2) | (channel_config >> 2);
117    header.push(profile_and_sampling);
118
119    let frame_length_high = ((frame_length >> 11) & 0x03) as u8;
120    let frame_length_mid = ((frame_length >> 3) & 0xFF) as u8;
121    header.push((channel_config & 3) << 6 | frame_length_high);
122    header.push(frame_length_mid);
123
124    let frame_length_low = ((frame_length & 0x07) << 5) | 0x1F;
125    header.push(frame_length_low as u8);
126    header.push(0xFC);
127
128    if has_crc {
129        header.extend_from_slice(&[0x00, 0x00]);
130    }
131
132    header
133}
134
135fn sample_rate_index(sample_rate: u32) -> u8 {
136    match sample_rate {
137        96000 => 0x0,
138        88200 => 0x1,
139        64000 => 0x2,
140        48000 => 0x3,
141        44100 => 0x4,
142        32000 => 0x5,
143        24000 => 0x6,
144        22050 => 0x7,
145        16000 => 0x8,
146        12000 => 0x9,
147        11025 => 0xA,
148        8000 => 0xB,
149        7350 => 0xC,
150        _ => 0xF, // Invalid sample rate
151    }
152}
153
154#[cfg(test)]
155mod tests {
156    use super::*;
157    use mse_fmp4::aac::{AdtsHeader, ChannelConfiguration, SamplingFrequency};
158
159    #[test]
160    fn test_adts_header_parsing() {
161        let data = vec![0u8; 200]; // Dummy AAC frame data
162        let channels = 2u8;
163        let sample_rate = 44100u32;
164        let adts_payload = create_adts_header(0x66, channels, sample_rate, data.len(), false);
165        let mut full_payload = adts_payload.clone();
166        full_payload.extend_from_slice(&data);
167
168        let adts = AdtsHeader::read_from(&full_payload[..]).unwrap();
169        assert_eq!(adts.frame_len, 207);
170        assert_eq!(adts.sampling_frequency, SamplingFrequency::Hz44100);
171        assert_eq!(
172            adts.channel_configuration,
173            ChannelConfiguration::TwoChannels
174        );
175        assert_eq!(adts.profile, mse_fmp4::aac::AacProfile::Lc);
176    }
177}