]>
Commit | Line | Data |
---|---|---|
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 | } |