]>
Commit | Line | Data |
---|---|---|
41a3a050 KS |
1 | use nihav_core::codecs::*; |
2 | use nihav_core::io::byteio::*; | |
3 | ||
4 | const fn chord_val(val: u8) -> u32 { | |
5 | (val as u32) * 0x7FFF / 247 | |
6 | } | |
7 | ||
8 | fn 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)] | |
19 | enum CodecType { | |
20 | S8, | |
21 | #[default] | |
22 | U8, | |
23 | S16, | |
24 | Logarithmic, | |
25 | } | |
26 | ||
27 | #[derive(Default)] | |
28 | struct RawDecoder { | |
29 | info: NACodecInfoRef, | |
30 | chmap: NAChannelMap, | |
31 | blk_size: usize, | |
32 | codec_type: CodecType, | |
33 | } | |
34 | ||
35 | impl RawDecoder { | |
36 | fn new() -> Self { Self::default() } | |
37 | } | |
38 | ||
39 | impl 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 | ||
148 | impl 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 | ||
154 | pub fn get_decoder() -> Box<dyn NADecoder + Send> { | |
155 | Box::new(RawDecoder::new()) | |
156 | } | |
157 | ||
158 | #[derive(Default)] | |
159 | struct RawPacketiser { | |
160 | stream: Option<NAStreamRef>, | |
161 | blk_size: usize, | |
162 | asize: u64, | |
163 | buf: Vec<u8>, | |
164 | } | |
165 | ||
166 | impl RawPacketiser { | |
167 | fn new() -> Self { Self::default() } | |
168 | } | |
169 | ||
170 | impl 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 | ||
217 | pub fn get_packetiser() -> Box<dyn NAPacketiser + Send> { | |
218 | Box::new(RawPacketiser::new()) | |
219 | } | |
220 | ||
221 | #[cfg(test)] | |
222 | mod 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 | } |