]>
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]; | |
141 | for i in 0..esc.len() { | |
e6aaad5c | 142 | esc[i] = 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 | } | |
252 | fn decode_frame(&mut self, br: &mut BitReader) -> DecoderResult<bool> { | |
253 | let mut is_intra = true; | |
254 | let blocks = self.bw * self.bh; | |
255 | ||
256 | self.mmap_tree.reset(); | |
257 | self.mclr_tree.reset(); | |
258 | self.full_tree.reset(); | |
259 | self.type_tree.reset(); | |
260 | ||
261 | let mut block = 0; | |
262 | while block < blocks { | |
263 | let btype = br.read_bigtree(&mut self.type_tree)?; | |
264 | let run = SMK_BLOCK_RUNS[((btype as usize) >> 2) & 0x3F]; | |
265 | validate!(run <= blocks - block); | |
266 | match btype & 3 { | |
267 | 0 => { // two-colour pattern | |
268 | for i in 0..run { | |
269 | let clr = br.read_bigtree(&mut self.mclr_tree)?; | |
270 | let mut map = br.read_bigtree(&mut self.mmap_tree)?; | |
271 | let hi = (clr >> 8) as u8; | |
272 | let lo = (clr & 0xFF) as u8; | |
273 | let mut doff = self.block_pos(block + i); | |
274 | for _ in 0..4 { | |
275 | self.frame[doff + 0] = if (map & 1) != 0 { hi } else { lo }; | |
276 | self.frame[doff + 1] = if (map & 2) != 0 { hi } else { lo }; | |
277 | self.frame[doff + 2] = if (map & 4) != 0 { hi } else { lo }; | |
278 | self.frame[doff + 3] = if (map & 8) != 0 { hi } else { lo }; | |
279 | map >>= 4; | |
280 | doff += self.stride; | |
281 | } | |
282 | } | |
283 | }, | |
284 | 1 => { // full | |
285 | let mode; | |
286 | if !self.is_ver4 || !br.read_bool()? { | |
287 | mode = 0; | |
288 | } else { | |
289 | mode = 1 + br.read(1)?; | |
290 | } | |
291 | for i in 0..run { | |
292 | let mut doff = self.block_pos(block + i); | |
293 | match mode { | |
294 | 0 => { | |
295 | for _ in 0..4 { | |
296 | let clr0 = br.read_bigtree(&mut self.full_tree)?; | |
297 | let clr1 = br.read_bigtree(&mut self.full_tree)?; | |
298 | self.frame[doff + 0] = (clr1 & 0xFF) as u8; | |
299 | self.frame[doff + 1] = (clr1 >> 8) as u8; | |
300 | self.frame[doff + 2] = (clr0 & 0xFF) as u8; | |
301 | self.frame[doff + 3] = (clr0 >> 8) as u8; | |
302 | doff += self.stride; | |
303 | } | |
304 | }, | |
305 | 1 => { | |
306 | for _ in 0..2 { | |
307 | let clr = br.read_bigtree(&mut self.full_tree)?; | |
308 | self.frame[doff + 0] = (clr & 0xFF) as u8; | |
309 | self.frame[doff + 1] = (clr & 0xFF) as u8; | |
310 | self.frame[doff + 2] = (clr >> 8) as u8; | |
311 | self.frame[doff + 3] = (clr >> 8) as u8; | |
312 | doff += self.stride; | |
313 | self.frame[doff + 0] = (clr & 0xFF) as u8; | |
314 | self.frame[doff + 1] = (clr & 0xFF) as u8; | |
315 | self.frame[doff + 2] = (clr >> 8) as u8; | |
316 | self.frame[doff + 3] = (clr >> 8) as u8; | |
317 | doff += self.stride; | |
318 | } | |
319 | }, | |
320 | 2 => { | |
321 | for _ in 0..2 { | |
322 | let clr0 = br.read_bigtree(&mut self.full_tree)?; | |
323 | let clr1 = br.read_bigtree(&mut self.full_tree)?; | |
324 | self.frame[doff + 0] = (clr1 & 0xFF) as u8; | |
325 | self.frame[doff + 1] = (clr1 >> 8) as u8; | |
326 | self.frame[doff + 2] = (clr0 & 0xFF) as u8; | |
327 | self.frame[doff + 3] = (clr0 >> 8) as u8; | |
328 | doff += self.stride; | |
329 | self.frame[doff + 0] = (clr1 & 0xFF) as u8; | |
330 | self.frame[doff + 1] = (clr1 >> 8) as u8; | |
331 | self.frame[doff + 2] = (clr0 & 0xFF) as u8; | |
332 | self.frame[doff + 3] = (clr0 >> 8) as u8; | |
333 | doff += self.stride; | |
334 | } | |
335 | }, | |
336 | _ => unreachable!(), | |
337 | }; | |
338 | } | |
339 | }, | |
340 | 2 => { // skip | |
341 | is_intra = false; | |
342 | }, | |
343 | 3 => { // fill | |
344 | let clr = (btype >> 8) as u8; | |
345 | for i in 0..run { | |
346 | let mut doff = self.block_pos(block + i); | |
347 | for _ in 0..4 { | |
348 | self.frame[doff + 0] = clr; | |
349 | self.frame[doff + 1] = clr; | |
350 | self.frame[doff + 2] = clr; | |
351 | self.frame[doff + 3] = clr; | |
352 | doff += self.stride; | |
353 | } | |
354 | } | |
355 | }, | |
356 | _ => unreachable!(), | |
357 | }; | |
358 | block += run; | |
359 | } | |
360 | Ok(is_intra) | |
361 | } | |
362 | fn output_frame(&self, buf: &mut NAVideoBuffer<u8>) { | |
363 | let stride = buf.get_stride(0); | |
1a967e6b | 364 | let data = buf.get_data_mut().unwrap(); |
606c448e KS |
365 | let dst = data.as_mut_slice(); |
366 | let is_scaled = (self.flags & SMK_FLAG_SCALED) != 0; | |
367 | let is_interlaced = (self.flags & SMK_FLAG_INTERLACED) != 0; | |
368 | let mut didx = 0; | |
369 | let mut sidx = 0; | |
370 | for _ in 0..self.h { | |
bf109afe | 371 | dst[didx..][..self.w].copy_from_slice(&self.frame[sidx..][..self.w]); |
606c448e KS |
372 | sidx += self.stride; |
373 | didx += stride; | |
374 | if is_scaled { | |
375 | for x in 0..self.w { dst[didx + x] = dst[didx - stride + x]; } | |
376 | didx += stride; | |
377 | } | |
378 | if is_interlaced { | |
379 | for x in 0..self.w { dst[didx + x] = 0; } | |
380 | didx += stride; | |
381 | if is_scaled { | |
382 | for x in 0..self.w { dst[didx + x] = 0; } | |
383 | didx += stride; | |
384 | } | |
385 | } | |
386 | } | |
387 | } | |
388 | } | |
389 | ||
390 | impl NADecoder for SmackerVideoDecoder { | |
01613464 | 391 | fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { |
606c448e KS |
392 | if let NACodecTypeInfo::Video(vinfo) = info.get_properties() { |
393 | let w = vinfo.get_width(); | |
394 | let h = vinfo.get_height(); | |
395 | let fmt = PAL8_FORMAT; | |
396 | ||
397 | self.w = w; | |
398 | self.h = h; | |
399 | self.bw = w >> 2; | |
400 | self.bh = h >> 2; | |
401 | let edata = info.get_extradata().unwrap(); | |
402 | validate!(edata.len() > 24); | |
403 | ||
404 | self.stride = w; | |
405 | self.frame.resize(w * h, 0); | |
406 | ||
407 | let mut mr = MemoryReader::new_read(&edata); | |
408 | let mut br = ByteReader::new(&mut mr); | |
409 | let magic = br.read_u32be()?; | |
410 | self.flags = br.read_u32le()?; | |
411 | let mmap_size = br.read_u32le()?; | |
412 | let mclr_size = br.read_u32le()?; | |
413 | let full_size = br.read_u32le()?; | |
414 | let type_size = br.read_u32le()?; | |
415 | ||
416 | self.is_ver4 = (magic & 0xFF) == 0x34; | |
fa90ccfb | 417 | let mut br = BitReader::new(&edata[24..], BitReaderMode::LE); |
606c448e KS |
418 | self.mmap_tree.decode(&mut br, mmap_size)?; |
419 | self.mclr_tree.decode(&mut br, mclr_size)?; | |
420 | self.full_tree.decode(&mut br, full_size)?; | |
421 | self.type_tree.decode(&mut br, type_size)?; | |
422 | ||
423 | let mut out_h = h; | |
424 | if (self.flags & SMK_FLAG_INTERLACED) != 0 { | |
425 | out_h <<= 1; | |
426 | } | |
427 | if (self.flags & SMK_FLAG_SCALED) != 0 { | |
428 | out_h <<= 1; | |
429 | } | |
430 | let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(w, out_h, false, fmt)); | |
2422d969 | 431 | self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref(); |
606c448e KS |
432 | |
433 | Ok(()) | |
434 | } else { | |
435 | Err(DecoderError::InvalidData) | |
436 | } | |
437 | } | |
01613464 | 438 | fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { |
606c448e KS |
439 | let src = pkt.get_buffer(); |
440 | validate!(src.len() >= PAL_SIZE); | |
441 | ||
442 | let is_intra; | |
443 | let ftype; | |
b70cc006 | 444 | let bufinfo; |
606c448e | 445 | if src.len() > PAL_SIZE { |
fa90ccfb | 446 | let mut br = BitReader::new(&src[PAL_SIZE..], BitReaderMode::LE); |
606c448e | 447 | |
7e6086e5 | 448 | bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 2)?; |
606c448e KS |
449 | let mut buf = bufinfo.get_vbuf().unwrap(); |
450 | is_intra = self.decode_frame(&mut br)?; | |
451 | self.output_frame(&mut buf); | |
452 | let paloff = buf.get_offset(1); | |
1a967e6b | 453 | let data = buf.get_data_mut().unwrap(); |
606c448e KS |
454 | let dst = data.as_mut_slice(); |
455 | let palout = &mut dst[paloff..][..PAL_SIZE]; | |
456 | palout.copy_from_slice(&src[0..PAL_SIZE]); | |
457 | ftype = if is_intra { FrameType::I } else { FrameType::P }; | |
458 | } else { | |
459 | bufinfo = NABufferType::None; | |
460 | ftype = FrameType::Skip; | |
461 | is_intra = false; | |
462 | } | |
463 | ||
464 | let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo); | |
465 | frm.set_keyframe(is_intra); | |
466 | frm.set_frame_type(ftype); | |
171860fc | 467 | Ok(frm.into_ref()) |
606c448e | 468 | } |
f9be4e75 KS |
469 | fn flush(&mut self) { |
470 | } | |
606c448e KS |
471 | } |
472 | ||
7d57ae2f KS |
473 | impl NAOptionHandler for SmackerVideoDecoder { |
474 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
475 | fn set_options(&mut self, _options: &[NAOption]) { } | |
476 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
477 | } | |
478 | ||
08a1fab7 | 479 | pub fn get_decoder_video() -> Box<dyn NADecoder + Send> { |
606c448e KS |
480 | Box::new(SmackerVideoDecoder::new()) |
481 | } | |
482 | ||
483 | struct SmackerAudioDecoder { | |
484 | ainfo: NAAudioInfo, | |
485 | chmap: NAChannelMap, | |
486 | chans: usize, | |
487 | bits: u8, | |
488 | } | |
489 | ||
490 | impl SmackerAudioDecoder { | |
491 | fn new() -> Self { | |
492 | Self { | |
493 | ainfo: NAAudioInfo::new(0, 1, SND_S16P_FORMAT, 0), | |
494 | chmap: NAChannelMap::new(), | |
495 | chans: 0, | |
496 | bits: 0, | |
497 | } | |
498 | } | |
499 | } | |
500 | ||
501 | impl NADecoder for SmackerAudioDecoder { | |
01613464 | 502 | fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { |
606c448e KS |
503 | if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() { |
504 | self.bits = ainfo.get_format().get_bits(); | |
70e792a8 | 505 | let fmt = if self.bits == 8 { SND_U8_FORMAT } else { SND_S16_FORMAT }; |
606c448e KS |
506 | self.chans = ainfo.get_channels() as usize; |
507 | self.ainfo = NAAudioInfo::new(ainfo.get_sample_rate(), ainfo.get_channels(), fmt, 0); | |
508 | self.chmap = NAChannelMap::from_str(if ainfo.get_channels() == 2 {"L,R"} else {"C"}).unwrap(); | |
509 | Ok(()) | |
510 | } else { | |
511 | Err(DecoderError::InvalidData) | |
512 | } | |
513 | } | |
bf109afe | 514 | #[allow(clippy::manual_memcpy)] |
01613464 | 515 | fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { |
606c448e KS |
516 | let info = pkt.get_stream().get_info(); |
517 | if let NACodecTypeInfo::Audio(_) = info.get_properties() { | |
518 | let src = pkt.get_buffer(); | |
519 | validate!(src.len() > 4); | |
fa90ccfb | 520 | let mut br = BitReader::new(&src, BitReaderMode::LE); |
606c448e KS |
521 | let unp_size = br.read(32)? as usize; |
522 | if !br.read_bool()? { | |
523 | let mut frm = NAFrame::new_from_pkt(pkt, info.clone(), NABufferType::None); | |
524 | frm.set_frame_type(FrameType::Skip); | |
171860fc | 525 | return Ok(frm.into_ref()); |
606c448e KS |
526 | } |
527 | let stereo = br.read_bool()?; | |
528 | let bits16 = br.read_bool()?; | |
529 | validate!(!(stereo ^ (self.chans == 2))); | |
530 | validate!(!(bits16 ^ (self.bits == 16))); | |
531 | ||
b70cc006 | 532 | let abuf; |
606c448e KS |
533 | let samples; |
534 | let nch = if stereo { 2 } else { 1 }; | |
535 | if bits16 { | |
536 | samples = unp_size / 2 / nch; | |
537 | let mask = if stereo { 1 } else { 0 }; | |
538 | let mut trees: [SmackerTree8; 4] = [SmackerTree8::new(), SmackerTree8::new(), SmackerTree8::new(), SmackerTree8::new()]; | |
539 | for i in 0..nch*2 { | |
540 | trees[i].decode(&mut br)?; | |
541 | } | |
542 | let mut pred: [i16; 2] = [0; 2]; | |
543 | for i in 0..nch { | |
544 | let hi = br.read(8)?; | |
545 | let lo = br.read(8)?; | |
546 | pred[nch - i - 1] = (lo | (hi << 8)) as i16; | |
547 | } | |
548 | ||
549 | abuf = alloc_audio_buffer(self.ainfo, samples, self.chmap.clone())?; | |
550 | let mut adata = abuf.get_abuf_i16().unwrap(); | |
1a967e6b | 551 | let dst = adata.get_data_mut().unwrap(); |
606c448e | 552 | for ch in 0..nch { |
70e792a8 | 553 | dst[ch] = pred[ch]; |
606c448e KS |
554 | } |
555 | for i in nch..(unp_size >> 1) { | |
556 | let idx = i & mask; | |
557 | let lo = br.read_tree8(&trees[idx * 2 + 0])? as u16; | |
558 | let hi = br.read_tree8(&trees[idx * 2 + 1])? as u16; | |
559 | let diff = (lo | (hi << 8)) as i16; | |
560 | pred[idx] = pred[idx].wrapping_add(diff); | |
70e792a8 | 561 | dst[i] = pred[idx]; |
606c448e KS |
562 | } |
563 | } else { | |
564 | samples = unp_size / nch; | |
565 | abuf = alloc_audio_buffer(self.ainfo, samples, self.chmap.clone())?; | |
566 | let mut adata = abuf.get_abuf_u8().unwrap(); | |
1a967e6b | 567 | let dst = adata.get_data_mut().unwrap(); |
606c448e KS |
568 | if stereo { |
569 | let mut trees: [SmackerTree8; 2] = [SmackerTree8::new(), SmackerTree8::new()]; | |
570 | trees[0].decode(&mut br)?; | |
571 | trees[1].decode(&mut br)?; | |
572 | let pred0 = br.read(8)? as u8; | |
573 | let pred1 = br.read(8)? as u8; | |
574 | let mut pred: [u8; 2] = [ pred1, pred0 ]; | |
575 | for ch in 0..2 { dst[ch] = pred[ch]; } | |
576 | for i in 2..unp_size { | |
e6aaad5c | 577 | let diff = br.read_tree8(&trees[i & 1])?; |
606c448e KS |
578 | pred[i & 1] = pred[i & 1].wrapping_add(diff); |
579 | dst[i] = pred[i & 1]; | |
580 | } | |
581 | } else { | |
582 | let mut tree = SmackerTree8::new(); | |
583 | tree.decode(&mut br)?; | |
584 | let mut pred = br.read(8)? as u8; | |
585 | dst[0] = pred; | |
586 | for i in 1..unp_size { | |
e6aaad5c | 587 | let diff = br.read_tree8(&tree)?; |
606c448e KS |
588 | pred = pred.wrapping_add(diff); |
589 | dst[i] = pred; | |
590 | } | |
591 | } | |
592 | } | |
593 | let mut frm = NAFrame::new_from_pkt(pkt, info, abuf); | |
594 | frm.set_duration(Some(samples as u64)); | |
595 | frm.set_keyframe(false); | |
171860fc | 596 | Ok(frm.into_ref()) |
606c448e KS |
597 | } else { |
598 | Err(DecoderError::InvalidData) | |
599 | } | |
600 | } | |
f9be4e75 KS |
601 | fn flush(&mut self) { |
602 | } | |
606c448e KS |
603 | } |
604 | ||
7d57ae2f KS |
605 | impl NAOptionHandler for SmackerAudioDecoder { |
606 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
607 | fn set_options(&mut self, _options: &[NAOption]) { } | |
608 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
609 | } | |
610 | ||
08a1fab7 | 611 | pub fn get_decoder_audio() -> Box<dyn NADecoder + Send> { |
606c448e KS |
612 | Box::new(SmackerAudioDecoder::new()) |
613 | } | |
614 | ||
615 | #[cfg(test)] | |
616 | mod test { | |
617 | use nihav_core::codecs::RegisteredDecoders; | |
618 | use nihav_core::demuxers::RegisteredDemuxers; | |
ce742854 | 619 | use nihav_codec_support::test::dec_video::*; |
78fb6560 | 620 | use crate::rad_register_all_decoders; |
e64739f8 | 621 | use crate::rad_register_all_demuxers; |
606c448e KS |
622 | #[test] |
623 | fn test_smkvid() { | |
624 | let mut dmx_reg = RegisteredDemuxers::new(); | |
625 | rad_register_all_demuxers(&mut dmx_reg); | |
626 | let mut dec_reg = RegisteredDecoders::new(); | |
78fb6560 | 627 | rad_register_all_decoders(&mut dec_reg); |
606c448e | 628 | |
886cde48 | 629 | // sample from Heroes of Might and Magic 2 |
72be6d12 KS |
630 | test_decoding("smacker", "smacker-video", "assets/RAD/credits.smk", None, &dmx_reg, &dec_reg, |
631 | ExpectedTestResult::MD5Frames(vec![ | |
632 | [0x0983944a, 0xa23503f8, 0x2602b589, 0x13b53480], | |
633 | [0xb6c2bf1e, 0x2ee5fa60, 0x9896a6dc, 0x760b5737], | |
634 | [0xc7c6d112, 0x2c3c5bac, 0x63684974, 0xa6573b1e], | |
635 | [0x100e2871, 0xbc670db7, 0x54a802e5, 0xb5ba0b07], | |
636 | [0xcd9d22ce, 0x7f195dc9, 0x93c47105, 0x6acf8aa7], | |
637 | [0x84e82fdb, 0x304f24a8, 0x17466d73, 0x20182c33], | |
638 | [0xfcae613f, 0xddab2bd4, 0x9d351ee5, 0x2d0aea24], | |
639 | [0xea32a37c, 0x94d76dda, 0xbb34ca1d, 0xfc9d8a25], | |
640 | [0x37855f28, 0xb508a386, 0x1f0bd981, 0x0f967e25], | |
641 | [0x9b9f453a, 0xf6e34fe7, 0x9279fd71, 0x850a4f36]])); | |
606c448e KS |
642 | } |
643 | #[test] | |
72be6d12 | 644 | fn test_smkaud_u8() { |
606c448e KS |
645 | let mut dmx_reg = RegisteredDemuxers::new(); |
646 | rad_register_all_demuxers(&mut dmx_reg); | |
647 | let mut dec_reg = RegisteredDecoders::new(); | |
78fb6560 | 648 | rad_register_all_decoders(&mut dec_reg); |
606c448e | 649 | |
886cde48 | 650 | // sample: https://samples.mplayerhq.hu/game-formats/smacker/wetlands/wetlogo.smk |
72be6d12 KS |
651 | test_decoding("smacker", "smacker-audio", "assets/RAD/wetlogo.smk", None, &dmx_reg, &dec_reg, |
652 | ExpectedTestResult::MD5([0xc686b833, 0x0a203038, 0x012f6d9b, 0xa4186d44])); | |
653 | } | |
654 | #[test] | |
655 | fn test_smkaud_s16() { | |
656 | let mut dmx_reg = RegisteredDemuxers::new(); | |
657 | rad_register_all_demuxers(&mut dmx_reg); | |
658 | let mut dec_reg = RegisteredDecoders::new(); | |
78fb6560 | 659 | rad_register_all_decoders(&mut dec_reg); |
72be6d12 | 660 | |
886cde48 | 661 | // sample: https://samples.mplayerhq.hu/game-formats/smacker/20130507_audio-distortion.smk |
72be6d12 KS |
662 | test_decoding("smacker", "smacker-audio", "assets/RAD/20130507_audio-distortion.smk", None, &dmx_reg, &dec_reg, |
663 | ExpectedTestResult::MD5([0x942a0922, 0x182bb5fd, 0x94ab7a59, 0x2028d810])); | |
606c448e KS |
664 | } |
665 | } |