add raw audio support in Acorn Replay Movie format
[nihav.git] / nihav-acorn / src / codecs / rawaudio.rs
CommitLineData
41a3a050
KS
1use nihav_core::codecs::*;
2use nihav_core::io::byteio::*;
3
4const fn chord_val(val: u8) -> u32 {
5 (val as u32) * 0x7FFF / 247
6}
7
8fn vidc_mu_law(val: u8) -> i16 {
9 const CHORDS: [u32; 9] = [chord_val(0), chord_val(1), chord_val(3), chord_val(7),
10 chord_val(15), chord_val(31), chord_val(63), chord_val(127), chord_val(247) ];
11
12 let chord = ((val >> 4) & 7) as usize;
13 let point = u32::from(val & 0xF);
14
15 (CHORDS[chord] + point * (CHORDS[chord + 1] - CHORDS[chord]) / 8) as i16
16}
17
18#[derive(Default,Debug,Clone,Copy,PartialEq)]
19enum CodecType {
20 S8,
21 #[default]
22 U8,
23 S16,
24 Logarithmic,
25}
26
27#[derive(Default)]
28struct RawDecoder {
29 info: NACodecInfoRef,
30 chmap: NAChannelMap,
31 blk_size: usize,
32 codec_type: CodecType,
33}
34
35impl RawDecoder {
36 fn new() -> Self { Self::default() }
37}
38
39impl NADecoder for RawDecoder {
40 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
41 if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() {
42 let channels = ainfo.channels;
43 let srate = ainfo.sample_rate;
44 let bits = ainfo.format.bits;
45 validate!(info.get_extradata().is_some());
46
47 if let Some(edata) = info.get_extradata() {
48 let mut is_vidc = false;
49 let mut is_unsigned = false;
50
51 for i in 0..edata.len() {
52 let head = &edata[i..];
53 if (head.len() >= 4 && &head[..4] == b"VIDC") || (head.len() >= 11 && &head[..11] == b"exponential") {
54 is_vidc = true;
55 break;
56 }
57 if head.len() >= 8 && (&head[..8] == b"unsigned" || &head[..8] == b"UNSIGNED") {
58 is_unsigned = true;
59 }
60 }
61 self.codec_type = if is_vidc {
62 CodecType::Logarithmic
63 } else if bits == 8 {
64 if is_unsigned {
65 CodecType::U8
66 } else {
67 CodecType::S8
68 }
69 } else {
70 CodecType::S16
71 };
72 } else {
73 return Err(DecoderError::InvalidData);
74 }
75
76 match channels {
77 1 => self.chmap.add_channel(NAChannelType::C),
78 2 => self.chmap.add_channels(&[NAChannelType::L, NAChannelType::R]),
79 _ => return Err(DecoderError::InvalidData),
80 }
81
82 self.blk_size = match self.codec_type {
83 CodecType::U8 | CodecType::S8 | CodecType::Logarithmic => channels as usize,
84 CodecType::S16 => channels as usize * 2,
85 };
86
87 let fmt = match self.codec_type {
88 CodecType::U8 | CodecType::S8 => SND_U8_FORMAT,
89 CodecType::S16 | CodecType::Logarithmic => SND_S16_FORMAT,
90 };
91
92 let myinfo = NACodecTypeInfo::Audio(NAAudioInfo::new(srate, channels, fmt, 0));
93 self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
94
95 Ok(())
96 } else {
97 Err(DecoderError::InvalidData)
98 }
99 }
100 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
101 let src = pkt.get_buffer();
102 validate!(!src.is_empty() && (src.len() % self.blk_size) == 0);
103
104 let bufinfo = alloc_audio_buffer(self.info.get_properties().get_audio_info().unwrap(), src.len() / self.blk_size, self.chmap.clone())?;
105 match self.codec_type {
106 CodecType::S8 => {
107 let mut buf = bufinfo.get_abuf_u8().unwrap();
108 let dst = buf.get_data_mut().unwrap();
109 for (dst, &src) in dst.iter_mut().zip(src.iter()) {
110 *dst = src ^ 0x80;
111 }
112 },
113 CodecType::U8 => {
114 let mut buf = bufinfo.get_abuf_u8().unwrap();
115 let dst = buf.get_data_mut().unwrap();
116 dst[..src.len()].copy_from_slice(&src);
117 },
118 CodecType::S16 => {
119 let mut buf = bufinfo.get_abuf_i16().unwrap();
120 let dst = buf.get_data_mut().unwrap();
121
122 for (dst, src) in dst.iter_mut().zip(src.chunks_exact(2)) {
123 *dst = read_u16le(src)? as i16;
124 }
125 },
126 CodecType::Logarithmic => {
127 let mut buf = bufinfo.get_abuf_i16().unwrap();
128 let dst = buf.get_data_mut().unwrap();
129
130 for (dst, &val) in dst.iter_mut().zip(src.iter()) {
131 let sign = (val & 0x01) != 0;
132 *dst = vidc_mu_law(val >> 1);
133 if sign {
134 *dst = -*dst;
135 }
136 }
137 },
138 }
139
140 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo);
141 frm.set_keyframe(true);
142 frm.set_frame_type(FrameType::I);
143 Ok(frm.into_ref())
144 }
145 fn flush(&mut self) {}
146}
147
148impl NAOptionHandler for RawDecoder {
149 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
150 fn set_options(&mut self, _options: &[NAOption]) { }
151 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
152}
153
154pub fn get_decoder() -> Box<dyn NADecoder + Send> {
155 Box::new(RawDecoder::new())
156}
157
158#[derive(Default)]
159struct RawPacketiser {
160 stream: Option<NAStreamRef>,
161 blk_size: usize,
162 asize: u64,
163 buf: Vec<u8>,
164}
165
166impl RawPacketiser {
167 fn new() -> Self { Self::default() }
168}
169
170impl NAPacketiser for RawPacketiser {
171 fn attach_stream(&mut self, stream: NAStreamRef) {
172 if let NACodecTypeInfo::Audio(ainfo) = stream.get_info().get_properties() {
173 self.blk_size = (ainfo.channels as usize) * (ainfo.format.bits as usize) / 8;
174 }
175 self.stream = Some(stream);
176 }
177 fn add_data(&mut self, src: &[u8]) -> bool {
178 self.buf.extend_from_slice(src);
179 self.buf.len() < (1 << 10)
180 }
181 fn parse_stream(&mut self, id: u32) -> DecoderResult<NAStreamRef> {
182 if let Some(ref stream) = self.stream {
183 let mut stream = NAStream::clone(stream);
184 stream.id = id;
185 Ok(stream.into_ref())
186 } else {
187 Err(DecoderError::MissingReference)
188 }
189 }
190 fn skip_junk(&mut self) -> DecoderResult<usize> {
191 Err(DecoderError::NotImplemented)
192 }
193 fn get_packet(&mut self, stream: NAStreamRef) -> DecoderResult<Option<NAPacket>> {
194 if self.blk_size == 0 {
195 return Err(DecoderError::MissingReference);
196 }
197
198 if self.buf.len() < 2 {
199 return Ok(None);
200 }
201
202 let data_len = self.buf.len();
203 let mut data = Vec::new();
204 std::mem::swap(&mut self.buf, &mut data);
205
206 let ts = NATimeInfo::new(Some(self.asize), None, None, stream.tb_num, stream.tb_den);
207 self.asize += (data_len / self.blk_size) as u64;
208
209 Ok(Some(NAPacket::new(stream, ts, true, data)))
210 }
211 fn reset(&mut self) {
212 self.buf.clear();
213 }
214 fn bytes_left(&self) -> usize { self.buf.len() }
215}
216
217pub fn get_packetiser() -> Box<dyn NAPacketiser + Send> {
218 Box::new(RawPacketiser::new())
219}
220
221#[cfg(test)]
222mod test {
223 use nihav_core::codecs::{RegisteredDecoders, RegisteredPacketisers};
224 use nihav_core::demuxers::RegisteredRawDemuxers;
225 use nihav_codec_support::test::dec_video::*;
226 use crate::*;
227
228 #[test]
229 fn test_format_s8() {
230 let mut dmx_reg = RegisteredRawDemuxers::new();
231 acorn_register_all_raw_demuxers(&mut dmx_reg);
232 let mut pkt_reg = RegisteredPacketisers::new();
233 acorn_register_all_packetisers(&mut pkt_reg);
234 let mut dec_reg = RegisteredDecoders::new();
235 acorn_register_all_decoders(&mut dec_reg);
236
237 // a sample from Acorn Replay Demonstration Disc 2
238 test_decoding_raw("armovie", "arm_rawaudio", "assets/Acorn/CHEMSET2", Some(1),
239 &dmx_reg, &pkt_reg, &dec_reg,
240 ExpectedTestResult::MD5([0x167985bf, 0xd82c3fb0, 0x125ff24e, 0xa7408c57]));
241 }
242
243 #[test]
244 fn test_format_u8() {
245 let mut dmx_reg = RegisteredRawDemuxers::new();
246 acorn_register_all_raw_demuxers(&mut dmx_reg);
247 let mut pkt_reg = RegisteredPacketisers::new();
248 acorn_register_all_packetisers(&mut pkt_reg);
249 let mut dec_reg = RegisteredDecoders::new();
250 acorn_register_all_decoders(&mut dec_reg);
251
252 // a sample from Cine Clips by Oregan Software Developments
253 test_decoding_raw("armovie", "arm_rawaudio", "assets/Acorn/COLOURPLUS", Some(1),
254 &dmx_reg, &pkt_reg, &dec_reg,
255 ExpectedTestResult::MD5([0x2f0dc76b, 0x208372ad, 0xa986fb0b, 0x1024dcc8]));
256 }
257
258 #[test]
259 fn test_format_vidc() {
260 let mut dmx_reg = RegisteredRawDemuxers::new();
261 acorn_register_all_raw_demuxers(&mut dmx_reg);
262 let mut pkt_reg = RegisteredPacketisers::new();
263 acorn_register_all_packetisers(&mut pkt_reg);
264 let mut dec_reg = RegisteredDecoders::new();
265 acorn_register_all_decoders(&mut dec_reg);
266
267 // a sample from Cine Clips by Oregan Software Developments
268 test_decoding_raw("armovie", "arm_rawaudio", "assets/Acorn/CFC2", Some(1),
269 &dmx_reg, &pkt_reg, &dec_reg,
270 ExpectedTestResult::MD5([0x3c2a6e48, 0x6e511c72, 0xd30b5813, 0x42d98a71]));
271 }
272
273 #[test]
274 fn test_format_s16() {
275 let mut dmx_reg = RegisteredRawDemuxers::new();
276 acorn_register_all_raw_demuxers(&mut dmx_reg);
277 let mut pkt_reg = RegisteredPacketisers::new();
278 acorn_register_all_packetisers(&mut pkt_reg);
279 let mut dec_reg = RegisteredDecoders::new();
280 acorn_register_all_decoders(&mut dec_reg);
281
282 // a sample from Cine Clips by Oregan Software Developments
283 test_decoding_raw("armovie", "arm_rawaudio", "assets/Acorn/SKYHIGH", Some(1),
284 &dmx_reg, &pkt_reg, &dec_reg,
285 ExpectedTestResult::MD5([0xd2003a1c, 0xfe38974f, 0xa1850a5b, 0xb4313217]));
286 }
287}