symphonia_format_riff/wave/
mod.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 std::io::{Seek, SeekFrom};
9
10use symphonia_core::codecs::CodecParameters;
11use symphonia_core::errors::{seek_error, unsupported_error};
12use symphonia_core::errors::{Result, SeekErrorKind};
13use symphonia_core::formats::prelude::*;
14use symphonia_core::io::*;
15use symphonia_core::meta::{Metadata, MetadataLog};
16use symphonia_core::probe::{Descriptor, Instantiate, QueryDescriptor};
17use symphonia_core::support_format;
18
19use log::{debug, error};
20
21use crate::common::{
22    append_data_params, append_format_params, next_packet, ByteOrder, ChunksReader, PacketInfo,
23};
24mod chunks;
25use chunks::*;
26
27/// WAVE is actually a RIFF stream, with a "RIFF" ASCII stream marker.
28const WAVE_STREAM_MARKER: [u8; 4] = *b"RIFF";
29/// A possible RIFF form is "wave".
30const WAVE_RIFF_FORM: [u8; 4] = *b"WAVE";
31
32/// Waveform Audio File Format (WAV) format reader.
33///
34/// `WavReader` implements a demuxer for the WAVE container format.
35pub struct WavReader {
36    reader: MediaSourceStream,
37    tracks: Vec<Track>,
38    cues: Vec<Cue>,
39    metadata: MetadataLog,
40    packet_info: PacketInfo,
41    data_start_pos: u64,
42    data_end_pos: u64,
43}
44
45impl QueryDescriptor for WavReader {
46    fn query() -> &'static [Descriptor] {
47        &[
48            // WAVE RIFF form
49            support_format!(
50                "wave",
51                "Waveform Audio File Format",
52                &["wav", "wave"],
53                &["audio/vnd.wave", "audio/x-wav", "audio/wav", "audio/wave"],
54                &[b"RIFF"]
55            ),
56        ]
57    }
58
59    fn score(_context: &[u8]) -> u8 {
60        255
61    }
62}
63
64impl FormatReader for WavReader {
65    fn try_new(mut source: MediaSourceStream, _options: &FormatOptions) -> Result<Self> {
66        // The RIFF marker should be present.
67        let marker = source.read_quad_bytes()?;
68
69        if marker != WAVE_STREAM_MARKER {
70            return unsupported_error("wav: missing riff stream marker");
71        }
72
73        // A Wave file is one large RIFF chunk, with the actual meta and audio data as sub-chunks.
74        // Therefore, the header was the chunk ID, and the next 4 bytes is the length of the RIFF
75        // chunk.
76        let riff_len = source.read_u32()?;
77        let riff_form = source.read_quad_bytes()?;
78
79        // The RIFF chunk contains WAVE data.
80        if riff_form != WAVE_RIFF_FORM {
81            error!("riff form is not wave ({})", String::from_utf8_lossy(&riff_form));
82
83            return unsupported_error("wav: riff form is not wave");
84        }
85
86        let mut riff_chunks =
87            ChunksReader::<RiffWaveChunks>::new(riff_len, ByteOrder::LittleEndian);
88
89        let mut codec_params = CodecParameters::new();
90        let mut metadata: MetadataLog = Default::default();
91        let mut packet_info = PacketInfo::without_blocks(0);
92
93        loop {
94            let chunk = riff_chunks.next(&mut source)?;
95
96            // The last chunk should always be a data chunk, if it is not, then the stream is
97            // unsupported.
98            if chunk.is_none() {
99                return unsupported_error("wav: missing data chunk");
100            }
101
102            match chunk.unwrap() {
103                RiffWaveChunks::Format(fmt) => {
104                    let format = fmt.parse(&mut source)?;
105
106                    // The Format chunk contains the block_align field and possible additional information
107                    // to handle packetization and seeking.
108                    packet_info = format.packet_info()?;
109                    codec_params
110                        .with_max_frames_per_packet(packet_info.get_max_frames_per_packet())
111                        .with_frames_per_block(packet_info.frames_per_block);
112
113                    // Append Format chunk fields to codec parameters.
114                    append_format_params(
115                        &mut codec_params,
116                        &format.format_data,
117                        format.sample_rate,
118                    );
119                }
120                RiffWaveChunks::Fact(fct) => {
121                    let fact = fct.parse(&mut source)?;
122
123                    // Append Fact chunk fields to codec parameters.
124                    append_fact_params(&mut codec_params, &fact);
125                }
126                RiffWaveChunks::List(lst) => {
127                    let list = lst.parse(&mut source)?;
128
129                    // Riff Lists can have many different forms, but WavReader only supports Info
130                    // lists.
131                    match &list.form {
132                        b"INFO" => metadata.push(read_info_chunk(&mut source, list.len)?),
133                        _ => list.skip(&mut source)?,
134                    }
135                }
136                RiffWaveChunks::Data(dat) => {
137                    let data = dat.parse(&mut source)?;
138
139                    // Record the bounds of the data chunk.
140                    let data_start_pos = source.pos();
141                    let data_end_pos = data_start_pos + u64::from(data.len);
142
143                    // Append Data chunk fields to codec parameters.
144                    append_data_params(&mut codec_params, data.len as u64, &packet_info);
145
146                    // Add a new track using the collected codec parameters.
147                    return Ok(WavReader {
148                        reader: source,
149                        tracks: vec![Track::new(0, codec_params)],
150                        cues: Vec::new(),
151                        metadata,
152                        packet_info,
153                        data_start_pos,
154                        data_end_pos,
155                    });
156                }
157            }
158        }
159    }
160
161    fn next_packet(&mut self) -> Result<Packet> {
162        next_packet(
163            &mut self.reader,
164            &self.packet_info,
165            &self.tracks,
166            self.data_start_pos,
167            self.data_end_pos,
168        )
169    }
170
171    fn metadata(&mut self) -> Metadata<'_> {
172        self.metadata.metadata()
173    }
174
175    fn cues(&self) -> &[Cue] {
176        &self.cues
177    }
178
179    fn tracks(&self) -> &[Track] {
180        &self.tracks
181    }
182
183    fn seek(&mut self, _mode: SeekMode, to: SeekTo) -> Result<SeekedTo> {
184        if self.tracks.is_empty() || self.packet_info.is_empty() {
185            return seek_error(SeekErrorKind::Unseekable);
186        }
187
188        let params = &self.tracks[0].codec_params;
189
190        let ts = match to {
191            // Frame timestamp given.
192            SeekTo::TimeStamp { ts, .. } => ts,
193            // Time value given, calculate frame timestamp from sample rate.
194            SeekTo::Time { time, .. } => {
195                // Use the sample rate to calculate the frame timestamp. If sample rate is not
196                // known, the seek cannot be completed.
197                if let Some(sample_rate) = params.sample_rate {
198                    TimeBase::new(1, sample_rate).calc_timestamp(time)
199                }
200                else {
201                    return seek_error(SeekErrorKind::Unseekable);
202                }
203            }
204        };
205
206        // If the total number of frames in the track is known, verify the desired frame timestamp
207        // does not exceed it.
208        if let Some(n_frames) = params.n_frames {
209            if ts > n_frames {
210                return seek_error(SeekErrorKind::OutOfRange);
211            }
212        }
213
214        debug!("seeking to frame_ts={}", ts);
215
216        // WAVE is not internally packetized for PCM codecs. Packetization is simulated by trying to
217        // read a constant number of samples or blocks every call to next_packet. Therefore, a packet begins
218        // wherever the data stream is currently positioned. Since timestamps on packets should be
219        // determinstic, instead of seeking to the exact timestamp requested and starting the next
220        // packet there, seek to a packet boundary. In this way, packets will have have the same
221        // timestamps regardless if the stream was seeked or not.
222        let actual_ts = self.packet_info.get_actual_ts(ts);
223
224        // Calculate the absolute byte offset of the desired audio frame.
225        let seek_pos = self.data_start_pos + (actual_ts * self.packet_info.block_size);
226
227        // If the reader supports seeking we can seek directly to the frame's offset wherever it may
228        // be.
229        if self.reader.is_seekable() {
230            self.reader.seek(SeekFrom::Start(seek_pos))?;
231        }
232        // If the reader does not support seeking, we can only emulate forward seeks by consuming
233        // bytes. If the reader has to seek backwards, return an error.
234        else {
235            let current_pos = self.reader.pos();
236            if seek_pos >= current_pos {
237                self.reader.ignore_bytes(seek_pos - current_pos)?;
238            }
239            else {
240                return seek_error(SeekErrorKind::ForwardOnly);
241            }
242        }
243
244        debug!("seeked to packet_ts={} (delta={})", actual_ts, actual_ts as i64 - ts as i64);
245
246        Ok(SeekedTo { track_id: 0, actual_ts, required_ts: ts })
247    }
248
249    fn into_inner(self: Box<Self>) -> MediaSourceStream {
250        self.reader
251    }
252}