symphonia_codec_aac/
adts.rs

1// Symphonia
2// Copyright (c) 2019-2022 The Project Symphonia Developers.
3//
4// This Source Code Form is subject to the terms of the Mozilla Public
5// License, v. 2.0. If a copy of the MPL was not distributed with this
6// file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
8use symphonia_core::errors::unsupported_error;
9use symphonia_core::support_format;
10
11use symphonia_core::audio::Channels;
12use symphonia_core::codecs::{CodecParameters, CODEC_TYPE_AAC};
13use symphonia_core::errors::{decode_error, seek_error, Result, SeekErrorKind};
14use symphonia_core::formats::prelude::*;
15use symphonia_core::io::*;
16use symphonia_core::meta::{Metadata, MetadataLog};
17use symphonia_core::probe::{Descriptor, Instantiate, QueryDescriptor};
18
19use std::io::{Seek, SeekFrom};
20
21use super::common::{map_channels, M4AType, AAC_SAMPLE_RATES, M4A_TYPES};
22
23use log::{debug, info};
24
25const SAMPLES_PER_AAC_PACKET: u64 = 1024;
26
27/// Audio Data Transport Stream (ADTS) format reader.
28///
29/// `AdtsReader` implements a demuxer for ADTS (AAC native frames).
30pub struct AdtsReader {
31    reader: MediaSourceStream,
32    tracks: Vec<Track>,
33    cues: Vec<Cue>,
34    metadata: MetadataLog,
35    first_frame_pos: u64,
36    next_packet_ts: u64,
37}
38
39impl QueryDescriptor for AdtsReader {
40    fn query() -> &'static [Descriptor] {
41        &[support_format!(
42            "aac",
43            "Audio Data Transport Stream (native AAC)",
44            &["aac"],
45            &["audio/aac"],
46            &[&[0xff, 0xf1]]
47        )]
48    }
49
50    fn score(_context: &[u8]) -> u8 {
51        255
52    }
53}
54
55#[derive(Debug)]
56#[allow(dead_code)]
57struct AdtsHeader {
58    profile: M4AType,
59    channels: Option<Channels>,
60    sample_rate: u32,
61    frame_len: usize,
62}
63
64impl AdtsHeader {
65    const SIZE: usize = 7;
66
67    fn sync<B: ReadBytes>(reader: &mut B) -> Result<()> {
68        let mut sync = 0u16;
69
70        while sync != 0xfff1 {
71            sync = (sync << 8) | u16::from(reader.read_u8()?);
72        }
73
74        Ok(())
75    }
76
77    fn read<B: ReadBytes>(reader: &mut B) -> Result<Self> {
78        AdtsHeader::sync(reader)?;
79
80        // The header may be 5 or 7 bytes (without or with protection).
81        let mut buf = [0u8; 7];
82        reader.read_buf_exact(&mut buf[..5])?;
83
84        let mut bs = BitReaderLtr::new(&buf);
85
86        // Profile
87        let profile = M4A_TYPES[bs.read_bits_leq32(2)? as usize + 1];
88
89        // Sample rate index.
90        let sample_rate = match bs.read_bits_leq32(4)? as usize {
91            15 => return decode_error("adts: forbidden sample rate"),
92            13 | 14 => return decode_error("adts: reserved sample rate"),
93            idx => AAC_SAMPLE_RATES[idx],
94        };
95
96        // Private bit.
97        bs.ignore_bit()?;
98
99        // Channel configuration
100        let channels = match bs.read_bits_leq32(3)? {
101            0 => None,
102            idx => map_channels(idx),
103        };
104
105        // Originality, Home, Copyrighted ID bit, Copyright ID start bits. Only used for encoding.
106        bs.ignore_bits(4)?;
107
108        // Frame length = Header size (7) + AAC frame size
109        let frame_len = bs.read_bits_leq32(13)? as usize;
110
111        if frame_len < AdtsHeader::SIZE {
112            return decode_error("adts: invalid adts frame length");
113        }
114
115        let _fullness = bs.read_bits_leq32(11)?;
116        let num_aac_frames = bs.read_bits_leq32(2)? + 1;
117
118        // TODO: Support multiple AAC packets per ADTS packet.
119        if num_aac_frames > 1 {
120            return unsupported_error("adts: only 1 aac frame per adts packet is supported");
121        }
122
123        Ok(AdtsHeader { profile, channels, sample_rate, frame_len: frame_len - AdtsHeader::SIZE })
124    }
125}
126
127impl FormatReader for AdtsReader {
128    fn try_new(mut source: MediaSourceStream, _options: &FormatOptions) -> Result<Self> {
129        let header = AdtsHeader::read(&mut source)?;
130
131        // Use the header to populate the codec parameters.
132        let mut params = CodecParameters::new();
133
134        params
135            .for_codec(CODEC_TYPE_AAC)
136            .with_sample_rate(header.sample_rate)
137            .with_time_base(TimeBase::new(1, header.sample_rate));
138
139        if let Some(channels) = header.channels {
140            params.with_channels(channels);
141        }
142
143        // Rewind back to the start of the frame.
144        source.seek_buffered_rev(AdtsHeader::SIZE);
145
146        let first_frame_pos = source.pos();
147
148        let n_frames = approximate_frame_count(&mut source)?;
149        if let Some(n_frames) = n_frames {
150            info!("estimating duration from bitrate, may be inaccurate for vbr files");
151            params.with_n_frames(n_frames);
152        }
153
154        Ok(AdtsReader {
155            reader: source,
156            tracks: vec![Track::new(0, params)],
157            cues: Vec::new(),
158            metadata: Default::default(),
159            first_frame_pos,
160            next_packet_ts: 0,
161        })
162    }
163
164    fn next_packet(&mut self) -> Result<Packet> {
165        // Parse the header to get the calculated frame size.
166        let header = AdtsHeader::read(&mut self.reader)?;
167
168        // TODO: Support multiple AAC packets per ADTS packet.
169
170        let ts = self.next_packet_ts;
171
172        self.next_packet_ts += SAMPLES_PER_AAC_PACKET;
173
174        Ok(Packet::new_from_boxed_slice(
175            0,
176            ts,
177            SAMPLES_PER_AAC_PACKET,
178            self.reader.read_boxed_slice_exact(header.frame_len)?,
179        ))
180    }
181
182    fn metadata(&mut self) -> Metadata<'_> {
183        self.metadata.metadata()
184    }
185
186    fn cues(&self) -> &[Cue] {
187        &self.cues
188    }
189
190    fn tracks(&self) -> &[Track] {
191        &self.tracks
192    }
193
194    fn seek(&mut self, _mode: SeekMode, to: SeekTo) -> Result<SeekedTo> {
195        // Get the timestamp of the desired audio frame.
196        let required_ts = match to {
197            // Frame timestamp given.
198            SeekTo::TimeStamp { ts, .. } => ts,
199            // Time value given, calculate frame timestamp from sample rate.
200            SeekTo::Time { time, .. } => {
201                // Use the sample rate to calculate the frame timestamp. If sample rate is not
202                // known, the seek cannot be completed.
203                if let Some(sample_rate) = self.tracks[0].codec_params.sample_rate {
204                    TimeBase::new(1, sample_rate).calc_timestamp(time)
205                }
206                else {
207                    return seek_error(SeekErrorKind::Unseekable);
208                }
209            }
210        };
211
212        debug!("seeking to ts={}", required_ts);
213
214        // If the desired timestamp is less-than the next packet timestamp, attempt to seek
215        // to the start of the stream.
216        if required_ts < self.next_packet_ts {
217            // If the reader is not seekable then only forward seeks are possible.
218            if self.reader.is_seekable() {
219                let seeked_pos = self.reader.seek(SeekFrom::Start(self.first_frame_pos))?;
220
221                // Since the elementary stream has no timestamp information, the position seeked
222                // to must be exactly as requested.
223                if seeked_pos != self.first_frame_pos {
224                    return seek_error(SeekErrorKind::Unseekable);
225                }
226            }
227            else {
228                return seek_error(SeekErrorKind::ForwardOnly);
229            }
230
231            // Successfuly seeked to the start of the stream, reset the next packet timestamp.
232            self.next_packet_ts = 0;
233        }
234
235        // Parse frames from the stream until the frame containing the desired timestamp is
236        // reached.
237        loop {
238            // Parse the next frame header.
239            let header = AdtsHeader::read(&mut self.reader)?;
240
241            // TODO: Support multiple AAC packets per ADTS packet.
242
243            // If the next frame's timestamp would exceed the desired timestamp, rewind back to the
244            // start of this frame and end the search.
245            if self.next_packet_ts + SAMPLES_PER_AAC_PACKET > required_ts {
246                self.reader.seek_buffered_rev(AdtsHeader::SIZE);
247                break;
248            }
249
250            // Otherwise, ignore the frame body.
251            self.reader.ignore_bytes(header.frame_len as u64)?;
252
253            // Increment the timestamp for the next packet.
254            self.next_packet_ts += SAMPLES_PER_AAC_PACKET;
255        }
256
257        debug!(
258            "seeked to ts={} (delta={})",
259            self.next_packet_ts,
260            required_ts as i64 - self.next_packet_ts as i64
261        );
262
263        Ok(SeekedTo { track_id: 0, required_ts, actual_ts: self.next_packet_ts })
264    }
265
266    fn into_inner(self: Box<Self>) -> MediaSourceStream {
267        self.reader
268    }
269}
270
271fn approximate_frame_count(mut source: &mut MediaSourceStream) -> Result<Option<u64>> {
272    let original_pos = source.pos();
273    let total_len = match source.byte_len() {
274        Some(len) => len - original_pos,
275        _ => return Ok(None),
276    };
277
278    let mut parsed_n_frames = 0;
279    let mut n_bytes = 0;
280
281    if !source.is_seekable() {
282        // The maximum length in bytes of frames to consume from the stream to sample.
283        const MAX_LEN: u64 = 16 * 1024;
284
285        source.ensure_seekback_buffer(MAX_LEN as usize);
286        let mut scoped_stream = ScopedStream::new(&mut source, MAX_LEN);
287
288        while let Ok(header) = AdtsHeader::read(&mut scoped_stream) {
289            if scoped_stream.ignore_bytes(header.frame_len as u64).is_err() {
290                break;
291            }
292
293            parsed_n_frames += 1;
294            n_bytes += header.frame_len + AdtsHeader::SIZE;
295        }
296
297        let _ = source.seek_buffered(original_pos);
298    }
299    else {
300        // The number of points to sample within the stream.
301        const NUM_SAMPLE_POINTS: u64 = 4;
302
303        let step = (total_len - original_pos) / NUM_SAMPLE_POINTS;
304
305        // Skip the first sample point (start of file) since it is an outlier.
306        for new_pos in (original_pos..total_len - step).step_by(step as usize).skip(1) {
307            let res = source.seek(SeekFrom::Start(new_pos));
308            if res.is_err() {
309                break;
310            }
311
312            for _ in 0..=100 {
313                let header = match AdtsHeader::read(&mut source) {
314                    Ok(header) => header,
315                    _ => break,
316                };
317
318                if source.ignore_bytes(header.frame_len as u64).is_err() {
319                    break;
320                }
321
322                parsed_n_frames += 1;
323                n_bytes += header.frame_len + AdtsHeader::SIZE;
324            }
325        }
326
327        let _ = source.seek(SeekFrom::Start(original_pos))?;
328    }
329
330    debug!("adts: Parsed {} of {} bytes to approximate duration", n_bytes, total_len);
331
332    match parsed_n_frames {
333        0 => Ok(None),
334        _ => Ok(Some(total_len / (n_bytes as u64 / parsed_n_frames) * SAMPLES_PER_AAC_PACKET)),
335    }
336}