songbird/input/codecs/
raw.rs1use std::io::{Seek, SeekFrom};
2use symphonia::core::{
3 audio::Channels,
4 codecs::{CodecParameters, CODEC_TYPE_PCM_F32LE},
5 errors::{self as symph_err, Result as SymphResult, SeekErrorKind},
6 formats::prelude::*,
7 io::{MediaSource, MediaSourceStream, ReadBytes, SeekBuffered},
8 meta::{Metadata as SymphMetadata, MetadataLog},
9 probe::{Descriptor, Instantiate, QueryDescriptor},
10};
11
12impl QueryDescriptor for RawReader {
13 fn query() -> &'static [Descriptor] {
14 &[symphonia_core::support_format!(
15 "raw",
16 "Raw arbitrary-length f32 audio container.",
17 &["rawf32"],
18 &[],
19 &[b"SbirdRaw"]
20 )]
21 }
22
23 fn score(_context: &[u8]) -> u8 {
24 255
25 }
26}
27
28pub struct RawReader {
37 source: MediaSourceStream,
38 track: Track,
39 meta: MetadataLog,
40 curr_ts: TimeStamp,
41 max_ts: Option<TimeStamp>,
42}
43
44impl FormatReader for RawReader {
45 fn try_new(mut source: MediaSourceStream, _options: &FormatOptions) -> SymphResult<Self> {
46 let mut magic = [0u8; 8];
47 ReadBytes::read_buf_exact(&mut source, &mut magic[..])?;
48
49 if &magic != b"SbirdRaw" {
50 source.seek_buffered_rel(-(magic.len() as isize));
51 return symph_err::decode_error("rawf32: illegal magic byte sequence.");
52 }
53
54 let sample_rate = source.read_u32()?;
55 let n_chans = source.read_u32()?;
56
57 let chans = match n_chans {
58 1 => Channels::FRONT_LEFT,
59 2 => Channels::FRONT_LEFT | Channels::FRONT_RIGHT,
60 _ =>
61 return symph_err::decode_error(
62 "rawf32: channel layout is not stereo or mono for fmt_pcm",
63 ),
64 };
65
66 let mut codec_params = CodecParameters::new();
67
68 codec_params
69 .for_codec(CODEC_TYPE_PCM_F32LE)
70 .with_bits_per_coded_sample((std::mem::size_of::<f32>() as u32) * 8)
71 .with_bits_per_sample((std::mem::size_of::<f32>() as u32) * 8)
72 .with_sample_rate(sample_rate)
73 .with_time_base(TimeBase::new(1, sample_rate))
74 .with_sample_format(symphonia_core::sample::SampleFormat::F32)
75 .with_max_frames_per_packet(sample_rate as u64 / 50)
76 .with_channels(chans);
77
78 Ok(Self {
79 source,
80 track: Track {
81 id: 0,
82 language: None,
83 codec_params,
84 },
85 meta: MetadataLog::default(),
86 curr_ts: 0,
87 max_ts: None,
88 })
89 }
90
91 fn cues(&self) -> &[Cue] {
92 &[]
93 }
94
95 fn metadata(&mut self) -> SymphMetadata<'_> {
96 self.meta.metadata()
97 }
98
99 fn seek(&mut self, _mode: SeekMode, to: SeekTo) -> SymphResult<SeekedTo> {
100 let can_backseek = self.source.is_seekable();
101
102 let track = &self.track;
103 let rate = track.codec_params.sample_rate;
104 let ts = match to {
105 SeekTo::Time { time, .. } =>
106 if let Some(rate) = rate {
107 TimeBase::new(1, rate).calc_timestamp(time)
108 } else {
109 return symph_err::seek_error(SeekErrorKind::Unseekable);
110 },
111 SeekTo::TimeStamp { ts, .. } => ts,
112 };
113
114 if let Some(max_ts) = self.max_ts {
115 if ts > max_ts {
116 return symph_err::seek_error(SeekErrorKind::OutOfRange);
117 }
118 }
119
120 let backseek_needed = self.curr_ts > ts;
121
122 if backseek_needed && !can_backseek {
123 return symph_err::seek_error(SeekErrorKind::ForwardOnly);
124 }
125
126 let chan_count = track
127 .codec_params
128 .channels
129 .expect("Channel count is built into format.")
130 .count() as u64;
131
132 let seek_pos = 16 + (std::mem::size_of::<f32>() as u64) * (ts * chan_count);
133
134 self.source.seek(SeekFrom::Start(seek_pos))?;
135 self.curr_ts = ts;
136
137 Ok(SeekedTo {
138 track_id: track.id,
139 required_ts: ts,
140 actual_ts: ts,
141 })
142 }
143
144 fn tracks(&self) -> &[Track] {
145 std::slice::from_ref(&self.track)
146 }
147
148 fn default_track(&self) -> Option<&Track> {
149 Some(&self.track)
150 }
151
152 fn next_packet(&mut self) -> SymphResult<Packet> {
153 let track = &self.track;
154 let rate = track
155 .codec_params
156 .sample_rate
157 .expect("Sample rate is built into format.") as usize;
158
159 let chan_count = track
160 .codec_params
161 .channels
162 .expect("Channel count is built into format.")
163 .count();
164
165 let sample_unit = std::mem::size_of::<f32>() * chan_count;
166
167 let buf = self.source.read_boxed_slice((rate / 50) * sample_unit)?;
169
170 let sample_ct = (buf.len() / sample_unit) as u64;
171 let out = Packet::new_from_boxed_slice(0, self.curr_ts, sample_ct, buf);
172
173 self.curr_ts += sample_ct;
174
175 Ok(out)
176 }
177
178 fn into_inner(self: Box<Self>) -> MediaSourceStream {
179 self.source
180 }
181}