h264: miscellaneous micro-optimisations
[nihav.git] / nihav-itu / src / codecs / h264 / mb_recon.rs
CommitLineData
11d7aef2 1use nihav_core::codecs::{DecoderResult, DecoderError};
495b7ec0 2use nihav_core::frame::*;
11d7aef2
KS
3use nihav_codec_support::codecs::{MV, ZERO_MV};
4use super::{CurrentMBInfo, I4X4_SCAN, Shareable};
5use super::dispatch::{ThreadDispatcher, FrameDecodingStatus};
495b7ec0 6use super::dsp::*;
56a17e69 7use super::pic_ref::SliceRefs;
495b7ec0
KS
8use super::slice::{SliceHeader, WeightInfo, DEF_WEIGHT_INFO};
9use super::types::*;
10
11fn pred_intra(frm: &mut NASimpleVideoFrame<u8>, sstate: &SliceState, mb_info: &CurrentMBInfo) {
12 let yoff = frm.offset[0] + sstate.mb_x * 16 + sstate.mb_y * 16 * frm.stride[0];
13 match mb_info.mb_type {
14 MBType::Intra16x16(imode, _, _) => {
15 let id = if imode != 2 || (sstate.has_top && sstate.has_left) {
16 imode as usize
17 } else if !sstate.has_top && !sstate.has_left {
18 IPRED8_DC128
19 } else if !sstate.has_left {
20 IPRED8_DC_TOP
21 } else {
22 IPRED8_DC_LEFT
23 };
24 IPRED_FUNCS16X16[id](&mut frm.data[yoff..], frm.stride[0], &sstate.top_line_y[sstate.mb_x * 16..], &sstate.left_y);
25 },
26 MBType::Intra8x8 => {
27 let mut ictx = IPred8Context::new();
28 for part in 0..4 {
29 let x = (part & 1) * 2;
30 let y = part & 2;
31 let blk4 = x + y * 4;
32
33 let cur_yoff = yoff + x * 4 + y * 4 * frm.stride[0];
34 let has_top = y > 0 || sstate.has_top;
35 let has_left = x > 0 || sstate.has_left;
36 let imode = mb_info.ipred[blk4];
37 let id = if imode != IntraPredMode::DC || (has_top && has_left) {
38 let im_id: u8 = imode.into();
39 im_id as usize
40 } else if !has_top && !has_left {
41 IPRED4_DC128
42 } else if !has_left {
43 IPRED4_DC_TOP
44 } else {
45 IPRED4_DC_LEFT
46 };
47 let mb_idx = sstate.mb_x + sstate.mb_y * sstate.mb_w;
48 let noright = (y == 2 || sstate.mb_x == sstate.mb_w - 1 || mb_idx < sstate.mb_start + sstate.mb_w) && (x == 2);
49 let has_tl = (has_top && x > 0) || (has_left && y > 0) || (x == 0 && y == 0 && sstate.mb_x > 0 && mb_idx > sstate.mb_start + sstate.mb_w);
50 if id != IPRED4_DC128 {
51 let top = if y == 0 {
52 &sstate.top_line_y[sstate.mb_x * 16 + x * 4..]
53 } else {
54 &frm.data[cur_yoff - frm.stride[0]..]
55 };
56 let mut left_buf = [0; 9];
57 let left = if x == 0 {
58 &sstate.left_y[y * 4..]
59 } else {
60 if has_tl {
61 if y == 0 {
62 left_buf[0] = sstate.top_line_y[sstate.mb_x * 16 + x * 4 - 1];
63 } else {
64 left_buf[0] = frm.data[cur_yoff - 1 - frm.stride[0]];
65 }
66 }
67 if has_left {
68 for (dst, src) in left_buf[1..].iter_mut().zip(frm.data[cur_yoff - 1..].chunks(frm.stride[0])) {
69 *dst = src[0];
70 }
71 }
72 &left_buf
73 };
74 ictx.fill(top, left, has_top, has_top && !noright, has_left, has_tl);
75 }
76 IPRED_FUNCS8X8_LUMA[id](&mut frm.data[cur_yoff..], frm.stride[0], &ictx);
77 if mb_info.coded[blk4] {
78 add_coeffs8(frm.data, cur_yoff, frm.stride[0], &mb_info.coeffs8x8[part].coeffs);
79 }
80 }
81 },
82 MBType::Intra4x4 => {
83 for &(x,y) in I4X4_SCAN.iter() {
84 let x = x as usize;
85 let y = y as usize;
86 let cur_yoff = yoff + x * 4 + y * 4 * frm.stride[0];
87 let has_top = y > 0 || sstate.has_top;
88 let has_left = x > 0 || sstate.has_left;
89 let imode = mb_info.ipred[x + y * 4];
90 let id = if imode != IntraPredMode::DC || (has_top && has_left) {
91 let im_id: u8 = imode.into();
92 im_id as usize
93 } else if !has_top && !has_left {
94 IPRED4_DC128
95 } else if !has_left {
96 IPRED4_DC_TOP
97 } else {
98 IPRED4_DC_LEFT
99 };
100 let noright = (sstate.mb_x == sstate.mb_w - 1 || sstate.mb_x + sstate.mb_y * sstate.mb_w < sstate.mb_start + sstate.mb_w) && (x == 3);
101 let tr: [u8; 4] = if y == 0 {
102 let tsrc = &sstate.top_line_y[sstate.mb_x * 16 + x * 4..];
103 if has_top && !noright {
104 [tsrc[4], tsrc[5], tsrc[6], tsrc[7]]
105 } else if has_top {
106 [tsrc[3]; 4]
107 } else {
108 [0; 4]
109 }
110 } else if (x & 1) == 0 || (x == 1 && y == 2) {
111 let i = cur_yoff - frm.stride[0];
112 [frm.data[i + 4], frm.data[i + 5], frm.data[i + 6], frm.data[i + 7]]
113 } else {
114 let i = cur_yoff - frm.stride[0];
115 [frm.data[i + 3], frm.data[i + 3], frm.data[i + 3], frm.data[i + 3]]
116 };
117 let mut top = [128; 4];
118 let mut left = [128; 9];
119 if y == 0 {
120 if has_top {
121 top.copy_from_slice(&sstate.top_line_y[sstate.mb_x * 16 + x * 4..][..4]);
122 }
123 } else {
124 top.copy_from_slice(&frm.data[cur_yoff - frm.stride[0]..][..4]);
125 }
126 if x == 0 {
127 if has_left {
128 for (dst, &src) in left.iter_mut().zip(sstate.left_y[y * 4..].iter()) {
129 *dst = src;
130 }
131 }
132 } else {
133 if y == 0 {
134 if x == 0 {
135 left[0] = sstate.left_y[y * 4];
136 } else if has_top {
137 left[0] = sstate.top_line_y[sstate.mb_x * 16 + x * 4 - 1];
138 }
139 } else {
140 left[0] = frm.data[cur_yoff - frm.stride[0] - 1];
141 }
142 for (dst, row) in left[1..].iter_mut().zip(frm.data[cur_yoff - 1..].chunks(frm.stride[0])) {
143 *dst = row[0];
144 }
145 }
146 IPRED_FUNCS4X4[id](&mut frm.data[cur_yoff..], frm.stride[0], &top, &left, &tr);
147 if mb_info.coded[x + y * 4] {
148 add_coeffs(frm.data, cur_yoff, frm.stride[0], &mb_info.coeffs[x + y * 4]);
149 }
150 }
151 },
152 _ => unreachable!(),
153 };
154 let id = if mb_info.chroma_ipred != 0 || (sstate.has_top && sstate.has_left) {
155 mb_info.chroma_ipred as usize
156 } else if !sstate.has_top && !sstate.has_left {
157 IPRED8_DC128
158 } else if !sstate.has_left {
159 IPRED8_DC_TOP
160 } else {
161 IPRED8_DC_LEFT
162 };
163 for chroma in 1..3 {
164 let off = frm.offset[chroma] + sstate.mb_x * 8 + sstate.mb_y * 8 * frm.stride[chroma];
165 let top = &sstate.top_line_c[chroma - 1][sstate.mb_x * 8..];
166 IPRED_FUNCS8X8_CHROMA[id](&mut frm.data[off..], frm.stride[chroma], top, &sstate.left_c[chroma - 1]);
167 }
168}
169
170fn add_luma(frm: &mut NASimpleVideoFrame<u8>, sstate: &SliceState, mb_info: &CurrentMBInfo) {
171 let mut yoff = frm.offset[0] + sstate.mb_x * 16 + sstate.mb_y * 16 * frm.stride[0];
172 if !mb_info.transform_size_8x8 {
173 for y in 0..4 {
174 for x in 0..4 {
175 if mb_info.coded[x + y * 4] {
176 add_coeffs(frm.data, yoff + x * 4, frm.stride[0], &mb_info.coeffs[x + y * 4]);
177 }
178 }
179 yoff += frm.stride[0] * 4;
180 }
181 } else {
182 for y in 0..2 {
183 for x in 0..2 {
184 if mb_info.coded[x * 2 + y * 2 * 4] {
185 add_coeffs8(frm.data, yoff + x * 8, frm.stride[0], &mb_info.coeffs8x8[x + y * 2].coeffs);
186 }
187 }
188 yoff += frm.stride[0] * 8;
189 }
190 }
191}
192
193fn add_chroma(frm: &mut NASimpleVideoFrame<u8>, sstate: &SliceState, mb_info: &CurrentMBInfo) {
194 for chroma in 1..3 {
195 let mut off = frm.offset[chroma] + sstate.mb_x * 8 + sstate.mb_y * 8 * frm.stride[chroma];
196 for y in 0..2 {
197 for x in 0..2 {
198 let blk_no = 16 + (chroma - 1) * 4 + x + y * 2;
199 if mb_info.coded[blk_no] || mb_info.coeffs[blk_no][0] != 0 {
200 add_coeffs(frm.data, off + x * 4, frm.stride[chroma], &mb_info.coeffs[blk_no]);
201 }
202 }
203 off += frm.stride[chroma] * 4;
204 }
205 }
206}
207
2f9923e6 208fn do_p_mc(frm: &mut NASimpleVideoFrame<u8>, xpos: usize, ypos: usize, w: usize, h: usize, mv: MV, ref_pic: Option<NAVideoBufferRef<u8>>, weight: &WeightInfo, mc_dsp: &mut H264MC) {
495b7ec0
KS
209 if let Some(buf) = ref_pic {
210 if !weight.is_weighted() {
2f9923e6 211 mc_dsp.do_mc(frm, buf, xpos, ypos, w, h, mv);
495b7ec0 212 } else {
834e7b28
KS
213 let mut tmp = McBlock::new();
214 mc_dsp.mc_blocks(&mut tmp, buf, xpos, ypos, w, h, mv);
495b7ec0
KS
215
216 let yoff = frm.offset[0] + xpos + ypos * frm.stride[0];
217 let yw = if weight.luma_weighted {
218 [weight.luma_weight, weight.luma_offset, weight.luma_shift as i8]
219 } else {
220 [1, 0, 0]
221 };
76431444
KS
222 let wmode = match w {
223 2 => 0,
224 4 => 1,
225 8 => 2,
226 _ => 3,
227 };
834e7b28 228 (mc_dsp.put_block_weighted[wmode])(&mut frm.data[yoff..], frm.stride[0], &tmp.y, h, yw);
495b7ec0
KS
229
230 for chroma in 0..2 {
231 let cstride = frm.stride[chroma + 1];
232 let coff = frm.offset[chroma + 1] + xpos / 2 + ypos / 2 * cstride;
233 let cw = if weight.chroma_weighted {
234 [weight.chroma_weight[chroma], weight.chroma_offset[chroma], weight.chroma_shift as i8]
235 } else {
236 [1, 0, 0]
237 };
834e7b28 238 let csrc = if chroma == 0 { &tmp.u } else { &tmp.v };
76431444 239 (mc_dsp.put_block_weighted[wmode - 1])(&mut frm.data[coff..], cstride, csrc, h / 2, cw);
495b7ec0
KS
240 }
241 }
242 } else {
2f9923e6 243 mc_dsp.gray_block(frm, xpos, ypos, w, h);
495b7ec0
KS
244 }
245}
246
42005e25 247#[allow(clippy::match_like_matches_macro)]
2f9923e6 248fn do_b_mc(frm: &mut NASimpleVideoFrame<u8>, mode: BMode, xpos: usize, ypos: usize, w: usize, h: usize, mv0: MV, ref_pic0: Option<NAVideoBufferRef<u8>>, weight0: &WeightInfo, mv1: MV, ref_pic1: Option<NAVideoBufferRef<u8>>, weight1: &WeightInfo, mc_dsp: &mut H264MC) {
495b7ec0
KS
249 let do_weight = match (mode, weight0.is_weighted(), weight1.is_weighted()) {
250 (BMode::L0, true, _) => true,
251 (BMode::L1, _, true) => true,
252 (BMode::Bi, true, true) => true,
253 _ => false,
254 };
255 if !do_weight {
256 match mode {
257 BMode::L0 => {
258 if let Some(buf) = ref_pic0 {
2f9923e6 259 mc_dsp.do_mc(frm, buf, xpos, ypos, w, h, mv0);
495b7ec0 260 } else {
2f9923e6 261 mc_dsp.gray_block(frm, xpos, ypos, w, h);
495b7ec0
KS
262 }
263 },
264 BMode::L1 => {
265 if let Some(buf) = ref_pic1 {
2f9923e6 266 mc_dsp.do_mc(frm, buf, xpos, ypos, w, h, mv1);
495b7ec0 267 } else {
2f9923e6 268 mc_dsp.gray_block(frm, xpos, ypos, w, h);
495b7ec0
KS
269 }
270 },
271 BMode::Bi => {
272 match (ref_pic0, ref_pic1) {
273 (Some(buf0), Some(buf1)) => {
2f9923e6
KS
274 mc_dsp.do_mc(frm, buf0, xpos, ypos, w, h, mv0);
275 mc_dsp.do_mc_avg(frm, buf1, xpos, ypos, w, h, mv1);
495b7ec0
KS
276 },
277 (Some(buf0), None) => {
2f9923e6 278 mc_dsp.do_mc(frm, buf0, xpos, ypos, w, h, mv0);
495b7ec0
KS
279 },
280 (None, Some(buf1)) => {
2f9923e6 281 mc_dsp.do_mc(frm, buf1, xpos, ypos, w, h, mv1);
495b7ec0
KS
282 },
283 (None, None) => {
2f9923e6 284 mc_dsp.gray_block(frm, xpos, ypos, w, h);
495b7ec0
KS
285 },
286 };
287 },
288 };
289 } else {
834e7b28
KS
290 let mut tmp0 = McBlock::new();
291 let mut tmp1 = McBlock::new();
495b7ec0
KS
292 match (mode, ref_pic0, ref_pic1) {
293 (BMode::L0, Some(buf), _) | (BMode::L1, _, Some(buf)) => {
294 let (mv, weight) = if mode == BMode::L0 { (mv0, weight0) } else { (mv1, weight1) };
834e7b28 295 mc_dsp.mc_blocks(&mut tmp0, buf, xpos, ypos, w, h, mv);
495b7ec0
KS
296
297 let yoff = frm.offset[0] + xpos + ypos * frm.stride[0];
298 let yw = if weight.luma_weighted {
299 [weight.luma_weight, weight.luma_offset, weight.luma_shift as i8]
300 } else {
301 [1, 0, 0]
302 };
76431444
KS
303 let wmode = match w {
304 2 => 0,
305 4 => 1,
306 8 => 2,
307 _ => 3,
308 };
834e7b28 309 (mc_dsp.put_block_weighted[wmode])(&mut frm.data[yoff..], frm.stride[0], &tmp0.y, h, yw);
495b7ec0
KS
310
311 for chroma in 0..2 {
312 let cstride = frm.stride[chroma + 1];
313 let coff = frm.offset[chroma + 1] + xpos / 2 + ypos / 2 * cstride;
314 let cw = if weight.chroma_weighted {
315 [weight.chroma_weight[chroma], weight.chroma_offset[chroma], weight.chroma_shift as i8]
316 } else {
317 [1, 0, 0]
318 };
834e7b28 319 let csrc = if chroma == 0 { &tmp0.u } else { &tmp0.v };
76431444 320 (mc_dsp.put_block_weighted[wmode - 1])(&mut frm.data[coff..], cstride, csrc, h / 2, cw);
495b7ec0
KS
321 }
322 },
323 (BMode::Bi, Some(buf0), Some(buf1)) => { // do both and avg
834e7b28
KS
324 mc_dsp.mc_blocks(&mut tmp0, buf0, xpos, ypos, w, h, mv0);
325 mc_dsp.mc_blocks(&mut tmp1, buf1, xpos, ypos, w, h, mv1);
495b7ec0
KS
326
327 let yoff = frm.offset[0] + xpos + ypos * frm.stride[0];
328 let yw = match (weight0.luma_weighted, weight1.luma_weighted) {
329 (true, true) => [weight0.luma_weight, weight0.luma_offset, weight1.luma_weight, weight1.luma_offset, weight0.luma_shift as i8],
330 (true, false) => [weight0.luma_weight, weight0.luma_offset, 1 << weight0.luma_shift, 0, weight0.luma_shift as i8],
331 (false, true) => [1 << weight1.luma_shift, 0, weight1.luma_weight, weight1.luma_offset, weight1.luma_shift as i8],
332 (false, false) => [1, 0, 1, 0, 0],
333 };
76431444
KS
334 let wmode = match w {
335 2 => 0,
336 4 => 1,
337 8 => 2,
338 _ => 3,
339 };
834e7b28 340 (mc_dsp.put_block_weighted2[wmode])(&mut frm.data[yoff..], frm.stride[0], &tmp0.y, &tmp1.y, h, yw);
495b7ec0
KS
341
342 for chroma in 0..2 {
343 let cstride = frm.stride[chroma + 1];
344 let coff = frm.offset[chroma + 1] + xpos / 2 + ypos / 2 * cstride;
345 let cw0 = weight0.chroma_weight[chroma];
346 let co0 = weight0.chroma_offset[chroma];
347 let cw1 = weight1.chroma_weight[chroma];
348 let co1 = weight1.chroma_offset[chroma];
349 let cw = match (weight0.chroma_weighted, weight1.chroma_weighted) {
350 (true, true) => [cw0, co0, cw1, co1, weight0.luma_shift as i8],
351 (true, false) => [cw0, co0, 1 << weight0.luma_shift, 0, weight0.luma_shift as i8],
352 (false, true) => [1 << weight1.luma_shift, 0, cw1, co1, weight1.luma_shift as i8],
353 (false, false) => [1, 0, 1, 0, 0],
354 };
834e7b28
KS
355 let csrc0 = if chroma == 0 { &tmp0.u } else { &tmp0.v };
356 let csrc1 = if chroma == 0 { &tmp1.u } else { &tmp1.v };
76431444 357 (mc_dsp.put_block_weighted2[wmode - 1])(&mut frm.data[coff..], cstride, csrc0, csrc1, h / 2, cw);
495b7ec0
KS
358 }
359 },
360 _ => {
2f9923e6 361 mc_dsp.gray_block(frm, xpos, ypos, w, h);
495b7ec0
KS
362 },
363 };
364 }
365}
366
754ab49a 367fn do_b_mc_4x4bi(frm: &mut NASimpleVideoFrame<u8>, xpos: usize, ypos: usize, mv: &[MV; 2], ref_pic0: Option<NAVideoBufferRef<u8>>, weight0: &WeightInfo, ref_pic1: Option<NAVideoBufferRef<u8>>, weight1: &WeightInfo, mc_dsp: &mut H264MC) {
a9b33d5e
KS
368 if !weight0.is_weighted() || !weight1.is_weighted() {
369 match (ref_pic0, ref_pic1) {
370 (Some(buf0), Some(buf1)) => {
371 mc_dsp.do_mc(frm, buf0, xpos, ypos, 4, 4, mv[0]);
372 mc_dsp.do_mc_avg(frm, buf1, xpos, ypos, 4, 4, mv[1]);
373 },
374 (Some(buf0), None) => {
375 mc_dsp.do_mc(frm, buf0, xpos, ypos, 4, 4, mv[0]);
376 },
377 (None, Some(buf1)) => {
378 mc_dsp.do_mc(frm, buf1, xpos, ypos, 4, 4, mv[1]);
379 },
380 (None, None) => {
381 mc_dsp.gray_block(frm, xpos, ypos, 4, 4);
382 },
383 };
384 } else {
385 let mut tmp0 = McBlock::new();
386 let mut tmp1 = McBlock::new();
387 match (ref_pic0, ref_pic1) {
388 (Some(buf0), Some(buf1)) => { // do both and avg
389 mc_dsp.mc_blocks(&mut tmp0, buf0, xpos, ypos, 4, 4, mv[0]);
390 mc_dsp.mc_blocks(&mut tmp1, buf1, xpos, ypos, 4, 4, mv[1]);
391
392 let yoff = frm.offset[0] + xpos + ypos * frm.stride[0];
393 let yw = match (weight0.luma_weighted, weight1.luma_weighted) {
394 (true, true) => [weight0.luma_weight, weight0.luma_offset, weight1.luma_weight, weight1.luma_offset, weight0.luma_shift as i8],
395 (true, false) => [weight0.luma_weight, weight0.luma_offset, 1 << weight0.luma_shift, 0, weight0.luma_shift as i8],
396 (false, true) => [1 << weight1.luma_shift, 0, weight1.luma_weight, weight1.luma_offset, weight1.luma_shift as i8],
397 (false, false) => [1, 0, 1, 0, 0],
398 };
399 (mc_dsp.put_block_weighted2[1])(&mut frm.data[yoff..], frm.stride[0], &tmp0.y, &tmp1.y, 4, yw);
400
401 for chroma in 0..2 {
402 let cstride = frm.stride[chroma + 1];
403 let coff = frm.offset[chroma + 1] + xpos / 2 + ypos / 2 * cstride;
404 let cw0 = weight0.chroma_weight[chroma];
405 let co0 = weight0.chroma_offset[chroma];
406 let cw1 = weight1.chroma_weight[chroma];
407 let co1 = weight1.chroma_offset[chroma];
408 let cw = match (weight0.chroma_weighted, weight1.chroma_weighted) {
409 (true, true) => [cw0, co0, cw1, co1, weight0.luma_shift as i8],
410 (true, false) => [cw0, co0, 1 << weight0.luma_shift, 0, weight0.luma_shift as i8],
411 (false, true) => [1 << weight1.luma_shift, 0, cw1, co1, weight1.luma_shift as i8],
412 (false, false) => [1, 0, 1, 0, 0],
413 };
414 let csrc0 = if chroma == 0 { &tmp0.u } else { &tmp0.v };
415 let csrc1 = if chroma == 0 { &tmp1.u } else { &tmp1.v };
416 (mc_dsp.put_block_weighted2[0])(&mut frm.data[coff..], cstride, csrc0, csrc1, 2, cw);
417 }
418 },
419 _ => {
420 mc_dsp.gray_block(frm, xpos, ypos, 4, 4);
421 },
422 };
423 }
424}
425
56a17e69 426fn get_weights(slice_hdr: &SliceHeader, frame_refs: &SliceRefs, mode: BMode, weight_mode: u8, ref_l0: PicRef, ref_l1: PicRef) -> (WeightInfo, WeightInfo) {
495b7ec0
KS
427 let idx_l0 = ref_l0.index();
428 let idx_l1 = ref_l1.index();
429 if mode != BMode::Bi || weight_mode != 2 {
430 (slice_hdr.get_weight(0, idx_l0), slice_hdr.get_weight(1, idx_l1))
431 } else if let (Some(Some(ref pic0)), Some(Some(ref pic1))) = (frame_refs.ref_list0.get(idx_l0), frame_refs.ref_list1.get(idx_l1)) {
432 let r0_poc = pic0.full_id as u16;
433 let r1_poc = pic1.full_id as u16;
434 let cur_id = frame_refs.cur_id as u16;
435 if (r0_poc == r1_poc) || pic0.long_term.is_some() || pic1.long_term.is_some() {
436 return (DEF_WEIGHT_INFO, DEF_WEIGHT_INFO);
437 }
438
439 let td = (i32::from(r1_poc) - i32::from(r0_poc)).max(-128).min(127);
440 let tx = (16384 + (td / 2).abs()) / td;
441 let tb = (i32::from(cur_id) - i32::from(r0_poc)).max(-128).min(127);
442 let scale = ((tb * tx + 32) >> 6).max(-1024).min(1023);
443 if scale == 128 || (scale >> 2) < -64 || (scale >> 2) > 128 {
444 return (DEF_WEIGHT_INFO, DEF_WEIGHT_INFO);
445 }
446 let w1 = (scale >> 2) as i8;
447 let w0 = 64 - w1;
448
449 let weight0 = WeightInfo {
450 luma_weighted: true,
451 luma_weight: w0,
452 luma_offset: 0,
453 luma_shift: 5,
454 chroma_weighted: true,
455 chroma_weight: [w0; 2],
456 chroma_offset: [0; 2],
457 chroma_shift: 5,
458 };
459 let weight1 = WeightInfo {
460 luma_weighted: true,
461 luma_weight: w1,
462 luma_offset: 0,
463 luma_shift: 5,
464 chroma_weighted: true,
465 chroma_weight: [w1; 2],
466 chroma_offset: [0; 2],
467 chroma_shift: 5,
468 };
469
470 (weight0, weight1)
471 } else {
472 (DEF_WEIGHT_INFO, DEF_WEIGHT_INFO)
473 }
474}
475
56a17e69 476pub fn recon_mb(frm: &mut NASimpleVideoFrame<u8>, slice_hdr: &SliceHeader, mb_info: &CurrentMBInfo, sstate: &mut SliceState, frame_refs: &SliceRefs, mc_dsp: &mut H264MC, weight_mode: u8) {
495b7ec0
KS
477 let xpos = sstate.mb_x * 16;
478 let ypos = sstate.mb_y * 16;
479
480 match mb_info.mb_type {
481 MBType::Intra16x16(_, _, _) => {
42005e25 482 pred_intra(frm, sstate, mb_info);
495b7ec0
KS
483 },
484 MBType::Intra4x4 | MBType::Intra8x8 => {
42005e25 485 pred_intra(frm, sstate, mb_info);
495b7ec0
KS
486 },
487 MBType::PCM => {},
488 MBType::PSkip => {
489 let mv = sstate.get_cur_blk4(0).mv[0];
490 let rpic = frame_refs.select_ref_pic(0, 0);
491 let weight = &slice_hdr.get_weight(0, 0);
2f9923e6 492 do_p_mc(frm, xpos, ypos, 16, 16, mv, rpic, weight, mc_dsp);
495b7ec0
KS
493 },
494 MBType::P16x16 => {
495 let mv = sstate.get_cur_blk4(0).mv[0];
496 let rpic = frame_refs.select_ref_pic(0, mb_info.ref_l0[0].index());
497 let weight = &slice_hdr.get_weight(0, mb_info.ref_l0[0].index());
2f9923e6 498 do_p_mc(frm, xpos, ypos, 16, 16, mv, rpic, weight, mc_dsp);
495b7ec0
KS
499 },
500 MBType::P16x8 | MBType::P8x16 => {
501 let (bw, bh, bx, by) = if mb_info.mb_type == MBType::P16x8 {
502 (16, 8, 0, 8)
503 } else {
504 (8, 16, 8, 0)
505 };
506 let mv = sstate.get_cur_blk4(0).mv[0];
507 let rpic = frame_refs.select_ref_pic(0, mb_info.ref_l0[0].index());
508 let weight = &slice_hdr.get_weight(0, mb_info.ref_l0[0].index());
2f9923e6 509 do_p_mc(frm, xpos, ypos, bw, bh, mv, rpic, weight, mc_dsp);
495b7ec0
KS
510 let mv = sstate.get_cur_blk4(bx / 4 + by).mv[0];
511 let rpic = frame_refs.select_ref_pic(0, mb_info.ref_l0[1].index());
512 let weight = &slice_hdr.get_weight(0, mb_info.ref_l0[1].index());
2f9923e6 513 do_p_mc(frm, xpos + bx, ypos + by, bw, bh, mv, rpic, weight, mc_dsp);
495b7ec0
KS
514 },
515 MBType::P8x8 | MBType::P8x8Ref0 => {
516 for part in 0..4 {
517 let bx = (part & 1) * 8;
518 let by = (part & 2) * 4;
519 let mv = sstate.get_cur_blk4(bx / 4 + by).mv[0];
520 let rpic = frame_refs.select_ref_pic(0, mb_info.ref_l0[part].index());
521 let weight = &slice_hdr.get_weight(0, mb_info.ref_l0[part].index());
522
523 match mb_info.sub_mb_type[part] {
524 SubMBType::P8x8 => {
2f9923e6 525 do_p_mc(frm, xpos + bx, ypos + by, 8, 8, mv, rpic, weight, mc_dsp);
495b7ec0
KS
526 },
527 SubMBType::P8x4 => {
2f9923e6 528 do_p_mc(frm, xpos + bx, ypos + by, 8, 4, mv, rpic.clone(), weight, mc_dsp);
495b7ec0 529 let mv = sstate.get_cur_blk4(bx / 4 + by + 4).mv[0];
2f9923e6 530 do_p_mc(frm, xpos + bx, ypos + by + 4, 8, 4, mv, rpic, weight, mc_dsp);
495b7ec0
KS
531 },
532 SubMBType::P4x8 => {
2f9923e6 533 do_p_mc(frm, xpos + bx, ypos + by, 4, 8, mv, rpic.clone(), weight, mc_dsp);
495b7ec0 534 let mv = sstate.get_cur_blk4(bx / 4 + by + 1).mv[0];
2f9923e6 535 do_p_mc(frm, xpos + bx + 4, ypos + by, 4, 8, mv, rpic, weight, mc_dsp);
495b7ec0
KS
536 },
537 SubMBType::P4x4 => {
538 for sb_no in 0..4 {
539 let sxpos = xpos + bx + (sb_no & 1) * 4;
540 let sypos = ypos + by + (sb_no & 2) * 2;
541 let sblk_no = (bx / 4 + (sb_no & 1)) + ((by / 4) + (sb_no >> 1)) * 4;
542 let mv = sstate.get_cur_blk4(sblk_no).mv[0];
2f9923e6 543 do_p_mc(frm, sxpos, sypos, 4, 4, mv, rpic.clone(), weight, mc_dsp);
495b7ec0
KS
544 }
545 },
546 _ => unreachable!(),
547 };
548 }
549 },
550 MBType::B16x16(mode) => {
551 let mv0 = sstate.get_cur_blk4(0).mv[0];
552 let rpic0 = frame_refs.select_ref_pic(0, mb_info.ref_l0[0].index());
553 let mv1 = sstate.get_cur_blk4(0).mv[1];
554 let rpic1 = frame_refs.select_ref_pic(1, mb_info.ref_l1[0].index());
555 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, mode, weight_mode, mb_info.ref_l0[0], mb_info.ref_l1[0]);
2f9923e6 556 do_b_mc(frm, mode, xpos, ypos, 16, 16, mv0, rpic0, &weight0, mv1, rpic1, &weight1, mc_dsp);
495b7ec0
KS
557 },
558 MBType::B16x8(mode0, mode1) | MBType::B8x16(mode0, mode1) => {
559 let (pw, ph) = mb_info.mb_type.size();
560 let (px, py) = (pw & 8, ph & 8);
561 let modes = [mode0, mode1];
562 let (mut bx, mut by) = (0, 0);
563 for part in 0..2 {
564 let blk = if part == 0 { 0 } else { (px / 4) + py };
565 let mv0 = sstate.get_cur_blk4(blk).mv[0];
566 let rpic0 = frame_refs.select_ref_pic(0, mb_info.ref_l0[part].index());
567 let mv1 = sstate.get_cur_blk4(blk).mv[1];
568 let rpic1 = frame_refs.select_ref_pic(1, mb_info.ref_l1[part].index());
569 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, modes[part], weight_mode, mb_info.ref_l0[part], mb_info.ref_l1[part]);
2f9923e6 570 do_b_mc(frm, modes[part], xpos + bx, ypos + by, pw, ph, mv0, rpic0, &weight0, mv1, rpic1, &weight1, mc_dsp);
495b7ec0
KS
571 bx += px;
572 by += py;
573 }
574 },
575 MBType::Direct | MBType::BSkip => {
576 let colo_mb_type = frame_refs.get_colocated_info(sstate.mb_x, sstate.mb_y).0.mb_type;
577 let is_16x16 = colo_mb_type.is_16x16_ref();
578
579 if is_16x16 {
580 let mv = sstate.get_cur_blk4(0).mv;
581 let ref_idx = sstate.get_cur_blk8(0).ref_idx;
582 let rpic0 = frame_refs.select_ref_pic(0, ref_idx[0].index());
583 let rpic1 = frame_refs.select_ref_pic(1, ref_idx[1].index());
584 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, BMode::Bi, weight_mode, ref_idx[0], ref_idx[1]);
2f9923e6 585 do_b_mc(frm, BMode::Bi, xpos, ypos, 16, 16, mv[0], rpic0, &weight0, mv[1], rpic1, &weight1, mc_dsp);
495b7ec0
KS
586 } else {
587 for blk4 in 0..16 {
495b7ec0
KS
588 let ref_idx = sstate.get_cur_blk8(blk4_to_blk8(blk4)).ref_idx;
589 let rpic0 = frame_refs.select_ref_pic(0, ref_idx[0].index());
590 let rpic1 = frame_refs.select_ref_pic(1, ref_idx[1].index());
591 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, BMode::Bi, weight_mode, ref_idx[0], ref_idx[1]);
754ab49a 592 let mv = &sstate.get_cur_blk4(blk4).mv;
a9b33d5e 593 do_b_mc_4x4bi(frm, xpos + (blk4 & 3) * 4, ypos + (blk4 >> 2) * 4, mv, rpic0, &weight0, rpic1, &weight1, mc_dsp);
495b7ec0
KS
594 }
595 }
596 sstate.apply_to_blk8(|blk8| { blk8.ref_idx[0].set_direct(); blk8.ref_idx[1].set_direct(); });
597 },
598 MBType::B8x8 => {
599 for part in 0..4 {
600 let ridx = sstate.get_cur_blk8(part).ref_idx;
601 let rpic0 = frame_refs.select_ref_pic(0, ridx[0].index());
602 let rpic1 = frame_refs.select_ref_pic(1, ridx[1].index());
603 let subtype = mb_info.sub_mb_type[part];
604 let blk8 = (part & 1) * 2 + (part & 2) * 4;
605 let mut bx = (part & 1) * 8;
606 let mut by = (part & 2) * 4;
607 match subtype {
608 SubMBType::Direct8x8 => {
609 for blk in 0..4 {
495b7ec0
KS
610 let ref_idx = sstate.get_cur_blk8(bx / 8 + (by / 8) * 2).ref_idx;
611 let rpic0 = frame_refs.select_ref_pic(0, ref_idx[0].index());
612 let rpic1 = frame_refs.select_ref_pic(1, ref_idx[1].index());
613 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, BMode::Bi, weight_mode, ref_idx[0], ref_idx[1]);
754ab49a 614 let mv = &sstate.get_cur_blk4(bx / 4 + (by / 4) * 4).mv;
a9b33d5e 615 do_b_mc_4x4bi(frm, xpos + bx, ypos + by, mv, rpic0, &weight0, rpic1, &weight1, mc_dsp);
495b7ec0
KS
616 bx += 4;
617 if blk == 1 {
618 bx -= 8;
619 by += 4;
620 }
621 }
622 sstate.get_cur_blk8(part).ref_idx[0].set_direct();
623 sstate.get_cur_blk8(part).ref_idx[1].set_direct();
624 },
625 SubMBType::B8x8(mode) => {
626 let mv = sstate.get_cur_blk4(blk8).mv;
627 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, mode, weight_mode, ridx[0], ridx[1]);
2f9923e6 628 do_b_mc(frm, mode, xpos + bx, ypos + by, 8, 8, mv[0], rpic0, &weight0, mv[1], rpic1, &weight1, mc_dsp);
495b7ec0
KS
629 },
630 SubMBType::B8x4(mode) | SubMBType::B4x8(mode) => {
631 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, mode, weight_mode, ridx[0], ridx[1]);
632 let (pw, ph) = subtype.size();
633 let mv = sstate.get_cur_blk4(blk8).mv;
2f9923e6 634 do_b_mc(frm, mode, xpos + bx, ypos + by, pw, ph, mv[0], rpic0.clone(), &weight0, mv[1], rpic1.clone(), &weight1, mc_dsp);
495b7ec0
KS
635 let addr2 = blk8 + (pw & 4) / 4 + (ph & 4);
636 let mv = sstate.get_cur_blk4(addr2).mv;
2f9923e6 637 do_b_mc(frm, mode, xpos + bx + (pw & 4), ypos + by + (ph & 4), pw, ph, mv[0], rpic0, &weight0, mv[1], rpic1, &weight1, mc_dsp);
495b7ec0
KS
638 },
639 SubMBType::B4x4(mode) => {
640 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, mode, weight_mode, ridx[0], ridx[1]);
641 for i in 0..4 {
642 let addr2 = blk8 + (i & 1) + (i & 2) * 2;
643 let mv = sstate.get_cur_blk4(addr2).mv;
2f9923e6 644 do_b_mc(frm, mode, xpos + bx, ypos + by, 4, 4, mv[0], rpic0.clone(), &weight0, mv[1], rpic1.clone(), &weight1, mc_dsp);
495b7ec0
KS
645 bx += 4;
646 if i == 1 {
647 bx -= 8;
648 by += 4;
649 }
650 }
651 },
652 _ => unreachable!(),
653 };
654 }
655 },
656 };
657 if !mb_info.mb_type.is_skip() {
658 if mb_info.mb_type != MBType::Intra4x4 && mb_info.mb_type != MBType::Intra8x8 {
42005e25 659 add_luma(frm, sstate, mb_info);
495b7ec0 660 }
42005e25 661 add_chroma(frm, sstate, mb_info);
495b7ec0
KS
662 }
663}
11d7aef2
KS
664
665pub fn wait_for_mb(disp: &Shareable<ThreadDispatcher>, sstate: &SliceState, xpos: usize, ypos: usize, mv: MV, ref_id: u32) -> DecoderResult<()> {
666 let xpos = xpos as isize + ((mv.x >> 2) as isize) + 4;
667 let ypos = ypos as isize + ((mv.y >> 2) as isize) + 4;
668 let dst_mb_x = ((xpos.max(0) as usize) / 16).min(sstate.mb_w - 1);
669 let dst_mb_y = ((ypos.max(0) as usize) / 16).min(sstate.mb_h - 1);
670 let expected_mb = dst_mb_x + dst_mb_y * sstate.mb_w;
671 loop {
672 if let Ok(ds) = disp.read() {
673 match ds.check_pos(ref_id, expected_mb) {
674 FrameDecodingStatus::Ok => return Ok(()),
675 FrameDecodingStatus::NotReady => {},
676 _ => return Err(DecoderError::MissingReference),
677 };
678 }
679 std::thread::yield_now();
680 }
681}
682
683fn wait_b_mc(disp: &Shareable<ThreadDispatcher>, sstate: &SliceState, frame_refs: &SliceRefs, mv: [MV; 2], ref_idx: [PicRef; 2], xpos: usize, ypos: usize, w: usize, h: usize) -> DecoderResult<()> {
684 if let Some(ref_id) = frame_refs.get_ref_id(0, ref_idx[0].index()) {
685 wait_for_mb(disp, sstate, xpos + w, ypos + h, mv[0], ref_id)?;
686 }
687 if let Some(ref_id) = frame_refs.get_ref_id(1, ref_idx[1].index()) {
688 wait_for_mb(disp, sstate, xpos + w, ypos + h, mv[1], ref_id)?;
689 }
690 Ok(())
691}
692
693pub fn recon_mb_mt(frm: &mut NASimpleVideoFrame<u8>, slice_hdr: &SliceHeader, mb_info: &CurrentMBInfo, sstate: &mut SliceState, frame_refs: &SliceRefs, mc_dsp: &mut H264MC, weight_mode: u8, disp: &Shareable<ThreadDispatcher>) -> DecoderResult<()> {
694 let xpos = sstate.mb_x * 16;
695 let ypos = sstate.mb_y * 16;
696
697 match mb_info.mb_type {
698 MBType::Intra16x16(_, _, _) => {
699 pred_intra(frm, sstate, mb_info);
700 },
701 MBType::Intra4x4 | MBType::Intra8x8 => {
702 pred_intra(frm, sstate, mb_info);
703 },
704 MBType::PCM => {},
705 MBType::PSkip => {
706 let mv = sstate.get_cur_blk4(0).mv[0];
707 if let Some(ref_id) = frame_refs.get_ref_id(0, 0) {
708 wait_for_mb(disp, sstate, xpos + 16, ypos + 16, mv, ref_id)?;
709 }
710 let rpic = frame_refs.select_ref_pic(0, 0);
711 let weight = &slice_hdr.get_weight(0, 0);
712 do_p_mc(frm, xpos, ypos, 16, 16, mv, rpic, weight, mc_dsp);
713 },
714 MBType::P16x16 => {
715 let mv = sstate.get_cur_blk4(0).mv[0];
716 if let Some(ref_id) = frame_refs.get_ref_id(0, mb_info.ref_l0[0].index()) {
717 wait_for_mb(disp, sstate, xpos + 16, ypos + 16, mv, ref_id)?;
718 }
719 let rpic = frame_refs.select_ref_pic(0, mb_info.ref_l0[0].index());
720 let weight = &slice_hdr.get_weight(0, mb_info.ref_l0[0].index());
721 do_p_mc(frm, xpos, ypos, 16, 16, mv, rpic, weight, mc_dsp);
722 },
723 MBType::P16x8 | MBType::P8x16 => {
724 let (bw, bh, bx, by) = if mb_info.mb_type == MBType::P16x8 {
725 (16, 8, 0, 8)
726 } else {
727 (8, 16, 8, 0)
728 };
729 let mv = sstate.get_cur_blk4(0).mv[0];
730 if let Some(ref_id) = frame_refs.get_ref_id(0, mb_info.ref_l0[0].index()) {
731 wait_for_mb(disp, sstate, xpos + bw, ypos + bh, mv, ref_id)?;
732 }
733 let rpic = frame_refs.select_ref_pic(0, mb_info.ref_l0[0].index());
734 let weight = &slice_hdr.get_weight(0, mb_info.ref_l0[0].index());
735 do_p_mc(frm, xpos, ypos, bw, bh, mv, rpic, weight, mc_dsp);
736 let mv = sstate.get_cur_blk4(bx / 4 + by).mv[0];
737 if let Some(ref_id) = frame_refs.get_ref_id(0, mb_info.ref_l0[1].index()) {
738 wait_for_mb(disp, sstate, xpos + 16, ypos + 16, mv, ref_id)?;
739 }
740 let rpic = frame_refs.select_ref_pic(0, mb_info.ref_l0[1].index());
741 let weight = &slice_hdr.get_weight(0, mb_info.ref_l0[1].index());
742 do_p_mc(frm, xpos + bx, ypos + by, bw, bh, mv, rpic, weight, mc_dsp);
743 },
744 MBType::P8x8 | MBType::P8x8Ref0 => {
745 for part in 0..4 {
746 let bx = (part & 1) * 8;
747 let by = (part & 2) * 4;
748 let mv = sstate.get_cur_blk4(bx / 4 + by).mv[0];
749 let rpic = frame_refs.select_ref_pic(0, mb_info.ref_l0[part].index());
750 let weight = &slice_hdr.get_weight(0, mb_info.ref_l0[part].index());
751
752 match mb_info.sub_mb_type[part] {
753 SubMBType::P8x8 => {
754 if let Some(ref_id) = frame_refs.get_ref_id(0, mb_info.ref_l0[part].index()) {
755 wait_for_mb(disp, sstate, xpos + bx + 8, ypos + by + 8, mv, ref_id)?;
756 }
757 do_p_mc(frm, xpos + bx, ypos + by, 8, 8, mv, rpic, weight, mc_dsp);
758 },
759 SubMBType::P8x4 => {
760 if let Some(ref_id) = frame_refs.get_ref_id(0, mb_info.ref_l0[part].index()) {
761 wait_for_mb(disp, sstate, xpos + bx + 8, ypos + by + 4, mv, ref_id)?;
762 }
763 do_p_mc(frm, xpos + bx, ypos + by, 8, 4, mv, rpic.clone(), weight, mc_dsp);
764 let mv = sstate.get_cur_blk4(bx / 4 + by + 4).mv[0];
765 if let Some(ref_id) = frame_refs.get_ref_id(0, mb_info.ref_l0[part].index()) {
766 wait_for_mb(disp, sstate, xpos + bx + 8, ypos + by + 8, mv, ref_id)?;
767 }
768 do_p_mc(frm, xpos + bx, ypos + by + 4, 8, 4, mv, rpic, weight, mc_dsp);
769 },
770 SubMBType::P4x8 => {
771 if let Some(ref_id) = frame_refs.get_ref_id(0, mb_info.ref_l0[part].index()) {
772 wait_for_mb(disp, sstate, xpos + bx + 4, ypos + by + 8, mv, ref_id)?;
773 }
774 do_p_mc(frm, xpos + bx, ypos + by, 4, 8, mv, rpic.clone(), weight, mc_dsp);
775 let mv = sstate.get_cur_blk4(bx / 4 + by + 1).mv[0];
776 if let Some(ref_id) = frame_refs.get_ref_id(0, mb_info.ref_l0[part].index()) {
777 wait_for_mb(disp, sstate, xpos + bx + 8, ypos + by + 8, mv, ref_id)?;
778 }
779 do_p_mc(frm, xpos + bx + 4, ypos + by, 4, 8, mv, rpic, weight, mc_dsp);
780 },
781 SubMBType::P4x4 => {
782 for sb_no in 0..4 {
783 let sxpos = xpos + bx + (sb_no & 1) * 4;
784 let sypos = ypos + by + (sb_no & 2) * 2;
785 let sblk_no = (bx / 4 + (sb_no & 1)) + ((by / 4) + (sb_no >> 1)) * 4;
786 let mv = sstate.get_cur_blk4(sblk_no).mv[0];
787 if let Some(ref_id) = frame_refs.get_ref_id(0, mb_info.ref_l0[part].index()) {
788 wait_for_mb(disp, sstate, sxpos + 4, sypos + 4, mv, ref_id)?;
789 }
790 do_p_mc(frm, sxpos, sypos, 4, 4, mv, rpic.clone(), weight, mc_dsp);
791 }
792 },
793 _ => unreachable!(),
794 };
795 }
796 },
797 MBType::B16x16(mode) => {
798 let mv0 = sstate.get_cur_blk4(0).mv[0];
799 let rpic0 = frame_refs.select_ref_pic(0, mb_info.ref_l0[0].index());
800 let mv1 = sstate.get_cur_blk4(0).mv[1];
801 let rpic1 = frame_refs.select_ref_pic(1, mb_info.ref_l1[0].index());
802 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, mode, weight_mode, mb_info.ref_l0[0], mb_info.ref_l1[0]);
803 wait_b_mc(disp, sstate, frame_refs, [mv0, mv1], [mb_info.ref_l0[0], mb_info.ref_l1[0]], xpos, ypos, 16, 16)?;
804 do_b_mc(frm, mode, xpos, ypos, 16, 16, mv0, rpic0, &weight0, mv1, rpic1, &weight1, mc_dsp);
805 },
806 MBType::B16x8(mode0, mode1) | MBType::B8x16(mode0, mode1) => {
807 let (pw, ph) = mb_info.mb_type.size();
808 let (px, py) = (pw & 8, ph & 8);
809 let modes = [mode0, mode1];
810 let (mut bx, mut by) = (0, 0);
811 for part in 0..2 {
812 let blk = if part == 0 { 0 } else { (px / 4) + py };
813 let mv0 = sstate.get_cur_blk4(blk).mv[0];
814 let rpic0 = frame_refs.select_ref_pic(0, mb_info.ref_l0[part].index());
815 let mv1 = sstate.get_cur_blk4(blk).mv[1];
816 let rpic1 = frame_refs.select_ref_pic(1, mb_info.ref_l1[part].index());
817 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, modes[part], weight_mode, mb_info.ref_l0[part], mb_info.ref_l1[part]);
818 wait_b_mc(disp, sstate, frame_refs, [mv0, mv1], [mb_info.ref_l0[part], mb_info.ref_l1[part]], xpos + bx, ypos + by, pw, ph)?;
819 do_b_mc(frm, modes[part], xpos + bx, ypos + by, pw, ph, mv0, rpic0, &weight0, mv1, rpic1, &weight1, mc_dsp);
820 bx += px;
821 by += py;
822 }
823 },
824 MBType::Direct | MBType::BSkip => {
825 if let Some(ref_id) = frame_refs.get_ref_id(1, mb_info.ref_l1[0].index()) {
826 wait_for_mb(disp, sstate, xpos, ypos, ZERO_MV, ref_id)?;
827 }
828 let colo_mb_type = frame_refs.get_colocated_info(sstate.mb_x, sstate.mb_y).0.mb_type;
829 let is_16x16 = colo_mb_type.is_16x16_ref();
830
831 if is_16x16 {
832 let mv = sstate.get_cur_blk4(0).mv;
833 let ref_idx = sstate.get_cur_blk8(0).ref_idx;
834 let rpic0 = frame_refs.select_ref_pic(0, ref_idx[0].index());
835 let rpic1 = frame_refs.select_ref_pic(1, ref_idx[1].index());
836 if let Some(ref_id) = frame_refs.get_ref_id(0, mb_info.ref_l0[0].index()) {
837 wait_for_mb(disp, sstate, xpos + 16, ypos + 16, mv[0], ref_id)?;
838 }
839 if let Some(ref_id) = frame_refs.get_ref_id(1, mb_info.ref_l1[0].index()) {
840 wait_for_mb(disp, sstate, xpos + 16, ypos + 16, mv[1], ref_id)?;
841 }
842 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, BMode::Bi, weight_mode, ref_idx[0], ref_idx[1]);
843 wait_b_mc(disp, sstate, frame_refs, mv, ref_idx, xpos, ypos, 16, 16)?;
844 do_b_mc(frm, BMode::Bi, xpos, ypos, 16, 16, mv[0], rpic0, &weight0, mv[1], rpic1, &weight1, mc_dsp);
845 } else {
846 for blk4 in 0..16 {
847 let mv = sstate.get_cur_blk4(blk4).mv;
848 let ref_idx = sstate.get_cur_blk8(blk4_to_blk8(blk4)).ref_idx;
849 if let Some(ref_id) = frame_refs.get_ref_id(0, ref_idx[0].index()) {
850 wait_for_mb(disp, sstate, xpos + 16, ypos + 16, mv[0], ref_id)?;
851 }
852 if let Some(ref_id) = frame_refs.get_ref_id(1, ref_idx[1].index()) {
853 wait_for_mb(disp, sstate, xpos + 16, ypos + 16, mv[1], ref_id)?;
854 }
855 let rpic0 = frame_refs.select_ref_pic(0, ref_idx[0].index());
856 let rpic1 = frame_refs.select_ref_pic(1, ref_idx[1].index());
857 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, BMode::Bi, weight_mode, ref_idx[0], ref_idx[1]);
858 wait_b_mc(disp, sstate, frame_refs, mv, ref_idx, xpos + (blk4 & 3) * 4, ypos + (blk4 >> 2) * 4, 4, 4)?;
859 do_b_mc(frm, BMode::Bi, xpos + (blk4 & 3) * 4, ypos + (blk4 >> 2) * 4, 4, 4, mv[0], rpic0, &weight0, mv[1], rpic1, &weight1, mc_dsp);
860 }
861 }
862 sstate.apply_to_blk8(|blk8| { blk8.ref_idx[0].set_direct(); blk8.ref_idx[1].set_direct(); });
863 },
864 MBType::B8x8 => {
865 for part in 0..4 {
866 let ridx = sstate.get_cur_blk8(part).ref_idx;
867 let rpic0 = frame_refs.select_ref_pic(0, ridx[0].index());
868 let rpic1 = frame_refs.select_ref_pic(1, ridx[1].index());
869 let subtype = mb_info.sub_mb_type[part];
870 let blk8 = (part & 1) * 2 + (part & 2) * 4;
871 let mut bx = (part & 1) * 8;
872 let mut by = (part & 2) * 4;
873 match subtype {
874 SubMBType::Direct8x8 => {
875 for blk in 0..4 {
876 let mv = sstate.get_cur_blk4(bx / 4 + (by / 4) * 4).mv;
877 let ref_idx = sstate.get_cur_blk8(bx / 8 + (by / 8) * 2).ref_idx;
878 let rpic0 = frame_refs.select_ref_pic(0, ref_idx[0].index());
879 let rpic1 = frame_refs.select_ref_pic(1, ref_idx[1].index());
880 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, BMode::Bi, weight_mode, ref_idx[0], ref_idx[1]);
881 wait_b_mc(disp, sstate, frame_refs, mv, ref_idx, xpos + bx, ypos + by, 4, 4)?;
882 do_b_mc(frm, BMode::Bi, xpos + bx, ypos + by, 4, 4, mv[0], rpic0, &weight0, mv[1], rpic1, &weight1, mc_dsp);
883 bx += 4;
884 if blk == 1 {
885 bx -= 8;
886 by += 4;
887 }
888 }
889 sstate.get_cur_blk8(part).ref_idx[0].set_direct();
890 sstate.get_cur_blk8(part).ref_idx[1].set_direct();
891 },
892 SubMBType::B8x8(mode) => {
893 let mv = sstate.get_cur_blk4(blk8).mv;
894 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, mode, weight_mode, ridx[0], ridx[1]);
895 wait_b_mc(disp, sstate, frame_refs, mv, ridx, xpos + bx, ypos + by, 8, 8)?;
896 do_b_mc(frm, mode, xpos + bx, ypos + by, 8, 8, mv[0], rpic0, &weight0, mv[1], rpic1, &weight1, mc_dsp);
897 },
898 SubMBType::B8x4(mode) | SubMBType::B4x8(mode) => {
899 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, mode, weight_mode, ridx[0], ridx[1]);
900 let (pw, ph) = subtype.size();
901 let mv = sstate.get_cur_blk4(blk8).mv;
902 wait_b_mc(disp, sstate, frame_refs, mv, ridx, xpos + bx, ypos + by, pw, ph)?;
903 do_b_mc(frm, mode, xpos + bx, ypos + by, pw, ph, mv[0], rpic0.clone(), &weight0, mv[1], rpic1.clone(), &weight1, mc_dsp);
904 let addr2 = blk8 + (pw & 4) / 4 + (ph & 4);
905 let mv = sstate.get_cur_blk4(addr2).mv;
906 wait_b_mc(disp, sstate, frame_refs, mv, ridx, xpos + bx + (pw & 4), ypos + by + (ph & 4), pw, ph)?;
907 do_b_mc(frm, mode, xpos + bx + (pw & 4), ypos + by + (ph & 4), pw, ph, mv[0], rpic0, &weight0, mv[1], rpic1, &weight1, mc_dsp);
908 },
909 SubMBType::B4x4(mode) => {
910 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, mode, weight_mode, ridx[0], ridx[1]);
911 for i in 0..4 {
912 let addr2 = blk8 + (i & 1) + (i & 2) * 2;
913 let mv = sstate.get_cur_blk4(addr2).mv;
914 wait_b_mc(disp, sstate, frame_refs, mv, ridx, xpos + bx, ypos + by, 4, 4)?;
915 do_b_mc(frm, mode, xpos + bx, ypos + by, 4, 4, mv[0], rpic0.clone(), &weight0, mv[1], rpic1.clone(), &weight1, mc_dsp);
916 bx += 4;
917 if i == 1 {
918 bx -= 8;
919 by += 4;
920 }
921 }
922 },
923 _ => unreachable!(),
924 };
925 }
926 },
927 };
928 if !mb_info.mb_type.is_skip() {
929 if mb_info.mb_type != MBType::Intra4x4 && mb_info.mb_type != MBType::Intra8x8 {
930 add_luma(frm, sstate, mb_info);
931 }
932 add_chroma(frm, sstate, mb_info);
933 }
934 Ok(())
935}