symphonia_bundle_mp3/
demuxer.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::support_format;
9
10use symphonia_core::checksum::Crc16AnsiLe;
11use symphonia_core::codecs::CodecParameters;
12use symphonia_core::errors::{seek_error, Result, SeekErrorKind};
13use symphonia_core::formats::prelude::*;
14use symphonia_core::io::*;
15use symphonia_core::meta::{Metadata, MetadataLog};
16use symphonia_core::probe::{Descriptor, Instantiate, QueryDescriptor};
17
18use crate::common::{FrameHeader, MpegLayer};
19use crate::header::{self, MAX_MPEG_FRAME_SIZE, MPEG_HEADER_LEN};
20
21use std::io::{Seek, SeekFrom};
22
23use log::{debug, info, warn};
24
25/// MPEG1 and MPEG2 audio elementary stream reader.
26///
27/// `MpaReader` implements a demuxer for the MPEG1 and MPEG2 audio elementary stream.
28pub struct MpaReader {
29    reader: MediaSourceStream,
30    tracks: Vec<Track>,
31    cues: Vec<Cue>,
32    metadata: MetadataLog,
33    options: FormatOptions,
34    first_packet_pos: u64,
35    next_packet_ts: u64,
36}
37
38impl QueryDescriptor for MpaReader {
39    fn query() -> &'static [Descriptor] {
40        &[
41            // Layer 1
42            support_format!(
43                "mp1",
44                "MPEG Audio Layer 1 Native",
45                &["mp1"],
46                &["audio/mpeg", "audio/mp1"],
47                &[
48                    &[0xff, 0xfe], // MPEG 1 with CRC
49                    &[0xff, 0xff], // MPEG 1
50                    &[0xff, 0xf6], // MPEG 2 with CRC
51                    &[0xff, 0xf7], // MPEG 2
52                    &[0xff, 0xe6], // MPEG 2.5 with CRC
53                    &[0xff, 0xe7], // MPEG 2.5
54                ]
55            ),
56            // Layer 2
57            support_format!(
58                "mp2",
59                "MPEG Audio Layer 2 Native",
60                &["mp2"],
61                &["audio/mpeg", "audio/mp2"],
62                &[
63                    &[0xff, 0xfc], // MPEG 1 with CRC
64                    &[0xff, 0xfd], // MPEG 1
65                    &[0xff, 0xf4], // MPEG 2 with CRC
66                    &[0xff, 0xf5], // MPEG 2
67                    &[0xff, 0xe4], // MPEG 2.5 with CRC
68                    &[0xff, 0xe5], // MPEG 2.5
69                ]
70            ),
71            // Layer 3
72            support_format!(
73                "mp3",
74                "MPEG Audio Layer 3 Native",
75                &["mp3"],
76                &["audio/mpeg", "audio/mp3"],
77                &[
78                    &[0xff, 0xfa], // MPEG 1 with CRC
79                    &[0xff, 0xfb], // MPEG 1
80                    &[0xff, 0xf2], // MPEG 2 with CRC
81                    &[0xff, 0xf3], // MPEG 2
82                    &[0xff, 0xe2], // MPEG 2.5 with CRC
83                    &[0xff, 0xe3], // MPEG 2.5
84                ]
85            ),
86        ]
87    }
88
89    fn score(_context: &[u8]) -> u8 {
90        255
91    }
92}
93
94impl FormatReader for MpaReader {
95    fn try_new(mut source: MediaSourceStream, options: &FormatOptions) -> Result<Self> {
96        // Try to read the first MPEG frame.
97        let (header, packet) = read_mpeg_frame_strict(&mut source)?;
98
99        // Use the header to populate the codec parameters.
100        let mut params = CodecParameters::new();
101
102        params
103            .for_codec(header.codec())
104            .with_sample_rate(header.sample_rate)
105            .with_time_base(TimeBase::new(1, header.sample_rate))
106            .with_channels(header.channel_mode.channels());
107
108        // Check if there is a Xing/Info tag contained in the first frame.
109        if let Some(info_tag) = try_read_info_tag(&packet, &header) {
110            // The LAME tag contains ReplayGain and padding information.
111            let (delay, padding) = if let Some(lame_tag) = info_tag.lame {
112                params.with_delay(lame_tag.enc_delay).with_padding(lame_tag.enc_padding);
113
114                (lame_tag.enc_delay, lame_tag.enc_padding)
115            }
116            else {
117                (0, 0)
118            };
119
120            // The base Xing/Info tag may contain the number of frames.
121            if let Some(num_mpeg_frames) = info_tag.num_frames {
122                info!("using xing header for duration");
123
124                let num_frames = u64::from(num_mpeg_frames) * header.duration();
125
126                // Adjust for gapless playback.
127                if options.enable_gapless {
128                    params.with_n_frames(num_frames - u64::from(delay) - u64::from(padding));
129                }
130                else {
131                    params.with_n_frames(num_frames);
132                }
133            }
134        }
135        else if let Some(vbri_tag) = try_read_vbri_tag(&packet, &header) {
136            info!("using vbri header for duration");
137
138            let num_frames = u64::from(vbri_tag.num_mpeg_frames) * header.duration();
139
140            // Check if there is a VBRI tag.
141            params.with_n_frames(num_frames);
142        }
143        else {
144            // The first frame was not a Xing/Info header, rewind back to the start of the frame so
145            // that it may be decoded.
146            source.seek_buffered_rev(MPEG_HEADER_LEN + header.frame_size);
147
148            // Likely not a VBR file, so estimate the duration if seekable.
149            if source.is_seekable() {
150                info!("estimating duration from bitrate, may be inaccurate for vbr files");
151
152                if let Some(n_mpeg_frames) = estimate_num_mpeg_frames(&mut source) {
153                    params.with_n_frames(n_mpeg_frames * header.duration());
154                }
155            }
156        }
157
158        let first_packet_pos = source.pos();
159
160        Ok(MpaReader {
161            reader: source,
162            tracks: vec![Track::new(0, params)],
163            cues: Vec::new(),
164            metadata: Default::default(),
165            options: *options,
166            first_packet_pos,
167            next_packet_ts: 0,
168        })
169    }
170
171    fn next_packet(&mut self) -> Result<Packet> {
172        let (header, packet) = loop {
173            // Read the next MPEG frame.
174            let (header, packet) = read_mpeg_frame(&mut self.reader)?;
175
176            // Check if the packet contains a Xing, Info, or VBRI tag.
177            if is_maybe_info_tag(&packet, &header) {
178                if try_read_info_tag(&packet, &header).is_some() {
179                    // Discard the packet and tag since it was not at the start of the stream.
180                    warn!("found an unexpected xing tag, discarding");
181                    continue;
182                }
183            }
184            else if is_maybe_vbri_tag(&packet, &header)
185                && try_read_vbri_tag(&packet, &header).is_some()
186            {
187                // Discard the packet and tag since it was not at the start of the stream.
188                warn!("found an unexpected vbri tag, discarding");
189                continue;
190            }
191
192            break (header, packet);
193        };
194
195        // Each frame contains 1 or 2 granules with each granule being exactly 576 samples long.
196        let ts = self.next_packet_ts;
197        let duration = header.duration();
198
199        self.next_packet_ts += duration;
200
201        let mut packet = Packet::new_from_boxed_slice(0, ts, duration, packet.into_boxed_slice());
202
203        if self.options.enable_gapless {
204            symphonia_core::formats::util::trim_packet(
205                &mut packet,
206                self.tracks[0].codec_params.delay.unwrap_or(0),
207                self.tracks[0].codec_params.n_frames,
208            );
209        }
210
211        Ok(packet)
212    }
213
214    fn metadata(&mut self) -> Metadata<'_> {
215        self.metadata.metadata()
216    }
217
218    fn cues(&self) -> &[Cue] {
219        &self.cues
220    }
221
222    fn tracks(&self) -> &[Track] {
223        &self.tracks
224    }
225
226    fn seek(&mut self, mode: SeekMode, to: SeekTo) -> Result<SeekedTo> {
227        const MAX_REF_FRAMES: usize = 4;
228        const REF_FRAMES_MASK: usize = MAX_REF_FRAMES - 1;
229
230        // Get the timestamp of the desired audio frame.
231        let desired_ts = match to {
232            // Frame timestamp given.
233            SeekTo::TimeStamp { ts, .. } => ts,
234            // Time value given, calculate frame timestamp from sample rate.
235            SeekTo::Time { time, .. } => {
236                // Use the sample rate to calculate the frame timestamp. If sample rate is not
237                // known, the seek cannot be completed.
238                if let Some(sample_rate) = self.tracks[0].codec_params.sample_rate {
239                    TimeBase::new(1, sample_rate).calc_timestamp(time)
240                }
241                else {
242                    return seek_error(SeekErrorKind::Unseekable);
243                }
244            }
245        };
246
247        // If gapless playback is enabled, get the delay.
248        let delay = if self.options.enable_gapless {
249            u64::from(self.tracks[0].codec_params.delay.unwrap_or(0))
250        }
251        else {
252            0
253        };
254
255        // The required timestamp is offset by the delay.
256        let required_ts = desired_ts + delay;
257
258        // If the stream is unseekable and the required timestamp in the past, then return an
259        // error, it is not possible to seek to it.
260        let is_seekable = self.reader.is_seekable();
261
262        if !is_seekable && required_ts < self.next_packet_ts {
263            return seek_error(SeekErrorKind::ForwardOnly);
264        }
265
266        debug!("seeking to ts={} (+{} delay = {})", desired_ts, delay, required_ts);
267
268        // Step 1
269        //
270        // In coarse seek mode, the underlying media source stream will be roughly seeked based on
271        // the required timestamp and the total duration of the media. Coarse seek mode requires a
272        // seekable stream because the total length in bytes of the stream is required.
273        //
274        // In accurate seek mode, the underlying media source stream will not be seeked unless the
275        // required timestamp is in the past, in which case the stream is seeked back to the start.
276        match mode {
277            SeekMode::Coarse if is_seekable => self.preseek_coarse(required_ts, delay)?,
278            SeekMode::Accurate => self.preseek_accurate(required_ts)?,
279            _ => (),
280        };
281
282        // Step 2
283        //
284        // Following the pre-seek operation above, parse MPEG frames (packets) one-by-one from the
285        // current position in the stream until the frame containing the desired timestamp is
286        // reached. For coarse seeks, this should only parse a few packets. For accurate seeks, the
287        // entire stream could potentially be parsed.
288        let mut frames: [FramePos; MAX_REF_FRAMES] = Default::default();
289        let mut n_parsed = 0;
290
291        loop {
292            // Parse the next frame header.
293            let header = header::parse_frame_header(header::sync_frame(&mut self.reader)?)?;
294
295            // Position of the frame header.
296            let pos = self.reader.pos() - std::mem::size_of::<u32>() as u64;
297
298            // Calculate the duration of the frame.
299            let duration = header.duration();
300
301            // Add the frame to the frame ring.
302            frames[n_parsed & REF_FRAMES_MASK] = FramePos { pos, ts: self.next_packet_ts };
303            n_parsed += 1;
304
305            // If the next frame's timestamp would exceed the desired timestamp, rewind back to the
306            // start of this frame and end the search.
307            if self.next_packet_ts + duration > required_ts {
308                // The main_data_begin offset is a negative offset from the frame's header to where
309                // its main data begins. Therefore, for a decoder to properly decode this frame, the
310                // reader must provide previous (reference) frames up-to and including the frame
311                // that contains the first byte this frame's main_data.
312                let main_data_begin = read_main_data_begin(&mut self.reader, &header)? as u64;
313
314                debug!(
315                    "found frame with ts={} ({}) @ pos={} with main_data_begin={}",
316                    self.next_packet_ts.saturating_sub(delay),
317                    self.next_packet_ts,
318                    pos,
319                    main_data_begin
320                );
321
322                // The number of reference frames is 0 if main_data_begin is also 0. Otherwise,
323                // attempt to find the first (oldest) reference frame, then select 1 frame before
324                // that one to actually seek to.
325                let mut n_ref_frames = 0;
326                let mut ref_frame = &frames[(n_parsed - 1) & REF_FRAMES_MASK];
327
328                if main_data_begin > 0 {
329                    // The maximum number of reference frames is limited to the number of frames
330                    // read and the number of previous frames recorded.
331                    let max_ref_frames = std::cmp::min(n_parsed, frames.len());
332
333                    while n_ref_frames < max_ref_frames {
334                        ref_frame = &frames[(n_parsed - n_ref_frames - 1) & REF_FRAMES_MASK];
335
336                        if pos - ref_frame.pos >= main_data_begin {
337                            break;
338                        }
339
340                        n_ref_frames += 1;
341                    }
342
343                    debug!(
344                        "will seek -{} frame(s) to ts={} ({}) @ pos={} (-{} bytes)",
345                        n_ref_frames,
346                        ref_frame.ts.saturating_sub(delay),
347                        ref_frame.ts,
348                        ref_frame.pos,
349                        pos - ref_frame.pos
350                    );
351                }
352
353                // Do the actual seek to the reference frame.
354                self.next_packet_ts = ref_frame.ts;
355                self.reader.seek_buffered(ref_frame.pos);
356
357                break;
358            }
359
360            // Otherwise, ignore the frame body.
361            self.reader.ignore_bytes(header.frame_size as u64)?;
362
363            // Increment the timestamp for the next packet.
364            self.next_packet_ts += duration;
365        }
366
367        let actual_ts = self.next_packet_ts.saturating_sub(delay);
368
369        debug!(
370            "seeked to ts={} ({}) (delta={})",
371            actual_ts,
372            self.next_packet_ts,
373            self.next_packet_ts as i64 - required_ts as i64,
374        );
375
376        Ok(SeekedTo { track_id: 0, required_ts: required_ts - delay, actual_ts })
377    }
378
379    fn into_inner(self: Box<Self>) -> MediaSourceStream {
380        self.reader
381    }
382}
383
384impl MpaReader {
385    /// Seeks the media source stream to a byte position roughly where the packet with the required
386    /// timestamp should be located.
387    fn preseek_coarse(&mut self, required_ts: u64, delay: u64) -> Result<()> {
388        // If gapless playback is enabled, get the padding.
389        let padding = if self.options.enable_gapless {
390            u64::from(self.tracks[0].codec_params.padding.unwrap_or(0))
391        }
392        else {
393            0
394        };
395
396        // Get the total byte length of the stream. It is not possible to seek without this.
397        let total_byte_len = match self.reader.byte_len() {
398            Some(byte_len) => byte_len,
399            None => return seek_error(SeekErrorKind::Unseekable),
400        };
401
402        // Get the total duration in audio frames of the stream, including delay and padding. It is
403        // not possible to seek without this.
404        let duration = match self.tracks[0].codec_params.n_frames {
405            Some(num_frames) => num_frames + delay + padding,
406            None => return seek_error(SeekErrorKind::Unseekable),
407        };
408
409        // Calculate the total size of the audio data.
410        let audio_byte_len = total_byte_len - self.first_packet_pos;
411
412        // Calculate, roughly, where the packet containing the required timestamp is in the media
413        // source stream relative to the start of the audio data.
414        let packet_pos =
415            ((u128::from(required_ts) * u128::from(audio_byte_len)) / u128::from(duration)) as u64;
416
417        // It is preferable to return a packet with a timestamp before the requested timestamp.
418        // Therefore, subtract the maximum packet size from the position found above to ensure this.
419        let seek_pos = packet_pos.saturating_sub(MAX_MPEG_FRAME_SIZE) + self.first_packet_pos;
420
421        // Seek the media source stream.
422        self.reader.seek(SeekFrom::Start(seek_pos))?;
423
424        // Resync to the start of the next packet.
425        let (header, _) = read_mpeg_frame_strict(&mut self.reader)?;
426
427        // Calculate, roughly, the timestamp of the packet based on the byte position after resync.
428        let seeked_pos = self.reader.pos();
429
430        let ts = ((u128::from(seeked_pos - self.first_packet_pos) * u128::from(duration))
431            / u128::from(audio_byte_len)) as u64;
432
433        // Assuming the duration of a packet remains constant throughout the stream (not a
434        // guarantee, but usually the case), round the timestamp to a multiple of a packet duration.
435        let packet_dur = header.duration();
436
437        self.next_packet_ts = (ts / packet_dur) * packet_dur;
438
439        Ok(())
440    }
441
442    /// Seeks the media source stream back to the start of the first packet if the required
443    /// timestamp is in the past.
444    fn preseek_accurate(&mut self, required_ts: u64) -> Result<()> {
445        if required_ts < self.next_packet_ts {
446            let seeked_pos = self.reader.seek(SeekFrom::Start(self.first_packet_pos))?;
447
448            // Since the elementary stream has no timestamp information, the position seeked
449            // to must be exactly as requested.
450            if seeked_pos != self.first_packet_pos {
451                return seek_error(SeekErrorKind::Unseekable);
452            }
453
454            // Successfuly seeked to the start of the stream, reset the next packet timestamp.
455            self.next_packet_ts = 0;
456        }
457
458        Ok(())
459    }
460}
461
462/// Reads a MPEG frame and returns the header and buffer.
463fn read_mpeg_frame(reader: &mut MediaSourceStream) -> Result<(FrameHeader, Vec<u8>)> {
464    let (header, header_word) = loop {
465        // Sync to the next frame header.
466        let sync = header::sync_frame(reader)?;
467
468        // Parse the frame header fully.
469        if let Ok(header) = header::parse_frame_header(sync) {
470            break (header, sync);
471        }
472
473        warn!("invalid mpeg audio header");
474    };
475
476    // Allocate frame buffer.
477    let mut packet = vec![0u8; MPEG_HEADER_LEN + header.frame_size];
478    packet[0..MPEG_HEADER_LEN].copy_from_slice(&header_word.to_be_bytes());
479
480    // Read the frame body.
481    reader.read_buf_exact(&mut packet[MPEG_HEADER_LEN..])?;
482
483    // Return the parsed header and packet body.
484    Ok((header, packet))
485}
486
487/// Reads a MPEG frame and checks if the next frame begins after the packet.
488fn read_mpeg_frame_strict(reader: &mut MediaSourceStream) -> Result<(FrameHeader, Vec<u8>)> {
489    loop {
490        // Read the next MPEG frame.
491        let (header, packet) = read_mpeg_frame(reader)?;
492
493        // Get the position before trying to read the next header.
494        let pos = reader.pos();
495
496        // Read a sync word from the stream. If this read fails then the file may have ended and
497        // this check cannot be performed.
498        if let Ok(sync) = header::read_frame_header_word_no_sync(reader) {
499            // If the stream is not synced to the next frame's sync word, or the next frame header
500            // is not parseable or similar to the current frame header, then reject the current
501            // packet since the stream likely synced to random data.
502            if !header::is_frame_header_word_synced(sync) || !is_frame_header_similar(&header, sync)
503            {
504                warn!("skipping junk at {} bytes", pos - packet.len() as u64);
505
506                // Seek back to the second byte of the rejected packet to prevent syncing to the
507                // same spot again.
508                reader.seek_buffered_rev(packet.len() + MPEG_HEADER_LEN - 1);
509                continue;
510            }
511        }
512
513        // Jump back to the position before the next header was read.
514        reader.seek_buffered(pos);
515
516        break Ok((header, packet));
517    }
518}
519
520/// Check if a sync word parses to a frame header that is similar to the one provided.
521fn is_frame_header_similar(header: &FrameHeader, sync: u32) -> bool {
522    if let Ok(candidate) = header::parse_frame_header(sync) {
523        if header.version == candidate.version
524            && header.layer == candidate.layer
525            && header.sample_rate == candidate.sample_rate
526            && header.n_channels() == candidate.n_channels()
527        {
528            return true;
529        }
530    }
531
532    false
533}
534
535#[derive(Default)]
536struct FramePos {
537    ts: u64,
538    pos: u64,
539}
540
541/// Reads the main_data_begin field from the side information of a MPEG audio frame.
542fn read_main_data_begin<B: ReadBytes>(reader: &mut B, header: &FrameHeader) -> Result<u16> {
543    // After the head the optional CRC is present.
544    if header.has_crc {
545        let _crc = reader.read_be_u16()?;
546    }
547
548    // For MPEG version 1 the first 9 bits is main_data_begin.
549    let main_data_begin = if header.is_mpeg1() {
550        reader.read_be_u16()? >> 7
551    }
552    // For MPEG version 2 the first 8 bits is main_data_begin.
553    else {
554        u16::from(reader.read_u8()?)
555    };
556
557    Ok(main_data_begin)
558}
559
560/// Estimates the total number of MPEG frames in the media source stream.
561fn estimate_num_mpeg_frames(reader: &mut MediaSourceStream) -> Option<u64> {
562    const MAX_FRAMES: u32 = 16;
563    const MAX_LEN: usize = 16 * 1024;
564
565    // Macro to convert a Result to Option, and break a loop on exit.
566    macro_rules! break_on_err {
567        ($expr:expr) => {
568            match $expr {
569                Ok(a) => a,
570                _ => break None,
571            }
572        };
573    }
574
575    let start_pos = reader.pos();
576
577    let mut total_frame_len = 0;
578    let mut total_frames = 0;
579
580    let total_len = match reader.byte_len() {
581        Some(len) => len - start_pos,
582        _ => return None,
583    };
584
585    let num_mpeg_frames = loop {
586        // Read the frame header.
587        let header_val = break_on_err!(reader.read_be_u32());
588
589        // Parse the frame header.
590        let header = break_on_err!(header::parse_frame_header(header_val));
591
592        // Tabulate the size.
593        total_frame_len += MPEG_HEADER_LEN + header.frame_size;
594        total_frames += 1;
595
596        // Ignore the frame body.
597        break_on_err!(reader.ignore_bytes(header.frame_size as u64));
598
599        // Read up-to 16 frames, or 16kB, then calculate the average MPEG frame length, and from
600        // that, the total number of MPEG frames.
601        if total_frames > MAX_FRAMES || total_frame_len > MAX_LEN {
602            let avg_mpeg_frame_len = total_frame_len as f64 / total_frames as f64;
603            break Some((total_len as f64 / avg_mpeg_frame_len) as u64);
604        }
605    };
606
607    // Rewind back to the first frame seen upon entering this function.
608    reader.seek_buffered_rev((reader.pos() - start_pos) as usize);
609
610    num_mpeg_frames
611}
612
613const XING_TAG_ID: [u8; 4] = *b"Xing";
614const INFO_TAG_ID: [u8; 4] = *b"Info";
615
616/// The LAME tag is an extension to the Xing/Info tag.
617#[allow(dead_code)]
618struct LameTag {
619    encoder: String,
620    replaygain_peak: Option<f32>,
621    replaygain_radio: Option<f32>,
622    replaygain_audiophile: Option<f32>,
623    enc_delay: u32,
624    enc_padding: u32,
625}
626
627/// The Xing/Info time additional information for regarding a MP3 file.
628#[allow(dead_code)]
629struct XingInfoTag {
630    num_frames: Option<u32>,
631    num_bytes: Option<u32>,
632    toc: Option<[u8; 100]>,
633    quality: Option<u32>,
634    is_cbr: bool,
635    lame: Option<LameTag>,
636}
637
638/// Try to read a Xing/Info tag from the provided MPEG frame.
639fn try_read_info_tag(buf: &[u8], header: &FrameHeader) -> Option<XingInfoTag> {
640    // The Info header is a completely optional piece of information. Therefore, flatten an error
641    // reading the tag into a None.
642    try_read_info_tag_inner(buf, header).ok().flatten()
643}
644
645fn try_read_info_tag_inner(buf: &[u8], header: &FrameHeader) -> Result<Option<XingInfoTag>> {
646    // Do a quick check that this is a Xing/Info tag.
647    if !is_maybe_info_tag(buf, header) {
648        return Ok(None);
649    }
650
651    // The position of the Xing/Info tag relative to the end of the header. This is equal to the
652    // side information length for the frame.
653    let offset = header.side_info_len();
654
655    // Start the CRC with the header and side information.
656    let mut crc16 = Crc16AnsiLe::new(0);
657    crc16.process_buf_bytes(&buf[..offset + MPEG_HEADER_LEN]);
658
659    // Start reading the Xing/Info tag after the side information.
660    let mut reader = MonitorStream::new(BufReader::new(&buf[offset + MPEG_HEADER_LEN..]), crc16);
661
662    // Check for Xing/Info header.
663    let id = reader.read_quad_bytes()?;
664
665    if id != XING_TAG_ID && id != INFO_TAG_ID {
666        return Ok(None);
667    }
668
669    // The "Info" id is used for CBR files.
670    let is_cbr = id == INFO_TAG_ID;
671
672    // Flags indicates what information is provided in this Xing/Info tag.
673    let flags = reader.read_be_u32()?;
674
675    let num_frames = if flags & 0x1 != 0 { Some(reader.read_be_u32()?) } else { None };
676
677    let num_bytes = if flags & 0x2 != 0 { Some(reader.read_be_u32()?) } else { None };
678
679    let toc = if flags & 0x4 != 0 {
680        let mut toc = [0; 100];
681        reader.read_buf_exact(&mut toc)?;
682        Some(toc)
683    }
684    else {
685        None
686    };
687
688    let quality = if flags & 0x8 != 0 { Some(reader.read_be_u32()?) } else { None };
689
690    /// The full LAME extension size.
691    const LAME_EXT_LEN: u64 = 36;
692    /// The minimal LAME extension size up-to the encode delay & padding fields.
693    const MIN_LAME_EXT_LEN: u64 = 24;
694
695    // The LAME extension may not always be present, or complete. The important fields in the
696    // extension are within the first 24 bytes. Therefore, try to read those if they're available.
697    let lame = if reader.inner().bytes_available() >= MIN_LAME_EXT_LEN {
698        // Encoder string.
699        let mut encoder = [0; 9];
700        reader.read_buf_exact(&mut encoder)?;
701
702        // Revision.
703        let _revision = reader.read_u8()?;
704
705        // Lowpass filter value.
706        let _lowpass = reader.read_u8()?;
707
708        // Replay gain peak in 9.23 (bit) fixed-point format.
709        let replaygain_peak = match reader.read_be_u32()? {
710            0 => None,
711            peak => Some(32767.0 * (peak as f32 / 2.0f32.powi(23))),
712        };
713
714        // Radio replay gain.
715        let replaygain_radio = parse_lame_tag_replaygain(reader.read_be_u16()?, 1);
716
717        // Audiophile replay gain.
718        let replaygain_audiophile = parse_lame_tag_replaygain(reader.read_be_u16()?, 2);
719
720        // Encoding flags & ATH type.
721        let _encoding_flags = reader.read_u8()?;
722
723        // Arbitrary bitrate.
724        let _abr = reader.read_u8()?;
725
726        let (enc_delay, enc_padding) = {
727            let trim = reader.read_be_u24()?;
728
729            if encoder[..4] == *b"LAME" || encoder[..4] == *b"Lavf" || encoder[..4] == *b"Lavc" {
730                let delay = 528 + 1 + (trim >> 12);
731                let padding = trim & ((1 << 12) - 1);
732
733                (delay, padding.saturating_sub(528 + 1))
734            }
735            else {
736                (0, 0)
737            }
738        };
739
740        // If possible, attempt to read the extra fields of the extension if they weren't
741        // truncated.
742        let crc = if reader.inner().bytes_available() >= LAME_EXT_LEN - MIN_LAME_EXT_LEN {
743            // Flags.
744            let _misc = reader.read_u8()?;
745
746            // MP3 gain.
747            let _mp3_gain = reader.read_u8()?;
748
749            // Preset and surround info.
750            let _surround_info = reader.read_be_u16()?;
751
752            // Music length.
753            let _music_len = reader.read_be_u32()?;
754
755            // Music (audio) CRC.
756            let _music_crc = reader.read_be_u16()?;
757
758            // The tag CRC. LAME always includes this CRC regardless of the protection bit, but
759            // other encoders may only do so if the protection bit is set.
760            if header.has_crc || encoder[..4] == *b"LAME" {
761                // Read the CRC using the inner reader to not change the computed CRC.
762                Some(reader.inner_mut().read_be_u16()?)
763            }
764            else {
765                // No CRC is present.
766                None
767            }
768        }
769        else {
770            // The tag is truncated. No CRC will be present.
771            info!("xing tag lame extension is truncated");
772            None
773        };
774
775        // If there is no CRC, then assume the tag is correct. Otherwise, use the CRC.
776        let is_tag_ok = crc.map_or(true, |crc| crc == reader.monitor().crc());
777
778        if is_tag_ok {
779            // The CRC matched or is not present.
780            Some(LameTag {
781                encoder: String::from_utf8_lossy(&encoder).into(),
782                replaygain_peak,
783                replaygain_radio,
784                replaygain_audiophile,
785                enc_delay,
786                enc_padding,
787            })
788        }
789        else {
790            // The CRC did not match, this is probably not a LAME tag.
791            warn!("xing tag lame extension crc mismatch");
792            None
793        }
794    }
795    else {
796        // Frame not large enough for a LAME tag.
797        info!("xing tag too small for lame extension");
798        None
799    };
800
801    Ok(Some(XingInfoTag { num_frames, num_bytes, toc, quality, is_cbr, lame }))
802}
803
804fn parse_lame_tag_replaygain(value: u16, expected_name: u8) -> Option<f32> {
805    // The 3 most-significant bits are the name code.
806    let name = ((value & 0xe000) >> 13) as u8;
807
808    if name == expected_name {
809        let gain = (value & 0x01ff) as f32 / 10.0;
810        Some(if value & 0x200 != 0 { -gain } else { gain })
811    }
812    else {
813        None
814    }
815}
816
817/// Perform a fast check to see if the packet contains a Xing/Info tag. If this returns true, the
818/// packet should be parsed fully to ensure it is in fact a tag.
819fn is_maybe_info_tag(buf: &[u8], header: &FrameHeader) -> bool {
820    const MIN_XING_TAG_LEN: usize = 8;
821
822    // Only supported with layer 3 packets.
823    if header.layer != MpegLayer::Layer3 {
824        return false;
825    }
826
827    // The position of the Xing/Info tag relative to the start of the packet. This is equal to the
828    // side information length for the frame.
829    let offset = header.side_info_len() + MPEG_HEADER_LEN;
830
831    // The packet must be big enough to contain a tag.
832    if buf.len() < offset + MIN_XING_TAG_LEN {
833        return false;
834    }
835
836    // The tag ID must be present and correct.
837    let id = &buf[offset..offset + 4];
838
839    if id != XING_TAG_ID && id != INFO_TAG_ID {
840        return false;
841    }
842
843    // The side information should be zeroed.
844    !buf[MPEG_HEADER_LEN..offset].iter().any(|&b| b != 0)
845}
846
847const VBRI_TAG_ID: [u8; 4] = *b"VBRI";
848
849/// The contents of a VBRI tag.
850#[allow(dead_code)]
851struct VbriTag {
852    num_bytes: u32,
853    num_mpeg_frames: u32,
854}
855
856/// Try to read a VBRI tag from the provided MPEG frame.
857fn try_read_vbri_tag(buf: &[u8], header: &FrameHeader) -> Option<VbriTag> {
858    // The VBRI header is a completely optional piece of information. Therefore, flatten an error
859    // reading the tag into a None.
860    try_read_vbri_tag_inner(buf, header).ok().flatten()
861}
862
863fn try_read_vbri_tag_inner(buf: &[u8], header: &FrameHeader) -> Result<Option<VbriTag>> {
864    // Do a quick check that this is a VBRI tag.
865    if !is_maybe_vbri_tag(buf, header) {
866        return Ok(None);
867    }
868
869    let mut reader = BufReader::new(buf);
870
871    // The VBRI tag is always 32 bytes after the header.
872    reader.ignore_bytes(MPEG_HEADER_LEN as u64 + 32)?;
873
874    // Check for the VBRI signature.
875    let id = reader.read_quad_bytes()?;
876
877    if id != VBRI_TAG_ID {
878        return Ok(None);
879    }
880
881    // The version is always 1.
882    let version = reader.read_be_u16()?;
883
884    if version != 1 {
885        return Ok(None);
886    }
887
888    // Delay is a 2-byte big-endiann floating point value?
889    let _delay = reader.read_be_u16()?;
890    let _quality = reader.read_be_u16()?;
891
892    let num_bytes = reader.read_be_u32()?;
893    let num_mpeg_frames = reader.read_be_u32()?;
894
895    Ok(Some(VbriTag { num_bytes, num_mpeg_frames }))
896}
897
898/// Perform a fast check to see if the packet contains a VBRI tag. If this returns true, the
899/// packet should be parsed fully to ensure it is in fact a tag.
900fn is_maybe_vbri_tag(buf: &[u8], header: &FrameHeader) -> bool {
901    const MIN_VBRI_TAG_LEN: usize = 26;
902    const VBRI_TAG_OFFSET: usize = 36;
903
904    // Only supported with layer 3 packets.
905    if header.layer != MpegLayer::Layer3 {
906        return false;
907    }
908
909    // The packet must be big enough to contain a tag.
910    if buf.len() < VBRI_TAG_OFFSET + MIN_VBRI_TAG_LEN {
911        return false;
912    }
913
914    // The tag ID must be present and correct.
915    let id = &buf[VBRI_TAG_OFFSET..VBRI_TAG_OFFSET + 4];
916
917    if id != VBRI_TAG_ID {
918        return false;
919    }
920
921    // The bytes preceeding the VBRI tag (mostly the side information) should be all 0.
922    !buf[MPEG_HEADER_LEN..VBRI_TAG_OFFSET].iter().any(|&b| b != 0)
923}