]>
Commit | Line | Data |
---|---|---|
587a6d78 KS |
1 | use nihav_core::codecs::*; |
2 | use nihav_core::io::byteio::*; | |
b4d5b851 | 3 | use nihav_codec_support::codecs::{MV, ZERO_MV}; |
587a6d78 | 4 | use super::vpcommon::*; |
0cc75664 KS |
5 | use super::vp78::*; |
6 | use super::vp78data::*; | |
7 | use super::vp78dsp::*; | |
b922b48d | 8 | use super::vp7data::*; |
587a6d78 KS |
9 | use super::vp7dsp::*; |
10 | ||
587a6d78 KS |
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 | ||
587a6d78 KS |
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 | ||
47933c6d | 29 | fn decode_subblock(bc: &mut BoolCoder, coeffs: &mut [i16; 16], ctype: usize, pctx: u8, sbparams: &SBParams) -> u8 { |
587a6d78 KS |
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, | |
99cc55ef KS |
85 | pdc_pred_val: [i16; 2], |
86 | pdc_pred_count: [usize; 2], | |
587a6d78 KS |
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 | ||
587a6d78 | 102 | fn decode_mv_component(bc: &mut BoolCoder, probs: &[u8; 17]) -> i16 { |
587a6d78 KS |
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 | ||
587a6d78 KS |
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 | } | |
e6aaad5c | 207 | #[allow(clippy::field_reassign_with_default)] |
587a6d78 KS |
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<()> { | |
20b5a55f KS |
242 | for (probs, upd_probs) in self.dstate.coef_probs.iter_mut().zip(DCT_UPDATE_PROBS.iter()) { |
243 | for (probs, upd_probs) in probs.iter_mut().zip(upd_probs.iter()) { | |
244 | for (probs, upd_probs) in probs.iter_mut().zip(upd_probs.iter()) { | |
245 | for (prob, &upd_prob) in probs.iter_mut().zip(upd_probs.iter()) { | |
246 | if bc.read_prob(upd_prob) { | |
247 | *prob = bc.read_byte(); | |
587a6d78 KS |
248 | } |
249 | } | |
250 | } | |
251 | } | |
252 | } | |
253 | Ok(()) | |
254 | } | |
255 | fn read_mv_prob_upd(&mut self, bc: &mut BoolCoder) -> DecoderResult<()> { | |
20b5a55f KS |
256 | for (probs, upd_probs) in self.dstate.mv_probs.iter_mut().zip(MV_UPDATE_PROBS.iter()) { |
257 | for (prob, &upd_prob) in probs.iter_mut().zip(upd_probs.iter()) { | |
258 | if bc.read_prob(upd_prob) { | |
259 | *prob = bc.read_probability(); | |
587a6d78 KS |
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 | } | |
99cc55ef | 287 | fn decode_residue(&mut self, bc: &mut BoolCoder, mb_x: usize, mb_idx: usize, use_last: bool) { |
587a6d78 KS |
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]; | |
20b5a55f KS |
316 | let (y_coeffs, c_coeffs) = self.coeffs.split_at_mut(16); |
317 | for (i, (coeffs, y_has_ac)) in y_coeffs.iter_mut().zip(has_ac.iter_mut()).enumerate() { | |
587a6d78 KS |
318 | let bx = i & 3; |
319 | let by = i >> 2; | |
320 | let pred = &self.pcache.y_pred; | |
321 | let pidx = pred.xpos + mb_x * 4 + bx + by * pred.stride; | |
322 | let pctx = self.pcache.y_pred_left[by] + pred.data[pidx - pred.stride]; | |
323 | ||
20b5a55f | 324 | let has_nz = decode_subblock(bc, coeffs, ytype, pctx, &sbparams); |
587a6d78 KS |
325 | self.pcache.y_pred.data[pidx] = has_nz; |
326 | self.pcache.y_pred_left[by] = has_nz; | |
20b5a55f | 327 | *y_has_ac = has_nz > 0; |
587a6d78 KS |
328 | } |
329 | sbparams.qmat = &self.qmat[qmat_idx][1]; | |
20b5a55f KS |
330 | let (u_coeffs, v_coeffs) = c_coeffs.split_at_mut(4); |
331 | let (u_has_ac, v_has_ac) = has_ac[16..24].split_at_mut(4); | |
332 | for (i, (coeffs, u_has_ac)) in u_coeffs.iter_mut().zip(u_has_ac.iter_mut()).enumerate() { | |
587a6d78 KS |
333 | let bx = i & 1; |
334 | let by = (i >> 1) & 1; | |
335 | let pred = &self.pcache.u_pred; | |
336 | let pidx = pred.xpos + mb_x * 2 + bx + by * pred.stride; | |
337 | let pctx = self.pcache.u_pred_left[by] + pred.data[pidx - pred.stride]; | |
338 | ||
20b5a55f | 339 | let has_nz = decode_subblock(bc, coeffs, 2, pctx, &sbparams); |
587a6d78 KS |
340 | self.pcache.u_pred.data[pidx] = has_nz; |
341 | self.pcache.u_pred_left[by] = has_nz; | |
20b5a55f | 342 | *u_has_ac = has_nz > 0; |
587a6d78 | 343 | } |
20b5a55f | 344 | for (i, (coeffs, v_has_ac)) in v_coeffs.iter_mut().zip(v_has_ac.iter_mut()).enumerate() { |
587a6d78 KS |
345 | let bx = i & 1; |
346 | let by = (i >> 1) & 1; | |
347 | let pred = &self.pcache.v_pred; | |
348 | let pidx = pred.xpos + mb_x * 2 + bx + by * pred.stride; | |
349 | let pctx = self.pcache.v_pred_left[by] + pred.data[pidx - pred.stride]; | |
350 | ||
20b5a55f | 351 | let has_nz = decode_subblock(bc, coeffs, 2, pctx, &sbparams); |
587a6d78 KS |
352 | self.pcache.v_pred.data[pidx] = has_nz; |
353 | self.pcache.v_pred_left[by] = has_nz; | |
20b5a55f | 354 | *v_has_ac = has_nz > 0; |
587a6d78 KS |
355 | } |
356 | ||
357 | if self.dstate.has_y2 { | |
358 | let y2block = &mut self.coeffs[24]; | |
359 | if self.mb_info[mb_idx].mb_type != VPMBType::Intra { | |
360 | let mut dc = y2block[0]; | |
99cc55ef KS |
361 | let pdc_idx = if use_last { 0 } else { 1 }; |
362 | let pval = self.dstate.pdc_pred_val[pdc_idx]; | |
363 | ||
364 | if self.dstate.pdc_pred_count[pdc_idx] > 3 { | |
587a6d78 KS |
365 | dc += pval; |
366 | y2block[0] = dc; | |
367 | } | |
368 | if (pval == 0) || (dc == 0) || ((pval ^ dc) < 0) { | |
99cc55ef | 369 | self.dstate.pdc_pred_count[pdc_idx] = 0; |
587a6d78 | 370 | } else if dc == pval { |
99cc55ef | 371 | self.dstate.pdc_pred_count[pdc_idx] += 1; |
587a6d78 | 372 | } |
99cc55ef | 373 | self.dstate.pdc_pred_val[pdc_idx] = dc; |
587a6d78 KS |
374 | } |
375 | if has_ac[24] { | |
376 | idct4x4(y2block); | |
4726ca2c | 377 | } else if y2block[0] != 0 { |
587a6d78 KS |
378 | idct4x4_dc(y2block); |
379 | } | |
380 | for i in 0..16 { | |
381 | self.coeffs[i][0] = self.coeffs[24][i]; | |
382 | } | |
383 | } | |
20b5a55f KS |
384 | for (&has_ac, coeffs) in has_ac.iter().zip(self.coeffs.iter_mut()).take(24) { |
385 | if has_ac { | |
386 | idct4x4(coeffs); | |
387 | } else if coeffs[0] != 0 { | |
388 | idct4x4_dc(coeffs); | |
587a6d78 KS |
389 | } |
390 | } | |
391 | } | |
392 | ||
393 | 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) { | |
394 | self.qmat[0][0][0] = Y_DC_QUANTS[y_dc_q]; | |
395 | for i in 1..16 { | |
396 | self.qmat[0][0][i] = Y_AC_QUANTS[y_ac_q]; | |
397 | } | |
398 | self.qmat[0][1][0] = UV_DC_QUANTS[uv_dc_q]; | |
399 | for i in 1..16 { | |
400 | self.qmat[0][1][i] = UV_AC_QUANTS[uv_ac_q]; | |
401 | } | |
402 | self.qmat[0][2][0] = Y2_DC_QUANTS[y2_dc_q]; | |
403 | for i in 1..16 { | |
404 | self.qmat[0][2][i] = Y2_AC_QUANTS[y2_ac_q]; | |
405 | } | |
406 | if let Some(ref feat) = self.dstate.features[0] { | |
407 | for j in 0..4 { | |
408 | let q = feat.def_val[j] as usize; | |
409 | self.qmat[j + 1][0][0] = Y_DC_QUANTS[q]; | |
410 | for i in 1..16 { | |
411 | self.qmat[j + 1][0][i] = Y_AC_QUANTS[q]; | |
412 | } | |
413 | self.qmat[j + 1][1][0] = UV_DC_QUANTS[q]; | |
414 | for i in 1..16 { | |
415 | self.qmat[j + 1][1][i] = UV_AC_QUANTS[q]; | |
416 | } | |
417 | self.qmat[j + 1][2][0] = Y2_DC_QUANTS[q]; | |
418 | for i in 1..16 { | |
419 | self.qmat[j + 1][2][i] = Y2_AC_QUANTS[q]; | |
420 | } | |
421 | } | |
422 | } | |
423 | } | |
424 | fn fill_ymode(&mut self, mb_x: usize, mb_y: usize, ymode: PredMode) { | |
425 | let mut iidx = mb_x * 4 + mb_y * 4 * self.ymode_stride; | |
426 | for _ in 0..4 { | |
427 | for x in 0..4 { | |
428 | self.ymodes[iidx + x] = ymode; | |
429 | } | |
430 | iidx += self.ymode_stride; | |
431 | } | |
432 | } | |
433 | fn fill_mv(&mut self, mb_x: usize, mb_y: usize, mv: MV) { | |
434 | let mut iidx = mb_x * 4 + mb_y * 4 * self.mv_stride; | |
435 | for _ in 0..4 { | |
436 | for x in 0..4 { | |
437 | self.mvs[iidx + x] = mv; | |
438 | } | |
439 | iidx += self.mb_w * 4; | |
440 | } | |
441 | } | |
442 | fn find_mv_pred(&self, mb_x: usize, mb_y: usize) -> ([u8; 4], MV, MV, MV) { | |
587a6d78 KS |
443 | let mut nearest_mv = ZERO_MV; |
444 | let mut near_mv = ZERO_MV; | |
445 | ||
446 | let mut ct: [u8; 4] = [0; 4]; | |
447 | ||
448 | let start = if self.dstate.version == 0 { 1 } else { 0 }; | |
449 | let mvwrap = (self.mb_w as isize) + 1; | |
450 | for (yoff, xoff, weight, blk_no) in CAND_POS.iter() { | |
451 | let cx = (mb_x as isize) + (*xoff as isize); | |
452 | let cy = (mb_y as isize) + (*yoff as isize); | |
453 | let mvpos = cx + cy * mvwrap; | |
454 | if (mvpos < start) || ((mvpos % mvwrap) == (mvwrap - 1)) { | |
455 | ct[0] += weight; | |
456 | continue; | |
457 | } | |
458 | let cx = (mvpos % mvwrap) as usize; | |
459 | let cy = (mvpos / mvwrap) as usize; | |
460 | let bx = (*blk_no as usize) & 3; | |
461 | let by = (*blk_no as usize) >> 2; | |
462 | let blk_pos = cx * 4 + bx + (cy * 4 + by) * self.mv_stride; | |
463 | let mv = self.mvs[blk_pos]; | |
464 | if mv == ZERO_MV { | |
465 | ct[0] += weight; | |
466 | continue; | |
467 | } | |
468 | let idx; | |
469 | if (nearest_mv == ZERO_MV) || (nearest_mv == mv) { | |
470 | nearest_mv = mv; | |
471 | idx = 1; | |
472 | } else if near_mv == ZERO_MV { | |
473 | near_mv = mv; | |
474 | idx = 2; | |
475 | } else { | |
476 | idx = if mv == near_mv { 2 } else { 3 }; | |
477 | } | |
478 | ct[idx] += weight; | |
479 | } | |
20b5a55f | 480 | #[allow(clippy::collapsible_else_if)] |
587a6d78 KS |
481 | let pred_mv = if ct[1] > ct[2] { |
482 | if ct[1] >= ct[0] { nearest_mv } else { ZERO_MV } | |
483 | } else { | |
484 | if ct[2] >= ct[0] { near_mv } else { ZERO_MV } | |
485 | }; | |
486 | ||
487 | let mvprobs = [INTER_MODE_PROBS[ct[0] as usize][0], | |
488 | INTER_MODE_PROBS[ct[1] as usize][1], | |
489 | INTER_MODE_PROBS[ct[2] as usize][2], | |
490 | INTER_MODE_PROBS[ct[2] as usize][3]]; | |
491 | ||
492 | (mvprobs, nearest_mv, near_mv, pred_mv) | |
493 | } | |
494 | fn get_split_mv(&self, bc: &mut BoolCoder, mb_x: usize, mb_y: usize, bx: usize, by: usize, pred_mv: MV) -> MV { | |
495 | let mode = bc.read_tree(SUB_MV_REF_TREE, &SUB_MV_REF_PROBS); | |
496 | let mvidx = mb_x * 4 + bx + (mb_y * 4 + by) * self.mv_stride; | |
497 | match mode { | |
498 | SubMVRef::Left => { | |
499 | if (mb_x > 0) || (bx > 0) { | |
500 | self.mvs[mvidx - 1] | |
501 | } else { | |
502 | ZERO_MV | |
503 | } | |
504 | }, | |
505 | SubMVRef::Above => { | |
506 | if (mb_y > 0) || (by > 0) { | |
507 | self.mvs[mvidx - self.mv_stride] | |
508 | } else { | |
509 | ZERO_MV | |
510 | } | |
511 | }, | |
512 | SubMVRef::Zero => ZERO_MV, | |
513 | SubMVRef::New => { | |
514 | let dmy = decode_mv_component(bc, &self.dstate.mv_probs[0]); | |
515 | let dmx = decode_mv_component(bc, &self.dstate.mv_probs[1]); | |
516 | pred_mv + MV{ x: dmx, y: dmy } | |
517 | }, | |
518 | } | |
519 | } | |
520 | fn do_split_mv(&mut self, bc: &mut BoolCoder, mb_x: usize, mb_y: usize, pred_mv: MV) -> DecoderResult<()> { | |
521 | let split_mode = bc.read_tree(MV_SPLIT_MODE_TREE, &MV_SPLIT_MODE_PROBS); | |
522 | let mut mvidx = mb_x * 4 + mb_y * 4 * self.mv_stride; | |
523 | match split_mode { | |
524 | MVSplitMode::TopBottom => { | |
525 | let top_mv = self.get_split_mv(bc, mb_x, mb_y, 0, 0, pred_mv); | |
526 | for _ in 0..2 { | |
527 | for x in 0..4 { self.mvs[mvidx + x] = top_mv; } | |
528 | mvidx += self.mv_stride; | |
529 | } | |
530 | let bot_mv = self.get_split_mv(bc, mb_x, mb_y, 0, 2, pred_mv); | |
531 | for _ in 2..4 { | |
532 | for x in 0..4 { self.mvs[mvidx + x] = bot_mv; } | |
533 | mvidx += self.mv_stride; | |
534 | } | |
535 | }, | |
20b5a55f | 536 | #[allow(clippy::identity_op)] |
587a6d78 KS |
537 | MVSplitMode::LeftRight => { |
538 | let left_mv = self.get_split_mv(bc, mb_x, mb_y, 0, 0, pred_mv); | |
539 | self.mvs[mvidx + 1] = left_mv; | |
540 | let right_mv = self.get_split_mv(bc, mb_x, mb_y, 2, 0, pred_mv); | |
541 | for _ in 0..4 { | |
542 | self.mvs[mvidx + 0] = left_mv; | |
543 | self.mvs[mvidx + 1] = left_mv; | |
544 | self.mvs[mvidx + 2] = right_mv; | |
545 | self.mvs[mvidx + 3] = right_mv; | |
546 | mvidx += self.mv_stride; | |
547 | } | |
548 | }, | |
549 | MVSplitMode::Quarters => { | |
550 | for y in (0..4).step_by(2) { | |
551 | for x in (0..4).step_by(2) { | |
552 | self.mvs[mvidx + x] = self.get_split_mv(bc, mb_x, mb_y, x, y, pred_mv); | |
553 | self.mvs[mvidx + x + 1] = self.mvs[mvidx + x]; | |
554 | } | |
555 | for x in 0..4 { | |
556 | self.mvs[mvidx + x + self.mv_stride] = self.mvs[mvidx + x]; | |
557 | } | |
558 | mvidx += self.mv_stride * 2; | |
559 | } | |
560 | }, | |
561 | MVSplitMode::Sixteenths => { | |
562 | for y in 0..4 { | |
563 | for x in 0..4 { | |
564 | self.mvs[mvidx + x] = self.get_split_mv(bc, mb_x, mb_y, x, y, pred_mv); | |
565 | } | |
566 | mvidx += self.mv_stride; | |
567 | } | |
568 | }, | |
569 | }; | |
570 | Ok(()) | |
571 | } | |
572 | ||
573 | fn add_residue(&self, dframe: &mut NASimpleVideoFrame<u8>, mb_x: usize, mb_y: usize, do_luma: bool, pitch_mode: u8) { | |
574 | if do_luma { | |
575 | let ydst = &mut dframe.data[dframe.offset[0]..]; | |
576 | let ystride = dframe.stride[0]; | |
577 | let mut yoff = mb_x * 16 + mb_y * 16 * ystride; | |
578 | match pitch_mode { | |
579 | PITCH_MODE_NORMAL => { | |
580 | for y in 0..4 { | |
581 | for x in 0..4 { | |
582 | add_coeffs4x4(ydst, yoff + x * 4, ystride, &self.coeffs[x + y * 4]); | |
583 | } | |
584 | yoff += 4 * ystride; | |
585 | } | |
586 | }, | |
587 | PITCH_MODE_FOUR => { | |
588 | for y in 0..16 { | |
589 | add_coeffs16x1(ydst, yoff, &self.coeffs[y]); | |
590 | yoff += ystride; | |
591 | } | |
592 | }, | |
593 | PITCH_MODE_X2 => { | |
594 | for y in 0..2 { | |
595 | for x in 0..4 { | |
596 | add_coeffs4x4(ydst, yoff + x * 4, ystride * 2, &self.coeffs[x + y * 4]); | |
597 | } | |
598 | yoff += 8 * ystride; | |
599 | } | |
600 | yoff -= 15 * ystride; | |
601 | for y in 2..4 { | |
602 | for x in 0..4 { | |
603 | add_coeffs4x4(ydst, yoff + x * 4, ystride * 2, &self.coeffs[x + y * 4]); | |
604 | } | |
605 | yoff += 8 * ystride; | |
606 | } | |
607 | }, | |
608 | PITCH_MODE_X4 => { | |
609 | for y in 0..4 { | |
610 | for x in 0..4 { | |
611 | add_coeffs4x4(ydst, yoff + x * 4, ystride * 4, &self.coeffs[x + y * 4]); | |
612 | } | |
613 | yoff += ystride; | |
614 | } | |
615 | }, | |
616 | _ => unreachable!(), | |
617 | }; | |
618 | } | |
619 | let dst = &mut dframe.data[0..]; | |
620 | let mut uoff = dframe.offset[1] + mb_x * 8 + mb_y * 8 * dframe.stride[1]; | |
621 | let ustride = dframe.stride[1]; | |
622 | let mut voff = dframe.offset[2] + mb_x * 8 + mb_y * 8 * dframe.stride[2]; | |
623 | let vstride = dframe.stride[2]; | |
624 | if (pitch_mode == PITCH_MODE_NORMAL) || (pitch_mode == PITCH_MODE_FOUR) { | |
625 | for y in 0..2 { | |
626 | for x in 0..2 { | |
627 | add_coeffs4x4(dst, uoff + x * 4, ustride, &self.coeffs[16 + x + y * 2]); | |
628 | add_coeffs4x4(dst, voff + x * 4, vstride, &self.coeffs[20 + x + y * 2]); | |
629 | } | |
630 | uoff += ustride * 4; | |
631 | voff += vstride * 4; | |
632 | } | |
633 | } else { | |
634 | for y in 0..2 { | |
635 | for x in 0..2 { | |
636 | add_coeffs4x4(dst, uoff + x * 4, ustride * 2, &self.coeffs[16 + x + y * 2]); | |
637 | add_coeffs4x4(dst, voff + x * 4, vstride * 2, &self.coeffs[20 + x + y * 2]); | |
638 | } | |
639 | uoff += ustride; | |
640 | voff += vstride; | |
641 | } | |
642 | } | |
643 | } | |
644 | fn recon_intra_mb(&mut self, dframe: &mut NASimpleVideoFrame<u8>, mb_x: usize, mb_y: usize) -> DecoderResult<()> { | |
645 | let pitch = self.dstate.force_pitch.unwrap_or(0); | |
646 | let pitch_mode = (pitch >> 3) & 3; | |
647 | ||
648 | let mb_idx = mb_x + mb_y * self.mb_w; | |
649 | let has_top = mb_y > 0; | |
650 | let has_left = mb_x > 0; | |
651 | let ydst = &mut dframe.data[dframe.offset[0]..]; | |
652 | let ystride = dframe.stride[0]; | |
653 | let mut yoff = mb_x * 16 + mb_y * 16 * ystride; | |
654 | let ipred_ctx_y = &mut self.dstate.ipred_ctx_y; | |
655 | ipred_ctx_y.has_top = has_top; | |
656 | ipred_ctx_y.has_left = has_left; | |
657 | let is_normal = self.mb_info[mb_idx].ymode != PredMode::BPred; | |
658 | if is_normal { | |
659 | ipred_ctx_y.fill(ydst, yoff, ystride, 16, 16); | |
660 | match self.mb_info[mb_idx].ymode { | |
661 | PredMode::DCPred => IPred16x16::ipred_dc(ydst, yoff, ystride, ipred_ctx_y), | |
662 | PredMode::HPred => IPred16x16::ipred_h (ydst, yoff, ystride, ipred_ctx_y), | |
663 | PredMode::VPred => IPred16x16::ipred_v (ydst, yoff, ystride, ipred_ctx_y), | |
664 | PredMode::TMPred => IPred16x16::ipred_tm(ydst, yoff, ystride, ipred_ctx_y), | |
665 | _ => unreachable!(), | |
666 | }; | |
667 | } else { | |
668 | validate!((pitch_mode == PITCH_MODE_NORMAL) || (pitch_mode == PITCH_MODE_X2)); | |
669 | let mut iidx = mb_x * 4 + mb_y * 4 * self.ymode_stride; | |
670 | let mut tr_save = [0x80u8; 16]; | |
671 | if pitch_mode == PITCH_MODE_X2 { | |
672 | // reorganise coefficient data for interlaced case | |
673 | for y in (0..4).step_by(2) { | |
674 | for x in 0..4 { | |
675 | let mut tmpblock = [0i16; 16 * 2]; | |
676 | let eidx = x + y * 4; | |
677 | let oidx = x + y * 4 + 4; | |
678 | for i in 0..4 { | |
679 | for j in 0..4 { | |
20b5a55f | 680 | tmpblock[i * 8 + j] = self.coeffs[eidx][i * 4 + j]; |
587a6d78 KS |
681 | tmpblock[i * 8 + 4 + j] = self.coeffs[oidx][i * 4 + j]; |
682 | } | |
683 | } | |
684 | self.coeffs[eidx].copy_from_slice(&tmpblock[0..16]); | |
685 | self.coeffs[oidx].copy_from_slice(&tmpblock[16..32]); | |
686 | } | |
687 | } | |
688 | } | |
44901bc9 | 689 | let tr_edge = if has_top { ydst[yoff - ystride + 15] } else { 0x80 }; |
587a6d78 KS |
690 | for y in 0..4 { |
691 | for x in 0..4 { | |
692 | ipred_ctx_y.has_left = has_left || x > 0; | |
693 | let bmode = self.ymodes[iidx + x]; | |
694 | let cur_yoff = yoff + x * 4; | |
44901bc9 KS |
695 | let has_tr = ipred_ctx_y.has_top && ((x < 3) || ((y == 0) && (mb_y < self.mb_w - 1))); |
696 | let has_dl = ipred_ctx_y.has_left && (x == 0) && (y < 3); | |
587a6d78 KS |
697 | ipred_ctx_y.fill(ydst, cur_yoff, ystride, |
698 | if has_tr { 8 } else { 4 }, | |
699 | if has_dl { 8 } else { 4 }); | |
700 | if !has_tr { | |
701 | for i in 0..4 { | |
702 | ipred_ctx_y.top[i + 4] = tr_save[x * 4 + i]; | |
703 | } | |
704 | } else { | |
705 | for i in 0..4 { | |
706 | tr_save[x * 4 + i] = ipred_ctx_y.top[i + 4]; | |
707 | } | |
708 | } | |
44901bc9 KS |
709 | if (mb_x == self.mb_w - 1) && has_top && (x == 3) { |
710 | for i in 0..4 { | |
711 | ipred_ctx_y.top[i + 4] = tr_edge; | |
712 | } | |
713 | } | |
587a6d78 KS |
714 | match bmode { |
715 | PredMode::DCPred => IPred4x4::ipred_dc(ydst, cur_yoff, ystride, ipred_ctx_y), | |
716 | PredMode::TMPred => IPred4x4::ipred_tm(ydst, cur_yoff, ystride, ipred_ctx_y), | |
717 | PredMode::HPred => IPred4x4::ipred_he(ydst, cur_yoff, ystride, ipred_ctx_y), | |
718 | PredMode::VPred => IPred4x4::ipred_ve(ydst, cur_yoff, ystride, ipred_ctx_y), | |
719 | PredMode::LDPred => IPred4x4::ipred_ld(ydst, cur_yoff, ystride, ipred_ctx_y), | |
720 | PredMode::RDPred => IPred4x4::ipred_rd(ydst, cur_yoff, ystride, ipred_ctx_y), | |
721 | PredMode::VRPred => IPred4x4::ipred_vr(ydst, cur_yoff, ystride, ipred_ctx_y), | |
722 | PredMode::VLPred => IPred4x4::ipred_vl(ydst, cur_yoff, ystride, ipred_ctx_y), | |
723 | PredMode::HDPred => IPred4x4::ipred_hd(ydst, cur_yoff, ystride, ipred_ctx_y), | |
724 | PredMode::HUPred => IPred4x4::ipred_hu(ydst, cur_yoff, ystride, ipred_ctx_y), | |
725 | _ => unreachable!(), | |
726 | }; | |
727 | add_coeffs4x4(ydst, cur_yoff, ystride, &self.coeffs[x + y * 4]); | |
728 | } | |
729 | ipred_ctx_y.has_top = true; | |
730 | yoff += 4 * ystride; | |
731 | iidx += self.ymode_stride; | |
732 | } | |
733 | } | |
734 | let dst = &mut dframe.data[0..]; | |
735 | let uoff = dframe.offset[1] + mb_x * 8 + mb_y * 8 * dframe.stride[1]; | |
736 | let ustride = dframe.stride[1]; | |
737 | let voff = dframe.offset[2] + mb_x * 8 + mb_y * 8 * dframe.stride[2]; | |
738 | let vstride = dframe.stride[2]; | |
739 | let ipred_ctx_u = &mut self.dstate.ipred_ctx_u; | |
740 | let ipred_ctx_v = &mut self.dstate.ipred_ctx_v; | |
741 | ipred_ctx_u.has_top = has_top; | |
742 | ipred_ctx_v.has_top = has_top; | |
743 | ipred_ctx_u.has_left = has_left; | |
744 | ipred_ctx_v.has_left = has_left; | |
745 | ipred_ctx_u.fill(dst, uoff, ustride, 8, 8); | |
746 | ipred_ctx_v.fill(dst, voff, vstride, 8, 8); | |
747 | match self.mb_info[mb_idx].uvmode { | |
748 | PredMode::DCPred => { | |
749 | IPred8x8::ipred_dc(dst, uoff, ustride, ipred_ctx_u); | |
750 | IPred8x8::ipred_dc(dst, voff, vstride, ipred_ctx_v); | |
751 | }, | |
752 | PredMode::HPred => { | |
753 | IPred8x8::ipred_h(dst, uoff, ustride, ipred_ctx_u); | |
754 | IPred8x8::ipred_h(dst, voff, vstride, ipred_ctx_v); | |
755 | }, | |
756 | PredMode::VPred => { | |
757 | IPred8x8::ipred_v(dst, uoff, ustride, ipred_ctx_u); | |
758 | IPred8x8::ipred_v(dst, voff, vstride, ipred_ctx_v); | |
759 | }, | |
760 | PredMode::TMPred => { | |
761 | IPred8x8::ipred_tm(dst, uoff, ustride, ipred_ctx_u); | |
762 | IPred8x8::ipred_tm(dst, voff, vstride, ipred_ctx_v); | |
763 | }, | |
764 | _ => unreachable!(), | |
765 | }; | |
766 | self.add_residue(dframe, mb_x, mb_y, is_normal, pitch_mode); | |
767 | Ok(()) | |
768 | } | |
20b5a55f | 769 | #[allow(clippy::collapsible_else_if)] |
587a6d78 KS |
770 | fn recon_inter_mb(&mut self, dframe: &mut NASimpleVideoFrame<u8>, mb_x: usize, mb_y: usize, use_last: bool) { |
771 | let pitch = self.dstate.force_pitch.unwrap_or(0); | |
772 | let pitch_dmode = (pitch >> 3) & 3; | |
773 | let pitch_smode = pitch & 7; | |
774 | ||
775 | let refframe = (if use_last { self.shuf.get_last() } else { self.shuf.get_golden() }).unwrap(); | |
776 | let single_mv = self.mb_info[mb_x + mb_y * self.mb_w].mb_type != VPMBType::InterFourMV; | |
777 | let mut iidx = mb_x * 4 + mb_y * 4 * self.mv_stride; | |
6f263099 | 778 | let mc_buf = self.mc_buf.get_data_mut().unwrap(); |
587a6d78 KS |
779 | |
780 | let dst = &mut dframe.data[0..]; | |
781 | let ystride = dframe.stride[0]; | |
782 | let mut yoff = dframe.offset[0] + mb_x * 16 + mb_y * 16 * ystride; | |
783 | if pitch_smode == 0 { | |
784 | if single_mv { | |
785 | mc_block16x16(dst, yoff, ystride, mb_x * 16, mb_y * 16, | |
6f263099 | 786 | self.mvs[iidx].x * 2, self.mvs[iidx].y * 2, refframe.clone(), 0, mc_buf); |
587a6d78 KS |
787 | } else { |
788 | for y in 0..4 { | |
789 | for x in 0..4 { | |
790 | mc_block4x4(dst, yoff + x * 4, ystride, mb_x * 16 + x * 4, mb_y * 16 + y * 4, | |
6f263099 | 791 | self.mvs[iidx + x].x * 2, self.mvs[iidx + x].y * 2, refframe.clone(), 0, mc_buf); |
587a6d78 KS |
792 | } |
793 | yoff += 4 * ystride; | |
794 | iidx += self.mv_stride; | |
795 | } | |
796 | } | |
797 | } else { | |
798 | if single_mv { | |
799 | mc_block_special(dst, yoff, ystride, mb_x * 16, mb_y * 16, | |
800 | self.mvs[iidx].x * 2, self.mvs[iidx].y * 2, | |
6f263099 | 801 | refframe.clone(), 0, mc_buf, 16, pitch_smode); |
587a6d78 KS |
802 | } else { |
803 | for y in 0..4 { | |
804 | for x in 0..4 { | |
805 | mc_block_special(dst, yoff + x * 4, ystride, | |
806 | mb_x * 16 + x * 4, mb_y * 16 + y * 4, | |
807 | self.mvs[iidx + x].x * 2, self.mvs[iidx + x].y * 2, | |
6f263099 | 808 | refframe.clone(), 0, mc_buf, 4, pitch_smode); |
587a6d78 KS |
809 | } |
810 | yoff += 4 * ystride; | |
811 | iidx += self.mv_stride; | |
812 | } | |
813 | } | |
814 | } | |
815 | ||
816 | let mut iidx = mb_x * 4 + mb_y * 4 * self.mv_stride; | |
817 | let mut uoff = dframe.offset[1] + mb_x * 8 + mb_y * 8 * dframe.stride[1]; | |
818 | let ustride = dframe.stride[1]; | |
819 | let mut voff = dframe.offset[2] + mb_x * 8 + mb_y * 8 * dframe.stride[2]; | |
820 | let vstride = dframe.stride[2]; | |
821 | if single_mv { | |
822 | let chroma_mv = self.mvs[iidx]; | |
823 | ||
824 | if pitch_smode == 0 { | |
6f263099 KS |
825 | mc_block8x8(dst, uoff, ustride, mb_x * 8, mb_y * 8, chroma_mv.x, chroma_mv.y, refframe.clone(), 1, mc_buf); |
826 | mc_block8x8(dst, voff, vstride, mb_x * 8, mb_y * 8, chroma_mv.x, chroma_mv.y, refframe, 2, mc_buf); | |
587a6d78 KS |
827 | } else { |
828 | mc_block_special(dst, uoff, ustride, mb_x * 8, mb_y * 8, chroma_mv.x, chroma_mv.y, | |
6f263099 | 829 | refframe.clone(), 1, mc_buf, 8, pitch_smode); |
587a6d78 | 830 | mc_block_special(dst, voff, vstride, mb_x * 8, mb_y * 8, chroma_mv.x, chroma_mv.y, |
6f263099 | 831 | refframe, 2, mc_buf, 8, pitch_smode); |
587a6d78 KS |
832 | } |
833 | } else { | |
834 | for y in 0..2 { | |
835 | for x in 0..2 { | |
7589c13a KS |
836 | let mut chroma_mv = self.mvs[iidx + x * 2] + self.mvs[iidx + x * 2 + 1] |
837 | + self.mvs[iidx + x * 2 + self.mv_stride] | |
838 | + self.mvs[iidx + x * 2 + self.mv_stride + 1]; | |
839 | if chroma_mv.x < 0 { | |
840 | chroma_mv.x += 1; | |
841 | } else { | |
842 | chroma_mv.x += 2; | |
843 | } | |
844 | if chroma_mv.y < 0 { | |
845 | chroma_mv.y += 1; | |
846 | } else { | |
847 | chroma_mv.y += 2; | |
848 | } | |
849 | chroma_mv.x >>= 2; | |
850 | chroma_mv.y >>= 2; | |
587a6d78 KS |
851 | |
852 | if pitch_smode == 0 { | |
7589c13a | 853 | mc_block4x4(dst, uoff + x * 4, ustride, mb_x * 8 + x * 4, mb_y * 8 + y * 4, |
6f263099 | 854 | chroma_mv.x, chroma_mv.y, refframe.clone(), 1, mc_buf); |
7589c13a | 855 | mc_block4x4(dst, voff + x * 4, vstride, mb_x * 8 + x * 4, mb_y * 8 + y * 4, |
6f263099 | 856 | chroma_mv.x, chroma_mv.y, refframe.clone(), 2, mc_buf); |
587a6d78 | 857 | } else { |
7589c13a | 858 | mc_block_special(dst, uoff + x * 4, ustride, mb_x * 8 + x * 4, mb_y * 8 + y * 4, |
6f263099 | 859 | chroma_mv.x, chroma_mv.y, refframe.clone(), 1, mc_buf, |
587a6d78 | 860 | 4, pitch_smode); |
7589c13a | 861 | mc_block_special(dst, voff + x * 4, vstride, mb_x * 8 + x * 4, mb_y * 8 + y * 4, |
6f263099 | 862 | chroma_mv.x, chroma_mv.y, refframe.clone(), 2, mc_buf, |
587a6d78 KS |
863 | 4, pitch_smode); |
864 | } | |
865 | } | |
866 | uoff += ustride * 4; | |
867 | voff += vstride * 4; | |
868 | iidx += 2 * self.mv_stride; | |
869 | } | |
870 | } | |
871 | self.add_residue(dframe, mb_x, mb_y, true, pitch_dmode); | |
872 | } | |
873 | fn loop_filter_mb(&mut self, dframe: &mut NASimpleVideoFrame<u8>, mb_x: usize, mb_y: usize, loop_str: u8) { | |
47933c6d KS |
874 | let edge_thr = i16::from(loop_str) + 2; |
875 | let luma_thr = i16::from(loop_str); | |
876 | let chroma_thr = i16::from(loop_str) * 2; | |
587a6d78 | 877 | let inner_thr = if self.dstate.loop_sharpness == 0 { |
47933c6d | 878 | i16::from(loop_str) |
587a6d78 | 879 | } else { |
47933c6d | 880 | let bound1 = i16::from(9 - self.dstate.loop_sharpness); |
587a6d78 | 881 | let shift = (self.dstate.loop_sharpness + 3) >> 2; |
47933c6d | 882 | (i16::from(loop_str) >> shift).min(bound1) |
587a6d78 | 883 | }; |
47933c6d | 884 | let hev_thr = i16::from(HIGH_EDGE_VAR_THR[if self.dstate.is_intra { 1 } else { 0 }][loop_str as usize]); |
587a6d78 KS |
885 | |
886 | let ystride = dframe.stride[0]; | |
887 | let ustride = dframe.stride[1]; | |
888 | let vstride = dframe.stride[2]; | |
889 | let ypos = dframe.offset[0] + mb_x * 16 + mb_y * 16 * ystride; | |
890 | let upos = dframe.offset[1] + mb_x * 8 + mb_y * 8 * ustride; | |
891 | let vpos = dframe.offset[2] + mb_x * 8 + mb_y * 8 * vstride; | |
892 | ||
893 | let (loop_edge, loop_inner) = if self.dstate.lf_simple { | |
894 | (simple_loop_filter as LoopFilterFunc, simple_loop_filter as LoopFilterFunc) | |
895 | } else { | |
896 | (normal_loop_filter_edge as LoopFilterFunc, normal_loop_filter_inner as LoopFilterFunc) | |
897 | }; | |
898 | ||
899 | if mb_x > 0 { | |
900 | loop_edge(dframe.data, ypos, 1, ystride, 16, edge_thr, inner_thr, hev_thr); | |
901 | loop_edge(dframe.data, upos, 1, ustride, 8, edge_thr, inner_thr, hev_thr); | |
902 | loop_edge(dframe.data, vpos, 1, vstride, 8, edge_thr, inner_thr, hev_thr); | |
903 | } | |
904 | if mb_y > 0 { | |
905 | loop_edge(dframe.data, ypos, ystride, 1, 16, edge_thr, inner_thr, hev_thr); | |
906 | loop_edge(dframe.data, upos, ustride, 1, 8, edge_thr, inner_thr, hev_thr); | |
907 | loop_edge(dframe.data, vpos, vstride, 1, 8, edge_thr, inner_thr, hev_thr); | |
908 | } | |
909 | ||
910 | for y in 1..4 { | |
911 | loop_inner(dframe.data, ypos + y * 4 * ystride, ystride, 1, 16, luma_thr, inner_thr, hev_thr); | |
912 | } | |
913 | loop_inner(dframe.data, upos + 4 * ustride, ustride, 1, 8, chroma_thr, inner_thr, hev_thr); | |
914 | loop_inner(dframe.data, vpos + 4 * vstride, vstride, 1, 8, chroma_thr, inner_thr, hev_thr); | |
915 | ||
916 | for x in 1..4 { | |
917 | loop_inner(dframe.data, ypos + x * 4, 1, ystride, 16, luma_thr, inner_thr, hev_thr); | |
918 | } | |
919 | loop_inner(dframe.data, upos + 4, 1, ustride, 8, chroma_thr, inner_thr, hev_thr); | |
920 | loop_inner(dframe.data, vpos + 4, 1, vstride, 8, chroma_thr, inner_thr, hev_thr); | |
921 | } | |
922 | } | |
923 | ||
924 | impl NADecoder for VP7Decoder { | |
925 | fn init(&mut self, supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { | |
926 | if let NACodecTypeInfo::Video(vinfo) = info.get_properties() { | |
927 | let fmt = YUV420_FORMAT; | |
928 | let myvinfo = NAVideoInfo::new(vinfo.get_width(), vinfo.get_height(), false, fmt); | |
47933c6d | 929 | let myinfo = NACodecTypeInfo::Video(myvinfo); |
587a6d78 KS |
930 | self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref(); |
931 | ||
932 | supp.pool_u8.set_dec_bufs(4); | |
933 | supp.pool_u8.prealloc_video(NAVideoInfo::new(myvinfo.get_width(), myvinfo.get_height(), false, vinfo.get_format()), 4)?; | |
934 | self.set_dimensions(myvinfo.get_width(), myvinfo.get_height()); | |
935 | Ok(()) | |
936 | } else { | |
937 | Err(DecoderError::InvalidData) | |
938 | } | |
939 | } | |
b7c882c1 | 940 | #[allow(clippy::cognitive_complexity)] |
20b5a55f | 941 | #[allow(clippy::collapsible_else_if)] |
587a6d78 KS |
942 | fn decode(&mut self, supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { |
943 | let src = pkt.get_buffer(); | |
944 | ||
945 | validate!(src.len() > 4); | |
946 | ||
947 | let frame_tag = read_u24le(src.as_slice())?; | |
948 | self.dstate.is_intra = (frame_tag & 1) == 0; | |
949 | self.dstate.version = ((frame_tag >> 1) & 7) as u8; | |
950 | let part2_off = (frame_tag >> 4) as usize; | |
951 | let part1_off = if self.dstate.version == 0 { 4 } else { 3 }; | |
952 | ||
953 | validate!(src.len() > part1_off + part2_off); | |
954 | let mut bc = BoolCoder::new(&src[part1_off..][..part2_off])?; | |
955 | let mut bc_main = BoolCoder::new(&src[part1_off + part2_off..])?; | |
956 | if self.dstate.is_intra { | |
957 | let width = bc.read_bits(12) as usize; | |
958 | let height = bc.read_bits(12) as usize; | |
959 | let _scalev = bc.read_bits(2); | |
960 | let _scaleh = bc.read_bits(2); | |
961 | validate!((width > 0) && (height > 0)); | |
962 | self.set_dimensions(width, height); | |
963 | ||
964 | self.dstate.reset(); | |
9ceb80a2 | 965 | self.scan.copy_from_slice(&DEFAULT_SCAN_ORDER); |
6e24ec0b KS |
966 | } else { |
967 | if !self.shuf.has_refs() { | |
968 | return Err(DecoderError::MissingReference); | |
969 | } | |
587a6d78 KS |
970 | } |
971 | ||
972 | self.read_features(&mut bc)?; | |
973 | ||
974 | let y_ac_q = bc.read_bits(7) as usize; | |
975 | let y_dc_q = if bc.read_bool() { bc.read_bits(7) as usize } else { y_ac_q }; | |
976 | let y2_dc_q = if bc.read_bool() { bc.read_bits(7) as usize } else { y_ac_q }; | |
977 | let y2_ac_q = if bc.read_bool() { bc.read_bits(7) as usize } else { y_ac_q }; | |
978 | let uv_dc_q = if bc.read_bool() { bc.read_bits(7) as usize } else { y_ac_q }; | |
979 | let uv_ac_q = if bc.read_bool() { bc.read_bits(7) as usize } else { y_ac_q }; | |
980 | self.set_qmat(y_dc_q, y_ac_q, y2_dc_q, y2_ac_q, uv_dc_q, uv_ac_q); | |
981 | ||
982 | let update_gf = if self.dstate.is_intra { true } else { bc.read_bool() }; | |
983 | ||
984 | let mut has_fading_feature = true; | |
985 | let mut keep_probs = true; | |
986 | if self.dstate.version != 0 { | |
987 | keep_probs = bc.read_bool(); | |
988 | if self.dstate.is_intra { | |
989 | has_fading_feature = true; | |
990 | } else { | |
991 | has_fading_feature = bc.read_bool(); | |
992 | } | |
993 | } | |
994 | ||
995 | if has_fading_feature { | |
996 | self.dstate.fading = bc.read_bool(); | |
997 | if self.dstate.fading { | |
998 | self.dstate.fade_alpha = bc.read_sbits(8) as u16; | |
999 | self.dstate.fade_beta = bc.read_sbits(8) as u16; | |
1000 | if let Some(pframe) = self.shuf.get_last() { | |
1001 | let mut fframe = supp.pool_u8.get_free().unwrap(); | |
1002 | let mut dframe = NASimpleVideoFrame::from_video_buf(&mut fframe).unwrap(); | |
1003 | fade_frame(pframe, &mut dframe, self.dstate.fade_alpha, self.dstate.fade_beta); | |
1004 | self.shuf.add_frame(fframe); | |
1005 | } | |
1006 | } | |
1007 | } else { | |
1008 | self.dstate.fading = false; | |
1009 | } | |
1010 | ||
1011 | if self.dstate.version == 0 { | |
1012 | self.dstate.lf_simple = bc.read_bool(); | |
1013 | } | |
1014 | ||
1015 | if bc.read_bool() { | |
1016 | for i in 1..16 { | |
1017 | self.scan[i] = DEFAULT_SCAN_ORDER[bc.read_bits(4) as usize]; | |
1018 | } | |
1019 | } | |
1020 | ||
1021 | if self.dstate.version != 0 { | |
1022 | self.dstate.lf_simple = bc.read_bool(); | |
1023 | } else { | |
1024 | self.dstate.lf_simple = false; | |
1025 | } | |
1026 | ||
1027 | self.dstate.loop_filter_level = bc.read_bits(6) as u8; | |
1028 | self.dstate.loop_sharpness = bc.read_bits(3) as u8; | |
1029 | ||
1030 | self.read_dct_coef_prob_upd(&mut bc)?; | |
1031 | ||
1032 | if !self.dstate.is_intra { | |
1033 | self.dstate.prob_intra_pred = bc.read_byte(); | |
1034 | self.dstate.prob_last_pred = bc.read_byte(); | |
1035 | if bc.read_bool() { | |
1036 | for i in 0..4 { | |
1037 | self.dstate.kf_ymode_prob[i] = bc.read_byte(); | |
1038 | } | |
1039 | } | |
1040 | if bc.read_bool() { | |
1041 | for i in 0..3 { | |
1042 | self.dstate.kf_uvmode_prob[i] = bc.read_byte(); | |
1043 | } | |
1044 | } | |
1045 | self.read_mv_prob_upd(&mut bc)?; | |
1046 | } | |
1047 | if !keep_probs { | |
1048 | self.tmp_scan.copy_from_slice(&self.scan); | |
1049 | } | |
1050 | ||
1051 | let vinfo = NAVideoInfo::new(self.width, self.height, false, YUV420_FORMAT); | |
1052 | let ret = supp.pool_u8.get_free(); | |
1053 | if ret.is_none() { | |
1054 | return Err(DecoderError::AllocError); | |
1055 | } | |
1056 | let mut buf = ret.unwrap(); | |
1057 | if buf.get_info() != vinfo { | |
1058 | self.shuf.clear(); | |
1059 | supp.pool_u8.reset(); | |
1060 | supp.pool_u8.prealloc_video(vinfo, 4)?; | |
1061 | let ret = supp.pool_u8.get_free(); | |
1062 | if ret.is_none() { | |
1063 | return Err(DecoderError::AllocError); | |
1064 | } | |
1065 | buf = ret.unwrap(); | |
1066 | } | |
1067 | let mut dframe = NASimpleVideoFrame::from_video_buf(&mut buf).unwrap(); | |
1068 | ||
1069 | let mut mb_idx = 0; | |
1070 | self.pcache.reset(); | |
f7125215 | 1071 | if self.dstate.is_intra || (self.dstate.version > 0) { |
99cc55ef KS |
1072 | self.dstate.pdc_pred_val = [0; 2]; |
1073 | self.dstate.pdc_pred_count = [0; 2]; | |
f7125215 | 1074 | } |
587a6d78 KS |
1075 | let mut use_last = true; |
1076 | for mb_y in 0..self.mb_h { | |
1077 | for mb_x in 0..self.mb_w { | |
1078 | self.decode_mb_features(&mut bc, mb_x, mb_y)?; | |
1079 | self.dstate.has_y2 = true; | |
1080 | if self.dstate.is_intra { | |
1081 | let ymode = bc.read_tree(KF_Y_MODE_TREE, KF_Y_MODE_TREE_PROBS); | |
1082 | if ymode == PredMode::BPred { | |
1083 | self.dstate.has_y2 = false; | |
1084 | let mut iidx = mb_x * 4 + mb_y * 4 * self.ymode_stride; | |
1085 | for y in 0..4 { | |
1086 | for x in 0..4 { | |
1087 | let top_mode = if (y > 0) || (mb_y > 0) { | |
1088 | self.ymodes[iidx + x - self.ymode_stride] | |
1089 | } else { | |
1090 | PredMode::DCPred | |
1091 | }; | |
1092 | let left_mode = if (x > 0) || (mb_x > 0) { | |
1093 | self.ymodes[iidx + x - 1] | |
1094 | } else { | |
1095 | PredMode::DCPred | |
1096 | }; | |
1097 | let top_idx = top_mode.to_b_index(); | |
1098 | let left_idx = left_mode.to_b_index(); | |
1099 | let bmode = bc.read_tree(B_MODE_TREE, &KF_B_MODE_TREE_PROBS[top_idx][left_idx]); | |
1100 | self.ymodes[iidx + x] = bmode; | |
1101 | } | |
1102 | iidx += self.ymode_stride; | |
1103 | } | |
1104 | } else { | |
1105 | self.fill_ymode(mb_x, mb_y, ymode.to_b_mode()); | |
1106 | } | |
1107 | let uvmode = bc.read_tree(UV_MODE_TREE, KF_UV_MODE_TREE_PROBS); | |
1108 | self.mb_info[mb_idx].mb_type = VPMBType::Intra; | |
1109 | self.mb_info[mb_idx].ymode = ymode; | |
1110 | self.mb_info[mb_idx].uvmode = uvmode; | |
1111 | } else if !bc.read_prob(self.dstate.prob_intra_pred) { | |
1112 | let ymode = bc.read_tree(Y_MODE_TREE, &self.dstate.kf_ymode_prob); | |
1113 | if ymode == PredMode::BPred { | |
1114 | self.dstate.has_y2 = false; | |
1115 | let mut iidx = mb_x * 4 + mb_y * 4 * self.ymode_stride; | |
1116 | for _y in 0..4 { | |
1117 | for x in 0..4 { | |
1118 | let bmode = bc.read_tree(B_MODE_TREE, B_MODE_TREE_PROBS); | |
1119 | self.ymodes[iidx + x] = bmode; | |
1120 | } | |
1121 | iidx += self.ymode_stride; | |
1122 | } | |
1123 | } else { | |
1124 | self.fill_ymode(mb_x, mb_y, PredMode::Inter); | |
1125 | } | |
1126 | let uvmode = bc.read_tree(UV_MODE_TREE, &self.dstate.kf_uvmode_prob); | |
1127 | self.mb_info[mb_idx].mb_type = VPMBType::Intra; | |
1128 | self.mb_info[mb_idx].ymode = ymode; | |
1129 | self.mb_info[mb_idx].uvmode = uvmode; | |
1130 | self.fill_mv(mb_x, mb_y, ZERO_MV); | |
1131 | } else { | |
1132 | use_last = !bc.read_prob(self.dstate.prob_last_pred); | |
1133 | ||
1134 | let (mvprobs, nearest_mv, near_mv, pred_mv) = self.find_mv_pred(mb_x, mb_y); | |
1135 | let mbtype = bc.read_tree(MV_REF_TREE, &mvprobs); | |
1136 | ||
1137 | match mbtype { | |
1138 | VPMBType::InterNearest => { | |
1139 | self.fill_mv(mb_x, mb_y, nearest_mv); | |
1140 | }, | |
1141 | VPMBType::InterNear => { | |
1142 | self.fill_mv(mb_x, mb_y, near_mv); | |
1143 | }, | |
1144 | VPMBType::InterNoMV => { | |
1145 | self.fill_mv(mb_x, mb_y, ZERO_MV); | |
1146 | }, | |
1147 | VPMBType::InterMV => { | |
1148 | let dmy = decode_mv_component(&mut bc, &self.dstate.mv_probs[0]); | |
1149 | let dmx = decode_mv_component(&mut bc, &self.dstate.mv_probs[1]); | |
1150 | let new_mv = pred_mv + MV{ x: dmx, y: dmy }; | |
1151 | self.fill_mv(mb_x, mb_y, new_mv); | |
1152 | }, | |
1153 | VPMBType::InterFourMV => { | |
1154 | self.do_split_mv(&mut bc, mb_x, mb_y, pred_mv)?; | |
1155 | }, | |
1156 | _ => unreachable!(), | |
1157 | }; | |
1158 | ||
1159 | self.fill_ymode(mb_x, mb_y, PredMode::Inter); | |
1160 | self.mb_info[mb_idx].mb_type = mbtype; | |
1161 | self.mb_info[mb_idx].ymode = PredMode::Inter; | |
1162 | self.mb_info[mb_idx].uvmode = PredMode::Inter; | |
1163 | } | |
99cc55ef | 1164 | self.decode_residue(&mut bc_main, mb_x, mb_idx, use_last); |
587a6d78 KS |
1165 | match self.mb_info[mb_idx].mb_type { |
1166 | VPMBType::Intra => { | |
1167 | self.recon_intra_mb(&mut dframe, mb_x, mb_y)?; | |
1168 | }, | |
1169 | _ => { | |
1170 | self.recon_inter_mb(&mut dframe, mb_x, mb_y, use_last); | |
1171 | }, | |
1172 | } | |
1173 | if let Some(loop_str) = self.dstate.force_loop_str { | |
1174 | self.mb_info[mb_idx].loop_str = loop_str; | |
1175 | } else { | |
1176 | self.mb_info[mb_idx].loop_str = self.dstate.loop_filter_level; | |
1177 | } | |
1178 | self.mb_info[mb_idx].upd_gf = self.dstate.force_gf_update; | |
1179 | mb_idx += 1; | |
1180 | } | |
1181 | self.pcache.update_row(); | |
1182 | } | |
1183 | let mut mb_idx = 0; | |
1184 | for mb_y in 0..self.mb_h { | |
1185 | for mb_x in 0..self.mb_w { | |
1186 | let loop_str = self.mb_info[mb_idx].loop_str; | |
1187 | self.loop_filter_mb(&mut dframe, mb_x, mb_y, loop_str); | |
1188 | mb_idx += 1; | |
1189 | } | |
1190 | } | |
1191 | if !update_gf && self.dstate.features[2].is_some() { | |
1192 | let gf = self.shuf.get_golden().unwrap(); | |
1193 | let mut new_gf = supp.pool_u8.get_copy(&gf).unwrap(); | |
1194 | let dframe = NASimpleVideoFrame::from_video_buf(&mut new_gf).unwrap(); | |
1195 | let mut mb_idx = 0; | |
6f263099 | 1196 | let mc_buf = self.mc_buf.get_data_mut().unwrap(); |
587a6d78 KS |
1197 | for mb_y in 0..self.mb_h { |
1198 | for mb_x in 0..self.mb_w { | |
1199 | if self.mb_info[mb_idx].upd_gf { | |
6f263099 KS |
1200 | 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); |
1201 | 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); | |
1202 | 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); | |
587a6d78 KS |
1203 | } |
1204 | mb_idx += 1; | |
1205 | } | |
1206 | } | |
1207 | self.shuf.add_golden_frame(new_gf); | |
1208 | } | |
1209 | ||
1210 | if !keep_probs { | |
1211 | self.scan.copy_from_slice(&self.tmp_scan); | |
1212 | } | |
1213 | if update_gf { | |
1214 | self.shuf.add_golden_frame(buf.clone()); | |
1215 | } | |
1216 | self.shuf.add_frame(buf.clone()); | |
1217 | ||
1218 | let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::Video(buf)); | |
1219 | frm.set_keyframe(self.dstate.is_intra); | |
1220 | frm.set_frame_type(if self.dstate.is_intra { FrameType::I } else { FrameType::P }); | |
1221 | Ok(frm.into_ref()) | |
1222 | } | |
f9be4e75 KS |
1223 | fn flush(&mut self) { |
1224 | self.shuf.clear(); | |
1225 | } | |
587a6d78 KS |
1226 | } |
1227 | ||
7d57ae2f KS |
1228 | impl NAOptionHandler for VP7Decoder { |
1229 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
1230 | fn set_options(&mut self, _options: &[NAOption]) { } | |
1231 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
1232 | } | |
1233 | ||
ac818eac | 1234 | pub fn get_decoder() -> Box<dyn NADecoder + Send> { |
587a6d78 KS |
1235 | Box::new(VP7Decoder::new()) |
1236 | } | |
1237 | ||
1238 | #[cfg(test)] | |
1239 | mod test { | |
1240 | use nihav_core::codecs::RegisteredDecoders; | |
1241 | use nihav_core::demuxers::RegisteredDemuxers; | |
ce742854 | 1242 | use nihav_codec_support::test::dec_video::*; |
78fb6560 | 1243 | use crate::duck_register_all_decoders; |
e64739f8 | 1244 | use nihav_commonfmt::generic_register_all_demuxers; |
587a6d78 KS |
1245 | |
1246 | #[test] | |
1247 | fn test_vp7() { | |
1248 | let mut dmx_reg = RegisteredDemuxers::new(); | |
1249 | generic_register_all_demuxers(&mut dmx_reg); | |
1250 | let mut dec_reg = RegisteredDecoders::new(); | |
78fb6560 | 1251 | duck_register_all_decoders(&mut dec_reg); |
587a6d78 | 1252 | |
886cde48 | 1253 | // sample from https://trac.ffmpeg.org/ticket/5580 |
d24468d9 | 1254 | test_decoding("avi", "vp7", "assets/Duck/interlaced_blit_pitch.avi", Some(12), &dmx_reg, |
d9dcff04 KS |
1255 | &dec_reg, ExpectedTestResult::MD5Frames(vec![ |
1256 | [0xb79fb6f8, 0xed51ac9e, 0x9e423456, 0xc0918e7f], | |
1257 | [0xbf8d1274, 0x83515e15, 0x8c0887de, 0xfbfd05d3], | |
1258 | [0x8ad00466, 0x80b6cbfb, 0x54de408e, 0x9efbc05e], | |
1259 | [0x144122c5, 0x6897b553, 0x93474d29, 0x1a1274ec], | |
1260 | [0x06ff5d07, 0x55825d38, 0x072b0a78, 0xfcb5020f], | |
1261 | [0xfd01591b, 0xc42113e7, 0xc5a5550f, 0xb30f3b02], | |
1262 | [0x155e0d6e, 0x96d75e06, 0x9bd7ce87, 0xacf868e1], | |
1263 | [0xfd79103a, 0x695d21d3, 0xfeacb5b4, 0x1d869d08], | |
1264 | [0xf4bcfeac, 0x0d2c305c, 0x11416c96, 0x626a5ef6], | |
1265 | [0x3579b66c, 0x0a7d7dc0, 0xe80b0395, 0xf6a70661], | |
1266 | [0x5773768c, 0x813442e9, 0x4dd6f793, 0xb10fe55f], | |
1267 | [0xcaaf0ddb, 0x65c2410e, 0x95da5bba, 0x3b90128e], | |
1268 | [0x74773773, 0xe1dbadeb, 0x57aaf64b, 0x9c21e3c7]])); | |
587a6d78 KS |
1269 | } |
1270 | } |