Commit | Line | Data |
---|---|---|
5641dccf KS |
1 | use nihav_core::formats; |
2 | use nihav_core::codecs::*; | |
5641dccf | 3 | use nihav_core::io::byteio::*; |
afe29743 KS |
4 | use std::io::SeekFrom; |
5 | use std::mem; | |
4d965fde | 6 | use super::indeo3data::*; |
afe29743 KS |
7 | |
8 | #[derive(Clone, Copy)] | |
9 | struct MV { | |
10 | x: i8, | |
11 | y: i8 | |
12 | } | |
13 | ||
14 | struct Buffers { | |
15 | width: usize, | |
16 | height: usize, | |
7a95487c KS |
17 | cw: usize, |
18 | ch: usize, | |
7241e094 KS |
19 | sbuf: Vec<u8>, |
20 | dbuf: Vec<u8>, | |
afe29743 KS |
21 | } |
22 | ||
23 | const DEFAULT_PIXEL: u8 = 0x40; | |
24 | ||
25 | impl Buffers { | |
7241e094 | 26 | fn new() -> Self { Buffers { width: 0, height: 0, cw: 0, ch: 0, sbuf: Vec::new(), dbuf: Vec::new() } } |
afe29743 KS |
27 | fn reset(&mut self) { |
28 | self.width = 0; | |
29 | self.height = 0; | |
37952415 KS |
30 | self.sbuf.clear(); |
31 | self.dbuf.clear(); | |
afe29743 KS |
32 | } |
33 | fn alloc(&mut self, w: usize, h: usize) { | |
34 | self.width = w; | |
35 | self.height = h; | |
7a95487c KS |
36 | self.cw = ((w >> 2) + 3) & !3; |
37 | self.ch = ((h >> 2) + 3) & !3; | |
7241e094 KS |
38 | self.sbuf.resize(w * h + self.cw * self.ch * 2, DEFAULT_PIXEL); |
39 | self.dbuf.resize(w * h + self.cw * self.ch * 2, DEFAULT_PIXEL); | |
afe29743 | 40 | } |
7241e094 | 41 | fn flip(&mut self) { std::mem::swap(&mut self.sbuf, &mut self.dbuf); } |
afe29743 | 42 | fn get_stride(&mut self, planeno: usize) -> usize { |
7a95487c | 43 | if planeno == 0 { self.width } else { self.cw } |
afe29743 KS |
44 | } |
45 | fn get_offset(&mut self, planeno: usize) -> usize { | |
46 | match planeno { | |
47 | 1 => self.width * self.height, | |
7a95487c | 48 | 2 => self.width * self.height + self.cw * self.ch, |
afe29743 KS |
49 | _ => 0, |
50 | } | |
51 | } | |
52 | fn fill_framebuf(&mut self, fbuf: &mut NAVideoBuffer<u8>) { | |
53 | for planeno in 0..3 { | |
54 | let mut soff = self.get_offset(planeno); | |
55 | let mut doff = fbuf.get_offset(planeno); | |
56 | let sstride = self.get_stride(planeno); | |
57 | let dstride = fbuf.get_stride(planeno); | |
7a95487c | 58 | let width = if planeno == 0 { self.width } else { self.width >> 2 }; |
afe29743 | 59 | let height = if planeno == 0 { self.height } else { self.height >> 2 }; |
7241e094 | 60 | let src = self.dbuf.as_slice(); |
1a967e6b | 61 | let dst = fbuf.get_data_mut().unwrap(); |
afe29743 KS |
62 | for _ in 0..height { |
63 | for x in 0..width { | |
64 | dst[doff + x] = src[soff + x] * 2; | |
65 | } | |
66 | soff += sstride; | |
67 | doff += dstride; | |
68 | } | |
69 | } | |
70 | } | |
71 | fn copy_block(&mut self, doff: usize, soff: usize, stride: usize, w: usize, h: usize) { | |
72 | let mut sidx = soff; | |
73 | let mut didx = doff; | |
7241e094 | 74 | for _ in 0..h { |
5a6dec5f | 75 | self.dbuf[didx..][..w].copy_from_slice(&self.sbuf[sidx..][..w]); |
7241e094 KS |
76 | sidx += stride; |
77 | didx += stride; | |
afe29743 KS |
78 | } |
79 | } | |
80 | fn fill_block(&mut self, doff: usize, stride: usize, w: usize, h: usize, topline: bool) { | |
81 | let mut didx = doff; | |
82 | let mut buf: [u8; 8] = [0; 8]; | |
83 | if topline { | |
7241e094 KS |
84 | for _ in 0..h { |
85 | for i in 0..w { self.dbuf[didx + i] = DEFAULT_PIXEL; } | |
86 | didx += stride; | |
afe29743 KS |
87 | } |
88 | } else { | |
7241e094 KS |
89 | for i in 0..w { buf[i] = self.dbuf[didx - stride + i]; } |
90 | for _ in 0..h { | |
5a6dec5f | 91 | self.dbuf[didx..][..w].copy_from_slice(&buf[..w]); |
7241e094 | 92 | didx += stride; |
afe29743 KS |
93 | } |
94 | } | |
95 | } | |
96 | } | |
97 | ||
98 | #[allow(unused_variables)] | |
99 | fn apply_delta4x4(bufs: &mut Buffers, off: usize, stride: usize, | |
100 | deltas: &[u8], topline: bool, first_line: bool) { | |
7241e094 | 101 | let dst = &mut bufs.dbuf[off..][..4]; |
afe29743 KS |
102 | for i in 0..4 { dst[i] = dst[i].wrapping_add(deltas[i]) & 0x7F; } |
103 | } | |
104 | ||
105 | #[allow(unused_variables)] | |
106 | fn apply_delta4x8(bufs: &mut Buffers, off: usize, stride: usize, | |
107 | deltas: &[u8], topline: bool, first_line: bool) { | |
7241e094 | 108 | let dst = &mut bufs.dbuf[off..][..stride + 4]; |
afe29743 KS |
109 | for i in 0..4 { dst[i + stride] = dst[i].wrapping_add(deltas[i]) & 0x7F; } |
110 | if !topline { | |
111 | for i in 0..4 { dst[i] = (dst[i + stride] + dst[i]) >> 1; } | |
112 | } else { | |
113 | for i in 0..4 { dst[i] = dst[i + stride]; } | |
114 | } | |
115 | } | |
116 | ||
117 | #[allow(unused_variables)] | |
118 | fn apply_delta4x8m11(bufs: &mut Buffers, off: usize, stride: usize, | |
119 | deltas: &[u8], topline: bool, first_line: bool) { | |
7241e094 | 120 | let dst = &mut bufs.dbuf[off..][..stride + 4]; |
afe29743 KS |
121 | for i in 0..4 { dst[i] = dst[i] .wrapping_add(deltas[i]) & 0x7F; } |
122 | for i in 0..4 { dst[i + stride] = dst[i + stride].wrapping_add(deltas[i]) & 0x7F; } | |
123 | } | |
124 | ||
125 | #[allow(unused_variables)] | |
126 | fn apply_delta8x8p(bufs: &mut Buffers, off: usize, stride: usize, | |
127 | deltas: &[u8], topline: bool, first_line: bool) { | |
7241e094 | 128 | let dst = &mut bufs.dbuf[off..][..stride + 8]; |
afe29743 KS |
129 | for i in 0..8 { dst[i] = dst[i] .wrapping_add(deltas[i >> 1]) & 0x7F; } |
130 | for i in 0..8 { dst[i + stride] = dst[i + stride].wrapping_add(deltas[i >> 1]) & 0x7F; } | |
131 | } | |
132 | ||
133 | fn apply_delta8x8i(bufs: &mut Buffers, off: usize, stride: usize, | |
134 | deltas: &[u8], topline: bool, firstline: bool) { | |
7241e094 | 135 | let dst = &mut bufs.dbuf[off..][..stride + 8]; |
afe29743 KS |
136 | if !firstline { |
137 | for i in 0..8 { dst[i + stride] = dst[i ].wrapping_add(deltas[i >> 1]) & 0x7F; } | |
138 | } else { | |
139 | for i in 0..8 { dst[i + stride] = dst[i & !1].wrapping_add(deltas[i >> 1]) & 0x7F; } | |
140 | } | |
141 | if !topline { | |
142 | for i in 0..8 { dst[i] = (dst[i + stride] + dst[i]) >> 1; } | |
143 | } else { | |
144 | for i in 0..8 { dst[i] = dst[i + stride]; } | |
145 | } | |
146 | } | |
147 | ||
148 | fn copy_line_top(bufs: &mut Buffers, off: usize, stride: usize, bw: usize, topline: bool) { | |
149 | let mut buf: [u8; 8] = [0; 8]; | |
150 | if !topline { | |
7241e094 | 151 | let src = &bufs.dbuf[(off - stride)..(off - stride + bw)]; |
5a6dec5f | 152 | buf[..bw].copy_from_slice(&src[..bw]); |
afe29743 KS |
153 | } else { |
154 | for i in 0..bw { buf[i] = DEFAULT_PIXEL; } | |
155 | } | |
7241e094 | 156 | let dst = &mut bufs.dbuf[off..][..bw]; |
5a6dec5f | 157 | dst.copy_from_slice(&buf[..bw]); |
afe29743 KS |
158 | } |
159 | ||
160 | fn copy_line_top4x4(bufs: &mut Buffers, off: usize, stride: usize, topline: bool) { | |
161 | copy_line_top(bufs, off, stride, 4, topline); | |
162 | } | |
163 | ||
164 | fn copy_line_top4x8(bufs: &mut Buffers, off: usize, stride: usize, topline: bool) { | |
165 | copy_line_top(bufs, off, stride, 4, topline); | |
166 | copy_line_top(bufs, off + stride, stride, 4, false); | |
167 | } | |
168 | ||
169 | fn copy_line_top8x8(bufs: &mut Buffers, off: usize, stride: usize, topline: bool) { | |
170 | let mut buf: [u8; 8] = [0; 8]; | |
171 | if !topline { | |
7241e094 | 172 | let src = &bufs.dbuf[(off - stride)..(off - stride + 8)]; |
afe29743 KS |
173 | for i in 0..8 { buf[i] = src[i & !1]; } |
174 | } else { | |
175 | for i in 0..8 { buf[i] = DEFAULT_PIXEL; } | |
176 | } | |
7241e094 | 177 | let dst = &mut bufs.dbuf[off..][..8]; |
5a6dec5f | 178 | dst.copy_from_slice(&buf[..8]); |
afe29743 KS |
179 | } |
180 | ||
181 | fn fill_block8x8(bufs: &mut Buffers, doff: usize, stride: usize, h: usize, topline: bool, firstline: bool) { | |
182 | let mut didx = doff; | |
183 | let mut buf: [u8; 8] = [0; 8]; | |
184 | if firstline { | |
185 | for i in 0..8 { buf[i] = DEFAULT_PIXEL; } | |
afe29743 | 186 | } else { |
7241e094 | 187 | for i in 0..8 { buf[i] = bufs.dbuf[doff - stride + i]; } |
afe29743 KS |
188 | } |
189 | if topline && !firstline { | |
190 | for i in 0..4 { buf[i * 2 + 1] = buf[i * 2]; } | |
7241e094 | 191 | for i in 0..8 { bufs.dbuf[doff + i] = (bufs.dbuf[doff - stride + i] + buf[i]) >> 1; } |
afe29743 KS |
192 | } |
193 | ||
194 | let start = if !topline { 0 } else { 1 }; | |
8865cd08 KS |
195 | if topline { |
196 | didx += stride; | |
197 | } | |
7241e094 | 198 | for _ in start..h { |
5a6dec5f | 199 | bufs.dbuf[didx..][..8].copy_from_slice(&buf[..8]); |
7241e094 | 200 | didx += stride; |
afe29743 KS |
201 | } |
202 | } | |
203 | ||
204 | struct Indeo3Decoder { | |
2422d969 | 205 | info: NACodecInfoRef, |
afe29743 KS |
206 | bpos: u8, |
207 | bbuf: u8, | |
208 | width: u16, | |
209 | height: u16, | |
210 | mvs: Vec<MV>, | |
211 | altquant: [u8; 16], | |
212 | vq_offset: u8, | |
213 | bufs: Buffers, | |
3bc2f5a4 | 214 | requant_tab: [[u8; 128]; 8], |
afe29743 KS |
215 | } |
216 | ||
217 | #[derive(Clone,Copy)] | |
218 | struct IV3Cell { | |
219 | x: u16, | |
220 | y: u16, | |
221 | w: u16, | |
222 | h: u16, | |
223 | d: u8, | |
224 | vqt: bool, | |
225 | mv: Option<MV>, | |
226 | } | |
227 | ||
228 | impl IV3Cell { | |
229 | fn new(w: u16, h: u16) -> Self { | |
f2af8eca | 230 | IV3Cell { x: 0, y: 0, w, h, d: 20, vqt: false, mv: None } |
afe29743 KS |
231 | } |
232 | fn split_h(&self) -> (Self, Self) { | |
233 | let h1 = if self.h > 2 { ((self.h + 2) >> 2) << 1 } else { 1 }; | |
234 | let h2 = self.h - h1; | |
235 | let mut cell1 = *self; | |
236 | cell1.h = h1; | |
237 | cell1.d -= 1; | |
238 | let mut cell2 = *self; | |
239 | cell2.y += h1; | |
240 | cell2.h = h2; | |
241 | cell2.d -= 1; | |
242 | (cell1, cell2) | |
243 | } | |
244 | fn split_w(&self, stripw: u16) -> (Self, Self) { | |
245 | let w1 = if self.w > stripw { | |
246 | if self.w > stripw * 2 { stripw * 2 } else { stripw } | |
247 | } else { | |
248 | if self.w > 2 { ((self.w + 2) >> 2) << 1 } else { 1 } | |
249 | }; | |
250 | let w2 = self.w - w1; | |
251 | let mut cell1 = *self; | |
252 | cell1.w = w1; | |
253 | cell1.d -= 1; | |
254 | let mut cell2 = *self; | |
255 | cell2.x += w1; | |
256 | cell2.w = w2; | |
257 | cell2.d -= 1; | |
258 | (cell1, cell2) | |
259 | } | |
f2af8eca | 260 | fn no_mv(&self) -> bool { self.mv.is_none() } |
afe29743 KS |
261 | } |
262 | ||
263 | struct CellDecParams { | |
264 | tab: [usize; 2], | |
265 | bw: u16, | |
266 | bh: u16, | |
267 | swap_q: [bool; 2], | |
268 | hq: bool, | |
269 | apply_delta: fn (&mut Buffers, usize, usize, &[u8], bool, bool), | |
270 | copy_line_top: fn (&mut Buffers, usize, usize, bool), | |
271 | } | |
272 | ||
273 | const FRMH_TAG: u32 = ((b'F' as u32) << 24) | ((b'R' as u32) << 16) | |
274 | | ((b'M' as u32) << 8) | (b'H' as u32); | |
275 | ||
276 | const H_SPLIT: u8 = 0; | |
277 | const V_SPLIT: u8 = 1; | |
278 | const SKIP_OR_TREE: u8 = 2; | |
279 | ||
280 | impl Indeo3Decoder { | |
281 | fn new() -> Self { | |
3bc2f5a4 KS |
282 | const REQUANT_OFF: [i32; 8] = [ 0, 1, 0, 4, 4, 1, 0, 1 ]; |
283 | ||
2422d969 | 284 | let dummy_info = NACodecInfo::new_dummy(); |
3bc2f5a4 KS |
285 | |
286 | let mut requant_tab = [[0u8; 128]; 8]; | |
287 | for i in 0..8 { | |
288 | let step = (i as i32) + 2; | |
289 | let start = if (i == 3) || (i == 4) { -3 } else { step / 2 }; | |
290 | let mut last = 0; | |
291 | for j in 0..128 { | |
292 | requant_tab[i][j] = (((j as i32) + start) / step * step + REQUANT_OFF[i]) as u8; | |
293 | if requant_tab[i][j] < 128 { | |
294 | last = requant_tab[i][j]; | |
295 | } else { | |
296 | requant_tab[i][j] = last; | |
297 | } | |
298 | } | |
299 | } | |
300 | requant_tab[1][7] = 10; | |
301 | requant_tab[1][119] = 118; | |
302 | requant_tab[1][120] = 118; | |
303 | requant_tab[4][8] = 10; | |
304 | ||
afe29743 KS |
305 | Indeo3Decoder { info: dummy_info, bpos: 0, bbuf: 0, width: 0, height: 0, |
306 | mvs: Vec::new(), altquant: [0; 16], | |
3bc2f5a4 | 307 | vq_offset: 0, bufs: Buffers::new(), requant_tab } |
afe29743 KS |
308 | } |
309 | ||
310 | fn br_reset(&mut self) { | |
311 | self.bpos = 0; | |
312 | self.bbuf = 0; | |
313 | } | |
314 | ||
315 | fn get_2bits(&mut self, br: &mut ByteReader) -> DecoderResult<u8> { | |
316 | if self.bpos == 0 { | |
317 | self.bbuf = br.read_byte()?; | |
318 | self.bpos = 8; | |
319 | } | |
320 | self.bpos -= 2; | |
321 | Ok((self.bbuf >> self.bpos) & 0x3) | |
322 | } | |
323 | ||
b7c882c1 | 324 | #[allow(clippy::cognitive_complexity)] |
afe29743 | 325 | fn decode_cell_data(&mut self, br: &mut ByteReader, cell: IV3Cell, |
3bc2f5a4 | 326 | off: usize, stride: usize, params: CellDecParams, vq_idx: u8) -> DecoderResult<()> { |
afe29743 KS |
327 | let blk_w = cell.w * 4 / params.bw; |
328 | let blk_h = cell.h * 4 / params.bh; | |
329 | let scale: usize = if params.bh == 4 { 1 } else { 2 }; | |
330 | ||
331 | validate!((((cell.w * 4) % params.bw) == 0) && (((cell.h * 4) % params.bh) == 0)); | |
332 | ||
333 | let mut run_blocks = 0; | |
334 | let mut run_skip = false; | |
335 | ||
336 | let mut didx: usize = ((cell.x*4) as usize) + ((cell.y * 4) as usize) * stride + off; | |
337 | let mut sidx: usize; | |
0ddb146d | 338 | |
afe29743 KS |
339 | if cell.no_mv() { |
340 | sidx = 0; | |
341 | } else { | |
342 | let mv = cell.mv.unwrap(); | |
f2af8eca KS |
343 | let mx = i16::from(mv.x); |
344 | let my = i16::from(mv.y); | |
afe29743 KS |
345 | let l = (cell.x as i16) * 4 + mx; |
346 | let t = (cell.y as i16) * 4 + my; | |
347 | let r = ((cell.x + cell.w) as i16) * 4 + mx; | |
348 | let b = ((cell.y + cell.h) as i16) * 4 + my; | |
349 | validate!(l >= 0); | |
350 | validate!(t >= 0); | |
351 | validate!(r <= (self.width as i16)); | |
352 | validate!(b <= (self.height as i16)); | |
353 | sidx = (l as usize) + (t as usize) * stride + off; | |
354 | } | |
3bc2f5a4 KS |
355 | if vq_idx >= 8 { |
356 | let requant_tab = &self.requant_tab[(vq_idx & 7) as usize]; | |
357 | if cell.no_mv() { | |
358 | if cell.y > 0 { | |
359 | for x in 0..(cell.w as usize) * 4 { | |
360 | self.bufs.dbuf[didx + x - stride] = requant_tab[self.bufs.dbuf[didx + x - stride] as usize]; | |
361 | } | |
362 | } | |
363 | } else { | |
364 | for x in 0..(cell.w as usize) * 4 { | |
365 | self.bufs.sbuf[sidx + x] = requant_tab[self.bufs.sbuf[sidx + x] as usize]; | |
366 | } | |
367 | } | |
368 | } | |
afe29743 KS |
369 | for y in 0..blk_h { |
370 | let mut xoff: usize = 0; | |
371 | for _ in 0..blk_w { | |
372 | if run_blocks > 0 { | |
373 | if !run_skip || !cell.no_mv() { | |
374 | if !(params.bw == 8 && cell.no_mv()) { | |
375 | if !cell.no_mv() { | |
376 | self.bufs.copy_block(didx + xoff, sidx + xoff, stride, | |
377 | params.bw as usize, params.bh as usize); | |
378 | } else { | |
379 | self.bufs.fill_block(didx + xoff, stride, | |
380 | params.bw as usize, params.bh as usize, | |
381 | (cell.y == 0) && (y == 0)); | |
382 | } | |
383 | } else { | |
384 | fill_block8x8(&mut self.bufs, | |
385 | didx + xoff, stride, 8, | |
8f4c4020 | 386 | y == 0, (cell.y == 0) && (y == 0)); |
afe29743 KS |
387 | } |
388 | } | |
389 | run_blocks -= 1; | |
390 | } else { | |
391 | let mut line: usize = 0; | |
392 | while line < 4 { | |
393 | let c = br.read_byte()?; | |
394 | if c < 0xF8 { | |
395 | let delta_tab = if params.hq { | |
396 | IVI3_DELTA_CBS[params.tab[line & 1]] | |
397 | } else { | |
398 | IVI3_DELTA_CBS[params.tab[1]] | |
399 | }; | |
400 | let mut idx1; | |
401 | let mut idx2; | |
402 | if (c as usize) < delta_tab.data.len()/2 { | |
403 | idx1 = br.read_byte()? as usize; | |
0ddb146d | 404 | validate!(idx1 < delta_tab.data.len() / 2); |
afe29743 KS |
405 | idx2 = c as usize; |
406 | } else { | |
407 | let tmp = (c as usize) - delta_tab.data.len()/2; | |
408 | idx1 = tmp / (delta_tab.quad_radix as usize); | |
409 | idx2 = tmp % (delta_tab.quad_radix as usize); | |
410 | if params.swap_q[line & 1] { | |
411 | mem::swap(&mut idx1, &mut idx2); | |
412 | } | |
413 | } | |
414 | let deltas: [u8; 4] = [delta_tab.data[idx1 * 2] as u8, | |
415 | delta_tab.data[idx1 * 2 + 1] as u8, | |
416 | delta_tab.data[idx2 * 2 + 0] as u8, | |
417 | delta_tab.data[idx2 * 2 + 1] as u8]; | |
418 | let topline = (cell.y == 0) && (y == 0) && (line == 0); | |
419 | let first_line = (y == 0) && (line == 0); | |
420 | if cell.no_mv() { | |
421 | (params.copy_line_top)(&mut self.bufs, | |
422 | didx + xoff + line * scale * stride, | |
423 | stride, topline); | |
424 | } else { | |
425 | self.bufs.copy_block(didx + xoff + line * scale * stride, | |
426 | sidx + xoff + line * scale * stride, | |
427 | stride, params.bw as usize, scale); | |
428 | } | |
429 | (params.apply_delta)(&mut self.bufs, | |
430 | didx + xoff + line * scale * stride, | |
431 | stride, &deltas, topline, first_line); | |
432 | line += 1; | |
433 | } else { | |
434 | let mut tocopy: usize = 0; | |
435 | let mut do_copy = true; | |
436 | if c == 0xF8 { return Err(DecoderError::InvalidData); } | |
437 | if c == 0xF9 { | |
438 | run_blocks = 1; | |
439 | run_skip = true; | |
440 | validate!(line == 0); | |
441 | tocopy = 4; | |
442 | do_copy = !cell.no_mv(); | |
443 | } | |
444 | if c == 0xFA { | |
445 | validate!(line == 0); | |
446 | tocopy = 4; | |
447 | do_copy = !cell.no_mv(); | |
448 | } | |
449 | if c == 0xFB { | |
450 | let c = br.read_byte()?; | |
451 | validate!((c < 64) && ((c & 0x1F) != 0)); | |
452 | run_blocks = (c & 0x1F) - 1; | |
453 | run_skip = (c & 0x20) != 0; | |
454 | tocopy = 4 - line; | |
455 | if params.bw == 4 && cell.no_mv() && run_skip { | |
456 | do_copy = false; | |
457 | } | |
458 | } | |
459 | if c == 0xFC { | |
460 | run_skip = false; | |
461 | run_blocks = 1; | |
462 | tocopy = 4 - line; | |
463 | } | |
464 | if c >= 0xFD { | |
f2af8eca | 465 | let nl = 257 - i16::from(c) - (line as i16); |
afe29743 KS |
466 | validate!(nl > 0); |
467 | tocopy = nl as usize; | |
468 | } | |
469 | if do_copy { | |
0ddb146d | 470 | if !(params.bh == 8 && cell.no_mv()) { |
afe29743 KS |
471 | if !cell.no_mv() { |
472 | self.bufs.copy_block(didx + xoff + line * scale * stride, | |
473 | sidx + xoff + line * scale * stride, | |
474 | stride, params.bw as usize, | |
475 | tocopy * scale); | |
476 | } else { | |
477 | self.bufs.fill_block(didx + xoff + line * scale * stride, | |
478 | stride, params.bw as usize, | |
479 | tocopy * scale, | |
480 | (cell.y == 0) && (y == 0) && (line == 0)); | |
481 | } | |
482 | } else { | |
483 | fill_block8x8(&mut self.bufs, | |
484 | didx + xoff + line * 2 * stride, | |
485 | stride, tocopy * 2, | |
486 | (y == 0) && (line == 0), | |
487 | (cell.y == 0) && (y == 0) && (line == 0)); | |
488 | } | |
489 | } | |
490 | line += tocopy; | |
491 | } | |
492 | } | |
493 | } | |
494 | xoff += params.bw as usize; | |
495 | } | |
496 | didx += stride * (params.bh as usize); | |
497 | sidx += stride * (params.bh as usize); | |
498 | } | |
499 | Ok(()) | |
500 | } | |
501 | ||
502 | fn copy_cell(&mut self, cell: IV3Cell, off: usize, stride: usize) -> DecoderResult<()> { | |
503 | if cell.no_mv() { return Err(DecoderError::InvalidData); } | |
504 | let mv = cell.mv.unwrap(); | |
f2af8eca KS |
505 | let mx = i16::from(mv.x); |
506 | let my = i16::from(mv.y); | |
afe29743 KS |
507 | let l = (cell.x as i16) * 4 + mx; |
508 | let t = (cell.y as i16) * 4 + my; | |
509 | let r = ((cell.x + cell.w) as i16) * 4 + mx; | |
510 | let b = ((cell.y + cell.h) as i16) * 4 + my; | |
511 | validate!(l >= 0); | |
512 | validate!(t >= 0); | |
513 | validate!(r <= (self.width as i16)); | |
514 | validate!(b <= (self.height as i16)); | |
515 | let sidx: usize = off + (l as usize) + (t as usize) * stride; | |
516 | let didx: usize = off + ((cell.x * 4) as usize) + ((cell.y * 4) as usize) * stride; | |
517 | self.bufs.copy_block(didx, sidx, stride, (cell.w * 4) as usize, (cell.h * 4) as usize); | |
518 | Ok(()) | |
519 | } | |
520 | ||
521 | fn decode_cell(&mut self, br: &mut ByteReader, cell: IV3Cell, off: usize, | |
522 | stride: usize, intra: bool) -> DecoderResult<()> { | |
523 | let code = br.read_byte()?; | |
524 | let mode = code >> 4; | |
525 | let vq_idx = code & 0xF; | |
526 | ||
527 | let mut idx1: usize = vq_idx as usize; | |
528 | let mut idx2: usize = vq_idx as usize; | |
529 | if (mode == 1) || (mode == 4) { | |
530 | let c = self.altquant[vq_idx as usize]; | |
531 | idx1 = (c >> 4) as usize; | |
532 | idx2 = (c & 0xF) as usize; | |
0ddb146d KS |
533 | } else { |
534 | idx1 += self.vq_offset as usize; | |
535 | idx2 += self.vq_offset as usize; | |
afe29743 | 536 | } |
afe29743 KS |
537 | validate!((idx1 < 24) && (idx2 < 24)); |
538 | ||
539 | let mut cp = CellDecParams { | |
540 | tab: [idx2, idx1], | |
541 | bw: 0, bh: 0, | |
542 | swap_q: [idx2 >= 16, idx1 >= 16], | |
543 | hq: false, | |
544 | apply_delta: apply_delta4x4, | |
545 | copy_line_top: copy_line_top4x4, | |
546 | }; | |
547 | if (mode == 0) || (mode == 1) { | |
548 | cp.bw = 4; | |
549 | cp.bh = 4; | |
550 | cp.hq = true; | |
551 | } else if (mode == 3) || (mode == 4) { | |
552 | if !cell.no_mv() { return Err(DecoderError::InvalidData); } | |
553 | cp.bw = 4; | |
554 | cp.bh = 8; | |
555 | cp.hq = true; | |
556 | cp.apply_delta = apply_delta4x8; | |
557 | cp.copy_line_top = copy_line_top4x8; | |
558 | } else if mode == 10 { | |
559 | if !cell.no_mv() { | |
560 | validate!(!intra); | |
561 | cp.apply_delta = apply_delta8x8p; | |
562 | } else { | |
563 | cp.apply_delta = apply_delta8x8i; | |
564 | } | |
565 | cp.bw = 8; | |
566 | cp.bh = 8; | |
567 | cp.copy_line_top = copy_line_top8x8; | |
568 | } else if mode == 11 { | |
569 | if cell.no_mv() { return Err(DecoderError::InvalidData); } | |
570 | validate!(!intra); | |
571 | cp.bw = 4; | |
572 | cp.bh = 8; | |
573 | cp.apply_delta = apply_delta4x8m11; | |
574 | cp.copy_line_top = copy_line_top4x8; | |
575 | } else { | |
576 | return Err(DecoderError::InvalidData); | |
577 | } | |
3bc2f5a4 | 578 | self.decode_cell_data(br, cell, off, stride, cp, vq_idx) |
afe29743 KS |
579 | } |
580 | ||
581 | fn parse_tree(&mut self, br: &mut ByteReader, cell: IV3Cell, off: usize, | |
582 | stride: usize, stripw: u16, intra: bool) -> DecoderResult<()> { | |
583 | let op = self.get_2bits(br)?; | |
584 | if op == H_SPLIT { | |
585 | validate!(cell.h > 1); | |
586 | validate!(cell.d > 0); | |
587 | let (cell1, cell2) = cell.split_h(); | |
588 | self.parse_tree(br, cell1, off, stride, stripw, intra)?; | |
589 | self.parse_tree(br, cell2, off, stride, stripw, intra)?; | |
590 | Ok(()) | |
591 | } else if op == V_SPLIT { | |
592 | validate!(cell.w > 1); | |
593 | validate!(cell.d > 0); | |
594 | let (cell1, cell2) = cell.split_w(stripw); | |
595 | self.parse_tree(br, cell1, off, stride, stripw, intra)?; | |
596 | self.parse_tree(br, cell2, off, stride, stripw, intra)?; | |
597 | Ok(()) | |
598 | } else if op == SKIP_OR_TREE { | |
599 | if !cell.vqt { | |
600 | let mut newcell = cell; | |
601 | newcell.vqt = true; | |
602 | newcell.d -= 1; | |
603 | self.parse_tree(br, newcell, off, stride, stripw, intra) | |
604 | } else { | |
605 | validate!(!intra); | |
606 | let code = self.get_2bits(br)?; | |
607 | validate!(code < 2); | |
608 | if code == 1 { return Err(DecoderError::NotImplemented); } | |
609 | self.copy_cell(cell, off, stride) | |
610 | } | |
611 | } else { | |
612 | if !cell.vqt { | |
613 | let mut newcell = cell; | |
614 | newcell.vqt = true; | |
615 | newcell.d -= 1; | |
616 | let mv_idx = br.read_byte()? as usize; | |
617 | validate!(mv_idx < self.mvs.len()); | |
618 | newcell.mv = Some(self.mvs[mv_idx]); | |
619 | self.parse_tree(br, newcell, off, stride, stripw, intra) | |
620 | } else { | |
621 | self.decode_cell(br, cell, off, stride, intra) | |
622 | } | |
623 | } | |
624 | } | |
625 | ||
626 | fn decode_plane_intra(&mut self, br: &mut ByteReader, planeno: usize, | |
627 | start: u64, end: u64) -> DecoderResult<()> { | |
628 | let offs = self.bufs.get_offset(planeno); | |
629 | let stride = self.bufs.get_stride(planeno); | |
630 | br.seek(SeekFrom::Start(start))?; | |
631 | ||
632 | let nvec = br.read_u32le()?; | |
633 | validate!(nvec == 0); // for intra there should be no mc_vecs | |
37952415 | 634 | self.mvs.clear(); |
afe29743 KS |
635 | for _ in 0..nvec { |
636 | let x = br.read_byte()? as i8; | |
637 | let y = br.read_byte()? as i8; | |
f2af8eca | 638 | self.mvs.push(MV{ x, y }); |
afe29743 KS |
639 | } |
640 | ||
0ddb146d KS |
641 | let (cellwidth, cellheight) = if planeno == 0 { |
642 | (self.bufs.width >> 2, self.bufs.height >> 2) | |
643 | } else { | |
644 | (((self.bufs.width >> 2) + 3) >> 2, ((self.bufs.height >> 2) + 3) >> 2) | |
645 | }; | |
646 | let cell = IV3Cell::new(cellwidth as u16, cellheight as u16); | |
afe29743 KS |
647 | self.br_reset(); |
648 | self.parse_tree(br, cell, offs, stride, if planeno > 0 { 10 } else { 40 }, true)?; | |
649 | validate!(br.tell() <= end); | |
650 | Ok(()) | |
651 | } | |
652 | ||
653 | fn decode_plane_inter(&mut self, br: &mut ByteReader, planeno: usize, | |
654 | start: u64, end: u64) -> DecoderResult<()> { | |
655 | let offs = self.bufs.get_offset(planeno); | |
656 | let stride = self.bufs.get_stride(planeno); | |
657 | br.seek(SeekFrom::Start(start))?; | |
658 | ||
659 | let nvec = br.read_u32le()?; | |
660 | validate!(nvec <= 256); // for intra there should be no mc_vecs | |
37952415 | 661 | self.mvs.clear(); |
afe29743 KS |
662 | for _ in 0..nvec { |
663 | let y = br.read_byte()? as i8; | |
664 | let x = br.read_byte()? as i8; | |
f2af8eca | 665 | self.mvs.push(MV{ x, y }); |
afe29743 KS |
666 | } |
667 | ||
0ddb146d KS |
668 | let (cellwidth, cellheight) = if planeno == 0 { |
669 | (self.bufs.width >> 2, self.bufs.height >> 2) | |
670 | } else { | |
671 | (((self.bufs.width >> 2) + 3) >> 2, ((self.bufs.height >> 2) + 3) >> 2) | |
672 | }; | |
673 | let cell = IV3Cell::new(cellwidth as u16, cellheight as u16); | |
afe29743 KS |
674 | self.br_reset(); |
675 | self.parse_tree(br, cell, offs, stride, if planeno > 0 { 10 } else { 40 }, false)?; | |
676 | validate!(br.tell() <= end); | |
677 | Ok(()) | |
678 | } | |
679 | } | |
680 | ||
681 | const FLAG_KEYFRAME: u16 = 1 << 2; | |
682 | const FLAG_NONREF: u16 = 1 << 8; | |
683 | ||
684 | impl NADecoder for Indeo3Decoder { | |
01613464 | 685 | fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { |
afe29743 KS |
686 | if let NACodecTypeInfo::Video(vinfo) = info.get_properties() { |
687 | let w = vinfo.get_width(); | |
688 | let h = vinfo.get_height(); | |
689 | let fmt = formats::YUV410_FORMAT; | |
690 | let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(w, h, false, fmt)); | |
2422d969 | 691 | self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref(); |
afe29743 KS |
692 | self.bufs.reset(); |
693 | Ok(()) | |
694 | } else { | |
695 | Err(DecoderError::InvalidData) | |
696 | } | |
697 | } | |
01613464 | 698 | fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { |
afe29743 KS |
699 | let src = pkt.get_buffer(); |
700 | let mut mr = MemoryReader::new_read(&src); | |
701 | let mut br = ByteReader::new(&mut mr); | |
702 | let frameno = br.read_u32le()?; | |
703 | let hdr_2 = br.read_u32le()?; | |
704 | let check = br.read_u32le()?; | |
705 | let size = br.read_u32le()?; | |
706 | ||
707 | let data_start = br.tell(); | |
708 | ||
709 | if (frameno ^ hdr_2 ^ size ^ FRMH_TAG) != check { | |
710 | return Err(DecoderError::InvalidData); | |
711 | } | |
f2af8eca | 712 | if i64::from(size) > br.left() { return Err(DecoderError::InvalidData); } |
afe29743 KS |
713 | let ver = br.read_u16le()?; |
714 | if ver != 32 { return Err(DecoderError::NotImplemented); } | |
715 | let flags = br.read_u16le()?; | |
716 | let size2 = br.read_u32le()?; | |
c5e335bf KS |
717 | if size2 == 0x80 { |
718 | let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::None); | |
719 | frm.set_keyframe(false); | |
720 | frm.set_frame_type(FrameType::Skip); | |
721 | return Ok(frm.into_ref()); | |
722 | } | |
afe29743 KS |
723 | validate!(((size2 + 7) >> 3) <= size); |
724 | let cb = br.read_byte()?; | |
725 | self.vq_offset = cb; | |
726 | br.read_skip(3)?; | |
727 | let height = br.read_u16le()?; | |
728 | let width = br.read_u16le()?; | |
729 | validate!((width >= 16) && (width <= 640)); | |
730 | validate!((height >= 16) && (height <= 640)); | |
731 | validate!(((width & 3) == 0) && ((height & 3) == 0)); | |
b6e93e1b | 732 | let vinfo; |
afe29743 KS |
733 | if (self.bufs.width != (width as usize)) || (self.bufs.height != (height as usize)) { |
734 | self.bufs.alloc(width as usize, height as usize); | |
b6e93e1b KS |
735 | vinfo = NAVideoInfo::new(width as usize, height as usize, false, formats::YUV410_FORMAT); |
736 | } else { | |
737 | vinfo = self.info.get_properties().get_video_info().unwrap(); | |
afe29743 KS |
738 | } |
739 | self.width = width; | |
740 | self.height = height; | |
741 | ||
742 | let yoff = br.read_u32le()?; | |
743 | let uoff = br.read_u32le()?; | |
744 | let voff = br.read_u32le()?; | |
745 | if yoff > size { return Err(DecoderError::InvalidData); } | |
746 | if uoff > size { return Err(DecoderError::InvalidData); } | |
747 | if voff > size { return Err(DecoderError::InvalidData); } | |
748 | ||
749 | br.read_skip(4)?; | |
750 | br.read_buf(&mut self.altquant)?; | |
751 | ||
752 | let mut yend = src.len() as u32;//size; | |
753 | if (uoff < yend) && (uoff > yoff) { yend = uoff; } | |
754 | if (voff < yend) && (voff > yoff) { yend = voff; } | |
755 | let mut uend = size; | |
756 | if (yoff < uend) && (yoff > uoff) { uend = yoff; } | |
757 | if (voff < uend) && (voff > uoff) { uend = voff; } | |
758 | let mut vend = size; | |
759 | if (yoff < vend) && (yoff > voff) { vend = yoff; } | |
760 | if (uoff < vend) && (uoff > voff) { vend = uoff; } | |
761 | ||
5658bdcc | 762 | let intraframe = (flags & FLAG_KEYFRAME) != 0; |
f2af8eca | 763 | let bufinfo = alloc_video_buffer(vinfo, 4)?; |
afe29743 | 764 | let mut buf = bufinfo.get_vbuf().unwrap(); |
f2af8eca KS |
765 | let ystart = data_start + u64::from(yoff); |
766 | let ustart = data_start + u64::from(uoff); | |
767 | let vstart = data_start + u64::from(voff); | |
768 | let yendpos = data_start + u64::from(yend); | |
769 | let uendpos = data_start + u64::from(uend); | |
770 | let vendpos = data_start + u64::from(vend); | |
5658bdcc | 771 | if intraframe { |
afe29743 | 772 | self.decode_plane_intra(&mut br, 0, ystart, yendpos)?; |
0ddb146d KS |
773 | self.decode_plane_intra(&mut br, 1, vstart, vendpos)?; |
774 | self.decode_plane_intra(&mut br, 2, ustart, uendpos)?; | |
afe29743 KS |
775 | } else { |
776 | self.decode_plane_inter(&mut br, 0, ystart, yendpos)?; | |
0ddb146d KS |
777 | self.decode_plane_inter(&mut br, 1, vstart, vendpos)?; |
778 | self.decode_plane_inter(&mut br, 2, ustart, uendpos)?; | |
afe29743 KS |
779 | } |
780 | self.bufs.fill_framebuf(&mut buf); | |
781 | if (flags & FLAG_NONREF) == 0 { self.bufs.flip(); } | |
782 | let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo); | |
5658bdcc KS |
783 | frm.set_keyframe(intraframe); |
784 | frm.set_frame_type(if intraframe { FrameType::I } else { FrameType::P }); | |
171860fc | 785 | Ok(frm.into_ref()) |
afe29743 | 786 | } |
f9be4e75 KS |
787 | fn flush(&mut self) { |
788 | self.bufs.reset(); | |
789 | } | |
afe29743 KS |
790 | } |
791 | ||
7d57ae2f KS |
792 | impl NAOptionHandler for Indeo3Decoder { |
793 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
794 | fn set_options(&mut self, _options: &[NAOption]) { } | |
795 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
796 | } | |
797 | ||
08a1fab7 | 798 | pub fn get_decoder() -> Box<dyn NADecoder + Send> { |
379fd781 KS |
799 | Box::new(Indeo3Decoder::new()) |
800 | } | |
801 | ||
afe29743 KS |
802 | #[cfg(test)] |
803 | mod test { | |
3167c45c KS |
804 | use nihav_core::codecs::RegisteredDecoders; |
805 | use nihav_core::demuxers::RegisteredDemuxers; | |
ce742854 | 806 | use nihav_codec_support::test::dec_video::*; |
78fb6560 | 807 | use crate::indeo_register_all_decoders; |
e64739f8 | 808 | use nihav_commonfmt::generic_register_all_demuxers; |
afe29743 KS |
809 | #[test] |
810 | fn test_indeo3() { | |
3167c45c KS |
811 | let mut dmx_reg = RegisteredDemuxers::new(); |
812 | generic_register_all_demuxers(&mut dmx_reg); | |
813 | let mut dec_reg = RegisteredDecoders::new(); | |
78fb6560 | 814 | indeo_register_all_decoders(&mut dec_reg); |
3167c45c | 815 | |
886cde48 | 816 | // sample: https://samples.mplayerhq.hu/V-codecs/IV32/iv32_example.avi |
2890938d KS |
817 | test_decoding("avi", "indeo3", "assets/Indeo/iv32_example.avi", Some(10), |
818 | &dmx_reg, &dec_reg, ExpectedTestResult::MD5Frames(vec![ | |
819 | [0x90be698e, 0x326db071, 0x08e8c6a5, 0x39349acc], | |
820 | [0x25d677fc, 0x63f96aaa, 0xd412ca98, 0x61416313], | |
821 | [0xc4368250, 0x63e7b6bc, 0xffcff950, 0x11f13239], | |
822 | [0x7e869758, 0x027abc2e, 0x25204bca, 0x93fbaa03], | |
823 | [0x5a1e822c, 0x2b1a4cd5, 0x72059843, 0xe5689ad1], | |
824 | [0x3a971cce, 0x5ec22135, 0x1a45f802, 0x0f5f9264], | |
825 | [0x0a65f782, 0xd8767cf3, 0x878b4b8d, 0xfc94c88b], | |
826 | [0x4ac70139, 0x3300eac1, 0xba84b068, 0x47f5ff29], | |
827 | [0x3e8c8ec4, 0x9421b38c, 0x580abbbd, 0x92792d19], | |
828 | [0x9096ee9b, 0x8dd9fb14, 0x981e31e3, 0x3ffd7d29], | |
829 | [0x22dc71ec, 0x3d8f6f7e, 0x1a198982, 0x41d17ecc]])); | |
afe29743 KS |
830 | } |
831 | } |