symphonia_format_riff/aiff/
mod.rs1use 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;
20
21use crate::common::{
22 append_data_params, append_format_params, next_packet, ByteOrder, ChunksReader, PacketInfo,
23};
24mod chunks;
25use chunks::*;
26
27const AIFF_STREAM_MARKER: [u8; 4] = *b"FORM";
29const AIFF_RIFF_FORM: [u8; 4] = *b"AIFF";
31const AIFC_RIFF_FORM: [u8; 4] = *b"AIFC";
33
34pub struct AiffReader {
38 reader: MediaSourceStream,
39 tracks: Vec<Track>,
40 cues: Vec<Cue>,
41 metadata: MetadataLog,
42 packet_info: PacketInfo,
43 data_start_pos: u64,
44 data_end_pos: u64,
45}
46
47impl QueryDescriptor for AiffReader {
48 fn query() -> &'static [Descriptor] {
49 &[
50 support_format!(
52 "riff",
53 " Resource Interchange File Format",
54 &["aiff", "aif", "aifc"],
55 &["audio/aiff", "audio/x-aiff", " sound/aiff", "audio/x-pn-aiff"],
56 &[b"FORM"]
57 ),
58 ]
59 }
60
61 fn score(_context: &[u8]) -> u8 {
62 255
63 }
64}
65
66impl FormatReader for AiffReader {
67 fn try_new(mut source: MediaSourceStream, _options: &FormatOptions) -> Result<Self> {
68 let marker = source.read_quad_bytes()?;
70 if marker != AIFF_STREAM_MARKER {
71 return unsupported_error("aiff: missing riff stream marker");
72 }
73
74 let riff_len = source.read_be_u32()?;
78 let riff_form = source.read_quad_bytes()?;
79
80 let mut riff_chunks = ChunksReader::<RiffAiffChunks>::new(riff_len, ByteOrder::BigEndian);
81
82 let mut codec_params = CodecParameters::new();
83 let metadata: MetadataLog = Default::default();
85 let mut packet_info = PacketInfo::without_blocks(0);
86
87 loop {
88 let chunk = riff_chunks.next(&mut source)?;
89
90 if chunk.is_none() {
94 return unsupported_error("aiff: missing sound chunk");
95 }
96
97 match chunk.unwrap() {
98 RiffAiffChunks::Common(common) => {
99 let common = match riff_form {
100 AIFF_RIFF_FORM => common.parse_aiff(&mut source)?,
101 AIFC_RIFF_FORM => common.parse_aifc(&mut source)?,
102 _ => return unsupported_error("aiff: riff form is not supported"),
103 };
104
105 packet_info = common.packet_info()?;
108 codec_params
109 .with_max_frames_per_packet(packet_info.get_max_frames_per_packet())
110 .with_frames_per_block(packet_info.frames_per_block);
111
112 append_format_params(
114 &mut codec_params,
115 &common.format_data,
116 common.sample_rate,
117 );
118 }
119 RiffAiffChunks::Sound(dat) => {
120 let data = dat.parse(&mut source)?;
121
122 let data_start_pos = source.pos();
124 let data_end_pos = data_start_pos + u64::from(data.len);
125
126 append_data_params(&mut codec_params, data.len as u64, &packet_info);
128
129 return Ok(AiffReader {
131 reader: source,
132 tracks: vec![Track::new(0, codec_params)],
133 cues: Vec::new(),
134 metadata,
135 packet_info,
136 data_start_pos,
137 data_end_pos,
138 });
139 }
140 }
141 }
142 }
143
144 fn next_packet(&mut self) -> Result<Packet> {
145 next_packet(
146 &mut self.reader,
147 &self.packet_info,
148 &self.tracks,
149 self.data_start_pos,
150 self.data_end_pos,
151 )
152 }
153
154 fn metadata(&mut self) -> Metadata<'_> {
155 self.metadata.metadata()
156 }
157
158 fn cues(&self) -> &[Cue] {
159 &self.cues
160 }
161
162 fn tracks(&self) -> &[Track] {
163 &self.tracks
164 }
165
166 fn seek(&mut self, _mode: SeekMode, to: SeekTo) -> Result<SeekedTo> {
167 if self.tracks.is_empty() || self.packet_info.is_empty() {
168 return seek_error(SeekErrorKind::Unseekable);
169 }
170
171 let params = &self.tracks[0].codec_params;
172
173 let ts = match to {
174 SeekTo::TimeStamp { ts, .. } => ts,
176 SeekTo::Time { time, .. } => {
178 if let Some(sample_rate) = params.sample_rate {
181 TimeBase::new(1, sample_rate).calc_timestamp(time)
182 }
183 else {
184 return seek_error(SeekErrorKind::Unseekable);
185 }
186 }
187 };
188
189 if let Some(n_frames) = params.n_frames {
192 if ts > n_frames {
193 return seek_error(SeekErrorKind::OutOfRange);
194 }
195 }
196
197 debug!("seeking to frame_ts={}", ts);
198
199 let actual_ts = self.packet_info.get_actual_ts(ts);
206
207 let seek_pos = self.data_start_pos + (actual_ts * self.packet_info.block_size);
209
210 if self.reader.is_seekable() {
213 self.reader.seek(SeekFrom::Start(seek_pos))?;
214 }
215 else {
218 let current_pos = self.reader.pos();
219 if seek_pos >= current_pos {
220 self.reader.ignore_bytes(seek_pos - current_pos)?;
221 }
222 else {
223 return seek_error(SeekErrorKind::ForwardOnly);
224 }
225 }
226
227 debug!("seeked to packet_ts={} (delta={})", actual_ts, actual_ts as i64 - ts as i64);
228
229 Ok(SeekedTo { track_id: 0, actual_ts, required_ts: ts })
230 }
231
232 fn into_inner(self: Box<Self>) -> MediaSourceStream {
233 self.reader
234 }
235}