add LinePack decoder
[nihav.git] / nihav-game / src / codecs / hl_fmv.rs
1 use nihav_core::codecs::*;
2 use nihav_core::io::byteio::*;
3
4 const FRAME_W: usize = 320;
5 const FRAME_H: usize = 240;
6 const HIST_SIZE: usize = 32768;
7
8 struct Pattern {
9 len: u8,
10 pattern: [u8; 16],
11 }
12
13 struct HighlanderDecoder {
14 info: NACodecInfoRef,
15 hist: [u8; HIST_SIZE],
16 tmp1: [u8; FRAME_W * FRAME_H],
17 tmp2: [u8; FRAME_W * FRAME_H * 17 / 16],
18 }
19
20 fn unpack(src: &[u8], dst: &mut [u8], hist: &mut [u8; HIST_SIZE]) -> DecoderResult<usize> {
21 let mut mr = MemoryReader::new_read(src);
22 let mut br = ByteReader::new(&mut mr);
23
24 let mut mw = MemoryWriter::new_write(dst);
25 let mut bw = ByteWriter::new(&mut mw);
26
27 *hist = [0; HIST_SIZE];
28
29 let mut pprev = 0;
30 let mut prev = 0;
31 while br.left() > 0 {
32 let mut flags = br.read_byte()?;
33 for _ in 0..8 {
34 let idx = (usize::from(pprev) << 7) ^ usize::from(prev);
35 if (flags & 1) == 0 {
36 if br.left() == 0 {
37 break;
38 }
39 hist[idx] = br.read_byte()?;
40 }
41 let val = hist[idx];
42 bw.write_byte(val)?;
43
44 flags >>= 1;
45 pprev = prev;
46 prev = val;
47 }
48 }
49
50 Ok(bw.tell() as usize)
51 }
52
53 fn paint_frame(dst: &mut [u8], stride: usize, src: &[u8]) -> DecoderResult<()> {
54 let mut mr = MemoryReader::new_read(src);
55 let mut br = ByteReader::new(&mut mr);
56
57 let mut blk_offs = [0; 16];
58 for (y, offs) in blk_offs.chunks_mut(4).enumerate() {
59 offs[0] = stride * y;
60 offs[1] = stride * y + 1;
61 offs[2] = stride * y + 2;
62 offs[3] = stride * y + 3;
63 }
64
65 for row in dst.chunks_mut(stride * 4).take(FRAME_H / 4) {
66 for xoff in (0..FRAME_W).step_by(4) {
67 let idx = br.read_byte()? as usize;
68 validate!(idx < PAINT_MODE.len());
69 let mode = &PAINT_MODE[idx];
70 validate!(i64::from(mode.len) <= br.left());
71
72 for (&blk_off, &idx) in blk_offs.iter().zip(mode.pattern.iter()) {
73 if idx == 0xFF {
74 row[xoff + blk_off] = br.read_byte()?;
75 }
76 }
77 for (&blk_off, &idx) in blk_offs.iter().zip(mode.pattern.iter()) {
78 if idx != 0xFF {
79 row[xoff + blk_off] = row[xoff + blk_offs[idx as usize]];
80 }
81 }
82 }
83 }
84 Ok(())
85 }
86
87 impl HighlanderDecoder {
88 fn new() -> Self {
89 Self {
90 info: NACodecInfoRef::default(),
91 hist: [0; HIST_SIZE],
92 tmp1: [0; FRAME_W * FRAME_H],
93 tmp2: [0; FRAME_W * FRAME_H * 17 / 16],
94 }
95 }
96 }
97
98 impl NADecoder for HighlanderDecoder {
99 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
100 if let NACodecTypeInfo::Video(_vinfo) = info.get_properties() {
101 let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(FRAME_W, FRAME_H, false, PAL8_FORMAT));
102 self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
103
104 Ok(())
105 } else {
106 Err(DecoderError::InvalidData)
107 }
108 }
109 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
110 let src = pkt.get_buffer();
111 validate!(src.len() > 4);
112
113 let bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 0)?;
114 let bufo = bufinfo.get_vbuf();
115 let mut buf = bufo.unwrap();
116 let paloff = buf.get_offset(1);
117 let stride = buf.get_stride(0);
118 let data = buf.get_data_mut().unwrap();
119 let dst = data.as_mut_slice();
120
121 validate!(src.len() > 4);
122
123 let size = read_u32le(&src)? as usize;
124 validate!(size <= src.len() - 4);
125
126 let size2 = unpack(&src[4..][..size], &mut self.tmp1, &mut self.hist)?;
127 let size3 = unpack(&self.tmp1[..size2], &mut self.tmp2, &mut self.hist)?;
128 paint_frame(dst, stride, &self.tmp2[..size3])?;
129
130 let dpal = &mut dst[paloff..][..768];
131 for (dst, &src) in dpal.iter_mut().zip(DEFAULT_PAL.iter()) {
132 *dst = (src << 2) | (src >> 4);
133 }
134
135 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo);
136 frm.set_keyframe(true);
137 frm.set_frame_type(FrameType::I);
138 Ok(frm.into_ref())
139 }
140 fn flush(&mut self) {
141 }
142 }
143
144 impl NAOptionHandler for HighlanderDecoder {
145 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
146 fn set_options(&mut self, _options: &[NAOption]) { }
147 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
148 }
149
150
151 pub fn get_decoder() -> Box<dyn NADecoder + Send> {
152 Box::new(HighlanderDecoder::new())
153 }
154
155 #[cfg(test)]
156 mod test {
157 use nihav_core::codecs::RegisteredDecoders;
158 use nihav_core::demuxers::RegisteredDemuxers;
159 use nihav_codec_support::test::dec_video::*;
160 use crate::game_register_all_decoders;
161 use crate::game_register_all_demuxers;
162 // sample extracted from Highlander: The Last of the MacLeods unpublished game
163 #[test]
164 fn test_hl_fmv_video() {
165 let mut dmx_reg = RegisteredDemuxers::new();
166 game_register_all_demuxers(&mut dmx_reg);
167 let mut dec_reg = RegisteredDecoders::new();
168 game_register_all_decoders(&mut dec_reg);
169
170 test_decoding("hl-fmv", "hl-fmv-video", "assets/Game/0260.fmv", Some(10), &dmx_reg, &dec_reg,
171 ExpectedTestResult::MD5([0x369659f0, 0x417ad3a7, 0xc62dfc6f, 0x6e5fe871]));
172 }
173 }
174
175 const PAINT_MODE: [Pattern; 9] = [
176 Pattern {
177 len: 1,
178 pattern: [
179 0xFF, 0x00, 0x00, 0x00,
180 0x00, 0x00, 0x00, 0x00,
181 0x00, 0x00, 0x00, 0x00,
182 0x00, 0x00, 0x00, 0x00
183 ],
184 },
185 Pattern {
186 len: 2,
187 pattern: [
188 0x05, 0x09, 0x05, 0x09,
189 0x09, 0xFF, 0x09, 0x05,
190 0x05, 0xFF, 0x05, 0x09,
191 0x09, 0x05, 0x09, 0x05
192 ],
193 },
194 Pattern {
195 len: 2,
196 pattern: [
197 0xFF, 0xFF, 0x00, 0x01,
198 0x01, 0x01, 0x01, 0x01,
199 0x00, 0x01, 0x00, 0x01,
200 0x01, 0x01, 0x01, 0x01
201 ]
202 },
203 Pattern {
204 len: 2,
205 pattern: [
206 0xFF, 0xFF, 0x00, 0x01,
207 0x00, 0x00, 0x00, 0x00,
208 0x00, 0x01, 0x00, 0x01,
209 0x00, 0x00, 0x00, 0x00
210 ],
211 },
212 Pattern {
213 len: 2,
214 pattern: [
215 0x0E, 0x0E, 0x0E, 0x0E,
216 0x0E, 0x0F, 0x0E, 0x0F,
217 0x0E, 0x0E, 0x0E, 0x0E,
218 0x0E, 0x0F, 0xFF, 0xFF
219 ],
220 },
221 Pattern {
222 len: 2,
223 pattern: [
224 0x0F, 0x0F, 0x0F, 0x0F,
225 0x0E, 0x0F, 0x0E, 0x0F,
226 0x0F, 0x0F, 0x0F, 0x0F,
227 0x0E, 0x0F, 0xFF, 0xFF
228 ],
229 },
230 Pattern {
231 len: 5,
232 pattern: [
233 0xFF, 0xFF, 0x00, 0xFF,
234 0x01, 0xFF, 0x01, 0xFF,
235 0x00, 0x01, 0x00, 0x03,
236 0x03, 0x07, 0x03, 0x07
237 ],
238 },
239 Pattern {
240 len: 8,
241 pattern: [
242 0xFF, 0xFF, 0xFF, 0xFF,
243 0x01, 0x00, 0x03, 0x02,
244 0xFF, 0xFF, 0xFF, 0xFF,
245 0x09, 0x08, 0x0B, 0x0A
246 ],
247 },
248 Pattern {
249 len: 16,
250 pattern: [
251 0xFF, 0xFF, 0xFF, 0xFF,
252 0xFF, 0xFF, 0xFF, 0xFF,
253 0xFF, 0xFF, 0xFF, 0xFF,
254 0xFF, 0xFF, 0xFF, 0xFF
255 ],
256 }
257 ];
258
259 const DEFAULT_PAL: [u8; 768] = [
260 0x00, 0x00, 0x00,
261 0x00, 0x00, 0x20,
262 0x00, 0x20, 0x00,
263 0x00, 0x20, 0x20,
264 0x20, 0x00, 0x00,
265 0x20, 0x00, 0x20,
266 0x20, 0x20, 0x00,
267 0x30, 0x30, 0x30,
268 0x30, 0x37, 0x30,
269 0x3C, 0x32, 0x29,
270 0x01, 0x01, 0x01,
271 0x02, 0x02, 0x02,
272 0x03, 0x03, 0x03,
273 0x04, 0x04, 0x04,
274 0x05, 0x05, 0x05,
275 0x07, 0x07, 0x07,
276 0x08, 0x08, 0x08,
277 0x0A, 0x0A, 0x0A,
278 0x15, 0x15, 0x15,
279 0x13, 0x13, 0x13,
280 0x10, 0x10, 0x10,
281 0x0E, 0x0E, 0x0E,
282 0x20, 0x20, 0x20,
283 0x00, 0x00, 0x20,
284 0x00, 0x20, 0x00,
285 0x00, 0x20, 0x20,
286 0x20, 0x00, 0x00,
287 0x20, 0x00, 0x20,
288 0x20, 0x20, 0x00,
289 0x00, 0x00, 0x0C,
290 0x00, 0x00, 0x19,
291 0x00, 0x00, 0x26,
292 0x00, 0x00, 0x33,
293 0x00, 0x0C, 0x00,
294 0x00, 0x0C, 0x0C,
295 0x00, 0x0C, 0x19,
296 0x00, 0x0C, 0x26,
297 0x00, 0x0C, 0x33,
298 0x00, 0x0C, 0x3F,
299 0x00, 0x19, 0x00,
300 0x00, 0x19, 0x0C,
301 0x00, 0x19, 0x19,
302 0x00, 0x19, 0x26,
303 0x00, 0x19, 0x33,
304 0x00, 0x19, 0x3F,
305 0x00, 0x26, 0x00,
306 0x00, 0x26, 0x0C,
307 0x00, 0x26, 0x19,
308 0x00, 0x26, 0x26,
309 0x00, 0x26, 0x33,
310 0x00, 0x26, 0x3F,
311 0x00, 0x33, 0x00,
312 0x00, 0x33, 0x0C,
313 0x00, 0x33, 0x19,
314 0x00, 0x33, 0x26,
315 0x00, 0x33, 0x33,
316 0x00, 0x33, 0x3F,
317 0x00, 0x3F, 0x19,
318 0x00, 0x3F, 0x26,
319 0x00, 0x3F, 0x33,
320 0x0C, 0x00, 0x00,
321 0x0C, 0x00, 0x0C,
322 0x0C, 0x00, 0x19,
323 0x0C, 0x00, 0x26,
324 0x0C, 0x00, 0x33,
325 0x0C, 0x00, 0x3F,
326 0x0C, 0x0C, 0x00,
327 0x0C, 0x0C, 0x0C,
328 0x0C, 0x0C, 0x19,
329 0x0C, 0x0C, 0x26,
330 0x0C, 0x0C, 0x33,
331 0x0C, 0x0C, 0x3F,
332 0x0C, 0x19, 0x00,
333 0x0C, 0x19, 0x0C,
334 0x0C, 0x19, 0x19,
335 0x0C, 0x19, 0x26,
336 0x0C, 0x19, 0x33,
337 0x0C, 0x19, 0x3F,
338 0x0C, 0x26, 0x00,
339 0x0C, 0x26, 0x0C,
340 0x0C, 0x26, 0x19,
341 0x0C, 0x26, 0x26,
342 0x0C, 0x26, 0x33,
343 0x0C, 0x26, 0x3F,
344 0x0C, 0x33, 0x00,
345 0x0C, 0x33, 0x0C,
346 0x0C, 0x33, 0x19,
347 0x0C, 0x33, 0x26,
348 0x0C, 0x33, 0x33,
349 0x0C, 0x33, 0x3F,
350 0x0C, 0x3F, 0x0C,
351 0x0C, 0x3F, 0x19,
352 0x0C, 0x3F, 0x26,
353 0x0C, 0x3F, 0x33,
354 0x0C, 0x3F, 0x3F,
355 0x19, 0x00, 0x00,
356 0x19, 0x00, 0x0C,
357 0x19, 0x00, 0x19,
358 0x19, 0x00, 0x26,
359 0x19, 0x00, 0x33,
360 0x19, 0x00, 0x3F,
361 0x19, 0x0C, 0x00,
362 0x19, 0x0C, 0x0C,
363 0x19, 0x0C, 0x19,
364 0x19, 0x0C, 0x26,
365 0x19, 0x0C, 0x33,
366 0x19, 0x0C, 0x3F,
367 0x19, 0x19, 0x00,
368 0x19, 0x19, 0x0C,
369 0x19, 0x19, 0x19,
370 0x19, 0x19, 0x26,
371 0x19, 0x19, 0x33,
372 0x19, 0x26, 0x00,
373 0x19, 0x26, 0x0C,
374 0x19, 0x26, 0x19,
375 0x19, 0x26, 0x26,
376 0x19, 0x26, 0x33,
377 0x19, 0x26, 0x3F,
378 0x19, 0x33, 0x00,
379 0x19, 0x33, 0x0C,
380 0x19, 0x33, 0x26,
381 0x19, 0x33, 0x33,
382 0x19, 0x33, 0x3F,
383 0x19, 0x3F, 0x00,
384 0x19, 0x3F, 0x0C,
385 0x19, 0x3F, 0x26,
386 0x19, 0x3F, 0x33,
387 0x33, 0x00, 0x3F,
388 0x3F, 0x00, 0x33,
389 0x26, 0x26, 0x00,
390 0x26, 0x0C, 0x26,
391 0x26, 0x00, 0x26,
392 0x26, 0x00, 0x33,
393 0x26, 0x00, 0x00,
394 0x26, 0x0C, 0x0C,
395 0x26, 0x00, 0x19,
396 0x26, 0x0C, 0x33,
397 0x26, 0x00, 0x3F,
398 0x26, 0x19, 0x00,
399 0x26, 0x19, 0x0C,
400 0x26, 0x0C, 0x19,
401 0x26, 0x19, 0x26,
402 0x26, 0x19, 0x33,
403 0x26, 0x0C, 0x3F,
404 0x26, 0x26, 0x0C,
405 0x26, 0x26, 0x19,
406 0x26, 0x26, 0x26,
407 0x26, 0x26, 0x33,
408 0x26, 0x26, 0x3F,
409 0x26, 0x33, 0x00,
410 0x26, 0x33, 0x0C,
411 0x19, 0x33, 0x19,
412 0x26, 0x33, 0x26,
413 0x26, 0x33, 0x33,
414 0x26, 0x33, 0x3F,
415 0x26, 0x3F, 0x00,
416 0x26, 0x3F, 0x0C,
417 0x26, 0x33, 0x19,
418 0x26, 0x3F, 0x26,
419 0x26, 0x3F, 0x33,
420 0x26, 0x3F, 0x3F,
421 0x33, 0x00, 0x00,
422 0x26, 0x00, 0x0C,
423 0x33, 0x00, 0x19,
424 0x33, 0x00, 0x26,
425 0x33, 0x00, 0x33,
426 0x26, 0x0C, 0x00,
427 0x33, 0x0C, 0x0C,
428 0x33, 0x0C, 0x19,
429 0x33, 0x0C, 0x26,
430 0x33, 0x0C, 0x33,
431 0x33, 0x0C, 0x3F,
432 0x33, 0x19, 0x00,
433 0x33, 0x19, 0x0C,
434 0x26, 0x19, 0x19,
435 0x33, 0x19, 0x26,
436 0x33, 0x19, 0x33,
437 0x26, 0x19, 0x3F,
438 0x33, 0x26, 0x00,
439 0x33, 0x26, 0x0C,
440 0x33, 0x26, 0x19,
441 0x33, 0x26, 0x26,
442 0x33, 0x26, 0x33,
443 0x33, 0x26, 0x3F,
444 0x33, 0x33, 0x00,
445 0x33, 0x33, 0x0C,
446 0x33, 0x33, 0x19,
447 0x33, 0x33, 0x26,
448 0x33, 0x33, 0x33,
449 0x33, 0x33, 0x3F,
450 0x33, 0x3F, 0x00,
451 0x33, 0x3F, 0x0C,
452 0x26, 0x3F, 0x19,
453 0x33, 0x3F, 0x26,
454 0x33, 0x3F, 0x33,
455 0x33, 0x3F, 0x3F,
456 0x33, 0x00, 0x0C,
457 0x3F, 0x00, 0x19,
458 0x3F, 0x00, 0x26,
459 0x33, 0x0C, 0x00,
460 0x3F, 0x0C, 0x0C,
461 0x3F, 0x0C, 0x19,
462 0x3F, 0x0C, 0x26,
463 0x3F, 0x0C, 0x33,
464 0x3F, 0x0C, 0x3F,
465 0x3F, 0x19, 0x00,
466 0x3F, 0x19, 0x0C,
467 0x33, 0x19, 0x19,
468 0x3F, 0x19, 0x26,
469 0x3F, 0x19, 0x33,
470 0x33, 0x19, 0x3F,
471 0x3F, 0x26, 0x00,
472 0x3F, 0x26, 0x0C,
473 0x3F, 0x26, 0x19,
474 0x3F, 0x26, 0x26,
475 0x3F, 0x26, 0x33,
476 0x3F, 0x26, 0x3F,
477 0x3F, 0x33, 0x00,
478 0x3F, 0x33, 0x0C,
479 0x3F, 0x33, 0x19,
480 0x3F, 0x33, 0x26,
481 0x3F, 0x33, 0x33,
482 0x3F, 0x33, 0x3F,
483 0x3F, 0x3F, 0x0C,
484 0x33, 0x3F, 0x19,
485 0x3F, 0x3F, 0x26,
486 0x3F, 0x3F, 0x33,
487 0x19, 0x19, 0x3F,
488 0x19, 0x3F, 0x19,
489 0x19, 0x3F, 0x3F,
490 0x3F, 0x19, 0x19,
491 0x3F, 0x19, 0x3F,
492 0x3F, 0x3F, 0x19,
493 0x30, 0x30, 0x30,
494 0x17, 0x17, 0x17,
495 0x1D, 0x1D, 0x1D,
496 0x21, 0x21, 0x21,
497 0x25, 0x25, 0x25,
498 0x32, 0x32, 0x32,
499 0x2C, 0x2C, 0x2C,
500 0x35, 0x35, 0x35,
501 0x37, 0x37, 0x37,
502 0x38, 0x38, 0x38,
503 0x3A, 0x3A, 0x3A,
504 0x3C, 0x3C, 0x3C,
505 0x3E, 0x3E, 0x3E,
506 0x3C, 0x3E, 0x3F,
507 0x29, 0x28, 0x28,
508 0x20, 0x20, 0x20,
509 0x00, 0x00, 0x3F,
510 0x00, 0x3F, 0x00,
511 0x00, 0x3F, 0x3F,
512 0x3F, 0x00, 0x00,
513 0x3F, 0x00, 0x3F,
514 0x3F, 0x3F, 0x00,
515 0x3F, 0x3F, 0x3F
516 ];