1use oxideav_codec::{CodecRegistry, Decoder, Encoder};
23use oxideav_core::{
24 AudioFrame, CodecCapabilities, CodecId, CodecParameters, Error, Frame, MediaType, Packet,
25 Result, SampleFormat, TimeBase,
26};
27
28pub fn register(reg: &mut CodecRegistry) {
29 for id in CODEC_IDS {
30 let cid = CodecId::new(*id);
31 let caps = CodecCapabilities::audio(format!("{id}_sw"))
32 .with_lossless(true)
33 .with_intra_only(true);
34 reg.register_both(cid, caps, make_decoder, make_encoder);
35 }
36 for id in SLIN_ALIASES {
37 let cid = CodecId::new(*id);
38 let caps = CodecCapabilities::audio(format!("{id}_sw"))
39 .with_lossless(true)
40 .with_intra_only(true);
41 reg.register_both(cid, caps, make_decoder, make_encoder);
44 }
45}
46
47const CODEC_IDS: &[&str] = &[
48 "pcm_u8",
49 "pcm_s8",
50 "pcm_s16le",
51 "pcm_s24le",
52 "pcm_s32le",
53 "pcm_f32le",
54 "pcm_f64le",
55];
56
57pub(crate) const SLIN_ALIASES: &[&str] = &[
60 "slin", "slin8", "slin16", "slin24", "slin32", "slin44", "slin48", "slin96", "slin192",
61];
62
63pub fn sample_format_for(id: &CodecId) -> Option<SampleFormat> {
68 let s = id.as_str();
69 Some(match s {
70 "pcm_u8" => SampleFormat::U8,
71 "pcm_s8" => SampleFormat::S8,
72 "pcm_s16le" => SampleFormat::S16,
73 "pcm_s24le" => SampleFormat::S24,
74 "pcm_s32le" => SampleFormat::S32,
75 "pcm_f32le" => SampleFormat::F32,
76 "pcm_f64le" => SampleFormat::F64,
77 _ if SLIN_ALIASES.contains(&s) => SampleFormat::S16,
78 _ => return None,
79 })
80}
81
82pub fn codec_id_for(fmt: SampleFormat) -> Option<CodecId> {
85 Some(CodecId::new(match fmt {
86 SampleFormat::U8 => "pcm_u8",
87 SampleFormat::S8 => "pcm_s8",
88 SampleFormat::S16 => "pcm_s16le",
89 SampleFormat::S24 => "pcm_s24le",
90 SampleFormat::S32 => "pcm_s32le",
91 SampleFormat::F32 => "pcm_f32le",
92 SampleFormat::F64 => "pcm_f64le",
93 _ => return None,
94 }))
95}
96
97fn make_decoder(params: &CodecParameters) -> Result<Box<dyn Decoder>> {
98 let format = sample_format_for(¶ms.codec_id)
99 .ok_or_else(|| Error::CodecNotFound(params.codec_id.to_string()))?;
100 let channels = params
101 .channels
102 .ok_or_else(|| Error::invalid("PCM decoder requires channels"))?;
103 let sample_rate = params
104 .sample_rate
105 .ok_or_else(|| Error::invalid("PCM decoder requires sample_rate"))?;
106 Ok(Box::new(PcmDecoder {
107 id: params.codec_id.clone(),
108 format,
109 channels,
110 sample_rate,
111 pending: None,
112 eof: false,
113 }))
114}
115
116fn make_encoder(params: &CodecParameters) -> Result<Box<dyn Encoder>> {
117 let format = sample_format_for(¶ms.codec_id)
118 .ok_or_else(|| Error::CodecNotFound(params.codec_id.to_string()))?;
119 let channels = params
120 .channels
121 .ok_or_else(|| Error::invalid("PCM encoder requires channels"))?;
122 let sample_rate = params
123 .sample_rate
124 .ok_or_else(|| Error::invalid("PCM encoder requires sample_rate"))?;
125 let mut output = params.clone();
126 output.media_type = MediaType::Audio;
127 output.sample_format = Some(format);
128 Ok(Box::new(PcmEncoder {
129 format,
130 channels,
131 sample_rate,
132 output,
133 queue: std::collections::VecDeque::new(),
134 }))
135}
136
137struct PcmDecoder {
138 id: CodecId,
139 format: SampleFormat,
140 channels: u16,
141 sample_rate: u32,
142 pending: Option<Packet>,
143 eof: bool,
144}
145
146impl Decoder for PcmDecoder {
147 fn codec_id(&self) -> &CodecId {
148 &self.id
149 }
150
151 fn send_packet(&mut self, packet: &Packet) -> Result<()> {
152 if self.pending.is_some() {
153 return Err(Error::other(
154 "PCM decoder already has a buffered packet; call receive_frame first",
155 ));
156 }
157 self.pending = Some(packet.clone());
158 Ok(())
159 }
160
161 fn receive_frame(&mut self) -> Result<Frame> {
162 let Some(pkt) = self.pending.take() else {
163 return if self.eof {
164 Err(Error::Eof)
165 } else {
166 Err(Error::NeedMore)
167 };
168 };
169 let bps = self.format.bytes_per_sample();
170 let block = bps * self.channels as usize;
171 if block == 0 || pkt.data.len() % block != 0 {
172 return Err(Error::invalid("PCM packet size not a multiple of block"));
173 }
174 let samples = (pkt.data.len() / block) as u32;
175 Ok(Frame::Audio(AudioFrame {
176 format: self.format,
177 channels: self.channels,
178 sample_rate: self.sample_rate,
179 samples,
180 pts: pkt.pts,
181 time_base: pkt.time_base,
182 data: vec![pkt.data],
183 }))
184 }
185
186 fn flush(&mut self) -> Result<()> {
187 self.eof = true;
188 Ok(())
189 }
190}
191
192struct PcmEncoder {
193 format: SampleFormat,
194 channels: u16,
195 sample_rate: u32,
196 output: CodecParameters,
197 queue: std::collections::VecDeque<Packet>,
198}
199
200impl Encoder for PcmEncoder {
201 fn codec_id(&self) -> &CodecId {
202 &self.output.codec_id
203 }
204
205 fn output_params(&self) -> &CodecParameters {
206 &self.output
207 }
208
209 fn send_frame(&mut self, frame: &Frame) -> Result<()> {
210 let Frame::Audio(a) = frame else {
211 return Err(Error::invalid("PCM encoder requires audio frames"));
212 };
213 if a.format != self.format
214 || a.channels != self.channels
215 || a.sample_rate != self.sample_rate
216 {
217 return Err(Error::invalid(
218 "PCM encoder frame parameters do not match encoder configuration",
219 ));
220 }
221 if a.format.is_planar() {
222 return Err(Error::unsupported(
223 "PCM encoder takes interleaved input; convert planar → interleaved first",
224 ));
225 }
226 let data = a
227 .data
228 .first()
229 .ok_or_else(|| Error::invalid("empty audio frame"))?
230 .clone();
231 let bps = a.format.bytes_per_sample() * a.channels as usize;
232 let expected = bps * a.samples as usize;
233 if data.len() != expected {
234 return Err(Error::invalid("audio frame data length mismatch"));
235 }
236 let mut pkt = Packet::new(0, a.time_base, data);
237 pkt.pts = a.pts;
238 pkt.dts = a.pts;
239 pkt.duration = Some(a.samples as i64);
240 pkt.flags.keyframe = true;
241 self.queue.push_back(pkt);
242 Ok(())
243 }
244
245 fn receive_packet(&mut self) -> Result<Packet> {
246 self.queue.pop_front().ok_or(Error::NeedMore)
247 }
248
249 fn flush(&mut self) -> Result<()> {
250 Ok(())
251 }
252}
253
254pub fn params(format: SampleFormat, channels: u16, sample_rate: u32) -> Result<CodecParameters> {
256 let codec_id = codec_id_for(format)
257 .ok_or_else(|| Error::unsupported(format!("no PCM codec for {:?}", format)))?;
258 let mut p = CodecParameters::audio(codec_id);
259 p.sample_format = Some(format);
260 p.channels = Some(channels);
261 p.sample_rate = Some(sample_rate);
262 p.bit_rate =
263 Some((format.bytes_per_sample() as u64) * 8 * (channels as u64) * (sample_rate as u64));
264 Ok(p)
265}
266
267pub fn time_base_for(sample_rate: u32) -> TimeBase {
269 TimeBase::new(1, sample_rate as i64)
270}