]>
Commit | Line | Data |
---|---|---|
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 | 6 => 7, | |
681 | 7 => 7, | |
682 | _ => 0, | |
683 | }; | |
684 | ||
685 | self.frame.resize(w * h, 0); | |
686 | self.pal = [0; 768]; | |
687 | self.tile_off = Vec::with_capacity((w / self.tile_w) * (h / self.tile_h)); | |
688 | let mut off = 0; | |
689 | for _y in (0..h).step_by(self.tile_h) { | |
690 | for x in (0..w).step_by(self.tile_w) { | |
691 | self.tile_off.push(off + x); | |
692 | } | |
693 | off += w * self.tile_h; | |
694 | } | |
695 | Ok(()) | |
696 | } else { | |
697 | Err(DecoderError::InvalidData) | |
698 | } | |
699 | } | |
700 | fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { | |
701 | let src = pkt.get_buffer(); | |
702 | validate!(!src.is_empty()); | |
703 | ||
704 | let mut mr = MemoryReader::new_read(&src); | |
705 | let mut br = ByteReader::new(&mut mr); | |
706 | ||
707 | while br.left() >= 6 { | |
708 | let ctype = br.read_u16le()?; | |
709 | let csize = br.read_u32le()? as usize; | |
710 | validate!(csize <= (br.left() as usize)); | |
711 | match ctype { | |
712 | 1 => { | |
713 | validate!(csize <= 768); | |
714 | br.read_buf(&mut self.pal[..csize])?; | |
715 | for el in self.pal[..csize].iter_mut() { | |
716 | *el = (*el << 2) | (*el >> 4); | |
717 | } | |
718 | }, | |
719 | 2 | 3 | 4 | 9 | 11 => { | |
720 | if self.version == 5 { | |
721 | self.mode = if ctype == 9 || ctype == 11 { 7 } else { 6 }; | |
722 | } | |
723 | if self.version == 3 { | |
724 | self.decode_frame_v3(&mut br, ctype)?; | |
725 | } else if self.version < 6 { | |
726 | self.decode_frame_5(&mut br, ctype)?; | |
727 | } else { | |
728 | self.mode = if ctype == 11 { 7 } else { 6 }; | |
729 | self.decode_frame_7(&mut br, ctype)?; | |
730 | } | |
731 | }, | |
732 | 5 => { | |
733 | validate!(csize <= 256 && (csize & 1) == 0); | |
734 | for el in self.patterns[..csize/2].iter_mut() { | |
735 | *el = br.read_u16le()?; | |
736 | } | |
737 | }, | |
738 | 6 | 7 => { | |
739 | self.mode = ctype as u8; | |
740 | }, | |
741 | _ => return Err(DecoderError::InvalidData), | |
742 | }; | |
743 | } | |
744 | ||
745 | let mut bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 0)?; | |
746 | ||
747 | self.output_frame(&mut bufinfo, self.w, self.h); | |
748 | ||
749 | let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo); | |
750 | frm.set_frame_type(if pkt.is_keyframe() { FrameType::I } else { FrameType::P }); | |
751 | Ok(frm.into_ref()) | |
752 | } | |
753 | fn flush(&mut self) { | |
754 | } | |
755 | } | |
756 | ||
757 | impl NAOptionHandler for QVideoDecoder { | |
758 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
759 | fn set_options(&mut self, _options: &[NAOption]) { } | |
760 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
761 | } | |
762 | ||
763 | pub fn get_decoder() -> Box<dyn NADecoder + Send> { | |
764 | Box::new(QVideoDecoder::new()) | |
765 | } | |
766 | ||
767 | #[cfg(test)] | |
768 | mod test { | |
769 | use nihav_core::codecs::RegisteredDecoders; | |
770 | use nihav_core::demuxers::RegisteredDemuxers; | |
771 | use nihav_codec_support::test::dec_video::*; | |
772 | use crate::game_register_all_decoders; | |
773 | use crate::game_register_all_demuxers; | |
774 | ||
775 | // samples from Callahan's Crosstime Saloon, Deathgate, Mission Critical and Shannara games | |
776 | #[test] | |
777 | fn test_q_video3() { | |
778 | let mut dmx_reg = RegisteredDemuxers::new(); | |
779 | game_register_all_demuxers(&mut dmx_reg); | |
780 | let mut dec_reg = RegisteredDecoders::new(); | |
781 | game_register_all_decoders(&mut dec_reg); | |
782 | ||
783 | test_decoding("legend-q", "legend-q-video", "assets/Game/dgate101.q", Some(31), &dmx_reg, &dec_reg, | |
784 | ExpectedTestResult::MD5([0x9cc0014c, 0xf6332802, 0xfabeb715, 0xdfaa11c0])); | |
785 | } | |
786 | #[test] | |
787 | fn test_q_video4() { | |
788 | let mut dmx_reg = RegisteredDemuxers::new(); | |
789 | game_register_all_demuxers(&mut dmx_reg); | |
790 | let mut dec_reg = RegisteredDecoders::new(); | |
791 | game_register_all_decoders(&mut dec_reg); | |
792 | ||
793 | test_decoding("legend-q", "legend-q-video", "assets/Game/1925.Q", None, &dmx_reg, &dec_reg, | |
794 | ExpectedTestResult::MD5([0xe1af971a, 0xfb509816, 0x9d60f5d6, 0xbcf48a3b])); | |
795 | } | |
796 | #[test] | |
797 | fn test_q_video5() { | |
798 | let mut dmx_reg = RegisteredDemuxers::new(); | |
799 | game_register_all_demuxers(&mut dmx_reg); | |
800 | let mut dec_reg = RegisteredDecoders::new(); | |
801 | game_register_all_decoders(&mut dec_reg); | |
802 | ||
803 | test_decoding("legend-q", "legend-q-video", "assets/Game/mc703.q", Some(16), &dmx_reg, &dec_reg, | |
804 | ExpectedTestResult::MD5([0xf65ea3ce, 0x3052b2bb, 0xb10f8f69, 0x530d60f9])); | |
805 | } | |
806 | #[test] | |
807 | fn test_q_video7() { | |
808 | let mut dmx_reg = RegisteredDemuxers::new(); | |
809 | game_register_all_demuxers(&mut dmx_reg); | |
810 | let mut dec_reg = RegisteredDecoders::new(); | |
811 | game_register_all_decoders(&mut dec_reg); | |
812 | ||
813 | test_decoding("legend-q", "legend-q-video", "assets/Game/CCS003.Q", Some(16), &dmx_reg, &dec_reg, | |
814 | ExpectedTestResult::MD5([0x4c0f0712, 0xc6c39f5b, 0x5bb6902f, 0x9119940e])); | |
815 | } | |
816 | } | |
817 | ||
818 | const DEF_MVS: [(i8, i8); 256] = [ | |
819 | ( 0, 8), ( 1, 8), ( 2, 8), ( 3, 8), ( 4, 8), ( 5, 8), ( 6, 8), ( 7, 8), | |
820 | (-8, 8), (-1, 8), (-2, 8), (-3, 8), (-4, 8), (-5, 8), (-6, 8), (-7, 8), | |
821 | ( 0, 9), ( 1, 9), ( 2, 9), ( 3, 9), ( 4, 9), ( 5, 9), ( 6, 9), ( 7, 9), | |
822 | (-8, 9), (-1, 9), (-2, 9), (-3, 9), (-4, 9), (-5, 9), (-6, 9), (-7, 9), | |
823 | ( 0, 2), ( 1, 2), ( 2, 2), ( 3, 2), ( 4, 2), ( 5, 2), ( 6, 2), ( 7, 2), | |
824 | (-8, 2), (-1, 2), (-2, 2), (-3, 2), (-4, 2), (-5, 2), (-6, 2), (-7, 2), | |
825 | ( 0, 3), ( 1, 3), ( 2, 3), ( 3, 3), ( 4, 3), ( 5, 3), ( 6, 3), ( 7, 3), | |
826 | (-8, 3), (-1, 3), (-2, 3), (-3, 3), (-4, 3), (-5, 3), (-6, 3), (-7, 3), | |
827 | ( 0, 4), ( 1, 4), ( 2, 4), ( 3, 4), ( 4, 4), ( 5, 4), ( 6, 4), ( 7, 4), | |
828 | (-8, 4), (-1, 4), (-2, 4), (-3, 4), (-4, 4), (-5, 4), (-6, 4), (-7, 4), | |
829 | ( 0, 5), ( 1, 5), ( 2, 5), ( 3, 5), ( 4, 5), ( 5, 5), ( 6, 5), ( 7, 5), | |
830 | (-8, 5), (-1, 5), (-2, 5), (-3, 5), (-4, 5), (-5, 5), (-6, 5), (-7, 5), | |
831 | ( 0, 6), ( 1, 6), ( 2, 6), ( 3, 6), ( 4, 6), ( 5, 6), ( 6, 6), ( 7, 6), | |
832 | (-8, 6), (-1, 6), (-2, 6), (-3, 6), (-4, 6), (-5, 6), (-6, 6), (-7, 6), | |
833 | ( 0, 7), ( 1, 7), ( 2, 7), ( 3, 7), ( 4, 7), ( 5, 7), ( 6, 7), ( 7, 7), | |
834 | (-8, 7), (-1, 7), (-2, 7), (-3, 7), (-4, 7), (-5, 7), (-6, 7), (-7, 7), | |
835 | ( 0,-8), ( 1,-8), ( 2,-8), ( 3,-8), ( 4,-8), ( 5,-8), ( 6,-8), ( 7,-8), | |
836 | (-8,-8), (-1,-8), (-2,-8), (-3,-8), (-4,-8), (-5,-8), (-6,-8), (-7,-8), | |
837 | ( 0,-9), ( 1,-9), ( 2,-9), ( 3,-9), ( 4,-9), ( 5,-9), ( 6,-9), ( 7,-9), | |
838 | (-8,-9), (-1,-9), (-2,-9), (-3,-9), (-4,-9), (-5,-9), (-6,-9), (-7,-9), | |
839 | ( 0,-2), ( 1,-2), ( 2,-2), ( 3,-2), ( 4,-2), ( 5,-2), ( 6,-2), ( 7,-2), | |
840 | (-8,-2), (-1,-2), (-2,-2), (-3,-2), (-4,-2), (-5,-2), (-6,-2), (-7,-2), | |
841 | ( 0,-3), ( 1,-3), ( 2,-3), ( 3,-3), ( 4,-3), ( 5,-3), ( 6,-3), ( 7,-3), | |
842 | (-8,-3), (-1,-3), (-2,-3), (-3,-3), (-4,-3), (-5,-3), (-6,-3), (-7,-3), | |
843 | ( 0,-4), ( 1,-4), ( 2,-4), ( 3,-4), ( 4,-4), ( 5,-4), ( 6,-4), ( 7,-4), | |
844 | (-8,-4), (-1,-4), (-2,-4), (-3,-4), (-4,-4), (-5,-4), (-6,-4), (-7,-4), | |
845 | ( 0,-5), ( 1,-5), ( 2,-5), ( 3,-5), ( 4,-5), ( 5,-5), ( 6,-5), ( 7,-5), | |
846 | (-8,-5), (-1,-5), (-2,-5), (-3,-5), (-4,-5), (-5,-5), (-6,-5), (-7,-5), | |
847 | ( 0,-6), ( 1,-6), ( 2,-6), ( 3,-6), ( 4,-6), ( 5,-6), ( 6,-6), ( 7,-6), | |
848 | (-8,-6), (-1,-6), (-2,-6), (-3,-6), (-4,-6), (-5,-6), (-6,-6), (-7,-6), | |
849 | ( 0,-7), ( 1,-7), ( 2,-7), ( 3,-7), ( 4,-7), ( 5,-7), ( 6,-7), ( 7,-7), | |
850 | (-8,-7), (-1,-7), (-2,-7), (-3,-7), (-4,-7), (-5,-7), (-6,-7), (-7,-7) | |
851 | ]; |