support Legend Entertainment Q format version 7
[nihav.git] / nihav-game / src / codecs / q.rs
1 use nihav_core::frame::*;
2 use nihav_core::codecs::*;
3 use nihav_core::io::byteio::*;
4
5 #[derive(Clone,Copy,Debug,PartialEq)]
6 enum TileMode {
7 Start,
8 Fill,
9 ShortPattern(u8, u8),
10 LongPattern(u8, u8),
11 Run,
12 Reuse,
13 FB,
14 MV,
15 Forward(u16),
16 Backward(u16),
17 Skip,
18 }
19
20 struct QVideoDecoder {
21 info: NACodecInfoRef,
22 pal: [u8; 768],
23 frame: Vec<u8>,
24 w: usize,
25 h: usize,
26 tile_w: usize,
27 tile_h: usize,
28 tile_off: Vec<usize>,
29 mode: u8,
30 patterns: [u16; 128],
31 version: u8,
32 f8_cache: [[u8; 16]; 240],
33 }
34
35 macro_rules! copy_tile {
36 ($self: expr, $doff: expr, $soff: expr) => {
37 let mut doff = $doff;
38 let mut soff = $soff;
39 for _y in 0..$self.tile_h {
40 for x in 0..$self.tile_w {
41 $self.frame[doff + x] = $self.frame[soff + x];
42 }
43 doff += $self.w;
44 soff += $self.w;
45 }
46 }
47 }
48
49 impl QVideoDecoder {
50 fn new() -> Self {
51 QVideoDecoder {
52 info: NACodecInfoRef::default(),
53 pal: [0; 768],
54 frame: Vec::new(),
55 w: 0,
56 h: 0,
57 tile_off: Vec::new(),
58 mode: 0,
59 tile_w: 0,
60 tile_h: 0,
61 patterns: [0; 128],
62 version: 0,
63 f8_cache: [[0; 16]; 240],
64 }
65 }
66
67 fn decode_mode7_tile(dst: &mut [u8], stride: usize, br: &mut ByteReader) -> DecoderResult<()> {
68 let op = br.peek_byte()?;
69 if op < 0xF8 {
70 for dline in dst.chunks_mut(stride).take(4) {
71 br.read_buf(&mut dline[..4])?;
72 }
73 } else if op == 0xF8 || op == 0xFF {
74 br.read_byte()?;
75 } else {
76 br.read_byte()?;
77 let mut clr = [0; 8];
78 let nclr = (op - 0xF6) as usize;
79 if nclr <= 4 {
80 let mut pattern = br.read_u32le()?;
81 br.read_buf(&mut clr[..nclr])?;
82 for dline in dst.chunks_mut(stride).take(4) {
83 for el in dline[..4].iter_mut() {
84 *el = clr[(pattern & 3) as usize];
85 pattern >>= 2;
86 }
87 }
88 } else {
89 let mut pattern = br.read_u24le()?;
90 let pattern2 = br.read_u24le()?;
91 br.read_buf(&mut clr[..nclr])?;
92 for (y, dline) in dst.chunks_mut(stride).take(4).enumerate() {
93 for el in dline[..4].iter_mut() {
94 *el = clr[(pattern & 7) as usize];
95 pattern >>= 3;
96 }
97 if y == 1 {
98 pattern = pattern2;
99 }
100 }
101 }
102 }
103 Ok(())
104 }
105
106 fn decode_frame_v3(&mut self, br: &mut ByteReader, _ctype: u16) -> DecoderResult<()> {
107 let mut titer = self.tile_off.iter().enumerate();
108 let mut skip_mode = false;
109 while let Some((tile_no, &tile_off)) = titer.next() {
110 let op = br.read_byte()?;
111 if op < 0xF8 {
112 let clr0 = op;
113 let clr1 = br.read_byte()?;
114 if clr0 == clr1 {
115 for dline in self.frame[tile_off..].chunks_mut(self.w).take(self.tile_h) {
116 for el in dline[..self.tile_w].iter_mut() {
117 *el = clr0;
118 }
119 }
120 } else {
121 let mut pattern = br.read_u16le()?;
122 for dline in self.frame[tile_off..].chunks_mut(self.w).take(self.tile_h) {
123 for el in dline[..self.tile_w].iter_mut() {
124 *el = if (pattern & 0x8000) == 0 { clr0 } else { clr1 };
125 pattern <<= 1;
126 }
127 }
128 }
129 } else {
130 match op {
131 0xF8 => {
132 unimplemented!();
133 },
134 0xF9 => {
135 let run = br.read_byte()? as usize;
136 validate!(run > 0);
137
138 validate!(tile_no > 0);
139 let mut tile_off = tile_off;
140 for i in 0..run {
141 if !skip_mode {
142 copy_tile!(self, tile_off, self.tile_off[tile_no - 1]);
143 }
144 if i + 1 < run {
145 let (_tno, &toff) = titer.next().unwrap();
146 tile_off = toff;
147 }
148 }
149 },
150 0xFA => {
151 let off = br.read_u16le()? as usize;
152 validate!(tile_no + off < self.tile_off.len());
153 copy_tile!(self, tile_off, self.tile_off[tile_no + off]);
154 },
155 0xFB => {
156 let off = br.read_u16le()? as usize;
157 validate!(off <= tile_no);
158 copy_tile!(self, tile_off, self.tile_off[tile_no - off]);
159 },
160 0xFC => {
161 const MV_PART: [i8; 16] = [ 0, 4, 8, 12, 16, 20, 24, 28, -32, -4, -8, -12, -16, -20, -24, -28 ];
162
163 let idx = br.read_byte()? as usize;
164 let x = MV_PART[(idx & 0xF) as usize] as isize;
165 let y = MV_PART[(idx >> 4) as usize] as isize;
166 let src_off = (tile_off as isize) + x + y * (self.w as isize);
167 validate!(src_off >= 0);
168 validate!((src_off as usize) + self.tile_w + (self.tile_h - 1) * self.w <= self.w * self.h);
169
170 copy_tile!(self, tile_off, src_off as usize);
171 },
172 0xFD => {
173 let off = (br.read_byte()? as usize) + 1;
174 validate!(tile_no + off < self.tile_off.len());
175 copy_tile!(self, tile_off, self.tile_off[tile_no + off]);
176 },
177 0xFE => {
178 let off = (br.read_byte()? as usize) + 1;
179 validate!(off <= tile_no);
180 copy_tile!(self, tile_off, self.tile_off[tile_no - off]);
181 },
182 _ => {},
183 };
184 }
185 skip_mode = op == 0xFF;
186 }
187
188 Ok(())
189 }
190
191 fn decode_frame_5(&mut self, br: &mut ByteReader, _ctype: u16) -> DecoderResult<()> {
192 let mut titer = self.tile_off.iter().enumerate();
193 let mut last_mode = TileMode::Start;
194
195 while let Some((tile_no, &tile_off)) = titer.next() {
196 let op = br.read_byte()?;
197 if op < 0xF8 {
198 let clr0 = op;
199 let clr1 = br.read_byte()?;
200 if clr0 == clr1 {
201 for dline in self.frame[tile_off..].chunks_mut(self.w).take(self.tile_h) {
202 for el in dline[..self.tile_w].iter_mut() {
203 *el = clr0;
204 }
205 }
206 last_mode = TileMode::Fill;
207 } else {
208 let pat = br.read_byte()?;
209 let mut pattern = if pat < 128 {
210 last_mode = TileMode::ShortPattern(clr0, clr1);
211 self.patterns[pat as usize]
212 } else {
213 last_mode = TileMode::LongPattern(clr0, clr1);
214 u16::from(pat) | (u16::from(br.read_byte()?) << 8)
215 };
216 for dline in self.frame[tile_off..].chunks_mut(self.w).take(self.tile_h) {
217 for el in dline[..self.tile_w].iter_mut() {
218 *el = if (pattern & 0x8000) == 0 { clr0 } else { clr1 };
219 pattern <<= 1;
220 }
221 }
222 }
223 } else {
224 match op {
225 0xF8 => {
226 unimplemented!();
227 },
228 0xF9 => {
229 let run = br.read_byte()? as usize;
230 validate!(run > 0);
231
232 validate!(tile_no > 0);
233 validate!(last_mode != TileMode::Start);
234 let mut tile_no = tile_no;
235 let mut tile_off = tile_off;
236 for i in 0..run {
237 let copy_off = match last_mode {
238 TileMode::Forward(off) => {
239 tile_no + (off as usize)
240 },
241 TileMode::Backward(off) => {
242 validate!(tile_no >= (off as usize));
243 tile_no - (off as usize)
244 },
245 TileMode::Skip => self.tile_off.len(),
246 _ => tile_no - 1,
247 };
248 if copy_off < self.tile_off.len() {
249 copy_tile!(self, tile_off, self.tile_off[copy_off]);
250 }
251 if i + 1 < run {
252 let (tno, &toff) = titer.next().unwrap();
253 tile_no = tno;
254 tile_off = toff;
255 }
256 }
257 last_mode = TileMode::Run;
258 },
259 0xFA => {
260 let rtile = br.read_u16le()? as usize;
261 validate!(rtile < self.tile_off.len());
262 copy_tile!(self, tile_off, self.tile_off[rtile]);
263 last_mode = TileMode::Reuse;
264 },
265 0xFB => {
266 match self.mode {
267 6 => {
268 let run = br.read_byte()? as usize;
269 validate!(run >= 2);
270 let mut tile_no = tile_no;
271 let mut tile_off = tile_off;
272 for i in 0..run {
273 match last_mode {
274 TileMode::Start => return Err(DecoderError::InvalidData),
275 TileMode::Fill => {
276 let clr = br.read_byte()?;
277 for dline in self.frame[tile_off..].chunks_mut(self.w).take(self.tile_h) {
278 for el in dline[..self.tile_w].iter_mut() {
279 *el = clr;
280 }
281 }
282 },
283 TileMode::ShortPattern(clr0, clr1) => {
284 let pat = br.read_byte()?;
285 let mut pattern = if pat < 128 {
286 self.patterns[pat as usize]
287 } else {
288 u16::from(pat) | (u16::from(br.read_byte()?) << 8)
289 };
290 for dline in self.frame[tile_off..].chunks_mut(self.w).take(self.tile_h) {
291 for el in dline[..self.tile_w].iter_mut() {
292 *el = if (pattern & 0x8000) == 0 { clr0 } else { clr1 };
293 pattern <<= 1;
294 }
295 }
296 },
297 TileMode::LongPattern(clr0, clr1) => {
298 let mut pattern = br.read_u16le()?;
299 for dline in self.frame[tile_off..].chunks_mut(self.w).take(self.tile_h) {
300 for el in dline[..self.tile_w].iter_mut() {
301 *el = if (pattern & 0x8000) == 0 { clr0 } else { clr1 };
302 pattern <<= 1;
303 }
304 }
305 },
306 TileMode::Reuse => {
307 let rtile = br.read_u16le()? as usize;
308 validate!(rtile < self.tile_off.len());
309 copy_tile!(self, tile_off, self.tile_off[rtile]);
310 },
311 TileMode::MV => {
312 let idx = br.read_byte()? as usize;
313 let (x, y) = DEF_MVS[idx];
314 let src_off = (tile_off as isize) + (x as isize) * 4 + (y as isize) * 4 * (self.w as isize);
315 validate!(src_off >= 0);
316 validate!((src_off as usize) + self.tile_w + (self.tile_h - 1) * self.w <= self.w * self.h);
317 copy_tile!(self, tile_off, src_off as usize);
318 },
319 TileMode::Forward(_) => {
320 let off = (br.read_byte()? as usize) + 1;
321 validate!(tile_no + off < self.tile_off.len());
322 copy_tile!(self, tile_off, self.tile_off[tile_no + off]);
323 },
324 TileMode::Backward(_) => {
325 let off = (br.read_byte()? as usize) + 1;
326 validate!(off <= tile_no);
327 copy_tile!(self, tile_off, self.tile_off[tile_no - off]);
328 },
329 _ => unimplemented!(),
330 };
331
332 if i + 1 < run {
333 let (tno, &toff) = titer.next().unwrap();
334 tile_no = tno;
335 tile_off = toff;
336 }
337 }
338 },
339 7 => {
340 validate!(self.tile_w == 4 && self.tile_h == 4);
341 let run = br.read_byte()? as usize;
342 validate!(run > 0);
343
344 let mut tile_off = tile_off;
345 for i in 0..run {
346 Self::decode_mode7_tile(&mut self.frame[tile_off..], self.w, br)?;
347
348 if i + 1 < run {
349 let (_tno, &toff) = titer.next().unwrap();
350 tile_off = toff;
351 }
352 }
353 },
354 _ => {
355 unimplemented!();
356 },
357 };
358 last_mode = TileMode::FB;
359 },
360 0xFC => {
361 let idx = br.read_byte()? as usize;
362 let (x, y) = DEF_MVS[idx];
363 let src_off = (tile_off as isize) + (x as isize) * 4 + (y as isize) * 4 * (self.w as isize);
364 validate!(src_off >= 0);
365 validate!((src_off as usize) + self.tile_w + (self.tile_h - 1) * self.w <= self.w * self.h);
366
367 copy_tile!(self, tile_off, src_off as usize);
368 last_mode = TileMode::MV;
369 },
370 0xFD => {
371 let off = (br.read_byte()? as usize) + 1;
372 validate!(tile_no + off < self.tile_off.len());
373 copy_tile!(self, tile_off, self.tile_off[tile_no + off]);
374 last_mode = TileMode::Forward(off as u16);
375 },
376 0xFE => {
377 let off = (br.read_byte()? as usize) + 1;
378 validate!(off <= tile_no);
379 copy_tile!(self, tile_off, self.tile_off[tile_no - off]);
380 last_mode = TileMode::Backward(off as u16);
381 },
382 _ => {
383 last_mode = TileMode::Skip;
384 },
385 };
386 }
387 }
388
389 Ok(())
390 }
391 fn decode_frame_7(&mut self, br: &mut ByteReader, _ctype: u16) -> DecoderResult<()> {
392 let mut titer = self.tile_off.iter().enumerate();
393 let mut last_mode = TileMode::Start;
394
395 let mut f8_mode = false;
396 let row_size = self.w / self.tile_w;
397 let mut next_row = 0;
398 let mut f8_data = [0; 16];
399 let mut f8_pos = 0;
400
401 while let Some((tile_no, &tile_off)) = titer.next() {
402 if tile_no == next_row {
403 f8_mode = false;
404 next_row += row_size;
405 }
406 while br.peek_byte()? == 0xF8 {
407 br.read_byte()?;
408 if f8_mode {
409 f8_mode = false;
410 } else {
411 let idx = br.read_byte()? as usize;
412 if idx < 0x10 {
413 validate!(f8_pos < self.f8_cache.len());
414 br.peek_buf(&mut self.f8_cache[f8_pos])?;
415 if idx > 0 {
416 br.read_skip(idx)?;
417 }
418 f8_data = self.f8_cache[f8_pos];
419 } else {
420 f8_data = self.f8_cache[idx - 0x10];
421 self.f8_cache[f8_pos] = f8_data;
422 }
423 f8_pos += 1;
424 f8_mode = true;
425 }
426 }
427
428 let op = br.read_byte()?;
429 if op < 0xF8 {
430 let (clr0, clr1) = if !f8_mode {
431 if br.peek_byte()? < 0xF8 {
432 (op, br.read_byte()?)
433 } else {
434 (op, op)
435 }
436 } else {
437 (f8_data[(op & 0xF) as usize], f8_data[(op >> 4) as usize])
438 };
439 if clr0 == clr1 && (!f8_mode || ((op & 0xF) == (op >> 4))) {
440 for dline in self.frame[tile_off..].chunks_mut(self.w).take(self.tile_h) {
441 for el in dline[..self.tile_w].iter_mut() {
442 *el = clr0;
443 }
444 }
445 last_mode = TileMode::Fill;
446 } else {
447 let pat = br.read_byte()?;
448 let mut pattern = if pat < 128 {
449 last_mode = TileMode::ShortPattern(clr0, clr1);
450 self.patterns[pat as usize]
451 } else {
452 last_mode = TileMode::LongPattern(clr0, clr1);
453 u16::from(pat) | (u16::from(br.read_byte()?) << 8)
454 };
455 for dline in self.frame[tile_off..].chunks_mut(self.w).take(self.tile_h) {
456 for el in dline[..self.tile_w].iter_mut() {
457 *el = if (pattern & 0x8000) == 0 { clr0 } else { clr1 };
458 pattern <<= 1;
459 }
460 }
461 }
462 } else {
463 match op {
464 0xF8 => {
465 unreachable!();
466 },
467 0xF9 => {
468 let run = br.read_byte()? as usize;
469 validate!(run > 0);
470
471 validate!(tile_no > 0);
472 validate!(last_mode != TileMode::Start);
473 let mut tile_no = tile_no;
474 let mut tile_off = tile_off;
475 for i in 0..run {
476 let copy_off = match last_mode {
477 TileMode::Forward(off) => {
478 tile_no + (off as usize)
479 },
480 TileMode::Backward(off) => {
481 validate!(tile_no >= (off as usize));
482 tile_no - (off as usize)
483 },
484 TileMode::Skip => self.tile_off.len(),
485 _ => tile_no - 1,
486 };
487 if copy_off < self.tile_off.len() {
488 copy_tile!(self, tile_off, self.tile_off[copy_off]);
489 }
490 if i + 1 < run {
491 let (tno, &toff) = titer.next().unwrap();
492 tile_no = tno;
493 tile_off = toff;
494 }
495 }
496 last_mode = TileMode::Run;
497 },
498 0xFA => {
499 let rtile = br.read_u16le()? as usize;
500 validate!(rtile < self.tile_off.len());
501 copy_tile!(self, tile_off, self.tile_off[rtile]);
502 last_mode = TileMode::Reuse;
503 },
504 0xFB => {
505 match self.mode {
506 6 => {
507 let run = br.read_byte()? as usize;
508 validate!(run >= 2);
509 let mut tile_no = tile_no;
510 let mut tile_off = tile_off;
511 for i in 0..run {
512 match last_mode {
513 TileMode::Start => return Err(DecoderError::InvalidData),
514 TileMode::Fill => {
515 let clr = br.read_byte()?;
516 for dline in self.frame[tile_off..].chunks_mut(self.w).take(self.tile_h) {
517 for el in dline[..self.tile_w].iter_mut() {
518 *el = clr;
519 }
520 }
521 },
522 TileMode::ShortPattern(clr0, clr1) => {
523 let pat = br.read_byte()?;
524 let mut pattern = if pat < 128 {
525 self.patterns[pat as usize]
526 } else {
527 u16::from(pat) | (u16::from(br.read_byte()?) << 8)
528 };
529 for dline in self.frame[tile_off..].chunks_mut(self.w).take(self.tile_h) {
530 for el in dline[..self.tile_w].iter_mut() {
531 *el = if (pattern & 0x8000) == 0 { clr0 } else { clr1 };
532 pattern <<= 1;
533 }
534 }
535 },
536 TileMode::LongPattern(clr0, clr1) => {
537 let mut pattern = br.read_u16le()?;
538 for dline in self.frame[tile_off..].chunks_mut(self.w).take(self.tile_h) {
539 for el in dline[..self.tile_w].iter_mut() {
540 *el = if (pattern & 0x8000) == 0 { clr0 } else { clr1 };
541 pattern <<= 1;
542 }
543 }
544 },
545 TileMode::Reuse => {
546 let rtile = br.read_u16le()? as usize;
547 validate!(rtile < self.tile_off.len());
548 copy_tile!(self, tile_off, self.tile_off[rtile]);
549 },
550 TileMode::MV => {
551 let idx = br.read_byte()? as usize;
552 let (x, y) = DEF_MVS[idx];
553 let src_off = (tile_off as isize) + (x as isize) * 4 + (y as isize) * 4 * (self.w as isize);
554 validate!(src_off >= 0);
555 validate!((src_off as usize) + self.tile_w + (self.tile_h - 1) * self.w <= self.w * self.h);
556 copy_tile!(self, tile_off, src_off as usize);
557 },
558 TileMode::Forward(_) => {
559 let off = (br.read_byte()? as usize) + 1;
560 validate!(tile_no + off < self.tile_off.len());
561 copy_tile!(self, tile_off, self.tile_off[tile_no + off]);
562 },
563 TileMode::Backward(_) => {
564 let off = (br.read_byte()? as usize) + 1;
565 validate!(off <= tile_no);
566 copy_tile!(self, tile_off, self.tile_off[tile_no - off]);
567 },
568 _ => unimplemented!(),
569 };
570
571 if i + 1 < run {
572 let (tno, &toff) = titer.next().unwrap();
573 tile_no = tno;
574 tile_off = toff;
575 }
576 }
577 },
578 7 => {
579 validate!(self.tile_w == 4 && self.tile_h == 4);
580 let run = br.read_byte()? as usize;
581 validate!(run > 0);
582
583 let mut tile_off = tile_off;
584 for i in 0..run {
585 Self::decode_mode7_tile(&mut self.frame[tile_off..], self.w, br)?;
586
587 if i + 1 < run {
588 let (_tno, &toff) = titer.next().unwrap();
589 tile_off = toff;
590 }
591 }
592 },
593 _ => {
594 unimplemented!();
595 },
596 };
597 last_mode = TileMode::FB;
598 },
599 0xFC => {
600 let idx = br.read_byte()? as usize;
601 let (x, y) = DEF_MVS[idx];
602 let src_off = (tile_off as isize) + (x as isize) * 4 + (y as isize) * 4 * (self.w as isize);
603 validate!(src_off >= 0);
604 validate!((src_off as usize) + self.tile_w + (self.tile_h - 1) * self.w <= self.w * self.h);
605
606 copy_tile!(self, tile_off, src_off as usize);
607 last_mode = TileMode::MV;
608 },
609 0xFD => {
610 let off = (br.read_byte()? as usize) + 1;
611 validate!(tile_no + off < self.tile_off.len());
612 copy_tile!(self, tile_off, self.tile_off[tile_no + off]);
613 last_mode = TileMode::Forward(off as u16);
614 },
615 0xFE => {
616 let off = (br.read_byte()? as usize) + 1;
617 validate!(off <= tile_no);
618 copy_tile!(self, tile_off, self.tile_off[tile_no - off]);
619 last_mode = TileMode::Backward(off as u16);
620 },
621 _ => {
622 last_mode = TileMode::Skip;
623 },
624 };
625 }
626 }
627
628 Ok(())
629 }
630
631 fn output_frame(&mut self, bufinfo: &mut NABufferType, w: usize, h: usize) {
632 let bufo = bufinfo.get_vbuf();
633 let mut buf = bufo.unwrap();
634 let paloff = buf.get_offset(1);
635 let stride = buf.get_stride(0);
636 let data = buf.get_data_mut().unwrap();
637 let dst = data.as_mut_slice();
638
639 dst[paloff..][..768].copy_from_slice(&self.pal);
640 for (dline, sline) in dst.chunks_mut(stride).zip(self.frame.chunks(w)).take(h) {
641 dline[..w].copy_from_slice(sline);
642 }
643 }
644 }
645
646 impl NADecoder for QVideoDecoder {
647 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
648 if let NACodecTypeInfo::Video(_vinfo) = info.get_properties() {
649 let mut w;
650 let mut h;
651 if let Some(buf) = info.get_extradata() {
652 validate!(buf.len() >= 22);
653 w = read_u16le(&buf[4..])? as usize;
654 h = read_u16le(&buf[6..])? as usize;
655 self.tile_w = buf[8] as usize;
656 self.tile_h = buf[9] as usize;
657 validate!(self.tile_w > 0 && self.tile_h > 0);
658 if self.tile_w != 4 || self.tile_h != 4 {
659 return Err(DecoderError::NotImplemented);
660 }
661 self.version = buf[2];
662 if self.version != 3{
663 w *= self.tile_w;
664 h *= self.tile_h;
665 } else {
666 validate!((w % self.tile_w) == 0);
667 validate!((h % self.tile_h) == 0);
668 }
669 } else {
670 return Err(DecoderError::InvalidData);
671 }
672 let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(w, h, false, PAL8_FORMAT));
673 self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
674 self.w = w;
675 self.h = h;
676
677 self.mode = match self.version {
678 4 => 6,
679 5 => 7,
680 7 => 7,
681 _ => 0,
682 };
683
684 self.frame.resize(w * h, 0);
685 self.pal = [0; 768];
686 self.tile_off = Vec::with_capacity((w / self.tile_w) * (h / self.tile_h));
687 let mut off = 0;
688 for _y in (0..h).step_by(self.tile_h) {
689 for x in (0..w).step_by(self.tile_w) {
690 self.tile_off.push(off + x);
691 }
692 off += w * self.tile_h;
693 }
694 Ok(())
695 } else {
696 Err(DecoderError::InvalidData)
697 }
698 }
699 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
700 let src = pkt.get_buffer();
701 validate!(!src.is_empty());
702
703 let mut mr = MemoryReader::new_read(&src);
704 let mut br = ByteReader::new(&mut mr);
705
706 while br.left() >= 6 {
707 let ctype = br.read_u16le()?;
708 let csize = br.read_u32le()? as usize;
709 validate!(csize <= (br.left() as usize));
710 match ctype {
711 1 => {
712 validate!(csize <= 768);
713 br.read_buf(&mut self.pal[..csize])?;
714 for el in self.pal[..csize].iter_mut() {
715 *el = (*el << 2) | (*el >> 4);
716 }
717 },
718 2 | 3 | 4 | 9 | 11 => {
719 if self.version == 5 {
720 self.mode = if ctype == 9 || ctype == 11 { 7 } else { 6 };
721 }
722 if self.version == 3 {
723 self.decode_frame_v3(&mut br, ctype)?;
724 } else if self.version < 7 {
725 self.decode_frame_5(&mut br, ctype)?;
726 } else {
727 self.mode = if ctype == 11 { 7 } else { 6 };
728 self.decode_frame_7(&mut br, ctype)?;
729 }
730 },
731 5 => {
732 validate!(csize <= 256 && (csize & 1) == 0);
733 for el in self.patterns[..csize/2].iter_mut() {
734 *el = br.read_u16le()?;
735 }
736 },
737 6 | 7 => {
738 self.mode = ctype as u8;
739 },
740 _ => return Err(DecoderError::InvalidData),
741 };
742 }
743
744 let mut bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 0)?;
745
746 self.output_frame(&mut bufinfo, self.w, self.h);
747
748 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo);
749 frm.set_frame_type(if pkt.is_keyframe() { FrameType::I } else { FrameType::P });
750 Ok(frm.into_ref())
751 }
752 fn flush(&mut self) {
753 }
754 }
755
756 impl NAOptionHandler for QVideoDecoder {
757 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
758 fn set_options(&mut self, _options: &[NAOption]) { }
759 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
760 }
761
762 pub fn get_decoder() -> Box<dyn NADecoder + Send> {
763 Box::new(QVideoDecoder::new())
764 }
765
766 #[cfg(test)]
767 mod test {
768 use nihav_core::codecs::RegisteredDecoders;
769 use nihav_core::demuxers::RegisteredDemuxers;
770 use nihav_codec_support::test::dec_video::*;
771 use crate::game_register_all_decoders;
772 use crate::game_register_all_demuxers;
773
774 // samples from Callahan's Crosstime Saloon, Deathgate, Mission Critical and Shannara games
775 #[test]
776 fn test_q_video3() {
777 let mut dmx_reg = RegisteredDemuxers::new();
778 game_register_all_demuxers(&mut dmx_reg);
779 let mut dec_reg = RegisteredDecoders::new();
780 game_register_all_decoders(&mut dec_reg);
781
782 test_decoding("legend-q", "legend-q-video", "assets/Game/dgate101.q", Some(31), &dmx_reg, &dec_reg,
783 ExpectedTestResult::MD5([0x9cc0014c, 0xf6332802, 0xfabeb715, 0xdfaa11c0]));
784 }
785 #[test]
786 fn test_q_video4() {
787 let mut dmx_reg = RegisteredDemuxers::new();
788 game_register_all_demuxers(&mut dmx_reg);
789 let mut dec_reg = RegisteredDecoders::new();
790 game_register_all_decoders(&mut dec_reg);
791
792 test_decoding("legend-q", "legend-q-video", "assets/Game/1925.Q", None, &dmx_reg, &dec_reg,
793 ExpectedTestResult::MD5([0xe1af971a, 0xfb509816, 0x9d60f5d6, 0xbcf48a3b]));
794 }
795 #[test]
796 fn test_q_video5() {
797 let mut dmx_reg = RegisteredDemuxers::new();
798 game_register_all_demuxers(&mut dmx_reg);
799 let mut dec_reg = RegisteredDecoders::new();
800 game_register_all_decoders(&mut dec_reg);
801
802 test_decoding("legend-q", "legend-q-video", "assets/Game/mc703.q", Some(16), &dmx_reg, &dec_reg,
803 ExpectedTestResult::MD5([0xf65ea3ce, 0x3052b2bb, 0xb10f8f69, 0x530d60f9]));
804 }
805 #[test]
806 fn test_q_video7() {
807 let mut dmx_reg = RegisteredDemuxers::new();
808 game_register_all_demuxers(&mut dmx_reg);
809 let mut dec_reg = RegisteredDecoders::new();
810 game_register_all_decoders(&mut dec_reg);
811
812 test_decoding("legend-q", "legend-q-video", "assets/Game/CCS003.Q", Some(16), &dmx_reg, &dec_reg,
813 ExpectedTestResult::MD5([0x4c0f0712, 0xc6c39f5b, 0x5bb6902f, 0x9119940e]));
814 }
815 }
816
817 const DEF_MVS: [(i8, i8); 256] = [
818 ( 0, 8), ( 1, 8), ( 2, 8), ( 3, 8), ( 4, 8), ( 5, 8), ( 6, 8), ( 7, 8),
819 (-8, 8), (-1, 8), (-2, 8), (-3, 8), (-4, 8), (-5, 8), (-6, 8), (-7, 8),
820 ( 0, 9), ( 1, 9), ( 2, 9), ( 3, 9), ( 4, 9), ( 5, 9), ( 6, 9), ( 7, 9),
821 (-8, 9), (-1, 9), (-2, 9), (-3, 9), (-4, 9), (-5, 9), (-6, 9), (-7, 9),
822 ( 0, 2), ( 1, 2), ( 2, 2), ( 3, 2), ( 4, 2), ( 5, 2), ( 6, 2), ( 7, 2),
823 (-8, 2), (-1, 2), (-2, 2), (-3, 2), (-4, 2), (-5, 2), (-6, 2), (-7, 2),
824 ( 0, 3), ( 1, 3), ( 2, 3), ( 3, 3), ( 4, 3), ( 5, 3), ( 6, 3), ( 7, 3),
825 (-8, 3), (-1, 3), (-2, 3), (-3, 3), (-4, 3), (-5, 3), (-6, 3), (-7, 3),
826 ( 0, 4), ( 1, 4), ( 2, 4), ( 3, 4), ( 4, 4), ( 5, 4), ( 6, 4), ( 7, 4),
827 (-8, 4), (-1, 4), (-2, 4), (-3, 4), (-4, 4), (-5, 4), (-6, 4), (-7, 4),
828 ( 0, 5), ( 1, 5), ( 2, 5), ( 3, 5), ( 4, 5), ( 5, 5), ( 6, 5), ( 7, 5),
829 (-8, 5), (-1, 5), (-2, 5), (-3, 5), (-4, 5), (-5, 5), (-6, 5), (-7, 5),
830 ( 0, 6), ( 1, 6), ( 2, 6), ( 3, 6), ( 4, 6), ( 5, 6), ( 6, 6), ( 7, 6),
831 (-8, 6), (-1, 6), (-2, 6), (-3, 6), (-4, 6), (-5, 6), (-6, 6), (-7, 6),
832 ( 0, 7), ( 1, 7), ( 2, 7), ( 3, 7), ( 4, 7), ( 5, 7), ( 6, 7), ( 7, 7),
833 (-8, 7), (-1, 7), (-2, 7), (-3, 7), (-4, 7), (-5, 7), (-6, 7), (-7, 7),
834 ( 0,-8), ( 1,-8), ( 2,-8), ( 3,-8), ( 4,-8), ( 5,-8), ( 6,-8), ( 7,-8),
835 (-8,-8), (-1,-8), (-2,-8), (-3,-8), (-4,-8), (-5,-8), (-6,-8), (-7,-8),
836 ( 0,-9), ( 1,-9), ( 2,-9), ( 3,-9), ( 4,-9), ( 5,-9), ( 6,-9), ( 7,-9),
837 (-8,-9), (-1,-9), (-2,-9), (-3,-9), (-4,-9), (-5,-9), (-6,-9), (-7,-9),
838 ( 0,-2), ( 1,-2), ( 2,-2), ( 3,-2), ( 4,-2), ( 5,-2), ( 6,-2), ( 7,-2),
839 (-8,-2), (-1,-2), (-2,-2), (-3,-2), (-4,-2), (-5,-2), (-6,-2), (-7,-2),
840 ( 0,-3), ( 1,-3), ( 2,-3), ( 3,-3), ( 4,-3), ( 5,-3), ( 6,-3), ( 7,-3),
841 (-8,-3), (-1,-3), (-2,-3), (-3,-3), (-4,-3), (-5,-3), (-6,-3), (-7,-3),
842 ( 0,-4), ( 1,-4), ( 2,-4), ( 3,-4), ( 4,-4), ( 5,-4), ( 6,-4), ( 7,-4),
843 (-8,-4), (-1,-4), (-2,-4), (-3,-4), (-4,-4), (-5,-4), (-6,-4), (-7,-4),
844 ( 0,-5), ( 1,-5), ( 2,-5), ( 3,-5), ( 4,-5), ( 5,-5), ( 6,-5), ( 7,-5),
845 (-8,-5), (-1,-5), (-2,-5), (-3,-5), (-4,-5), (-5,-5), (-6,-5), (-7,-5),
846 ( 0,-6), ( 1,-6), ( 2,-6), ( 3,-6), ( 4,-6), ( 5,-6), ( 6,-6), ( 7,-6),
847 (-8,-6), (-1,-6), (-2,-6), (-3,-6), (-4,-6), (-5,-6), (-6,-6), (-7,-6),
848 ( 0,-7), ( 1,-7), ( 2,-7), ( 3,-7), ( 4,-7), ( 5,-7), ( 6,-7), ( 7,-7),
849 (-8,-7), (-1,-7), (-2,-7), (-3,-7), (-4,-7), (-5,-7), (-6,-7), (-7,-7)
850 ];