| 1 | use nihav_core::formats; |
| 2 | use nihav_core::codecs::*; |
| 3 | use nihav_core::io::byteio::*; |
| 4 | use std::io::SeekFrom; |
| 5 | use std::mem; |
| 6 | use super::indeo3data::*; |
| 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, |
| 17 | cw: usize, |
| 18 | ch: usize, |
| 19 | sbuf: Vec<u8>, |
| 20 | dbuf: Vec<u8>, |
| 21 | } |
| 22 | |
| 23 | const DEFAULT_PIXEL: u8 = 0x40; |
| 24 | |
| 25 | impl Buffers { |
| 26 | fn new() -> Self { Buffers { width: 0, height: 0, cw: 0, ch: 0, sbuf: Vec::new(), dbuf: Vec::new() } } |
| 27 | fn reset(&mut self) { |
| 28 | self.width = 0; |
| 29 | self.height = 0; |
| 30 | self.sbuf.clear(); |
| 31 | self.dbuf.clear(); |
| 32 | } |
| 33 | fn alloc(&mut self, w: usize, h: usize) { |
| 34 | self.width = w; |
| 35 | self.height = h; |
| 36 | self.cw = ((w >> 2) + 3) & !3; |
| 37 | self.ch = ((h >> 2) + 3) & !3; |
| 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); |
| 40 | } |
| 41 | fn flip(&mut self) { std::mem::swap(&mut self.sbuf, &mut self.dbuf); } |
| 42 | fn get_stride(&mut self, planeno: usize) -> usize { |
| 43 | if planeno == 0 { self.width } else { self.cw } |
| 44 | } |
| 45 | fn get_offset(&mut self, planeno: usize) -> usize { |
| 46 | match planeno { |
| 47 | 1 => self.width * self.height, |
| 48 | 2 => self.width * self.height + self.cw * self.ch, |
| 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); |
| 58 | let width = if planeno == 0 { self.width } else { self.width >> 2 }; |
| 59 | let height = if planeno == 0 { self.height } else { self.height >> 2 }; |
| 60 | let src = self.dbuf.as_slice(); |
| 61 | let dst = fbuf.get_data_mut().unwrap(); |
| 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; |
| 74 | for _ in 0..h { |
| 75 | self.dbuf[didx..][..w].copy_from_slice(&self.sbuf[sidx..][..w]); |
| 76 | sidx += stride; |
| 77 | didx += stride; |
| 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 { |
| 84 | for _ in 0..h { |
| 85 | for i in 0..w { self.dbuf[didx + i] = DEFAULT_PIXEL; } |
| 86 | didx += stride; |
| 87 | } |
| 88 | } else { |
| 89 | for i in 0..w { buf[i] = self.dbuf[didx - stride + i]; } |
| 90 | for _ in 0..h { |
| 91 | self.dbuf[didx..][..w].copy_from_slice(&buf[..w]); |
| 92 | didx += stride; |
| 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) { |
| 101 | let dst = &mut bufs.dbuf[off..][..4]; |
| 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) { |
| 108 | let dst = &mut bufs.dbuf[off..][..stride + 4]; |
| 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) { |
| 120 | let dst = &mut bufs.dbuf[off..][..stride + 4]; |
| 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) { |
| 128 | let dst = &mut bufs.dbuf[off..][..stride + 8]; |
| 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) { |
| 135 | let dst = &mut bufs.dbuf[off..][..stride + 8]; |
| 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 { |
| 151 | let src = &bufs.dbuf[(off - stride)..(off - stride + bw)]; |
| 152 | buf[..bw].copy_from_slice(&src[..bw]); |
| 153 | } else { |
| 154 | for i in 0..bw { buf[i] = DEFAULT_PIXEL; } |
| 155 | } |
| 156 | let dst = &mut bufs.dbuf[off..][..bw]; |
| 157 | dst.copy_from_slice(&buf[..bw]); |
| 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 { |
| 172 | let src = &bufs.dbuf[(off - stride)..(off - stride + 8)]; |
| 173 | for i in 0..8 { buf[i] = src[i & !1]; } |
| 174 | } else { |
| 175 | for i in 0..8 { buf[i] = DEFAULT_PIXEL; } |
| 176 | } |
| 177 | let dst = &mut bufs.dbuf[off..][..8]; |
| 178 | dst.copy_from_slice(&buf[..8]); |
| 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; } |
| 186 | } else { |
| 187 | for i in 0..8 { buf[i] = bufs.dbuf[doff - stride + i]; } |
| 188 | } |
| 189 | if topline && !firstline { |
| 190 | for i in 0..4 { buf[i * 2 + 1] = buf[i * 2]; } |
| 191 | for i in 0..8 { bufs.dbuf[doff + i] = (bufs.dbuf[doff - stride + i] + buf[i]) >> 1; } |
| 192 | } |
| 193 | |
| 194 | let start = if !topline { 0 } else { 1 }; |
| 195 | if topline { |
| 196 | didx += stride; |
| 197 | } |
| 198 | for _ in start..h { |
| 199 | bufs.dbuf[didx..][..8].copy_from_slice(&buf[..8]); |
| 200 | didx += stride; |
| 201 | } |
| 202 | } |
| 203 | |
| 204 | struct Indeo3Decoder { |
| 205 | info: NACodecInfoRef, |
| 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, |
| 214 | requant_tab: [[u8; 128]; 8], |
| 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 { |
| 230 | IV3Cell { x: 0, y: 0, w, h, d: 20, vqt: false, mv: None } |
| 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 | } |
| 260 | fn no_mv(&self) -> bool { self.mv.is_none() } |
| 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 { |
| 282 | const REQUANT_OFF: [i32; 8] = [ 0, 1, 0, 4, 4, 1, 0, 1 ]; |
| 283 | |
| 284 | let dummy_info = NACodecInfo::new_dummy(); |
| 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 | |
| 305 | Indeo3Decoder { info: dummy_info, bpos: 0, bbuf: 0, width: 0, height: 0, |
| 306 | mvs: Vec::new(), altquant: [0; 16], |
| 307 | vq_offset: 0, bufs: Buffers::new(), requant_tab } |
| 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 | |
| 324 | #[allow(clippy::cognitive_complexity)] |
| 325 | fn decode_cell_data(&mut self, br: &mut ByteReader, cell: IV3Cell, |
| 326 | off: usize, stride: usize, params: CellDecParams, vq_idx: u8) -> DecoderResult<()> { |
| 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; |
| 338 | |
| 339 | if cell.no_mv() { |
| 340 | sidx = 0; |
| 341 | } else { |
| 342 | let mv = cell.mv.unwrap(); |
| 343 | let mx = i16::from(mv.x); |
| 344 | let my = i16::from(mv.y); |
| 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 | } |
| 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 | } |
| 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, |
| 386 | y == 0, (cell.y == 0) && (y == 0)); |
| 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; |
| 404 | validate!(idx1 < delta_tab.data.len() / 2); |
| 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 { |
| 465 | let nl = 257 - i16::from(c) - (line as i16); |
| 466 | validate!(nl > 0); |
| 467 | tocopy = nl as usize; |
| 468 | } |
| 469 | if do_copy { |
| 470 | if !(params.bh == 8 && cell.no_mv()) { |
| 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(); |
| 505 | let mx = i16::from(mv.x); |
| 506 | let my = i16::from(mv.y); |
| 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; |
| 533 | } else { |
| 534 | idx1 += self.vq_offset as usize; |
| 535 | idx2 += self.vq_offset as usize; |
| 536 | } |
| 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 | } |
| 578 | self.decode_cell_data(br, cell, off, stride, cp, vq_idx) |
| 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 |
| 634 | self.mvs.clear(); |
| 635 | for _ in 0..nvec { |
| 636 | let x = br.read_byte()? as i8; |
| 637 | let y = br.read_byte()? as i8; |
| 638 | self.mvs.push(MV{ x, y }); |
| 639 | } |
| 640 | |
| 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); |
| 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 |
| 661 | self.mvs.clear(); |
| 662 | for _ in 0..nvec { |
| 663 | let y = br.read_byte()? as i8; |
| 664 | let x = br.read_byte()? as i8; |
| 665 | self.mvs.push(MV{ x, y }); |
| 666 | } |
| 667 | |
| 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); |
| 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 { |
| 685 | fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { |
| 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)); |
| 691 | self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref(); |
| 692 | self.bufs.reset(); |
| 693 | Ok(()) |
| 694 | } else { |
| 695 | Err(DecoderError::InvalidData) |
| 696 | } |
| 697 | } |
| 698 | fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { |
| 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 | } |
| 712 | if i64::from(size) > br.left() { return Err(DecoderError::InvalidData); } |
| 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()?; |
| 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 | } |
| 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)); |
| 732 | let vinfo; |
| 733 | if (self.bufs.width != (width as usize)) || (self.bufs.height != (height as usize)) { |
| 734 | self.bufs.alloc(width as usize, height as usize); |
| 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(); |
| 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 | |
| 762 | let intraframe = (flags & FLAG_KEYFRAME) != 0; |
| 763 | let bufinfo = alloc_video_buffer(vinfo, 4)?; |
| 764 | let mut buf = bufinfo.get_vbuf().unwrap(); |
| 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); |
| 771 | if intraframe { |
| 772 | self.decode_plane_intra(&mut br, 0, ystart, yendpos)?; |
| 773 | self.decode_plane_intra(&mut br, 1, vstart, vendpos)?; |
| 774 | self.decode_plane_intra(&mut br, 2, ustart, uendpos)?; |
| 775 | } else { |
| 776 | self.decode_plane_inter(&mut br, 0, ystart, yendpos)?; |
| 777 | self.decode_plane_inter(&mut br, 1, vstart, vendpos)?; |
| 778 | self.decode_plane_inter(&mut br, 2, ustart, uendpos)?; |
| 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); |
| 783 | frm.set_keyframe(intraframe); |
| 784 | frm.set_frame_type(if intraframe { FrameType::I } else { FrameType::P }); |
| 785 | Ok(frm.into_ref()) |
| 786 | } |
| 787 | fn flush(&mut self) { |
| 788 | self.bufs.reset(); |
| 789 | } |
| 790 | } |
| 791 | |
| 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 | |
| 798 | pub fn get_decoder() -> Box<dyn NADecoder + Send> { |
| 799 | Box::new(Indeo3Decoder::new()) |
| 800 | } |
| 801 | |
| 802 | #[cfg(test)] |
| 803 | mod test { |
| 804 | use nihav_core::codecs::RegisteredDecoders; |
| 805 | use nihav_core::demuxers::RegisteredDemuxers; |
| 806 | use nihav_codec_support::test::dec_video::*; |
| 807 | use crate::indeo_register_all_decoders; |
| 808 | use nihav_commonfmt::generic_register_all_demuxers; |
| 809 | #[test] |
| 810 | fn test_indeo3() { |
| 811 | let mut dmx_reg = RegisteredDemuxers::new(); |
| 812 | generic_register_all_demuxers(&mut dmx_reg); |
| 813 | let mut dec_reg = RegisteredDecoders::new(); |
| 814 | indeo_register_all_decoders(&mut dec_reg); |
| 815 | |
| 816 | // sample: https://samples.mplayerhq.hu/V-codecs/IV32/iv32_example.avi |
| 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]])); |
| 830 | } |
| 831 | } |