]>
Commit | Line | Data |
---|---|---|
606c448e KS |
1 | use nihav_core::codecs::*; |
2 | use nihav_core::io::byteio::*; | |
3 | use nihav_core::io::bitreader::*; | |
4 | use nihav_core::io::codebook::*; | |
5 | use std::str::FromStr; | |
6 | ||
7 | const PAL_SIZE: usize = 768; | |
8 | const SMK_FLAG_INTERLACED: u32 = 0x02; | |
9 | const SMK_FLAG_SCALED: u32 = 0x04; | |
10 | ||
11 | struct SmackerTree8 { | |
12 | cb: Option<Codebook<u8>>, | |
13 | defsym: u8, | |
14 | } | |
15 | ||
16 | fn get_tree8(br: &mut BitReader, bits: &mut [u8; 256], codes: &mut [u32; 256], syms: &mut [u8; 256], count: &mut usize, len: u8, prefix: u32) -> DecoderResult<()> { | |
17 | if !br.read_bool()? { | |
18 | bits[*count] = len; | |
19 | codes[*count] = prefix; | |
20 | syms[*count] = br.read(8)? as u8; | |
21 | *count += 1; | |
22 | } else { | |
23 | validate!((*count <= 256 - 2) && (len <= 31)); | |
24 | get_tree8(br, bits, codes, syms, count, len + 1, prefix)?; | |
25 | get_tree8(br, bits, codes, syms, count, len + 1, prefix | (1 << len))?; | |
26 | } | |
27 | Ok(()) | |
28 | } | |
29 | ||
30 | pub struct FullTableCodebookDescReader<'a> { | |
31 | bits: &'a [u8], | |
32 | codes: &'a [u32], | |
33 | syms: &'a [u8], | |
34 | } | |
35 | ||
36 | impl<'a> FullTableCodebookDescReader<'a> { | |
37 | pub fn new(codes: &'a [u32], bits: &'a [u8], syms: &'a [u8]) -> Self { | |
38 | Self { bits, codes, syms } | |
39 | } | |
40 | } | |
41 | impl<'a> CodebookDescReader<u8> for FullTableCodebookDescReader<'a> | |
42 | { | |
43 | fn bits(&mut self, idx: usize) -> u8 { self.bits[idx] } | |
44 | fn code(&mut self, idx: usize) -> u32 { self.codes[idx] } | |
45 | fn sym (&mut self, idx: usize) -> u8 { self.syms[idx] } | |
46 | fn len(&mut self) -> usize { self.bits.len() } | |
47 | } | |
48 | ||
49 | impl SmackerTree8 { | |
50 | fn new() -> Self { | |
51 | Self { | |
52 | cb: None, | |
53 | defsym: 0, | |
54 | } | |
55 | } | |
56 | fn decode(&mut self, br: &mut BitReader) -> DecoderResult<()> { | |
57 | if !br.read_bool()? { return Ok(()); } | |
58 | ||
59 | let mut bits: [u8; 256] = [0; 256]; | |
60 | let mut codes: [u32; 256] = [0; 256]; | |
61 | let mut syms: [u8; 256] = [0; 256]; | |
62 | let mut count = 0; | |
63 | ||
64 | get_tree8(br, &mut bits, &mut codes, &mut syms, &mut count, 0, 0)?; | |
65 | validate!(!br.read_bool()?); | |
66 | ||
67 | if count > 1 { | |
68 | let mut cr = FullTableCodebookDescReader::new(&codes[0..count], &bits[0..count], &syms[0..count]); | |
69 | let cb = Codebook::new(&mut cr, CodebookMode::LSB)?; | |
70 | self.cb = Some(cb); | |
71 | } else { | |
72 | self.defsym = syms[0]; | |
73 | } | |
74 | ||
75 | Ok(()) | |
76 | } | |
77 | } | |
78 | ||
79 | struct SmackerTree16 { | |
80 | tree: Vec<u32>, | |
81 | last: [usize; 3], | |
82 | } | |
83 | ||
84 | struct SmackerTree16Builder { | |
85 | tree_lo: SmackerTree8, | |
86 | tree_hi: SmackerTree8, | |
87 | nsyms: usize, | |
88 | esc: [u32; 3], | |
89 | } | |
90 | ||
91 | const SMK_BIGTREE_NODE: u32 = 0x80000000; | |
92 | const SMK_LAST_UNINIT: usize = 0xFFFFFFFF; | |
93 | ||
94 | impl SmackerTree16Builder { | |
95 | fn get_tree16(&mut self, br: &mut BitReader, tree: &mut SmackerTree16, depth: usize) -> DecoderResult<u32> { | |
96 | validate!(tree.tree.len() < self.nsyms); | |
2c031ed0 | 97 | validate!(depth <= 32); |
606c448e KS |
98 | if !br.read_bool()? { |
99 | let lo = br.read_tree8(&self.tree_lo)?; | |
100 | let hi = br.read_tree8(&self.tree_hi)?; | |
101 | let mut sym = (((hi as u16) << 8) | (lo as u16)) as u32; | |
102 | if sym == self.esc[0] { | |
103 | tree.last[0] = tree.tree.len(); | |
104 | sym = 0; | |
105 | } else if sym == self.esc[1] { | |
106 | tree.last[1] = tree.tree.len(); | |
107 | sym = 0; | |
108 | } else if sym == self.esc[2] { | |
109 | tree.last[2] = tree.tree.len(); | |
110 | sym = 0; | |
111 | } | |
112 | tree.tree.push(sym); | |
113 | Ok(1) | |
114 | } else { | |
115 | let cur_idx = tree.tree.len(); | |
116 | tree.tree.push(0); | |
117 | let lcount = self.get_tree16(br, tree, depth + 1)?; | |
118 | let rcount = self.get_tree16(br, tree, depth + 1)?; | |
119 | tree.tree[cur_idx] = SMK_BIGTREE_NODE | lcount; | |
120 | Ok(lcount + rcount + 1) | |
121 | } | |
122 | } | |
123 | } | |
124 | ||
125 | impl SmackerTree16 { | |
126 | fn new() -> Self { | |
127 | Self { | |
128 | tree: Vec::new(), | |
129 | last: [SMK_LAST_UNINIT; 3], | |
130 | } | |
131 | } | |
132 | fn decode(&mut self, br: &mut BitReader, size: u32) -> DecoderResult<()> { | |
133 | if !br.read_bool()? { return Ok(()); } | |
134 | ||
135 | let mut tree_lo = SmackerTree8::new(); | |
136 | tree_lo.decode(br)?; | |
137 | let mut tree_hi = SmackerTree8::new(); | |
138 | tree_hi.decode(br)?; | |
139 | ||
140 | let mut esc: [u32; 3] = [0; 3]; | |
3687b8b3 KS |
141 | for esc in esc.iter_mut() { |
142 | *esc = br.read(16)?; | |
606c448e KS |
143 | } |
144 | ||
145 | let nsyms = (((size + 3) >> 2) + 4) as usize; | |
146 | self.tree = Vec::with_capacity(nsyms); | |
147 | ||
148 | let mut tb = SmackerTree16Builder { tree_lo, tree_hi, nsyms, esc }; | |
149 | ||
150 | tb.get_tree16(br, self, 0)?; | |
151 | validate!(!br.read_bool()?); | |
152 | ||
153 | for i in 0..self.last.len() { | |
154 | if self.last[i] == SMK_LAST_UNINIT { | |
155 | self.last[i] = self.tree.len(); | |
156 | self.tree.push(0); | |
157 | } | |
158 | } | |
159 | validate!(self.tree.len() <= nsyms); | |
160 | Ok(()) | |
161 | } | |
162 | fn reset(&mut self) { | |
163 | for i in 0..self.last.len() { | |
af37e28a KS |
164 | if self.last[i] != SMK_LAST_UNINIT { |
165 | self.tree[self.last[i]] = 0; | |
166 | } | |
606c448e KS |
167 | } |
168 | } | |
169 | } | |
170 | ||
171 | trait ReadTree { | |
172 | fn read_tree8(&mut self, tree: &SmackerTree8) -> DecoderResult<u8>; | |
173 | fn read_bigtree(&mut self, tree: &mut SmackerTree16) -> DecoderResult<u16>; | |
174 | } | |
175 | ||
176 | impl<'a> ReadTree for BitReader<'a> { | |
177 | fn read_tree8(&mut self, tree: &SmackerTree8) -> DecoderResult<u8> { | |
178 | if let Some(ref cb) = tree.cb { | |
179 | Ok(self.read_cb(cb)?) | |
180 | } else { | |
181 | Ok(tree.defsym) | |
182 | } | |
183 | } | |
184 | fn read_bigtree(&mut self, tree: &mut SmackerTree16) -> DecoderResult<u16> { | |
185 | let mut pos = 0; | |
186 | while (tree.tree[pos] & SMK_BIGTREE_NODE) != 0 { | |
187 | if self.read_bool()? { | |
188 | pos += (tree.tree[pos] & !SMK_BIGTREE_NODE) as usize; | |
189 | } | |
190 | pos += 1; | |
191 | } | |
192 | let val = tree.tree[pos]; | |
193 | if val != tree.tree[tree.last[0]] { | |
194 | tree.tree[tree.last[2]] = tree.tree[tree.last[1]]; | |
195 | tree.tree[tree.last[1]] = tree.tree[tree.last[0]]; | |
196 | tree.tree[tree.last[0]] = val; | |
197 | } | |
198 | Ok(val as u16) | |
199 | } | |
200 | } | |
201 | ||
202 | const SMK_BLOCK_RUNS: [usize; 64] = [ | |
203 | 1, 2, 3, 4, 5, 6, 7, 8, | |
204 | 9, 10, 11, 12, 13, 14, 15, 16, | |
205 | 17, 18, 19, 20, 21, 22, 23, 24, | |
206 | 25, 26, 27, 28, 29, 30, 31, 32, | |
207 | 33, 34, 35, 36, 37, 38, 39, 40, | |
208 | 41, 42, 43, 44, 45, 46, 47, 48, | |
209 | 49, 50, 51, 52, 53, 54, 55, 56, | |
210 | 57, 58, 59, 128, 256, 512, 1024, 2048 | |
211 | ]; | |
212 | ||
213 | struct SmackerVideoDecoder { | |
2422d969 | 214 | info: NACodecInfoRef, |
606c448e KS |
215 | mmap_tree: SmackerTree16, |
216 | mclr_tree: SmackerTree16, | |
217 | full_tree: SmackerTree16, | |
218 | type_tree: SmackerTree16, | |
219 | w: usize, | |
220 | h: usize, | |
221 | bw: usize, | |
222 | bh: usize, | |
223 | is_ver4: bool, | |
224 | flags: u32, | |
225 | frame: Vec<u8>, | |
226 | stride: usize, | |
227 | } | |
228 | ||
229 | impl SmackerVideoDecoder { | |
230 | fn new() -> Self { | |
606c448e | 231 | Self { |
2422d969 | 232 | info: NACodecInfoRef::default(), |
606c448e KS |
233 | mmap_tree: SmackerTree16::new(), |
234 | mclr_tree: SmackerTree16::new(), | |
235 | full_tree: SmackerTree16::new(), | |
236 | type_tree: SmackerTree16::new(), | |
237 | w: 0, | |
238 | h: 0, | |
239 | bw: 0, | |
240 | bh: 0, | |
241 | is_ver4: false, | |
242 | flags: 0, | |
243 | frame: Vec::new(), | |
244 | stride: 0, | |
245 | } | |
246 | } | |
247 | fn block_pos(&self, blk_no: usize) -> usize { | |
248 | let bx = blk_no % self.bw; | |
249 | let by = blk_no / self.bw; | |
250 | bx * 4 + by * 4 * self.stride | |
251 | } | |
3687b8b3 | 252 | #[allow(clippy::identity_op)] |
606c448e KS |
253 | fn decode_frame(&mut self, br: &mut BitReader) -> DecoderResult<bool> { |
254 | let mut is_intra = true; | |
255 | let blocks = self.bw * self.bh; | |
256 | ||
257 | self.mmap_tree.reset(); | |
258 | self.mclr_tree.reset(); | |
259 | self.full_tree.reset(); | |
260 | self.type_tree.reset(); | |
261 | ||
262 | let mut block = 0; | |
263 | while block < blocks { | |
264 | let btype = br.read_bigtree(&mut self.type_tree)?; | |
265 | let run = SMK_BLOCK_RUNS[((btype as usize) >> 2) & 0x3F]; | |
266 | validate!(run <= blocks - block); | |
267 | match btype & 3 { | |
268 | 0 => { // two-colour pattern | |
269 | for i in 0..run { | |
270 | let clr = br.read_bigtree(&mut self.mclr_tree)?; | |
271 | let mut map = br.read_bigtree(&mut self.mmap_tree)?; | |
272 | let hi = (clr >> 8) as u8; | |
273 | let lo = (clr & 0xFF) as u8; | |
274 | let mut doff = self.block_pos(block + i); | |
275 | for _ in 0..4 { | |
276 | self.frame[doff + 0] = if (map & 1) != 0 { hi } else { lo }; | |
277 | self.frame[doff + 1] = if (map & 2) != 0 { hi } else { lo }; | |
278 | self.frame[doff + 2] = if (map & 4) != 0 { hi } else { lo }; | |
279 | self.frame[doff + 3] = if (map & 8) != 0 { hi } else { lo }; | |
280 | map >>= 4; | |
281 | doff += self.stride; | |
282 | } | |
283 | } | |
284 | }, | |
285 | 1 => { // full | |
45a8b7a2 | 286 | let mode = if !self.is_ver4 { |
3687b8b3 | 287 | 0 |
45a8b7a2 KS |
288 | } else if br.read_bool()? { |
289 | 1 | |
290 | } else if br.read_bool()? { | |
291 | 2 | |
3687b8b3 | 292 | } else { |
45a8b7a2 | 293 | 0 |
3687b8b3 | 294 | }; |
606c448e KS |
295 | for i in 0..run { |
296 | let mut doff = self.block_pos(block + i); | |
297 | match mode { | |
298 | 0 => { | |
299 | for _ in 0..4 { | |
300 | let clr0 = br.read_bigtree(&mut self.full_tree)?; | |
301 | let clr1 = br.read_bigtree(&mut self.full_tree)?; | |
302 | self.frame[doff + 0] = (clr1 & 0xFF) as u8; | |
303 | self.frame[doff + 1] = (clr1 >> 8) as u8; | |
304 | self.frame[doff + 2] = (clr0 & 0xFF) as u8; | |
305 | self.frame[doff + 3] = (clr0 >> 8) as u8; | |
306 | doff += self.stride; | |
307 | } | |
308 | }, | |
309 | 1 => { | |
310 | for _ in 0..2 { | |
311 | let clr = br.read_bigtree(&mut self.full_tree)?; | |
312 | self.frame[doff + 0] = (clr & 0xFF) as u8; | |
313 | self.frame[doff + 1] = (clr & 0xFF) as u8; | |
314 | self.frame[doff + 2] = (clr >> 8) as u8; | |
315 | self.frame[doff + 3] = (clr >> 8) as u8; | |
316 | doff += self.stride; | |
317 | self.frame[doff + 0] = (clr & 0xFF) as u8; | |
318 | self.frame[doff + 1] = (clr & 0xFF) as u8; | |
319 | self.frame[doff + 2] = (clr >> 8) as u8; | |
320 | self.frame[doff + 3] = (clr >> 8) as u8; | |
321 | doff += self.stride; | |
322 | } | |
323 | }, | |
324 | 2 => { | |
325 | for _ in 0..2 { | |
326 | let clr0 = br.read_bigtree(&mut self.full_tree)?; | |
327 | let clr1 = br.read_bigtree(&mut self.full_tree)?; | |
328 | self.frame[doff + 0] = (clr1 & 0xFF) as u8; | |
329 | self.frame[doff + 1] = (clr1 >> 8) as u8; | |
330 | self.frame[doff + 2] = (clr0 & 0xFF) as u8; | |
331 | self.frame[doff + 3] = (clr0 >> 8) as u8; | |
332 | doff += self.stride; | |
333 | self.frame[doff + 0] = (clr1 & 0xFF) as u8; | |
334 | self.frame[doff + 1] = (clr1 >> 8) as u8; | |
335 | self.frame[doff + 2] = (clr0 & 0xFF) as u8; | |
336 | self.frame[doff + 3] = (clr0 >> 8) as u8; | |
337 | doff += self.stride; | |
338 | } | |
339 | }, | |
340 | _ => unreachable!(), | |
341 | }; | |
342 | } | |
343 | }, | |
344 | 2 => { // skip | |
345 | is_intra = false; | |
346 | }, | |
347 | 3 => { // fill | |
348 | let clr = (btype >> 8) as u8; | |
349 | for i in 0..run { | |
350 | let mut doff = self.block_pos(block + i); | |
351 | for _ in 0..4 { | |
352 | self.frame[doff + 0] = clr; | |
353 | self.frame[doff + 1] = clr; | |
354 | self.frame[doff + 2] = clr; | |
355 | self.frame[doff + 3] = clr; | |
356 | doff += self.stride; | |
357 | } | |
358 | } | |
359 | }, | |
360 | _ => unreachable!(), | |
361 | }; | |
362 | block += run; | |
363 | } | |
364 | Ok(is_intra) | |
365 | } | |
366 | fn output_frame(&self, buf: &mut NAVideoBuffer<u8>) { | |
367 | let stride = buf.get_stride(0); | |
1a967e6b | 368 | let data = buf.get_data_mut().unwrap(); |
606c448e KS |
369 | let dst = data.as_mut_slice(); |
370 | let is_scaled = (self.flags & SMK_FLAG_SCALED) != 0; | |
371 | let is_interlaced = (self.flags & SMK_FLAG_INTERLACED) != 0; | |
372 | let mut didx = 0; | |
373 | let mut sidx = 0; | |
374 | for _ in 0..self.h { | |
bf109afe | 375 | dst[didx..][..self.w].copy_from_slice(&self.frame[sidx..][..self.w]); |
606c448e KS |
376 | sidx += self.stride; |
377 | didx += stride; | |
378 | if is_scaled { | |
379 | for x in 0..self.w { dst[didx + x] = dst[didx - stride + x]; } | |
380 | didx += stride; | |
381 | } | |
382 | if is_interlaced { | |
383 | for x in 0..self.w { dst[didx + x] = 0; } | |
384 | didx += stride; | |
385 | if is_scaled { | |
386 | for x in 0..self.w { dst[didx + x] = 0; } | |
387 | didx += stride; | |
388 | } | |
389 | } | |
390 | } | |
391 | } | |
392 | } | |
393 | ||
394 | impl NADecoder for SmackerVideoDecoder { | |
01613464 | 395 | fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { |
606c448e KS |
396 | if let NACodecTypeInfo::Video(vinfo) = info.get_properties() { |
397 | let w = vinfo.get_width(); | |
398 | let h = vinfo.get_height(); | |
399 | let fmt = PAL8_FORMAT; | |
400 | ||
401 | self.w = w; | |
402 | self.h = h; | |
403 | self.bw = w >> 2; | |
404 | self.bh = h >> 2; | |
405 | let edata = info.get_extradata().unwrap(); | |
406 | validate!(edata.len() > 24); | |
407 | ||
408 | self.stride = w; | |
409 | self.frame.resize(w * h, 0); | |
410 | ||
411 | let mut mr = MemoryReader::new_read(&edata); | |
412 | let mut br = ByteReader::new(&mut mr); | |
45a8b7a2 | 413 | let magic = br.read_tag()?; |
606c448e KS |
414 | self.flags = br.read_u32le()?; |
415 | let mmap_size = br.read_u32le()?; | |
416 | let mclr_size = br.read_u32le()?; | |
417 | let full_size = br.read_u32le()?; | |
418 | let type_size = br.read_u32le()?; | |
419 | ||
45a8b7a2 | 420 | self.is_ver4 = &magic == b"SMK4"; |
fa90ccfb | 421 | let mut br = BitReader::new(&edata[24..], BitReaderMode::LE); |
606c448e KS |
422 | self.mmap_tree.decode(&mut br, mmap_size)?; |
423 | self.mclr_tree.decode(&mut br, mclr_size)?; | |
424 | self.full_tree.decode(&mut br, full_size)?; | |
425 | self.type_tree.decode(&mut br, type_size)?; | |
426 | ||
427 | let mut out_h = h; | |
428 | if (self.flags & SMK_FLAG_INTERLACED) != 0 { | |
429 | out_h <<= 1; | |
430 | } | |
431 | if (self.flags & SMK_FLAG_SCALED) != 0 { | |
432 | out_h <<= 1; | |
433 | } | |
434 | let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(w, out_h, false, fmt)); | |
2422d969 | 435 | self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref(); |
606c448e KS |
436 | |
437 | Ok(()) | |
438 | } else { | |
439 | Err(DecoderError::InvalidData) | |
440 | } | |
441 | } | |
01613464 | 442 | fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { |
606c448e KS |
443 | let src = pkt.get_buffer(); |
444 | validate!(src.len() >= PAL_SIZE); | |
445 | ||
446 | let is_intra; | |
447 | let ftype; | |
b70cc006 | 448 | let bufinfo; |
606c448e | 449 | if src.len() > PAL_SIZE { |
fa90ccfb | 450 | let mut br = BitReader::new(&src[PAL_SIZE..], BitReaderMode::LE); |
606c448e | 451 | |
7e6086e5 | 452 | bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 2)?; |
606c448e KS |
453 | let mut buf = bufinfo.get_vbuf().unwrap(); |
454 | is_intra = self.decode_frame(&mut br)?; | |
455 | self.output_frame(&mut buf); | |
456 | let paloff = buf.get_offset(1); | |
1a967e6b | 457 | let data = buf.get_data_mut().unwrap(); |
606c448e KS |
458 | let dst = data.as_mut_slice(); |
459 | let palout = &mut dst[paloff..][..PAL_SIZE]; | |
460 | palout.copy_from_slice(&src[0..PAL_SIZE]); | |
461 | ftype = if is_intra { FrameType::I } else { FrameType::P }; | |
462 | } else { | |
463 | bufinfo = NABufferType::None; | |
464 | ftype = FrameType::Skip; | |
465 | is_intra = false; | |
466 | } | |
467 | ||
468 | let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo); | |
469 | frm.set_keyframe(is_intra); | |
470 | frm.set_frame_type(ftype); | |
171860fc | 471 | Ok(frm.into_ref()) |
606c448e | 472 | } |
f9be4e75 KS |
473 | fn flush(&mut self) { |
474 | } | |
606c448e KS |
475 | } |
476 | ||
7d57ae2f KS |
477 | impl NAOptionHandler for SmackerVideoDecoder { |
478 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
479 | fn set_options(&mut self, _options: &[NAOption]) { } | |
480 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
481 | } | |
482 | ||
08a1fab7 | 483 | pub fn get_decoder_video() -> Box<dyn NADecoder + Send> { |
606c448e KS |
484 | Box::new(SmackerVideoDecoder::new()) |
485 | } | |
486 | ||
487 | struct SmackerAudioDecoder { | |
488 | ainfo: NAAudioInfo, | |
489 | chmap: NAChannelMap, | |
490 | chans: usize, | |
491 | bits: u8, | |
492 | } | |
493 | ||
494 | impl SmackerAudioDecoder { | |
495 | fn new() -> Self { | |
496 | Self { | |
497 | ainfo: NAAudioInfo::new(0, 1, SND_S16P_FORMAT, 0), | |
498 | chmap: NAChannelMap::new(), | |
499 | chans: 0, | |
500 | bits: 0, | |
501 | } | |
502 | } | |
503 | } | |
504 | ||
505 | impl NADecoder for SmackerAudioDecoder { | |
01613464 | 506 | fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { |
606c448e KS |
507 | if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() { |
508 | self.bits = ainfo.get_format().get_bits(); | |
70e792a8 | 509 | let fmt = if self.bits == 8 { SND_U8_FORMAT } else { SND_S16_FORMAT }; |
606c448e KS |
510 | self.chans = ainfo.get_channels() as usize; |
511 | self.ainfo = NAAudioInfo::new(ainfo.get_sample_rate(), ainfo.get_channels(), fmt, 0); | |
512 | self.chmap = NAChannelMap::from_str(if ainfo.get_channels() == 2 {"L,R"} else {"C"}).unwrap(); | |
513 | Ok(()) | |
514 | } else { | |
515 | Err(DecoderError::InvalidData) | |
516 | } | |
517 | } | |
3687b8b3 | 518 | #[allow(clippy::identity_op)] |
01613464 | 519 | fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { |
606c448e KS |
520 | let info = pkt.get_stream().get_info(); |
521 | if let NACodecTypeInfo::Audio(_) = info.get_properties() { | |
522 | let src = pkt.get_buffer(); | |
523 | validate!(src.len() > 4); | |
fa90ccfb | 524 | let mut br = BitReader::new(&src, BitReaderMode::LE); |
606c448e KS |
525 | let unp_size = br.read(32)? as usize; |
526 | if !br.read_bool()? { | |
527 | let mut frm = NAFrame::new_from_pkt(pkt, info.clone(), NABufferType::None); | |
528 | frm.set_frame_type(FrameType::Skip); | |
171860fc | 529 | return Ok(frm.into_ref()); |
606c448e KS |
530 | } |
531 | let stereo = br.read_bool()?; | |
532 | let bits16 = br.read_bool()?; | |
533 | validate!(!(stereo ^ (self.chans == 2))); | |
534 | validate!(!(bits16 ^ (self.bits == 16))); | |
535 | ||
b70cc006 | 536 | let abuf; |
606c448e KS |
537 | let samples; |
538 | let nch = if stereo { 2 } else { 1 }; | |
539 | if bits16 { | |
540 | samples = unp_size / 2 / nch; | |
541 | let mask = if stereo { 1 } else { 0 }; | |
542 | let mut trees: [SmackerTree8; 4] = [SmackerTree8::new(), SmackerTree8::new(), SmackerTree8::new(), SmackerTree8::new()]; | |
3687b8b3 KS |
543 | for tree in trees[..nch*2].iter_mut() { |
544 | tree.decode(&mut br)?; | |
606c448e KS |
545 | } |
546 | let mut pred: [i16; 2] = [0; 2]; | |
547 | for i in 0..nch { | |
548 | let hi = br.read(8)?; | |
549 | let lo = br.read(8)?; | |
550 | pred[nch - i - 1] = (lo | (hi << 8)) as i16; | |
551 | } | |
552 | ||
553 | abuf = alloc_audio_buffer(self.ainfo, samples, self.chmap.clone())?; | |
554 | let mut adata = abuf.get_abuf_i16().unwrap(); | |
1a967e6b | 555 | let dst = adata.get_data_mut().unwrap(); |
3687b8b3 KS |
556 | dst[..nch].copy_from_slice(&pred[..nch]); |
557 | for (i, out) in dst[nch..(unp_size >> 1)].iter_mut().enumerate() { | |
606c448e KS |
558 | let idx = i & mask; |
559 | let lo = br.read_tree8(&trees[idx * 2 + 0])? as u16; | |
560 | let hi = br.read_tree8(&trees[idx * 2 + 1])? as u16; | |
561 | let diff = (lo | (hi << 8)) as i16; | |
562 | pred[idx] = pred[idx].wrapping_add(diff); | |
3687b8b3 | 563 | *out = pred[idx]; |
606c448e KS |
564 | } |
565 | } else { | |
566 | samples = unp_size / nch; | |
567 | abuf = alloc_audio_buffer(self.ainfo, samples, self.chmap.clone())?; | |
568 | let mut adata = abuf.get_abuf_u8().unwrap(); | |
1a967e6b | 569 | let dst = adata.get_data_mut().unwrap(); |
606c448e KS |
570 | if stereo { |
571 | let mut trees: [SmackerTree8; 2] = [SmackerTree8::new(), SmackerTree8::new()]; | |
572 | trees[0].decode(&mut br)?; | |
573 | trees[1].decode(&mut br)?; | |
574 | let pred0 = br.read(8)? as u8; | |
575 | let pred1 = br.read(8)? as u8; | |
576 | let mut pred: [u8; 2] = [ pred1, pred0 ]; | |
3687b8b3 KS |
577 | dst[..2].copy_from_slice(&pred); |
578 | for (i, out) in dst[2..unp_size].iter_mut().enumerate() { | |
e6aaad5c | 579 | let diff = br.read_tree8(&trees[i & 1])?; |
606c448e | 580 | pred[i & 1] = pred[i & 1].wrapping_add(diff); |
3687b8b3 | 581 | *out = pred[i & 1]; |
606c448e KS |
582 | } |
583 | } else { | |
584 | let mut tree = SmackerTree8::new(); | |
585 | tree.decode(&mut br)?; | |
586 | let mut pred = br.read(8)? as u8; | |
587 | dst[0] = pred; | |
3687b8b3 | 588 | for out in dst[1..unp_size].iter_mut() { |
e6aaad5c | 589 | let diff = br.read_tree8(&tree)?; |
606c448e | 590 | pred = pred.wrapping_add(diff); |
3687b8b3 | 591 | *out = pred; |
606c448e KS |
592 | } |
593 | } | |
594 | } | |
595 | let mut frm = NAFrame::new_from_pkt(pkt, info, abuf); | |
596 | frm.set_duration(Some(samples as u64)); | |
597 | frm.set_keyframe(false); | |
171860fc | 598 | Ok(frm.into_ref()) |
606c448e KS |
599 | } else { |
600 | Err(DecoderError::InvalidData) | |
601 | } | |
602 | } | |
f9be4e75 KS |
603 | fn flush(&mut self) { |
604 | } | |
606c448e KS |
605 | } |
606 | ||
7d57ae2f KS |
607 | impl NAOptionHandler for SmackerAudioDecoder { |
608 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
609 | fn set_options(&mut self, _options: &[NAOption]) { } | |
610 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
611 | } | |
612 | ||
08a1fab7 | 613 | pub fn get_decoder_audio() -> Box<dyn NADecoder + Send> { |
606c448e KS |
614 | Box::new(SmackerAudioDecoder::new()) |
615 | } | |
616 | ||
617 | #[cfg(test)] | |
618 | mod test { | |
619 | use nihav_core::codecs::RegisteredDecoders; | |
620 | use nihav_core::demuxers::RegisteredDemuxers; | |
ce742854 | 621 | use nihav_codec_support::test::dec_video::*; |
78fb6560 | 622 | use crate::rad_register_all_decoders; |
e64739f8 | 623 | use crate::rad_register_all_demuxers; |
606c448e KS |
624 | #[test] |
625 | fn test_smkvid() { | |
626 | let mut dmx_reg = RegisteredDemuxers::new(); | |
627 | rad_register_all_demuxers(&mut dmx_reg); | |
628 | let mut dec_reg = RegisteredDecoders::new(); | |
78fb6560 | 629 | rad_register_all_decoders(&mut dec_reg); |
606c448e | 630 | |
886cde48 | 631 | // sample from Heroes of Might and Magic 2 |
72be6d12 KS |
632 | test_decoding("smacker", "smacker-video", "assets/RAD/credits.smk", None, &dmx_reg, &dec_reg, |
633 | ExpectedTestResult::MD5Frames(vec![ | |
634 | [0x0983944a, 0xa23503f8, 0x2602b589, 0x13b53480], | |
635 | [0xb6c2bf1e, 0x2ee5fa60, 0x9896a6dc, 0x760b5737], | |
636 | [0xc7c6d112, 0x2c3c5bac, 0x63684974, 0xa6573b1e], | |
637 | [0x100e2871, 0xbc670db7, 0x54a802e5, 0xb5ba0b07], | |
638 | [0xcd9d22ce, 0x7f195dc9, 0x93c47105, 0x6acf8aa7], | |
639 | [0x84e82fdb, 0x304f24a8, 0x17466d73, 0x20182c33], | |
640 | [0xfcae613f, 0xddab2bd4, 0x9d351ee5, 0x2d0aea24], | |
641 | [0xea32a37c, 0x94d76dda, 0xbb34ca1d, 0xfc9d8a25], | |
642 | [0x37855f28, 0xb508a386, 0x1f0bd981, 0x0f967e25], | |
643 | [0x9b9f453a, 0xf6e34fe7, 0x9279fd71, 0x850a4f36]])); | |
606c448e KS |
644 | } |
645 | #[test] | |
45a8b7a2 KS |
646 | fn test_smkvid4() { |
647 | let mut dmx_reg = RegisteredDemuxers::new(); | |
648 | rad_register_all_demuxers(&mut dmx_reg); | |
649 | let mut dec_reg = RegisteredDecoders::new(); | |
650 | rad_register_all_decoders(&mut dec_reg); | |
651 | ||
652 | // sample from Army Man: Air Tactics | |
653 | test_decoding("smacker", "smacker-video", "assets/RAD/cine2.smk", Some(32000), &dmx_reg, &dec_reg, | |
654 | ExpectedTestResult::MD5Frames(vec![ | |
655 | [0x9da29a47, 0xd61a31ef, 0xa0da6b39, 0xbcf48d01], | |
656 | [0x604be492, 0x347854c0, 0xfeca481d, 0x98161276], | |
657 | [0x3922ad4a, 0x21ac6633, 0xe2c62e0b, 0x11cf3db5], | |
658 | [0xf1e58d8b, 0x539a6e41, 0x9ba5ebd6, 0x4129f62f], | |
659 | [0x549c73f5, 0x5eecbbc4, 0xcf301c7f, 0x7dfad240]])); | |
660 | } | |
661 | #[test] | |
72be6d12 | 662 | fn test_smkaud_u8() { |
606c448e KS |
663 | let mut dmx_reg = RegisteredDemuxers::new(); |
664 | rad_register_all_demuxers(&mut dmx_reg); | |
665 | let mut dec_reg = RegisteredDecoders::new(); | |
78fb6560 | 666 | rad_register_all_decoders(&mut dec_reg); |
606c448e | 667 | |
886cde48 | 668 | // sample: https://samples.mplayerhq.hu/game-formats/smacker/wetlands/wetlogo.smk |
72be6d12 KS |
669 | test_decoding("smacker", "smacker-audio", "assets/RAD/wetlogo.smk", None, &dmx_reg, &dec_reg, |
670 | ExpectedTestResult::MD5([0xc686b833, 0x0a203038, 0x012f6d9b, 0xa4186d44])); | |
671 | } | |
672 | #[test] | |
673 | fn test_smkaud_s16() { | |
674 | let mut dmx_reg = RegisteredDemuxers::new(); | |
675 | rad_register_all_demuxers(&mut dmx_reg); | |
676 | let mut dec_reg = RegisteredDecoders::new(); | |
78fb6560 | 677 | rad_register_all_decoders(&mut dec_reg); |
72be6d12 | 678 | |
886cde48 | 679 | // sample: https://samples.mplayerhq.hu/game-formats/smacker/20130507_audio-distortion.smk |
72be6d12 KS |
680 | test_decoding("smacker", "smacker-audio", "assets/RAD/20130507_audio-distortion.smk", None, &dmx_reg, &dec_reg, |
681 | ExpectedTestResult::MD5([0x942a0922, 0x182bb5fd, 0x94ab7a59, 0x2028d810])); | |
606c448e KS |
682 | } |
683 | } |