| 1 | use nihav_core::codecs::*; |
| 2 | use nihav_core::io::byteio::*; |
| 3 | use nihav_codec_support::codecs::{MV, ZERO_MV}; |
| 4 | use super::vpcommon::*; |
| 5 | use super::vp78::*; |
| 6 | use super::vp78data::*; |
| 7 | use super::vp78dsp::*; |
| 8 | use super::vp7data::*; |
| 9 | use super::vp7dsp::*; |
| 10 | |
| 11 | const PITCH_MODE_NORMAL: u8 = 0; |
| 12 | const PITCH_MODE_FOUR: u8 = 1; |
| 13 | const PITCH_MODE_X2: u8 = 2; |
| 14 | const PITCH_MODE_X4: u8 = 3; |
| 15 | |
| 16 | #[derive(Clone,Copy,Default)] |
| 17 | struct MBFeature { |
| 18 | present_prob: u8, |
| 19 | tree_probs: [u8; 3], |
| 20 | def_val: [u8; 4], |
| 21 | } |
| 22 | |
| 23 | struct SBParams<'a> { |
| 24 | coef_probs: &'a [[[[u8; 11]; 3]; 8]; 4], |
| 25 | scan: &'a [usize; 16], |
| 26 | qmat: &'a [i16; 16], |
| 27 | } |
| 28 | |
| 29 | fn decode_subblock(bc: &mut BoolCoder, coeffs: &mut [i16; 16], ctype: usize, pctx: u8, sbparams: &SBParams) -> u8 { |
| 30 | let mut has_nz = 0; |
| 31 | let start = if ctype != 0 { 0 } else { 1 }; |
| 32 | *coeffs = [0; 16]; |
| 33 | let mut cval = pctx as usize; |
| 34 | for idx in start..16 { |
| 35 | let probs = &sbparams.coef_probs[ctype][COEF_BANDS[idx]][cval]; |
| 36 | let tok = bc.read_tree(COEF_TREE, probs); |
| 37 | if tok == DCTToken::EOB { break; } |
| 38 | let level = expand_token(bc, tok); |
| 39 | coeffs[sbparams.scan[idx]] = level.wrapping_mul(sbparams.qmat[idx]); |
| 40 | cval = level.abs().min(2) as usize; |
| 41 | has_nz |= cval; |
| 42 | } |
| 43 | if has_nz > 0 { 1 } else { 0 } |
| 44 | } |
| 45 | |
| 46 | #[derive(Clone,Copy,Default)] |
| 47 | struct MBInfo { |
| 48 | mb_type: VPMBType, |
| 49 | ymode: PredMode, |
| 50 | uvmode: PredMode, |
| 51 | loop_str: u8, |
| 52 | upd_gf: bool, |
| 53 | } |
| 54 | |
| 55 | #[derive(Default)] |
| 56 | struct DecoderState { |
| 57 | features: [Option<MBFeature>; 4], |
| 58 | |
| 59 | fading: bool, |
| 60 | fade_alpha: u16, |
| 61 | fade_beta: u16, |
| 62 | |
| 63 | lf_simple: bool, |
| 64 | loop_filter_level: u8, |
| 65 | loop_sharpness: u8, |
| 66 | |
| 67 | is_intra: bool, |
| 68 | version: u8, |
| 69 | |
| 70 | kf_ymode_prob: [u8; 4], |
| 71 | kf_uvmode_prob: [u8; 3], |
| 72 | |
| 73 | prob_intra_pred: u8, |
| 74 | prob_last_pred: u8, |
| 75 | |
| 76 | coef_probs: [[[[u8; 11]; 3]; 8]; 4], |
| 77 | mv_probs: [[u8; 17]; 2], |
| 78 | |
| 79 | force_quant: Option<u8>, |
| 80 | force_loop_str: Option<u8>, |
| 81 | force_gf_update: bool, |
| 82 | force_pitch: Option<u8>, |
| 83 | |
| 84 | has_y2: bool, |
| 85 | pdc_pred_val: [i16; 2], |
| 86 | pdc_pred_count: [usize; 2], |
| 87 | |
| 88 | ipred_ctx_y: IPredContext, |
| 89 | ipred_ctx_u: IPredContext, |
| 90 | ipred_ctx_v: IPredContext, |
| 91 | } |
| 92 | |
| 93 | impl DecoderState { |
| 94 | fn reset(&mut self) { |
| 95 | self.kf_ymode_prob.copy_from_slice(Y_MODE_TREE_PROBS); |
| 96 | self.kf_uvmode_prob.copy_from_slice(UV_MODE_TREE_PROBS); |
| 97 | self.coef_probs.copy_from_slice(&DEFAULT_DCT_PROBS); |
| 98 | self.mv_probs.copy_from_slice(&DEFAULT_MV_PROBS); |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | fn decode_mv_component(bc: &mut BoolCoder, probs: &[u8; 17]) -> i16 { |
| 103 | let val = if !bc.read_prob(probs[0]) { |
| 104 | bc.read_tree(SMALL_MV_TREE, &probs[2..9]) |
| 105 | } else { |
| 106 | let raw_probs = &probs[9..]; |
| 107 | let mut raw = 0; |
| 108 | for ord in LONG_VECTOR_ORDER.iter() { |
| 109 | raw |= (bc.read_prob(raw_probs[*ord]) as i16) << *ord; |
| 110 | } |
| 111 | if (raw & 0xF0) != 0 { |
| 112 | raw |= (bc.read_prob(raw_probs[3]) as i16) << 3; |
| 113 | } else { |
| 114 | raw |= 1 << 3; |
| 115 | } |
| 116 | raw |
| 117 | }; |
| 118 | if (val == 0) || !bc.read_prob(probs[1]) { |
| 119 | val |
| 120 | } else { |
| 121 | -val |
| 122 | } |
| 123 | } |
| 124 | |
| 125 | struct VP7Decoder { |
| 126 | info: NACodecInfoRef, |
| 127 | |
| 128 | shuf: VPShuffler, |
| 129 | width: usize, |
| 130 | height: usize, |
| 131 | mb_w: usize, |
| 132 | mb_h: usize, |
| 133 | mb_info: Vec<MBInfo>, |
| 134 | mvs: Vec<MV>, |
| 135 | mv_stride: usize, |
| 136 | |
| 137 | ymodes: Vec<PredMode>, |
| 138 | ymode_stride: usize, |
| 139 | uvmodes: Vec<PredMode>, |
| 140 | uvmode_stride: usize, |
| 141 | |
| 142 | dstate: DecoderState, |
| 143 | pcache: PredCache, |
| 144 | |
| 145 | coeffs: [[i16; 16]; 25], |
| 146 | scan: [usize; 16], |
| 147 | qmat: [[[i16; 16]; 3]; 5], |
| 148 | |
| 149 | mc_buf: NAVideoBufferRef<u8>, |
| 150 | |
| 151 | tmp_scan: [usize; 16], |
| 152 | } |
| 153 | |
| 154 | impl VP7Decoder { |
| 155 | fn new() -> Self { |
| 156 | let vt = alloc_video_buffer(NAVideoInfo::new(128, 128, false, YUV420_FORMAT), 4).unwrap(); |
| 157 | let mut scan = [0; 16]; |
| 158 | scan.copy_from_slice(&DEFAULT_SCAN_ORDER); |
| 159 | let mc_buf = vt.get_vbuf().unwrap(); |
| 160 | Self { |
| 161 | info: NACodecInfoRef::default(), |
| 162 | |
| 163 | shuf: VPShuffler::new(), |
| 164 | width: 0, |
| 165 | height: 0, |
| 166 | mb_w: 0, |
| 167 | mb_h: 0, |
| 168 | mb_info: Vec::new(), |
| 169 | mvs: Vec::new(), |
| 170 | mv_stride: 0, |
| 171 | |
| 172 | ymodes: Vec::new(), |
| 173 | ymode_stride: 0, |
| 174 | uvmodes: Vec::new(), |
| 175 | uvmode_stride: 0, |
| 176 | |
| 177 | dstate: DecoderState::default(), |
| 178 | pcache: PredCache::new(), |
| 179 | |
| 180 | coeffs: [[0; 16]; 25], |
| 181 | scan, |
| 182 | tmp_scan: [0; 16], |
| 183 | qmat: [[[0; 16]; 3]; 5], |
| 184 | |
| 185 | mc_buf, |
| 186 | } |
| 187 | } |
| 188 | fn set_dimensions(&mut self, width: usize, height: usize) { |
| 189 | if (width == self.width) && (height == self.height) { |
| 190 | return; |
| 191 | } |
| 192 | self.width = width; |
| 193 | self.height = height; |
| 194 | self.mb_w = (self.width + 15) >> 4; |
| 195 | self.mb_h = (self.height + 15) >> 4; |
| 196 | self.mb_info.resize(self.mb_w * self.mb_h, MBInfo::default()); |
| 197 | self.mv_stride = self.mb_w * 4; |
| 198 | self.mvs.resize(self.mv_stride * self.mb_h * 4, ZERO_MV); |
| 199 | |
| 200 | self.ymode_stride = self.mb_w * 4; |
| 201 | self.uvmode_stride = self.mb_w; |
| 202 | self.ymodes.resize(self.ymode_stride * self.mb_h * 4, PredMode::default()); |
| 203 | self.uvmodes.resize(self.uvmode_stride * self.mb_h, PredMode::default()); |
| 204 | |
| 205 | self.pcache.resize(self.mb_w); |
| 206 | } |
| 207 | #[allow(clippy::field_reassign_with_default)] |
| 208 | fn read_features(&mut self, bc: &mut BoolCoder) -> DecoderResult<()> { |
| 209 | for (i, feat) in self.dstate.features.iter_mut().enumerate() { |
| 210 | if bc.read_bool() { |
| 211 | let mut feature = MBFeature::default(); |
| 212 | feature.present_prob = bc.read_byte(); |
| 213 | for tp in feature.tree_probs.iter_mut() { |
| 214 | if bc.read_bool() { |
| 215 | *tp = bc.read_byte(); |
| 216 | } else { |
| 217 | *tp = 255; |
| 218 | } |
| 219 | } |
| 220 | if i != 2 { |
| 221 | let fbits = match i { |
| 222 | 0 => 7, |
| 223 | 1 => 6, |
| 224 | _ => if self.dstate.version == 0 { 8 } else { 5 }, |
| 225 | }; |
| 226 | for dval in feature.def_val.iter_mut() { |
| 227 | if bc.read_bool() { |
| 228 | *dval = bc.read_bits(fbits) as u8; |
| 229 | } else { |
| 230 | *dval = 0; |
| 231 | } |
| 232 | } |
| 233 | } |
| 234 | *feat = Some(feature); |
| 235 | } else { |
| 236 | *feat = None; |
| 237 | } |
| 238 | } |
| 239 | Ok(()) |
| 240 | } |
| 241 | fn read_dct_coef_prob_upd(&mut self, bc: &mut BoolCoder) -> DecoderResult<()> { |
| 242 | for i in 0..4 { |
| 243 | for j in 0..8 { |
| 244 | for k in 0..3 { |
| 245 | for l in 0..11 { |
| 246 | if bc.read_prob(DCT_UPDATE_PROBS[i][j][k][l]) { |
| 247 | self.dstate.coef_probs[i][j][k][l] = bc.read_byte(); |
| 248 | } |
| 249 | } |
| 250 | } |
| 251 | } |
| 252 | } |
| 253 | Ok(()) |
| 254 | } |
| 255 | fn read_mv_prob_upd(&mut self, bc: &mut BoolCoder) -> DecoderResult<()> { |
| 256 | for comp in 0..2 { |
| 257 | for i in 0..17 { |
| 258 | if bc.read_prob(MV_UPDATE_PROBS[comp][i]) { |
| 259 | self.dstate.mv_probs[comp][i] = bc.read_probability(); |
| 260 | } |
| 261 | } |
| 262 | } |
| 263 | Ok(()) |
| 264 | } |
| 265 | fn decode_mb_features(&mut self, bc: &mut BoolCoder, _mb_x: usize, _mb_y: usize) -> DecoderResult<()> { |
| 266 | self.dstate.force_quant = None; |
| 267 | self.dstate.force_loop_str = None; |
| 268 | self.dstate.force_gf_update = false; |
| 269 | self.dstate.force_pitch = None; |
| 270 | for (i, feat) in self.dstate.features.iter().enumerate() { |
| 271 | if let Some(feat) = feat { |
| 272 | let present = bc.read_prob(feat.present_prob); |
| 273 | if present { |
| 274 | let ftype_idx = bc.read_tree(FEATURE_TREE, &feat.tree_probs); |
| 275 | let val = feat.def_val[ftype_idx]; |
| 276 | match i { |
| 277 | 0 => self.dstate.force_quant = Some(ftype_idx as u8), |
| 278 | 1 => self.dstate.force_loop_str = Some(val), |
| 279 | 2 => self.dstate.force_gf_update = true, |
| 280 | _ => self.dstate.force_pitch = Some(val), |
| 281 | }; |
| 282 | } |
| 283 | } |
| 284 | } |
| 285 | Ok(()) |
| 286 | } |
| 287 | fn decode_residue(&mut self, bc: &mut BoolCoder, mb_x: usize, mb_idx: usize, use_last: bool) { |
| 288 | let qmat_idx = if let Some(idx) = self.dstate.force_quant { (idx as usize) + 1 } else { 0 }; |
| 289 | let mut sbparams = SBParams { |
| 290 | scan: &DEFAULT_SCAN_ORDER, |
| 291 | qmat: &self.qmat[qmat_idx][2], |
| 292 | coef_probs: &self.dstate.coef_probs, |
| 293 | }; |
| 294 | let mut has_ac = [false; 25]; |
| 295 | let ytype; |
| 296 | if self.dstate.has_y2 { |
| 297 | let pred = &self.pcache.y2_pred; |
| 298 | let pidx = pred.xpos + mb_x; |
| 299 | let pctx = self.pcache.y2_pred_left + pred.data[pidx - pred.stride]; |
| 300 | |
| 301 | let has_nz = decode_subblock(bc, &mut self.coeffs[24], 1, pctx, &sbparams); |
| 302 | self.pcache.y2_pred.data[pidx] = has_nz; |
| 303 | self.pcache.y2_pred_left = has_nz; |
| 304 | has_ac[24] = has_nz > 0; |
| 305 | |
| 306 | ytype = 0; |
| 307 | } else { |
| 308 | let pred = &mut self.pcache.y2_pred; |
| 309 | let pidx = pred.xpos + mb_x; |
| 310 | pred.data[pidx] = pred.data[pidx - pred.stride]; |
| 311 | |
| 312 | ytype = 3; |
| 313 | } |
| 314 | sbparams.scan = &self.scan; |
| 315 | sbparams.qmat = &self.qmat[qmat_idx][0]; |
| 316 | for i in 0..16 { |
| 317 | let bx = i & 3; |
| 318 | let by = i >> 2; |
| 319 | let pred = &self.pcache.y_pred; |
| 320 | let pidx = pred.xpos + mb_x * 4 + bx + by * pred.stride; |
| 321 | let pctx = self.pcache.y_pred_left[by] + pred.data[pidx - pred.stride]; |
| 322 | |
| 323 | let has_nz = decode_subblock(bc, &mut self.coeffs[i], ytype, pctx, &sbparams); |
| 324 | self.pcache.y_pred.data[pidx] = has_nz; |
| 325 | self.pcache.y_pred_left[by] = has_nz; |
| 326 | has_ac[i] = has_nz > 0; |
| 327 | } |
| 328 | sbparams.qmat = &self.qmat[qmat_idx][1]; |
| 329 | for i in 16..20 { |
| 330 | let bx = i & 1; |
| 331 | let by = (i >> 1) & 1; |
| 332 | let pred = &self.pcache.u_pred; |
| 333 | let pidx = pred.xpos + mb_x * 2 + bx + by * pred.stride; |
| 334 | let pctx = self.pcache.u_pred_left[by] + pred.data[pidx - pred.stride]; |
| 335 | |
| 336 | let has_nz = decode_subblock(bc, &mut self.coeffs[i], 2, pctx, &sbparams); |
| 337 | self.pcache.u_pred.data[pidx] = has_nz; |
| 338 | self.pcache.u_pred_left[by] = has_nz; |
| 339 | has_ac[i] = has_nz > 0; |
| 340 | } |
| 341 | for i in 20..24 { |
| 342 | let bx = i & 1; |
| 343 | let by = (i >> 1) & 1; |
| 344 | let pred = &self.pcache.v_pred; |
| 345 | let pidx = pred.xpos + mb_x * 2 + bx + by * pred.stride; |
| 346 | let pctx = self.pcache.v_pred_left[by] + pred.data[pidx - pred.stride]; |
| 347 | |
| 348 | let has_nz = decode_subblock(bc, &mut self.coeffs[i], 2, pctx, &sbparams); |
| 349 | self.pcache.v_pred.data[pidx] = has_nz; |
| 350 | self.pcache.v_pred_left[by] = has_nz; |
| 351 | has_ac[i] = has_nz > 0; |
| 352 | } |
| 353 | |
| 354 | if self.dstate.has_y2 { |
| 355 | let y2block = &mut self.coeffs[24]; |
| 356 | if self.mb_info[mb_idx].mb_type != VPMBType::Intra { |
| 357 | let mut dc = y2block[0]; |
| 358 | let pdc_idx = if use_last { 0 } else { 1 }; |
| 359 | let pval = self.dstate.pdc_pred_val[pdc_idx]; |
| 360 | |
| 361 | if self.dstate.pdc_pred_count[pdc_idx] > 3 { |
| 362 | dc += pval; |
| 363 | y2block[0] = dc; |
| 364 | } |
| 365 | if (pval == 0) || (dc == 0) || ((pval ^ dc) < 0) { |
| 366 | self.dstate.pdc_pred_count[pdc_idx] = 0; |
| 367 | } else if dc == pval { |
| 368 | self.dstate.pdc_pred_count[pdc_idx] += 1; |
| 369 | } |
| 370 | self.dstate.pdc_pred_val[pdc_idx] = dc; |
| 371 | } |
| 372 | if has_ac[24] { |
| 373 | idct4x4(y2block); |
| 374 | } else if y2block[0] != 0 { |
| 375 | idct4x4_dc(y2block); |
| 376 | } |
| 377 | for i in 0..16 { |
| 378 | self.coeffs[i][0] = self.coeffs[24][i]; |
| 379 | } |
| 380 | } |
| 381 | for i in 0..24 { |
| 382 | if has_ac[i] { |
| 383 | idct4x4(&mut self.coeffs[i]); |
| 384 | } else if self.coeffs[i][0] != 0 { |
| 385 | idct4x4_dc(&mut self.coeffs[i]); |
| 386 | } |
| 387 | } |
| 388 | } |
| 389 | |
| 390 | fn set_qmat(&mut self, y_dc_q: usize, y_ac_q: usize, y2_dc_q: usize, y2_ac_q: usize, uv_dc_q: usize, uv_ac_q: usize) { |
| 391 | self.qmat[0][0][0] = Y_DC_QUANTS[y_dc_q]; |
| 392 | for i in 1..16 { |
| 393 | self.qmat[0][0][i] = Y_AC_QUANTS[y_ac_q]; |
| 394 | } |
| 395 | self.qmat[0][1][0] = UV_DC_QUANTS[uv_dc_q]; |
| 396 | for i in 1..16 { |
| 397 | self.qmat[0][1][i] = UV_AC_QUANTS[uv_ac_q]; |
| 398 | } |
| 399 | self.qmat[0][2][0] = Y2_DC_QUANTS[y2_dc_q]; |
| 400 | for i in 1..16 { |
| 401 | self.qmat[0][2][i] = Y2_AC_QUANTS[y2_ac_q]; |
| 402 | } |
| 403 | if let Some(ref feat) = self.dstate.features[0] { |
| 404 | for j in 0..4 { |
| 405 | let q = feat.def_val[j] as usize; |
| 406 | self.qmat[j + 1][0][0] = Y_DC_QUANTS[q]; |
| 407 | for i in 1..16 { |
| 408 | self.qmat[j + 1][0][i] = Y_AC_QUANTS[q]; |
| 409 | } |
| 410 | self.qmat[j + 1][1][0] = UV_DC_QUANTS[q]; |
| 411 | for i in 1..16 { |
| 412 | self.qmat[j + 1][1][i] = UV_AC_QUANTS[q]; |
| 413 | } |
| 414 | self.qmat[j + 1][2][0] = Y2_DC_QUANTS[q]; |
| 415 | for i in 1..16 { |
| 416 | self.qmat[j + 1][2][i] = Y2_AC_QUANTS[q]; |
| 417 | } |
| 418 | } |
| 419 | } |
| 420 | } |
| 421 | fn fill_ymode(&mut self, mb_x: usize, mb_y: usize, ymode: PredMode) { |
| 422 | let mut iidx = mb_x * 4 + mb_y * 4 * self.ymode_stride; |
| 423 | for _ in 0..4 { |
| 424 | for x in 0..4 { |
| 425 | self.ymodes[iidx + x] = ymode; |
| 426 | } |
| 427 | iidx += self.ymode_stride; |
| 428 | } |
| 429 | } |
| 430 | fn fill_mv(&mut self, mb_x: usize, mb_y: usize, mv: MV) { |
| 431 | let mut iidx = mb_x * 4 + mb_y * 4 * self.mv_stride; |
| 432 | for _ in 0..4 { |
| 433 | for x in 0..4 { |
| 434 | self.mvs[iidx + x] = mv; |
| 435 | } |
| 436 | iidx += self.mb_w * 4; |
| 437 | } |
| 438 | } |
| 439 | fn find_mv_pred(&self, mb_x: usize, mb_y: usize) -> ([u8; 4], MV, MV, MV) { |
| 440 | let mut nearest_mv = ZERO_MV; |
| 441 | let mut near_mv = ZERO_MV; |
| 442 | |
| 443 | let mut ct: [u8; 4] = [0; 4]; |
| 444 | |
| 445 | let start = if self.dstate.version == 0 { 1 } else { 0 }; |
| 446 | let mvwrap = (self.mb_w as isize) + 1; |
| 447 | for (yoff, xoff, weight, blk_no) in CAND_POS.iter() { |
| 448 | let cx = (mb_x as isize) + (*xoff as isize); |
| 449 | let cy = (mb_y as isize) + (*yoff as isize); |
| 450 | let mvpos = cx + cy * mvwrap; |
| 451 | if (mvpos < start) || ((mvpos % mvwrap) == (mvwrap - 1)) { |
| 452 | ct[0] += weight; |
| 453 | continue; |
| 454 | } |
| 455 | let cx = (mvpos % mvwrap) as usize; |
| 456 | let cy = (mvpos / mvwrap) as usize; |
| 457 | let bx = (*blk_no as usize) & 3; |
| 458 | let by = (*blk_no as usize) >> 2; |
| 459 | let blk_pos = cx * 4 + bx + (cy * 4 + by) * self.mv_stride; |
| 460 | let mv = self.mvs[blk_pos]; |
| 461 | if mv == ZERO_MV { |
| 462 | ct[0] += weight; |
| 463 | continue; |
| 464 | } |
| 465 | let idx; |
| 466 | if (nearest_mv == ZERO_MV) || (nearest_mv == mv) { |
| 467 | nearest_mv = mv; |
| 468 | idx = 1; |
| 469 | } else if near_mv == ZERO_MV { |
| 470 | near_mv = mv; |
| 471 | idx = 2; |
| 472 | } else { |
| 473 | idx = if mv == near_mv { 2 } else { 3 }; |
| 474 | } |
| 475 | ct[idx] += weight; |
| 476 | } |
| 477 | let pred_mv = if ct[1] > ct[2] { |
| 478 | if ct[1] >= ct[0] { nearest_mv } else { ZERO_MV } |
| 479 | } else { |
| 480 | if ct[2] >= ct[0] { near_mv } else { ZERO_MV } |
| 481 | }; |
| 482 | |
| 483 | let mvprobs = [INTER_MODE_PROBS[ct[0] as usize][0], |
| 484 | INTER_MODE_PROBS[ct[1] as usize][1], |
| 485 | INTER_MODE_PROBS[ct[2] as usize][2], |
| 486 | INTER_MODE_PROBS[ct[2] as usize][3]]; |
| 487 | |
| 488 | (mvprobs, nearest_mv, near_mv, pred_mv) |
| 489 | } |
| 490 | fn get_split_mv(&self, bc: &mut BoolCoder, mb_x: usize, mb_y: usize, bx: usize, by: usize, pred_mv: MV) -> MV { |
| 491 | let mode = bc.read_tree(SUB_MV_REF_TREE, &SUB_MV_REF_PROBS); |
| 492 | let mvidx = mb_x * 4 + bx + (mb_y * 4 + by) * self.mv_stride; |
| 493 | match mode { |
| 494 | SubMVRef::Left => { |
| 495 | if (mb_x > 0) || (bx > 0) { |
| 496 | self.mvs[mvidx - 1] |
| 497 | } else { |
| 498 | ZERO_MV |
| 499 | } |
| 500 | }, |
| 501 | SubMVRef::Above => { |
| 502 | if (mb_y > 0) || (by > 0) { |
| 503 | self.mvs[mvidx - self.mv_stride] |
| 504 | } else { |
| 505 | ZERO_MV |
| 506 | } |
| 507 | }, |
| 508 | SubMVRef::Zero => ZERO_MV, |
| 509 | SubMVRef::New => { |
| 510 | let dmy = decode_mv_component(bc, &self.dstate.mv_probs[0]); |
| 511 | let dmx = decode_mv_component(bc, &self.dstate.mv_probs[1]); |
| 512 | pred_mv + MV{ x: dmx, y: dmy } |
| 513 | }, |
| 514 | } |
| 515 | } |
| 516 | fn do_split_mv(&mut self, bc: &mut BoolCoder, mb_x: usize, mb_y: usize, pred_mv: MV) -> DecoderResult<()> { |
| 517 | let split_mode = bc.read_tree(MV_SPLIT_MODE_TREE, &MV_SPLIT_MODE_PROBS); |
| 518 | let mut mvidx = mb_x * 4 + mb_y * 4 * self.mv_stride; |
| 519 | match split_mode { |
| 520 | MVSplitMode::TopBottom => { |
| 521 | let top_mv = self.get_split_mv(bc, mb_x, mb_y, 0, 0, pred_mv); |
| 522 | for _ in 0..2 { |
| 523 | for x in 0..4 { self.mvs[mvidx + x] = top_mv; } |
| 524 | mvidx += self.mv_stride; |
| 525 | } |
| 526 | let bot_mv = self.get_split_mv(bc, mb_x, mb_y, 0, 2, pred_mv); |
| 527 | for _ in 2..4 { |
| 528 | for x in 0..4 { self.mvs[mvidx + x] = bot_mv; } |
| 529 | mvidx += self.mv_stride; |
| 530 | } |
| 531 | }, |
| 532 | MVSplitMode::LeftRight => { |
| 533 | let left_mv = self.get_split_mv(bc, mb_x, mb_y, 0, 0, pred_mv); |
| 534 | self.mvs[mvidx + 1] = left_mv; |
| 535 | let right_mv = self.get_split_mv(bc, mb_x, mb_y, 2, 0, pred_mv); |
| 536 | for _ in 0..4 { |
| 537 | self.mvs[mvidx + 0] = left_mv; |
| 538 | self.mvs[mvidx + 1] = left_mv; |
| 539 | self.mvs[mvidx + 2] = right_mv; |
| 540 | self.mvs[mvidx + 3] = right_mv; |
| 541 | mvidx += self.mv_stride; |
| 542 | } |
| 543 | }, |
| 544 | MVSplitMode::Quarters => { |
| 545 | for y in (0..4).step_by(2) { |
| 546 | for x in (0..4).step_by(2) { |
| 547 | self.mvs[mvidx + x] = self.get_split_mv(bc, mb_x, mb_y, x, y, pred_mv); |
| 548 | self.mvs[mvidx + x + 1] = self.mvs[mvidx + x]; |
| 549 | } |
| 550 | for x in 0..4 { |
| 551 | self.mvs[mvidx + x + self.mv_stride] = self.mvs[mvidx + x]; |
| 552 | } |
| 553 | mvidx += self.mv_stride * 2; |
| 554 | } |
| 555 | }, |
| 556 | MVSplitMode::Sixteenths => { |
| 557 | for y in 0..4 { |
| 558 | for x in 0..4 { |
| 559 | self.mvs[mvidx + x] = self.get_split_mv(bc, mb_x, mb_y, x, y, pred_mv); |
| 560 | } |
| 561 | mvidx += self.mv_stride; |
| 562 | } |
| 563 | }, |
| 564 | }; |
| 565 | Ok(()) |
| 566 | } |
| 567 | |
| 568 | fn add_residue(&self, dframe: &mut NASimpleVideoFrame<u8>, mb_x: usize, mb_y: usize, do_luma: bool, pitch_mode: u8) { |
| 569 | if do_luma { |
| 570 | let ydst = &mut dframe.data[dframe.offset[0]..]; |
| 571 | let ystride = dframe.stride[0]; |
| 572 | let mut yoff = mb_x * 16 + mb_y * 16 * ystride; |
| 573 | match pitch_mode { |
| 574 | PITCH_MODE_NORMAL => { |
| 575 | for y in 0..4 { |
| 576 | for x in 0..4 { |
| 577 | add_coeffs4x4(ydst, yoff + x * 4, ystride, &self.coeffs[x + y * 4]); |
| 578 | } |
| 579 | yoff += 4 * ystride; |
| 580 | } |
| 581 | }, |
| 582 | PITCH_MODE_FOUR => { |
| 583 | for y in 0..16 { |
| 584 | add_coeffs16x1(ydst, yoff, &self.coeffs[y]); |
| 585 | yoff += ystride; |
| 586 | } |
| 587 | }, |
| 588 | PITCH_MODE_X2 => { |
| 589 | for y in 0..2 { |
| 590 | for x in 0..4 { |
| 591 | add_coeffs4x4(ydst, yoff + x * 4, ystride * 2, &self.coeffs[x + y * 4]); |
| 592 | } |
| 593 | yoff += 8 * ystride; |
| 594 | } |
| 595 | yoff -= 15 * ystride; |
| 596 | for y in 2..4 { |
| 597 | for x in 0..4 { |
| 598 | add_coeffs4x4(ydst, yoff + x * 4, ystride * 2, &self.coeffs[x + y * 4]); |
| 599 | } |
| 600 | yoff += 8 * ystride; |
| 601 | } |
| 602 | }, |
| 603 | PITCH_MODE_X4 => { |
| 604 | for y in 0..4 { |
| 605 | for x in 0..4 { |
| 606 | add_coeffs4x4(ydst, yoff + x * 4, ystride * 4, &self.coeffs[x + y * 4]); |
| 607 | } |
| 608 | yoff += ystride; |
| 609 | } |
| 610 | }, |
| 611 | _ => unreachable!(), |
| 612 | }; |
| 613 | } |
| 614 | let dst = &mut dframe.data[0..]; |
| 615 | let mut uoff = dframe.offset[1] + mb_x * 8 + mb_y * 8 * dframe.stride[1]; |
| 616 | let ustride = dframe.stride[1]; |
| 617 | let mut voff = dframe.offset[2] + mb_x * 8 + mb_y * 8 * dframe.stride[2]; |
| 618 | let vstride = dframe.stride[2]; |
| 619 | if (pitch_mode == PITCH_MODE_NORMAL) || (pitch_mode == PITCH_MODE_FOUR) { |
| 620 | for y in 0..2 { |
| 621 | for x in 0..2 { |
| 622 | add_coeffs4x4(dst, uoff + x * 4, ustride, &self.coeffs[16 + x + y * 2]); |
| 623 | add_coeffs4x4(dst, voff + x * 4, vstride, &self.coeffs[20 + x + y * 2]); |
| 624 | } |
| 625 | uoff += ustride * 4; |
| 626 | voff += vstride * 4; |
| 627 | } |
| 628 | } else { |
| 629 | for y in 0..2 { |
| 630 | for x in 0..2 { |
| 631 | add_coeffs4x4(dst, uoff + x * 4, ustride * 2, &self.coeffs[16 + x + y * 2]); |
| 632 | add_coeffs4x4(dst, voff + x * 4, vstride * 2, &self.coeffs[20 + x + y * 2]); |
| 633 | } |
| 634 | uoff += ustride; |
| 635 | voff += vstride; |
| 636 | } |
| 637 | } |
| 638 | } |
| 639 | fn recon_intra_mb(&mut self, dframe: &mut NASimpleVideoFrame<u8>, mb_x: usize, mb_y: usize) -> DecoderResult<()> { |
| 640 | let pitch = self.dstate.force_pitch.unwrap_or(0); |
| 641 | let pitch_mode = (pitch >> 3) & 3; |
| 642 | |
| 643 | let mb_idx = mb_x + mb_y * self.mb_w; |
| 644 | let has_top = mb_y > 0; |
| 645 | let has_left = mb_x > 0; |
| 646 | let ydst = &mut dframe.data[dframe.offset[0]..]; |
| 647 | let ystride = dframe.stride[0]; |
| 648 | let mut yoff = mb_x * 16 + mb_y * 16 * ystride; |
| 649 | let ipred_ctx_y = &mut self.dstate.ipred_ctx_y; |
| 650 | ipred_ctx_y.has_top = has_top; |
| 651 | ipred_ctx_y.has_left = has_left; |
| 652 | let is_normal = self.mb_info[mb_idx].ymode != PredMode::BPred; |
| 653 | if is_normal { |
| 654 | ipred_ctx_y.fill(ydst, yoff, ystride, 16, 16); |
| 655 | match self.mb_info[mb_idx].ymode { |
| 656 | PredMode::DCPred => IPred16x16::ipred_dc(ydst, yoff, ystride, ipred_ctx_y), |
| 657 | PredMode::HPred => IPred16x16::ipred_h (ydst, yoff, ystride, ipred_ctx_y), |
| 658 | PredMode::VPred => IPred16x16::ipred_v (ydst, yoff, ystride, ipred_ctx_y), |
| 659 | PredMode::TMPred => IPred16x16::ipred_tm(ydst, yoff, ystride, ipred_ctx_y), |
| 660 | _ => unreachable!(), |
| 661 | }; |
| 662 | } else { |
| 663 | validate!((pitch_mode == PITCH_MODE_NORMAL) || (pitch_mode == PITCH_MODE_X2)); |
| 664 | let mut iidx = mb_x * 4 + mb_y * 4 * self.ymode_stride; |
| 665 | let mut tr_save = [0x80u8; 16]; |
| 666 | if pitch_mode == PITCH_MODE_X2 { |
| 667 | // reorganise coefficient data for interlaced case |
| 668 | for y in (0..4).step_by(2) { |
| 669 | for x in 0..4 { |
| 670 | let mut tmpblock = [0i16; 16 * 2]; |
| 671 | let eidx = x + y * 4; |
| 672 | let oidx = x + y * 4 + 4; |
| 673 | for i in 0..4 { |
| 674 | for j in 0..4 { |
| 675 | tmpblock[i * 8 + 0 + j] = self.coeffs[eidx][i * 4 + j]; |
| 676 | tmpblock[i * 8 + 4 + j] = self.coeffs[oidx][i * 4 + j]; |
| 677 | } |
| 678 | } |
| 679 | self.coeffs[eidx].copy_from_slice(&tmpblock[0..16]); |
| 680 | self.coeffs[oidx].copy_from_slice(&tmpblock[16..32]); |
| 681 | } |
| 682 | } |
| 683 | } |
| 684 | let tr_edge = if has_top { ydst[yoff - ystride + 15] } else { 0x80 }; |
| 685 | for y in 0..4 { |
| 686 | for x in 0..4 { |
| 687 | ipred_ctx_y.has_left = has_left || x > 0; |
| 688 | let bmode = self.ymodes[iidx + x]; |
| 689 | let cur_yoff = yoff + x * 4; |
| 690 | let has_tr = ipred_ctx_y.has_top && ((x < 3) || ((y == 0) && (mb_y < self.mb_w - 1))); |
| 691 | let has_dl = ipred_ctx_y.has_left && (x == 0) && (y < 3); |
| 692 | ipred_ctx_y.fill(ydst, cur_yoff, ystride, |
| 693 | if has_tr { 8 } else { 4 }, |
| 694 | if has_dl { 8 } else { 4 }); |
| 695 | if !has_tr { |
| 696 | for i in 0..4 { |
| 697 | ipred_ctx_y.top[i + 4] = tr_save[x * 4 + i]; |
| 698 | } |
| 699 | } else { |
| 700 | for i in 0..4 { |
| 701 | tr_save[x * 4 + i] = ipred_ctx_y.top[i + 4]; |
| 702 | } |
| 703 | } |
| 704 | if (mb_x == self.mb_w - 1) && has_top && (x == 3) { |
| 705 | for i in 0..4 { |
| 706 | ipred_ctx_y.top[i + 4] = tr_edge; |
| 707 | } |
| 708 | } |
| 709 | match bmode { |
| 710 | PredMode::DCPred => IPred4x4::ipred_dc(ydst, cur_yoff, ystride, ipred_ctx_y), |
| 711 | PredMode::TMPred => IPred4x4::ipred_tm(ydst, cur_yoff, ystride, ipred_ctx_y), |
| 712 | PredMode::HPred => IPred4x4::ipred_he(ydst, cur_yoff, ystride, ipred_ctx_y), |
| 713 | PredMode::VPred => IPred4x4::ipred_ve(ydst, cur_yoff, ystride, ipred_ctx_y), |
| 714 | PredMode::LDPred => IPred4x4::ipred_ld(ydst, cur_yoff, ystride, ipred_ctx_y), |
| 715 | PredMode::RDPred => IPred4x4::ipred_rd(ydst, cur_yoff, ystride, ipred_ctx_y), |
| 716 | PredMode::VRPred => IPred4x4::ipred_vr(ydst, cur_yoff, ystride, ipred_ctx_y), |
| 717 | PredMode::VLPred => IPred4x4::ipred_vl(ydst, cur_yoff, ystride, ipred_ctx_y), |
| 718 | PredMode::HDPred => IPred4x4::ipred_hd(ydst, cur_yoff, ystride, ipred_ctx_y), |
| 719 | PredMode::HUPred => IPred4x4::ipred_hu(ydst, cur_yoff, ystride, ipred_ctx_y), |
| 720 | _ => unreachable!(), |
| 721 | }; |
| 722 | add_coeffs4x4(ydst, cur_yoff, ystride, &self.coeffs[x + y * 4]); |
| 723 | } |
| 724 | ipred_ctx_y.has_top = true; |
| 725 | yoff += 4 * ystride; |
| 726 | iidx += self.ymode_stride; |
| 727 | } |
| 728 | } |
| 729 | let dst = &mut dframe.data[0..]; |
| 730 | let uoff = dframe.offset[1] + mb_x * 8 + mb_y * 8 * dframe.stride[1]; |
| 731 | let ustride = dframe.stride[1]; |
| 732 | let voff = dframe.offset[2] + mb_x * 8 + mb_y * 8 * dframe.stride[2]; |
| 733 | let vstride = dframe.stride[2]; |
| 734 | let ipred_ctx_u = &mut self.dstate.ipred_ctx_u; |
| 735 | let ipred_ctx_v = &mut self.dstate.ipred_ctx_v; |
| 736 | ipred_ctx_u.has_top = has_top; |
| 737 | ipred_ctx_v.has_top = has_top; |
| 738 | ipred_ctx_u.has_left = has_left; |
| 739 | ipred_ctx_v.has_left = has_left; |
| 740 | ipred_ctx_u.fill(dst, uoff, ustride, 8, 8); |
| 741 | ipred_ctx_v.fill(dst, voff, vstride, 8, 8); |
| 742 | match self.mb_info[mb_idx].uvmode { |
| 743 | PredMode::DCPred => { |
| 744 | IPred8x8::ipred_dc(dst, uoff, ustride, ipred_ctx_u); |
| 745 | IPred8x8::ipred_dc(dst, voff, vstride, ipred_ctx_v); |
| 746 | }, |
| 747 | PredMode::HPred => { |
| 748 | IPred8x8::ipred_h(dst, uoff, ustride, ipred_ctx_u); |
| 749 | IPred8x8::ipred_h(dst, voff, vstride, ipred_ctx_v); |
| 750 | }, |
| 751 | PredMode::VPred => { |
| 752 | IPred8x8::ipred_v(dst, uoff, ustride, ipred_ctx_u); |
| 753 | IPred8x8::ipred_v(dst, voff, vstride, ipred_ctx_v); |
| 754 | }, |
| 755 | PredMode::TMPred => { |
| 756 | IPred8x8::ipred_tm(dst, uoff, ustride, ipred_ctx_u); |
| 757 | IPred8x8::ipred_tm(dst, voff, vstride, ipred_ctx_v); |
| 758 | }, |
| 759 | _ => unreachable!(), |
| 760 | }; |
| 761 | self.add_residue(dframe, mb_x, mb_y, is_normal, pitch_mode); |
| 762 | Ok(()) |
| 763 | } |
| 764 | fn recon_inter_mb(&mut self, dframe: &mut NASimpleVideoFrame<u8>, mb_x: usize, mb_y: usize, use_last: bool) { |
| 765 | let pitch = self.dstate.force_pitch.unwrap_or(0); |
| 766 | let pitch_dmode = (pitch >> 3) & 3; |
| 767 | let pitch_smode = pitch & 7; |
| 768 | |
| 769 | let refframe = (if use_last { self.shuf.get_last() } else { self.shuf.get_golden() }).unwrap(); |
| 770 | let single_mv = self.mb_info[mb_x + mb_y * self.mb_w].mb_type != VPMBType::InterFourMV; |
| 771 | let mut iidx = mb_x * 4 + mb_y * 4 * self.mv_stride; |
| 772 | let mc_buf = self.mc_buf.get_data_mut().unwrap(); |
| 773 | |
| 774 | let dst = &mut dframe.data[0..]; |
| 775 | let ystride = dframe.stride[0]; |
| 776 | let mut yoff = dframe.offset[0] + mb_x * 16 + mb_y * 16 * ystride; |
| 777 | if pitch_smode == 0 { |
| 778 | if single_mv { |
| 779 | mc_block16x16(dst, yoff, ystride, mb_x * 16, mb_y * 16, |
| 780 | self.mvs[iidx].x * 2, self.mvs[iidx].y * 2, refframe.clone(), 0, mc_buf); |
| 781 | } else { |
| 782 | for y in 0..4 { |
| 783 | for x in 0..4 { |
| 784 | mc_block4x4(dst, yoff + x * 4, ystride, mb_x * 16 + x * 4, mb_y * 16 + y * 4, |
| 785 | self.mvs[iidx + x].x * 2, self.mvs[iidx + x].y * 2, refframe.clone(), 0, mc_buf); |
| 786 | } |
| 787 | yoff += 4 * ystride; |
| 788 | iidx += self.mv_stride; |
| 789 | } |
| 790 | } |
| 791 | } else { |
| 792 | if single_mv { |
| 793 | mc_block_special(dst, yoff, ystride, mb_x * 16, mb_y * 16, |
| 794 | self.mvs[iidx].x * 2, self.mvs[iidx].y * 2, |
| 795 | refframe.clone(), 0, mc_buf, 16, pitch_smode); |
| 796 | } else { |
| 797 | for y in 0..4 { |
| 798 | for x in 0..4 { |
| 799 | mc_block_special(dst, yoff + x * 4, ystride, |
| 800 | mb_x * 16 + x * 4, mb_y * 16 + y * 4, |
| 801 | self.mvs[iidx + x].x * 2, self.mvs[iidx + x].y * 2, |
| 802 | refframe.clone(), 0, mc_buf, 4, pitch_smode); |
| 803 | } |
| 804 | yoff += 4 * ystride; |
| 805 | iidx += self.mv_stride; |
| 806 | } |
| 807 | } |
| 808 | } |
| 809 | |
| 810 | let mut iidx = mb_x * 4 + mb_y * 4 * self.mv_stride; |
| 811 | let mut uoff = dframe.offset[1] + mb_x * 8 + mb_y * 8 * dframe.stride[1]; |
| 812 | let ustride = dframe.stride[1]; |
| 813 | let mut voff = dframe.offset[2] + mb_x * 8 + mb_y * 8 * dframe.stride[2]; |
| 814 | let vstride = dframe.stride[2]; |
| 815 | if single_mv { |
| 816 | let chroma_mv = self.mvs[iidx]; |
| 817 | |
| 818 | if pitch_smode == 0 { |
| 819 | mc_block8x8(dst, uoff, ustride, mb_x * 8, mb_y * 8, chroma_mv.x, chroma_mv.y, refframe.clone(), 1, mc_buf); |
| 820 | mc_block8x8(dst, voff, vstride, mb_x * 8, mb_y * 8, chroma_mv.x, chroma_mv.y, refframe, 2, mc_buf); |
| 821 | } else { |
| 822 | mc_block_special(dst, uoff, ustride, mb_x * 8, mb_y * 8, chroma_mv.x, chroma_mv.y, |
| 823 | refframe.clone(), 1, mc_buf, 8, pitch_smode); |
| 824 | mc_block_special(dst, voff, vstride, mb_x * 8, mb_y * 8, chroma_mv.x, chroma_mv.y, |
| 825 | refframe, 2, mc_buf, 8, pitch_smode); |
| 826 | } |
| 827 | } else { |
| 828 | for y in 0..2 { |
| 829 | for x in 0..2 { |
| 830 | let mut chroma_mv = self.mvs[iidx + x * 2] + self.mvs[iidx + x * 2 + 1] |
| 831 | + self.mvs[iidx + x * 2 + self.mv_stride] |
| 832 | + self.mvs[iidx + x * 2 + self.mv_stride + 1]; |
| 833 | if chroma_mv.x < 0 { |
| 834 | chroma_mv.x += 1; |
| 835 | } else { |
| 836 | chroma_mv.x += 2; |
| 837 | } |
| 838 | if chroma_mv.y < 0 { |
| 839 | chroma_mv.y += 1; |
| 840 | } else { |
| 841 | chroma_mv.y += 2; |
| 842 | } |
| 843 | chroma_mv.x >>= 2; |
| 844 | chroma_mv.y >>= 2; |
| 845 | |
| 846 | if pitch_smode == 0 { |
| 847 | mc_block4x4(dst, uoff + x * 4, ustride, mb_x * 8 + x * 4, mb_y * 8 + y * 4, |
| 848 | chroma_mv.x, chroma_mv.y, refframe.clone(), 1, mc_buf); |
| 849 | mc_block4x4(dst, voff + x * 4, vstride, mb_x * 8 + x * 4, mb_y * 8 + y * 4, |
| 850 | chroma_mv.x, chroma_mv.y, refframe.clone(), 2, mc_buf); |
| 851 | } else { |
| 852 | mc_block_special(dst, uoff + x * 4, ustride, mb_x * 8 + x * 4, mb_y * 8 + y * 4, |
| 853 | chroma_mv.x, chroma_mv.y, refframe.clone(), 1, mc_buf, |
| 854 | 4, pitch_smode); |
| 855 | mc_block_special(dst, voff + x * 4, vstride, mb_x * 8 + x * 4, mb_y * 8 + y * 4, |
| 856 | chroma_mv.x, chroma_mv.y, refframe.clone(), 2, mc_buf, |
| 857 | 4, pitch_smode); |
| 858 | } |
| 859 | } |
| 860 | uoff += ustride * 4; |
| 861 | voff += vstride * 4; |
| 862 | iidx += 2 * self.mv_stride; |
| 863 | } |
| 864 | } |
| 865 | self.add_residue(dframe, mb_x, mb_y, true, pitch_dmode); |
| 866 | } |
| 867 | fn loop_filter_mb(&mut self, dframe: &mut NASimpleVideoFrame<u8>, mb_x: usize, mb_y: usize, loop_str: u8) { |
| 868 | let edge_thr = i16::from(loop_str) + 2; |
| 869 | let luma_thr = i16::from(loop_str); |
| 870 | let chroma_thr = i16::from(loop_str) * 2; |
| 871 | let inner_thr = if self.dstate.loop_sharpness == 0 { |
| 872 | i16::from(loop_str) |
| 873 | } else { |
| 874 | let bound1 = i16::from(9 - self.dstate.loop_sharpness); |
| 875 | let shift = (self.dstate.loop_sharpness + 3) >> 2; |
| 876 | (i16::from(loop_str) >> shift).min(bound1) |
| 877 | }; |
| 878 | let hev_thr = i16::from(HIGH_EDGE_VAR_THR[if self.dstate.is_intra { 1 } else { 0 }][loop_str as usize]); |
| 879 | |
| 880 | let ystride = dframe.stride[0]; |
| 881 | let ustride = dframe.stride[1]; |
| 882 | let vstride = dframe.stride[2]; |
| 883 | let ypos = dframe.offset[0] + mb_x * 16 + mb_y * 16 * ystride; |
| 884 | let upos = dframe.offset[1] + mb_x * 8 + mb_y * 8 * ustride; |
| 885 | let vpos = dframe.offset[2] + mb_x * 8 + mb_y * 8 * vstride; |
| 886 | |
| 887 | let (loop_edge, loop_inner) = if self.dstate.lf_simple { |
| 888 | (simple_loop_filter as LoopFilterFunc, simple_loop_filter as LoopFilterFunc) |
| 889 | } else { |
| 890 | (normal_loop_filter_edge as LoopFilterFunc, normal_loop_filter_inner as LoopFilterFunc) |
| 891 | }; |
| 892 | |
| 893 | if mb_x > 0 { |
| 894 | loop_edge(dframe.data, ypos, 1, ystride, 16, edge_thr, inner_thr, hev_thr); |
| 895 | loop_edge(dframe.data, upos, 1, ustride, 8, edge_thr, inner_thr, hev_thr); |
| 896 | loop_edge(dframe.data, vpos, 1, vstride, 8, edge_thr, inner_thr, hev_thr); |
| 897 | } |
| 898 | if mb_y > 0 { |
| 899 | loop_edge(dframe.data, ypos, ystride, 1, 16, edge_thr, inner_thr, hev_thr); |
| 900 | loop_edge(dframe.data, upos, ustride, 1, 8, edge_thr, inner_thr, hev_thr); |
| 901 | loop_edge(dframe.data, vpos, vstride, 1, 8, edge_thr, inner_thr, hev_thr); |
| 902 | } |
| 903 | |
| 904 | for y in 1..4 { |
| 905 | loop_inner(dframe.data, ypos + y * 4 * ystride, ystride, 1, 16, luma_thr, inner_thr, hev_thr); |
| 906 | } |
| 907 | loop_inner(dframe.data, upos + 4 * ustride, ustride, 1, 8, chroma_thr, inner_thr, hev_thr); |
| 908 | loop_inner(dframe.data, vpos + 4 * vstride, vstride, 1, 8, chroma_thr, inner_thr, hev_thr); |
| 909 | |
| 910 | for x in 1..4 { |
| 911 | loop_inner(dframe.data, ypos + x * 4, 1, ystride, 16, luma_thr, inner_thr, hev_thr); |
| 912 | } |
| 913 | loop_inner(dframe.data, upos + 4, 1, ustride, 8, chroma_thr, inner_thr, hev_thr); |
| 914 | loop_inner(dframe.data, vpos + 4, 1, vstride, 8, chroma_thr, inner_thr, hev_thr); |
| 915 | } |
| 916 | } |
| 917 | |
| 918 | impl NADecoder for VP7Decoder { |
| 919 | fn init(&mut self, supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { |
| 920 | if let NACodecTypeInfo::Video(vinfo) = info.get_properties() { |
| 921 | let fmt = YUV420_FORMAT; |
| 922 | let myvinfo = NAVideoInfo::new(vinfo.get_width(), vinfo.get_height(), false, fmt); |
| 923 | let myinfo = NACodecTypeInfo::Video(myvinfo); |
| 924 | self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref(); |
| 925 | |
| 926 | supp.pool_u8.set_dec_bufs(4); |
| 927 | supp.pool_u8.prealloc_video(NAVideoInfo::new(myvinfo.get_width(), myvinfo.get_height(), false, vinfo.get_format()), 4)?; |
| 928 | self.set_dimensions(myvinfo.get_width(), myvinfo.get_height()); |
| 929 | Ok(()) |
| 930 | } else { |
| 931 | Err(DecoderError::InvalidData) |
| 932 | } |
| 933 | } |
| 934 | #[allow(clippy::cognitive_complexity)] |
| 935 | fn decode(&mut self, supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { |
| 936 | let src = pkt.get_buffer(); |
| 937 | |
| 938 | validate!(src.len() > 4); |
| 939 | |
| 940 | let frame_tag = read_u24le(src.as_slice())?; |
| 941 | self.dstate.is_intra = (frame_tag & 1) == 0; |
| 942 | self.dstate.version = ((frame_tag >> 1) & 7) as u8; |
| 943 | let part2_off = (frame_tag >> 4) as usize; |
| 944 | let part1_off = if self.dstate.version == 0 { 4 } else { 3 }; |
| 945 | |
| 946 | validate!(src.len() > part1_off + part2_off); |
| 947 | let mut bc = BoolCoder::new(&src[part1_off..][..part2_off])?; |
| 948 | let mut bc_main = BoolCoder::new(&src[part1_off + part2_off..])?; |
| 949 | if self.dstate.is_intra { |
| 950 | let width = bc.read_bits(12) as usize; |
| 951 | let height = bc.read_bits(12) as usize; |
| 952 | let _scalev = bc.read_bits(2); |
| 953 | let _scaleh = bc.read_bits(2); |
| 954 | validate!((width > 0) && (height > 0)); |
| 955 | self.set_dimensions(width, height); |
| 956 | |
| 957 | self.dstate.reset(); |
| 958 | self.scan.copy_from_slice(&DEFAULT_SCAN_ORDER); |
| 959 | } else { |
| 960 | if !self.shuf.has_refs() { |
| 961 | return Err(DecoderError::MissingReference); |
| 962 | } |
| 963 | } |
| 964 | |
| 965 | self.read_features(&mut bc)?; |
| 966 | |
| 967 | let y_ac_q = bc.read_bits(7) as usize; |
| 968 | let y_dc_q = if bc.read_bool() { bc.read_bits(7) as usize } else { y_ac_q }; |
| 969 | let y2_dc_q = if bc.read_bool() { bc.read_bits(7) as usize } else { y_ac_q }; |
| 970 | let y2_ac_q = if bc.read_bool() { bc.read_bits(7) as usize } else { y_ac_q }; |
| 971 | let uv_dc_q = if bc.read_bool() { bc.read_bits(7) as usize } else { y_ac_q }; |
| 972 | let uv_ac_q = if bc.read_bool() { bc.read_bits(7) as usize } else { y_ac_q }; |
| 973 | self.set_qmat(y_dc_q, y_ac_q, y2_dc_q, y2_ac_q, uv_dc_q, uv_ac_q); |
| 974 | |
| 975 | let update_gf = if self.dstate.is_intra { true } else { bc.read_bool() }; |
| 976 | |
| 977 | let mut has_fading_feature = true; |
| 978 | let mut keep_probs = true; |
| 979 | if self.dstate.version != 0 { |
| 980 | keep_probs = bc.read_bool(); |
| 981 | if self.dstate.is_intra { |
| 982 | has_fading_feature = true; |
| 983 | } else { |
| 984 | has_fading_feature = bc.read_bool(); |
| 985 | } |
| 986 | } |
| 987 | |
| 988 | if has_fading_feature { |
| 989 | self.dstate.fading = bc.read_bool(); |
| 990 | if self.dstate.fading { |
| 991 | self.dstate.fade_alpha = bc.read_sbits(8) as u16; |
| 992 | self.dstate.fade_beta = bc.read_sbits(8) as u16; |
| 993 | if let Some(pframe) = self.shuf.get_last() { |
| 994 | let mut fframe = supp.pool_u8.get_free().unwrap(); |
| 995 | let mut dframe = NASimpleVideoFrame::from_video_buf(&mut fframe).unwrap(); |
| 996 | fade_frame(pframe, &mut dframe, self.dstate.fade_alpha, self.dstate.fade_beta); |
| 997 | self.shuf.add_frame(fframe); |
| 998 | } |
| 999 | } |
| 1000 | } else { |
| 1001 | self.dstate.fading = false; |
| 1002 | } |
| 1003 | |
| 1004 | if self.dstate.version == 0 { |
| 1005 | self.dstate.lf_simple = bc.read_bool(); |
| 1006 | } |
| 1007 | |
| 1008 | if bc.read_bool() { |
| 1009 | for i in 1..16 { |
| 1010 | self.scan[i] = DEFAULT_SCAN_ORDER[bc.read_bits(4) as usize]; |
| 1011 | } |
| 1012 | } |
| 1013 | |
| 1014 | if self.dstate.version != 0 { |
| 1015 | self.dstate.lf_simple = bc.read_bool(); |
| 1016 | } else { |
| 1017 | self.dstate.lf_simple = false; |
| 1018 | } |
| 1019 | |
| 1020 | self.dstate.loop_filter_level = bc.read_bits(6) as u8; |
| 1021 | self.dstate.loop_sharpness = bc.read_bits(3) as u8; |
| 1022 | |
| 1023 | self.read_dct_coef_prob_upd(&mut bc)?; |
| 1024 | |
| 1025 | if !self.dstate.is_intra { |
| 1026 | self.dstate.prob_intra_pred = bc.read_byte(); |
| 1027 | self.dstate.prob_last_pred = bc.read_byte(); |
| 1028 | if bc.read_bool() { |
| 1029 | for i in 0..4 { |
| 1030 | self.dstate.kf_ymode_prob[i] = bc.read_byte(); |
| 1031 | } |
| 1032 | } |
| 1033 | if bc.read_bool() { |
| 1034 | for i in 0..3 { |
| 1035 | self.dstate.kf_uvmode_prob[i] = bc.read_byte(); |
| 1036 | } |
| 1037 | } |
| 1038 | self.read_mv_prob_upd(&mut bc)?; |
| 1039 | } |
| 1040 | if !keep_probs { |
| 1041 | self.tmp_scan.copy_from_slice(&self.scan); |
| 1042 | } |
| 1043 | |
| 1044 | let vinfo = NAVideoInfo::new(self.width, self.height, false, YUV420_FORMAT); |
| 1045 | let ret = supp.pool_u8.get_free(); |
| 1046 | if ret.is_none() { |
| 1047 | return Err(DecoderError::AllocError); |
| 1048 | } |
| 1049 | let mut buf = ret.unwrap(); |
| 1050 | if buf.get_info() != vinfo { |
| 1051 | self.shuf.clear(); |
| 1052 | supp.pool_u8.reset(); |
| 1053 | supp.pool_u8.prealloc_video(vinfo, 4)?; |
| 1054 | let ret = supp.pool_u8.get_free(); |
| 1055 | if ret.is_none() { |
| 1056 | return Err(DecoderError::AllocError); |
| 1057 | } |
| 1058 | buf = ret.unwrap(); |
| 1059 | } |
| 1060 | let mut dframe = NASimpleVideoFrame::from_video_buf(&mut buf).unwrap(); |
| 1061 | |
| 1062 | let mut mb_idx = 0; |
| 1063 | self.pcache.reset(); |
| 1064 | if self.dstate.is_intra || (self.dstate.version > 0) { |
| 1065 | self.dstate.pdc_pred_val = [0; 2]; |
| 1066 | self.dstate.pdc_pred_count = [0; 2]; |
| 1067 | } |
| 1068 | let mut use_last = true; |
| 1069 | for mb_y in 0..self.mb_h { |
| 1070 | for mb_x in 0..self.mb_w { |
| 1071 | self.decode_mb_features(&mut bc, mb_x, mb_y)?; |
| 1072 | self.dstate.has_y2 = true; |
| 1073 | if self.dstate.is_intra { |
| 1074 | let ymode = bc.read_tree(KF_Y_MODE_TREE, KF_Y_MODE_TREE_PROBS); |
| 1075 | if ymode == PredMode::BPred { |
| 1076 | self.dstate.has_y2 = false; |
| 1077 | let mut iidx = mb_x * 4 + mb_y * 4 * self.ymode_stride; |
| 1078 | for y in 0..4 { |
| 1079 | for x in 0..4 { |
| 1080 | let top_mode = if (y > 0) || (mb_y > 0) { |
| 1081 | self.ymodes[iidx + x - self.ymode_stride] |
| 1082 | } else { |
| 1083 | PredMode::DCPred |
| 1084 | }; |
| 1085 | let left_mode = if (x > 0) || (mb_x > 0) { |
| 1086 | self.ymodes[iidx + x - 1] |
| 1087 | } else { |
| 1088 | PredMode::DCPred |
| 1089 | }; |
| 1090 | let top_idx = top_mode.to_b_index(); |
| 1091 | let left_idx = left_mode.to_b_index(); |
| 1092 | let bmode = bc.read_tree(B_MODE_TREE, &KF_B_MODE_TREE_PROBS[top_idx][left_idx]); |
| 1093 | self.ymodes[iidx + x] = bmode; |
| 1094 | } |
| 1095 | iidx += self.ymode_stride; |
| 1096 | } |
| 1097 | } else { |
| 1098 | self.fill_ymode(mb_x, mb_y, ymode.to_b_mode()); |
| 1099 | } |
| 1100 | let uvmode = bc.read_tree(UV_MODE_TREE, KF_UV_MODE_TREE_PROBS); |
| 1101 | self.mb_info[mb_idx].mb_type = VPMBType::Intra; |
| 1102 | self.mb_info[mb_idx].ymode = ymode; |
| 1103 | self.mb_info[mb_idx].uvmode = uvmode; |
| 1104 | } else if !bc.read_prob(self.dstate.prob_intra_pred) { |
| 1105 | let ymode = bc.read_tree(Y_MODE_TREE, &self.dstate.kf_ymode_prob); |
| 1106 | if ymode == PredMode::BPred { |
| 1107 | self.dstate.has_y2 = false; |
| 1108 | let mut iidx = mb_x * 4 + mb_y * 4 * self.ymode_stride; |
| 1109 | for _y in 0..4 { |
| 1110 | for x in 0..4 { |
| 1111 | let bmode = bc.read_tree(B_MODE_TREE, B_MODE_TREE_PROBS); |
| 1112 | self.ymodes[iidx + x] = bmode; |
| 1113 | } |
| 1114 | iidx += self.ymode_stride; |
| 1115 | } |
| 1116 | } else { |
| 1117 | self.fill_ymode(mb_x, mb_y, PredMode::Inter); |
| 1118 | } |
| 1119 | let uvmode = bc.read_tree(UV_MODE_TREE, &self.dstate.kf_uvmode_prob); |
| 1120 | self.mb_info[mb_idx].mb_type = VPMBType::Intra; |
| 1121 | self.mb_info[mb_idx].ymode = ymode; |
| 1122 | self.mb_info[mb_idx].uvmode = uvmode; |
| 1123 | self.fill_mv(mb_x, mb_y, ZERO_MV); |
| 1124 | } else { |
| 1125 | use_last = !bc.read_prob(self.dstate.prob_last_pred); |
| 1126 | |
| 1127 | let (mvprobs, nearest_mv, near_mv, pred_mv) = self.find_mv_pred(mb_x, mb_y); |
| 1128 | let mbtype = bc.read_tree(MV_REF_TREE, &mvprobs); |
| 1129 | |
| 1130 | match mbtype { |
| 1131 | VPMBType::InterNearest => { |
| 1132 | self.fill_mv(mb_x, mb_y, nearest_mv); |
| 1133 | }, |
| 1134 | VPMBType::InterNear => { |
| 1135 | self.fill_mv(mb_x, mb_y, near_mv); |
| 1136 | }, |
| 1137 | VPMBType::InterNoMV => { |
| 1138 | self.fill_mv(mb_x, mb_y, ZERO_MV); |
| 1139 | }, |
| 1140 | VPMBType::InterMV => { |
| 1141 | let dmy = decode_mv_component(&mut bc, &self.dstate.mv_probs[0]); |
| 1142 | let dmx = decode_mv_component(&mut bc, &self.dstate.mv_probs[1]); |
| 1143 | let new_mv = pred_mv + MV{ x: dmx, y: dmy }; |
| 1144 | self.fill_mv(mb_x, mb_y, new_mv); |
| 1145 | }, |
| 1146 | VPMBType::InterFourMV => { |
| 1147 | self.do_split_mv(&mut bc, mb_x, mb_y, pred_mv)?; |
| 1148 | }, |
| 1149 | _ => unreachable!(), |
| 1150 | }; |
| 1151 | |
| 1152 | self.fill_ymode(mb_x, mb_y, PredMode::Inter); |
| 1153 | self.mb_info[mb_idx].mb_type = mbtype; |
| 1154 | self.mb_info[mb_idx].ymode = PredMode::Inter; |
| 1155 | self.mb_info[mb_idx].uvmode = PredMode::Inter; |
| 1156 | } |
| 1157 | self.decode_residue(&mut bc_main, mb_x, mb_idx, use_last); |
| 1158 | match self.mb_info[mb_idx].mb_type { |
| 1159 | VPMBType::Intra => { |
| 1160 | self.recon_intra_mb(&mut dframe, mb_x, mb_y)?; |
| 1161 | }, |
| 1162 | _ => { |
| 1163 | self.recon_inter_mb(&mut dframe, mb_x, mb_y, use_last); |
| 1164 | }, |
| 1165 | } |
| 1166 | if let Some(loop_str) = self.dstate.force_loop_str { |
| 1167 | self.mb_info[mb_idx].loop_str = loop_str; |
| 1168 | } else { |
| 1169 | self.mb_info[mb_idx].loop_str = self.dstate.loop_filter_level; |
| 1170 | } |
| 1171 | self.mb_info[mb_idx].upd_gf = self.dstate.force_gf_update; |
| 1172 | mb_idx += 1; |
| 1173 | } |
| 1174 | self.pcache.update_row(); |
| 1175 | } |
| 1176 | let mut mb_idx = 0; |
| 1177 | for mb_y in 0..self.mb_h { |
| 1178 | for mb_x in 0..self.mb_w { |
| 1179 | let loop_str = self.mb_info[mb_idx].loop_str; |
| 1180 | self.loop_filter_mb(&mut dframe, mb_x, mb_y, loop_str); |
| 1181 | mb_idx += 1; |
| 1182 | } |
| 1183 | } |
| 1184 | if !update_gf && self.dstate.features[2].is_some() { |
| 1185 | let gf = self.shuf.get_golden().unwrap(); |
| 1186 | let mut new_gf = supp.pool_u8.get_copy(&gf).unwrap(); |
| 1187 | let dframe = NASimpleVideoFrame::from_video_buf(&mut new_gf).unwrap(); |
| 1188 | let mut mb_idx = 0; |
| 1189 | let mc_buf = self.mc_buf.get_data_mut().unwrap(); |
| 1190 | for mb_y in 0..self.mb_h { |
| 1191 | for mb_x in 0..self.mb_w { |
| 1192 | if self.mb_info[mb_idx].upd_gf { |
| 1193 | mc_block16x16(dframe.data, dframe.offset[0] + mb_x * 16 + mb_y * 16 * dframe.stride[0], dframe.stride[0], mb_x * 16, mb_y * 16, 0, 0, buf.clone(), 0, mc_buf); |
| 1194 | mc_block8x8(dframe.data, dframe.offset[1] + mb_x * 8 + mb_y * 8 * dframe.stride[1], dframe.stride[1], mb_x * 8, mb_y * 8, 0, 0, buf.clone(), 1, mc_buf); |
| 1195 | mc_block8x8(dframe.data, dframe.offset[2] + mb_x * 8 + mb_y * 8 * dframe.stride[2], dframe.stride[2], mb_x * 8, mb_y * 8, 0, 0, buf.clone(), 2, mc_buf); |
| 1196 | } |
| 1197 | mb_idx += 1; |
| 1198 | } |
| 1199 | } |
| 1200 | self.shuf.add_golden_frame(new_gf); |
| 1201 | } |
| 1202 | |
| 1203 | if !keep_probs { |
| 1204 | self.scan.copy_from_slice(&self.tmp_scan); |
| 1205 | } |
| 1206 | if update_gf { |
| 1207 | self.shuf.add_golden_frame(buf.clone()); |
| 1208 | } |
| 1209 | self.shuf.add_frame(buf.clone()); |
| 1210 | |
| 1211 | let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::Video(buf)); |
| 1212 | frm.set_keyframe(self.dstate.is_intra); |
| 1213 | frm.set_frame_type(if self.dstate.is_intra { FrameType::I } else { FrameType::P }); |
| 1214 | Ok(frm.into_ref()) |
| 1215 | } |
| 1216 | fn flush(&mut self) { |
| 1217 | self.shuf.clear(); |
| 1218 | } |
| 1219 | } |
| 1220 | |
| 1221 | impl NAOptionHandler for VP7Decoder { |
| 1222 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } |
| 1223 | fn set_options(&mut self, _options: &[NAOption]) { } |
| 1224 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } |
| 1225 | } |
| 1226 | |
| 1227 | pub fn get_decoder() -> Box<dyn NADecoder + Send> { |
| 1228 | Box::new(VP7Decoder::new()) |
| 1229 | } |
| 1230 | |
| 1231 | #[cfg(test)] |
| 1232 | mod test { |
| 1233 | use nihav_core::codecs::RegisteredDecoders; |
| 1234 | use nihav_core::demuxers::RegisteredDemuxers; |
| 1235 | use nihav_codec_support::test::dec_video::*; |
| 1236 | use crate::duck_register_all_decoders; |
| 1237 | use nihav_commonfmt::generic_register_all_demuxers; |
| 1238 | |
| 1239 | #[test] |
| 1240 | fn test_vp7() { |
| 1241 | let mut dmx_reg = RegisteredDemuxers::new(); |
| 1242 | generic_register_all_demuxers(&mut dmx_reg); |
| 1243 | let mut dec_reg = RegisteredDecoders::new(); |
| 1244 | duck_register_all_decoders(&mut dec_reg); |
| 1245 | |
| 1246 | // sample from https://trac.ffmpeg.org/ticket/5580 |
| 1247 | test_decoding("avi", "vp7", "assets/Duck/interlaced_blit_pitch.avi", Some(12), &dmx_reg, |
| 1248 | &dec_reg, ExpectedTestResult::MD5Frames(vec![ |
| 1249 | [0xb79fb6f8, 0xed51ac9e, 0x9e423456, 0xc0918e7f], |
| 1250 | [0xbf8d1274, 0x83515e15, 0x8c0887de, 0xfbfd05d3], |
| 1251 | [0x8ad00466, 0x80b6cbfb, 0x54de408e, 0x9efbc05e], |
| 1252 | [0x144122c5, 0x6897b553, 0x93474d29, 0x1a1274ec], |
| 1253 | [0x06ff5d07, 0x55825d38, 0x072b0a78, 0xfcb5020f], |
| 1254 | [0xfd01591b, 0xc42113e7, 0xc5a5550f, 0xb30f3b02], |
| 1255 | [0x155e0d6e, 0x96d75e06, 0x9bd7ce87, 0xacf868e1], |
| 1256 | [0xfd79103a, 0x695d21d3, 0xfeacb5b4, 0x1d869d08], |
| 1257 | [0xf4bcfeac, 0x0d2c305c, 0x11416c96, 0x626a5ef6], |
| 1258 | [0x3579b66c, 0x0a7d7dc0, 0xe80b0395, 0xf6a70661], |
| 1259 | [0x5773768c, 0x813442e9, 0x4dd6f793, 0xb10fe55f], |
| 1260 | [0xcaaf0ddb, 0x65c2410e, 0x95da5bba, 0x3b90128e], |
| 1261 | [0x74773773, 0xe1dbadeb, 0x57aaf64b, 0x9c21e3c7]])); |
| 1262 | } |
| 1263 | } |