]> git.nihav.org Git - nihav.git/blame - nihav-rad/src/codecs/smacker.rs
avimux: do not record palette change chunks in OpenDML index
[nihav.git] / nihav-rad / src / codecs / smacker.rs
CommitLineData
606c448e
KS
1use nihav_core::codecs::*;
2use nihav_core::io::byteio::*;
3use nihav_core::io::bitreader::*;
4use nihav_core::io::codebook::*;
5use std::str::FromStr;
6
7const PAL_SIZE: usize = 768;
8const SMK_FLAG_INTERLACED: u32 = 0x02;
9const SMK_FLAG_SCALED: u32 = 0x04;
10
11struct SmackerTree8 {
12 cb: Option<Codebook<u8>>,
13 defsym: u8,
14}
15
16fn 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
30pub struct FullTableCodebookDescReader<'a> {
31 bits: &'a [u8],
32 codes: &'a [u32],
33 syms: &'a [u8],
34}
35
36impl<'a> FullTableCodebookDescReader<'a> {
37 pub fn new(codes: &'a [u32], bits: &'a [u8], syms: &'a [u8]) -> Self {
38 Self { bits, codes, syms }
39 }
40}
41impl<'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
49impl 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
79struct SmackerTree16 {
80 tree: Vec<u32>,
81 last: [usize; 3],
82}
83
84struct SmackerTree16Builder {
85 tree_lo: SmackerTree8,
86 tree_hi: SmackerTree8,
87 nsyms: usize,
88 esc: [u32; 3],
89}
90
91const SMK_BIGTREE_NODE: u32 = 0x80000000;
92const SMK_LAST_UNINIT: usize = 0xFFFFFFFF;
93
94impl 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
125impl 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
171trait ReadTree {
172 fn read_tree8(&mut self, tree: &SmackerTree8) -> DecoderResult<u8>;
173 fn read_bigtree(&mut self, tree: &mut SmackerTree16) -> DecoderResult<u16>;
174}
175
176impl<'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
202const 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
213struct 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
229impl 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
394impl 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
477impl 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 483pub fn get_decoder_video() -> Box<dyn NADecoder + Send> {
606c448e
KS
484 Box::new(SmackerVideoDecoder::new())
485}
486
487struct SmackerAudioDecoder {
488 ainfo: NAAudioInfo,
489 chmap: NAChannelMap,
490 chans: usize,
491 bits: u8,
492}
493
494impl 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
505impl 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
607impl 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 613pub fn get_decoder_audio() -> Box<dyn NADecoder + Send> {
606c448e
KS
614 Box::new(SmackerAudioDecoder::new())
615}
616
617#[cfg(test)]
618mod 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}