h264: add multi-threaded decoder
[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
KS
212 } else {
213 let mut ytmp = [0; 16 * 16];
214 let mut utmp = [0; 16 * 16];
215 let mut vtmp = [0; 16 * 16];
2f9923e6 216 mc_dsp.mc_blocks(&mut ytmp, &mut utmp, &mut vtmp, buf, xpos, ypos, w, h, mv);
495b7ec0
KS
217
218 let yoff = frm.offset[0] + xpos + ypos * frm.stride[0];
219 let yw = if weight.luma_weighted {
220 [weight.luma_weight, weight.luma_offset, weight.luma_shift as i8]
221 } else {
222 [1, 0, 0]
223 };
76431444
KS
224 let wmode = match w {
225 2 => 0,
226 4 => 1,
227 8 => 2,
228 _ => 3,
229 };
230 (mc_dsp.put_block_weighted[wmode])(&mut frm.data[yoff..], frm.stride[0], &ytmp, h, yw);
495b7ec0
KS
231
232 for chroma in 0..2 {
233 let cstride = frm.stride[chroma + 1];
234 let coff = frm.offset[chroma + 1] + xpos / 2 + ypos / 2 * cstride;
235 let cw = if weight.chroma_weighted {
236 [weight.chroma_weight[chroma], weight.chroma_offset[chroma], weight.chroma_shift as i8]
237 } else {
238 [1, 0, 0]
239 };
240 let csrc = if chroma == 0 { &utmp } else { &vtmp };
76431444 241 (mc_dsp.put_block_weighted[wmode - 1])(&mut frm.data[coff..], cstride, csrc, h / 2, cw);
495b7ec0
KS
242 }
243 }
244 } else {
2f9923e6 245 mc_dsp.gray_block(frm, xpos, ypos, w, h);
495b7ec0
KS
246 }
247}
248
42005e25 249#[allow(clippy::match_like_matches_macro)]
2f9923e6 250fn 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
251 let do_weight = match (mode, weight0.is_weighted(), weight1.is_weighted()) {
252 (BMode::L0, true, _) => true,
253 (BMode::L1, _, true) => true,
254 (BMode::Bi, true, true) => true,
255 _ => false,
256 };
257 if !do_weight {
258 match mode {
259 BMode::L0 => {
260 if let Some(buf) = ref_pic0 {
2f9923e6 261 mc_dsp.do_mc(frm, buf, xpos, ypos, w, h, mv0);
495b7ec0 262 } else {
2f9923e6 263 mc_dsp.gray_block(frm, xpos, ypos, w, h);
495b7ec0
KS
264 }
265 },
266 BMode::L1 => {
267 if let Some(buf) = ref_pic1 {
2f9923e6 268 mc_dsp.do_mc(frm, buf, xpos, ypos, w, h, mv1);
495b7ec0 269 } else {
2f9923e6 270 mc_dsp.gray_block(frm, xpos, ypos, w, h);
495b7ec0
KS
271 }
272 },
273 BMode::Bi => {
274 match (ref_pic0, ref_pic1) {
275 (Some(buf0), Some(buf1)) => {
2f9923e6
KS
276 mc_dsp.do_mc(frm, buf0, xpos, ypos, w, h, mv0);
277 mc_dsp.do_mc_avg(frm, buf1, xpos, ypos, w, h, mv1);
495b7ec0
KS
278 },
279 (Some(buf0), None) => {
2f9923e6 280 mc_dsp.do_mc(frm, buf0, xpos, ypos, w, h, mv0);
495b7ec0
KS
281 },
282 (None, Some(buf1)) => {
2f9923e6 283 mc_dsp.do_mc(frm, buf1, xpos, ypos, w, h, mv1);
495b7ec0
KS
284 },
285 (None, None) => {
2f9923e6 286 mc_dsp.gray_block(frm, xpos, ypos, w, h);
495b7ec0
KS
287 },
288 };
289 },
290 };
291 } else {
292 let mut ytmp0 = [0x80; 16 * 16];
293 let mut utmp0 = [0x80; 16 * 16];
294 let mut vtmp0 = [0x80; 16 * 16];
295 let mut ytmp1 = [0x80; 16 * 16];
296 let mut utmp1 = [0x80; 16 * 16];
297 let mut vtmp1 = [0x80; 16 * 16];
298 match (mode, ref_pic0, ref_pic1) {
299 (BMode::L0, Some(buf), _) | (BMode::L1, _, Some(buf)) => {
300 let (mv, weight) = if mode == BMode::L0 { (mv0, weight0) } else { (mv1, weight1) };
2f9923e6 301 mc_dsp.mc_blocks(&mut ytmp0, &mut utmp0, &mut vtmp0, buf, xpos, ypos, w, h, mv);
495b7ec0
KS
302
303 let yoff = frm.offset[0] + xpos + ypos * frm.stride[0];
304 let yw = if weight.luma_weighted {
305 [weight.luma_weight, weight.luma_offset, weight.luma_shift as i8]
306 } else {
307 [1, 0, 0]
308 };
76431444
KS
309 let wmode = match w {
310 2 => 0,
311 4 => 1,
312 8 => 2,
313 _ => 3,
314 };
315 (mc_dsp.put_block_weighted[wmode])(&mut frm.data[yoff..], frm.stride[0], &ytmp0, h, yw);
495b7ec0
KS
316
317 for chroma in 0..2 {
318 let cstride = frm.stride[chroma + 1];
319 let coff = frm.offset[chroma + 1] + xpos / 2 + ypos / 2 * cstride;
320 let cw = if weight.chroma_weighted {
321 [weight.chroma_weight[chroma], weight.chroma_offset[chroma], weight.chroma_shift as i8]
322 } else {
323 [1, 0, 0]
324 };
325 let csrc = if chroma == 0 { &utmp0 } else { &vtmp0 };
76431444 326 (mc_dsp.put_block_weighted[wmode - 1])(&mut frm.data[coff..], cstride, csrc, h / 2, cw);
495b7ec0
KS
327 }
328 },
329 (BMode::Bi, Some(buf0), Some(buf1)) => { // do both and avg
2f9923e6
KS
330 mc_dsp.mc_blocks(&mut ytmp0, &mut utmp0, &mut vtmp0, buf0, xpos, ypos, w, h, mv0);
331 mc_dsp.mc_blocks(&mut ytmp1, &mut utmp1, &mut vtmp1, buf1, xpos, ypos, w, h, mv1);
495b7ec0
KS
332
333 let yoff = frm.offset[0] + xpos + ypos * frm.stride[0];
334 let yw = match (weight0.luma_weighted, weight1.luma_weighted) {
335 (true, true) => [weight0.luma_weight, weight0.luma_offset, weight1.luma_weight, weight1.luma_offset, weight0.luma_shift as i8],
336 (true, false) => [weight0.luma_weight, weight0.luma_offset, 1 << weight0.luma_shift, 0, weight0.luma_shift as i8],
337 (false, true) => [1 << weight1.luma_shift, 0, weight1.luma_weight, weight1.luma_offset, weight1.luma_shift as i8],
338 (false, false) => [1, 0, 1, 0, 0],
339 };
76431444
KS
340 let wmode = match w {
341 2 => 0,
342 4 => 1,
343 8 => 2,
344 _ => 3,
345 };
346 (mc_dsp.put_block_weighted2[wmode])(&mut frm.data[yoff..], frm.stride[0], &ytmp0, &ytmp1, h, yw);
495b7ec0
KS
347
348 for chroma in 0..2 {
349 let cstride = frm.stride[chroma + 1];
350 let coff = frm.offset[chroma + 1] + xpos / 2 + ypos / 2 * cstride;
351 let cw0 = weight0.chroma_weight[chroma];
352 let co0 = weight0.chroma_offset[chroma];
353 let cw1 = weight1.chroma_weight[chroma];
354 let co1 = weight1.chroma_offset[chroma];
355 let cw = match (weight0.chroma_weighted, weight1.chroma_weighted) {
356 (true, true) => [cw0, co0, cw1, co1, weight0.luma_shift as i8],
357 (true, false) => [cw0, co0, 1 << weight0.luma_shift, 0, weight0.luma_shift as i8],
358 (false, true) => [1 << weight1.luma_shift, 0, cw1, co1, weight1.luma_shift as i8],
359 (false, false) => [1, 0, 1, 0, 0],
360 };
361 let csrc0 = if chroma == 0 { &utmp0 } else { &vtmp0 };
362 let csrc1 = if chroma == 0 { &utmp1 } else { &vtmp1 };
76431444 363 (mc_dsp.put_block_weighted2[wmode - 1])(&mut frm.data[coff..], cstride, csrc0, csrc1, h / 2, cw);
495b7ec0
KS
364 }
365 },
366 _ => {
2f9923e6 367 mc_dsp.gray_block(frm, xpos, ypos, w, h);
495b7ec0
KS
368 },
369 };
370 }
371}
372
56a17e69 373fn get_weights(slice_hdr: &SliceHeader, frame_refs: &SliceRefs, mode: BMode, weight_mode: u8, ref_l0: PicRef, ref_l1: PicRef) -> (WeightInfo, WeightInfo) {
495b7ec0
KS
374 let idx_l0 = ref_l0.index();
375 let idx_l1 = ref_l1.index();
376 if mode != BMode::Bi || weight_mode != 2 {
377 (slice_hdr.get_weight(0, idx_l0), slice_hdr.get_weight(1, idx_l1))
378 } 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)) {
379 let r0_poc = pic0.full_id as u16;
380 let r1_poc = pic1.full_id as u16;
381 let cur_id = frame_refs.cur_id as u16;
382 if (r0_poc == r1_poc) || pic0.long_term.is_some() || pic1.long_term.is_some() {
383 return (DEF_WEIGHT_INFO, DEF_WEIGHT_INFO);
384 }
385
386 let td = (i32::from(r1_poc) - i32::from(r0_poc)).max(-128).min(127);
387 let tx = (16384 + (td / 2).abs()) / td;
388 let tb = (i32::from(cur_id) - i32::from(r0_poc)).max(-128).min(127);
389 let scale = ((tb * tx + 32) >> 6).max(-1024).min(1023);
390 if scale == 128 || (scale >> 2) < -64 || (scale >> 2) > 128 {
391 return (DEF_WEIGHT_INFO, DEF_WEIGHT_INFO);
392 }
393 let w1 = (scale >> 2) as i8;
394 let w0 = 64 - w1;
395
396 let weight0 = WeightInfo {
397 luma_weighted: true,
398 luma_weight: w0,
399 luma_offset: 0,
400 luma_shift: 5,
401 chroma_weighted: true,
402 chroma_weight: [w0; 2],
403 chroma_offset: [0; 2],
404 chroma_shift: 5,
405 };
406 let weight1 = WeightInfo {
407 luma_weighted: true,
408 luma_weight: w1,
409 luma_offset: 0,
410 luma_shift: 5,
411 chroma_weighted: true,
412 chroma_weight: [w1; 2],
413 chroma_offset: [0; 2],
414 chroma_shift: 5,
415 };
416
417 (weight0, weight1)
418 } else {
419 (DEF_WEIGHT_INFO, DEF_WEIGHT_INFO)
420 }
421}
422
56a17e69 423pub 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
424 let xpos = sstate.mb_x * 16;
425 let ypos = sstate.mb_y * 16;
426
427 match mb_info.mb_type {
428 MBType::Intra16x16(_, _, _) => {
42005e25 429 pred_intra(frm, sstate, mb_info);
495b7ec0
KS
430 },
431 MBType::Intra4x4 | MBType::Intra8x8 => {
42005e25 432 pred_intra(frm, sstate, mb_info);
495b7ec0
KS
433 },
434 MBType::PCM => {},
435 MBType::PSkip => {
436 let mv = sstate.get_cur_blk4(0).mv[0];
437 let rpic = frame_refs.select_ref_pic(0, 0);
438 let weight = &slice_hdr.get_weight(0, 0);
2f9923e6 439 do_p_mc(frm, xpos, ypos, 16, 16, mv, rpic, weight, mc_dsp);
495b7ec0
KS
440 },
441 MBType::P16x16 => {
442 let mv = sstate.get_cur_blk4(0).mv[0];
443 let rpic = frame_refs.select_ref_pic(0, mb_info.ref_l0[0].index());
444 let weight = &slice_hdr.get_weight(0, mb_info.ref_l0[0].index());
2f9923e6 445 do_p_mc(frm, xpos, ypos, 16, 16, mv, rpic, weight, mc_dsp);
495b7ec0
KS
446 },
447 MBType::P16x8 | MBType::P8x16 => {
448 let (bw, bh, bx, by) = if mb_info.mb_type == MBType::P16x8 {
449 (16, 8, 0, 8)
450 } else {
451 (8, 16, 8, 0)
452 };
453 let mv = sstate.get_cur_blk4(0).mv[0];
454 let rpic = frame_refs.select_ref_pic(0, mb_info.ref_l0[0].index());
455 let weight = &slice_hdr.get_weight(0, mb_info.ref_l0[0].index());
2f9923e6 456 do_p_mc(frm, xpos, ypos, bw, bh, mv, rpic, weight, mc_dsp);
495b7ec0
KS
457 let mv = sstate.get_cur_blk4(bx / 4 + by).mv[0];
458 let rpic = frame_refs.select_ref_pic(0, mb_info.ref_l0[1].index());
459 let weight = &slice_hdr.get_weight(0, mb_info.ref_l0[1].index());
2f9923e6 460 do_p_mc(frm, xpos + bx, ypos + by, bw, bh, mv, rpic, weight, mc_dsp);
495b7ec0
KS
461 },
462 MBType::P8x8 | MBType::P8x8Ref0 => {
463 for part in 0..4 {
464 let bx = (part & 1) * 8;
465 let by = (part & 2) * 4;
466 let mv = sstate.get_cur_blk4(bx / 4 + by).mv[0];
467 let rpic = frame_refs.select_ref_pic(0, mb_info.ref_l0[part].index());
468 let weight = &slice_hdr.get_weight(0, mb_info.ref_l0[part].index());
469
470 match mb_info.sub_mb_type[part] {
471 SubMBType::P8x8 => {
2f9923e6 472 do_p_mc(frm, xpos + bx, ypos + by, 8, 8, mv, rpic, weight, mc_dsp);
495b7ec0
KS
473 },
474 SubMBType::P8x4 => {
2f9923e6 475 do_p_mc(frm, xpos + bx, ypos + by, 8, 4, mv, rpic.clone(), weight, mc_dsp);
495b7ec0 476 let mv = sstate.get_cur_blk4(bx / 4 + by + 4).mv[0];
2f9923e6 477 do_p_mc(frm, xpos + bx, ypos + by + 4, 8, 4, mv, rpic, weight, mc_dsp);
495b7ec0
KS
478 },
479 SubMBType::P4x8 => {
2f9923e6 480 do_p_mc(frm, xpos + bx, ypos + by, 4, 8, mv, rpic.clone(), weight, mc_dsp);
495b7ec0 481 let mv = sstate.get_cur_blk4(bx / 4 + by + 1).mv[0];
2f9923e6 482 do_p_mc(frm, xpos + bx + 4, ypos + by, 4, 8, mv, rpic, weight, mc_dsp);
495b7ec0
KS
483 },
484 SubMBType::P4x4 => {
485 for sb_no in 0..4 {
486 let sxpos = xpos + bx + (sb_no & 1) * 4;
487 let sypos = ypos + by + (sb_no & 2) * 2;
488 let sblk_no = (bx / 4 + (sb_no & 1)) + ((by / 4) + (sb_no >> 1)) * 4;
489 let mv = sstate.get_cur_blk4(sblk_no).mv[0];
2f9923e6 490 do_p_mc(frm, sxpos, sypos, 4, 4, mv, rpic.clone(), weight, mc_dsp);
495b7ec0
KS
491 }
492 },
493 _ => unreachable!(),
494 };
495 }
496 },
497 MBType::B16x16(mode) => {
498 let mv0 = sstate.get_cur_blk4(0).mv[0];
499 let rpic0 = frame_refs.select_ref_pic(0, mb_info.ref_l0[0].index());
500 let mv1 = sstate.get_cur_blk4(0).mv[1];
501 let rpic1 = frame_refs.select_ref_pic(1, mb_info.ref_l1[0].index());
502 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, mode, weight_mode, mb_info.ref_l0[0], mb_info.ref_l1[0]);
2f9923e6 503 do_b_mc(frm, mode, xpos, ypos, 16, 16, mv0, rpic0, &weight0, mv1, rpic1, &weight1, mc_dsp);
495b7ec0
KS
504 },
505 MBType::B16x8(mode0, mode1) | MBType::B8x16(mode0, mode1) => {
506 let (pw, ph) = mb_info.mb_type.size();
507 let (px, py) = (pw & 8, ph & 8);
508 let modes = [mode0, mode1];
509 let (mut bx, mut by) = (0, 0);
510 for part in 0..2 {
511 let blk = if part == 0 { 0 } else { (px / 4) + py };
512 let mv0 = sstate.get_cur_blk4(blk).mv[0];
513 let rpic0 = frame_refs.select_ref_pic(0, mb_info.ref_l0[part].index());
514 let mv1 = sstate.get_cur_blk4(blk).mv[1];
515 let rpic1 = frame_refs.select_ref_pic(1, mb_info.ref_l1[part].index());
516 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, modes[part], weight_mode, mb_info.ref_l0[part], mb_info.ref_l1[part]);
2f9923e6 517 do_b_mc(frm, modes[part], xpos + bx, ypos + by, pw, ph, mv0, rpic0, &weight0, mv1, rpic1, &weight1, mc_dsp);
495b7ec0
KS
518 bx += px;
519 by += py;
520 }
521 },
522 MBType::Direct | MBType::BSkip => {
523 let colo_mb_type = frame_refs.get_colocated_info(sstate.mb_x, sstate.mb_y).0.mb_type;
524 let is_16x16 = colo_mb_type.is_16x16_ref();
525
526 if is_16x16 {
527 let mv = sstate.get_cur_blk4(0).mv;
528 let ref_idx = sstate.get_cur_blk8(0).ref_idx;
529 let rpic0 = frame_refs.select_ref_pic(0, ref_idx[0].index());
530 let rpic1 = frame_refs.select_ref_pic(1, ref_idx[1].index());
531 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, BMode::Bi, weight_mode, ref_idx[0], ref_idx[1]);
2f9923e6 532 do_b_mc(frm, BMode::Bi, xpos, ypos, 16, 16, mv[0], rpic0, &weight0, mv[1], rpic1, &weight1, mc_dsp);
495b7ec0
KS
533 } else {
534 for blk4 in 0..16 {
535 let mv = sstate.get_cur_blk4(blk4).mv;
536 let ref_idx = sstate.get_cur_blk8(blk4_to_blk8(blk4)).ref_idx;
537 let rpic0 = frame_refs.select_ref_pic(0, ref_idx[0].index());
538 let rpic1 = frame_refs.select_ref_pic(1, ref_idx[1].index());
539 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, BMode::Bi, weight_mode, ref_idx[0], ref_idx[1]);
2f9923e6 540 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);
495b7ec0
KS
541 }
542 }
543 sstate.apply_to_blk8(|blk8| { blk8.ref_idx[0].set_direct(); blk8.ref_idx[1].set_direct(); });
544 },
545 MBType::B8x8 => {
546 for part in 0..4 {
547 let ridx = sstate.get_cur_blk8(part).ref_idx;
548 let rpic0 = frame_refs.select_ref_pic(0, ridx[0].index());
549 let rpic1 = frame_refs.select_ref_pic(1, ridx[1].index());
550 let subtype = mb_info.sub_mb_type[part];
551 let blk8 = (part & 1) * 2 + (part & 2) * 4;
552 let mut bx = (part & 1) * 8;
553 let mut by = (part & 2) * 4;
554 match subtype {
555 SubMBType::Direct8x8 => {
556 for blk in 0..4 {
557 let mv = sstate.get_cur_blk4(bx / 4 + (by / 4) * 4).mv;
558 let ref_idx = sstate.get_cur_blk8(bx / 8 + (by / 8) * 2).ref_idx;
559 let rpic0 = frame_refs.select_ref_pic(0, ref_idx[0].index());
560 let rpic1 = frame_refs.select_ref_pic(1, ref_idx[1].index());
561 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, BMode::Bi, weight_mode, ref_idx[0], ref_idx[1]);
2f9923e6 562 do_b_mc(frm, BMode::Bi, xpos + bx, ypos + by, 4, 4, mv[0], rpic0, &weight0, mv[1], rpic1, &weight1, mc_dsp);
495b7ec0
KS
563 bx += 4;
564 if blk == 1 {
565 bx -= 8;
566 by += 4;
567 }
568 }
569 sstate.get_cur_blk8(part).ref_idx[0].set_direct();
570 sstate.get_cur_blk8(part).ref_idx[1].set_direct();
571 },
572 SubMBType::B8x8(mode) => {
573 let mv = sstate.get_cur_blk4(blk8).mv;
574 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, mode, weight_mode, ridx[0], ridx[1]);
2f9923e6 575 do_b_mc(frm, mode, xpos + bx, ypos + by, 8, 8, mv[0], rpic0, &weight0, mv[1], rpic1, &weight1, mc_dsp);
495b7ec0
KS
576 },
577 SubMBType::B8x4(mode) | SubMBType::B4x8(mode) => {
578 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, mode, weight_mode, ridx[0], ridx[1]);
579 let (pw, ph) = subtype.size();
580 let mv = sstate.get_cur_blk4(blk8).mv;
2f9923e6 581 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
582 let addr2 = blk8 + (pw & 4) / 4 + (ph & 4);
583 let mv = sstate.get_cur_blk4(addr2).mv;
2f9923e6 584 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
585 },
586 SubMBType::B4x4(mode) => {
587 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, mode, weight_mode, ridx[0], ridx[1]);
588 for i in 0..4 {
589 let addr2 = blk8 + (i & 1) + (i & 2) * 2;
590 let mv = sstate.get_cur_blk4(addr2).mv;
2f9923e6 591 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
592 bx += 4;
593 if i == 1 {
594 bx -= 8;
595 by += 4;
596 }
597 }
598 },
599 _ => unreachable!(),
600 };
601 }
602 },
603 };
604 if !mb_info.mb_type.is_skip() {
605 if mb_info.mb_type != MBType::Intra4x4 && mb_info.mb_type != MBType::Intra8x8 {
42005e25 606 add_luma(frm, sstate, mb_info);
495b7ec0 607 }
42005e25 608 add_chroma(frm, sstate, mb_info);
495b7ec0
KS
609 }
610}
11d7aef2
KS
611
612pub fn wait_for_mb(disp: &Shareable<ThreadDispatcher>, sstate: &SliceState, xpos: usize, ypos: usize, mv: MV, ref_id: u32) -> DecoderResult<()> {
613 let xpos = xpos as isize + ((mv.x >> 2) as isize) + 4;
614 let ypos = ypos as isize + ((mv.y >> 2) as isize) + 4;
615 let dst_mb_x = ((xpos.max(0) as usize) / 16).min(sstate.mb_w - 1);
616 let dst_mb_y = ((ypos.max(0) as usize) / 16).min(sstate.mb_h - 1);
617 let expected_mb = dst_mb_x + dst_mb_y * sstate.mb_w;
618 loop {
619 if let Ok(ds) = disp.read() {
620 match ds.check_pos(ref_id, expected_mb) {
621 FrameDecodingStatus::Ok => return Ok(()),
622 FrameDecodingStatus::NotReady => {},
623 _ => return Err(DecoderError::MissingReference),
624 };
625 }
626 std::thread::yield_now();
627 }
628}
629
630fn 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<()> {
631 if let Some(ref_id) = frame_refs.get_ref_id(0, ref_idx[0].index()) {
632 wait_for_mb(disp, sstate, xpos + w, ypos + h, mv[0], ref_id)?;
633 }
634 if let Some(ref_id) = frame_refs.get_ref_id(1, ref_idx[1].index()) {
635 wait_for_mb(disp, sstate, xpos + w, ypos + h, mv[1], ref_id)?;
636 }
637 Ok(())
638}
639
640pub 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<()> {
641 let xpos = sstate.mb_x * 16;
642 let ypos = sstate.mb_y * 16;
643
644 match mb_info.mb_type {
645 MBType::Intra16x16(_, _, _) => {
646 pred_intra(frm, sstate, mb_info);
647 },
648 MBType::Intra4x4 | MBType::Intra8x8 => {
649 pred_intra(frm, sstate, mb_info);
650 },
651 MBType::PCM => {},
652 MBType::PSkip => {
653 let mv = sstate.get_cur_blk4(0).mv[0];
654 if let Some(ref_id) = frame_refs.get_ref_id(0, 0) {
655 wait_for_mb(disp, sstate, xpos + 16, ypos + 16, mv, ref_id)?;
656 }
657 let rpic = frame_refs.select_ref_pic(0, 0);
658 let weight = &slice_hdr.get_weight(0, 0);
659 do_p_mc(frm, xpos, ypos, 16, 16, mv, rpic, weight, mc_dsp);
660 },
661 MBType::P16x16 => {
662 let mv = sstate.get_cur_blk4(0).mv[0];
663 if let Some(ref_id) = frame_refs.get_ref_id(0, mb_info.ref_l0[0].index()) {
664 wait_for_mb(disp, sstate, xpos + 16, ypos + 16, mv, ref_id)?;
665 }
666 let rpic = frame_refs.select_ref_pic(0, mb_info.ref_l0[0].index());
667 let weight = &slice_hdr.get_weight(0, mb_info.ref_l0[0].index());
668 do_p_mc(frm, xpos, ypos, 16, 16, mv, rpic, weight, mc_dsp);
669 },
670 MBType::P16x8 | MBType::P8x16 => {
671 let (bw, bh, bx, by) = if mb_info.mb_type == MBType::P16x8 {
672 (16, 8, 0, 8)
673 } else {
674 (8, 16, 8, 0)
675 };
676 let mv = sstate.get_cur_blk4(0).mv[0];
677 if let Some(ref_id) = frame_refs.get_ref_id(0, mb_info.ref_l0[0].index()) {
678 wait_for_mb(disp, sstate, xpos + bw, ypos + bh, mv, ref_id)?;
679 }
680 let rpic = frame_refs.select_ref_pic(0, mb_info.ref_l0[0].index());
681 let weight = &slice_hdr.get_weight(0, mb_info.ref_l0[0].index());
682 do_p_mc(frm, xpos, ypos, bw, bh, mv, rpic, weight, mc_dsp);
683 let mv = sstate.get_cur_blk4(bx / 4 + by).mv[0];
684 if let Some(ref_id) = frame_refs.get_ref_id(0, mb_info.ref_l0[1].index()) {
685 wait_for_mb(disp, sstate, xpos + 16, ypos + 16, mv, ref_id)?;
686 }
687 let rpic = frame_refs.select_ref_pic(0, mb_info.ref_l0[1].index());
688 let weight = &slice_hdr.get_weight(0, mb_info.ref_l0[1].index());
689 do_p_mc(frm, xpos + bx, ypos + by, bw, bh, mv, rpic, weight, mc_dsp);
690 },
691 MBType::P8x8 | MBType::P8x8Ref0 => {
692 for part in 0..4 {
693 let bx = (part & 1) * 8;
694 let by = (part & 2) * 4;
695 let mv = sstate.get_cur_blk4(bx / 4 + by).mv[0];
696 let rpic = frame_refs.select_ref_pic(0, mb_info.ref_l0[part].index());
697 let weight = &slice_hdr.get_weight(0, mb_info.ref_l0[part].index());
698
699 match mb_info.sub_mb_type[part] {
700 SubMBType::P8x8 => {
701 if let Some(ref_id) = frame_refs.get_ref_id(0, mb_info.ref_l0[part].index()) {
702 wait_for_mb(disp, sstate, xpos + bx + 8, ypos + by + 8, mv, ref_id)?;
703 }
704 do_p_mc(frm, xpos + bx, ypos + by, 8, 8, mv, rpic, weight, mc_dsp);
705 },
706 SubMBType::P8x4 => {
707 if let Some(ref_id) = frame_refs.get_ref_id(0, mb_info.ref_l0[part].index()) {
708 wait_for_mb(disp, sstate, xpos + bx + 8, ypos + by + 4, mv, ref_id)?;
709 }
710 do_p_mc(frm, xpos + bx, ypos + by, 8, 4, mv, rpic.clone(), weight, mc_dsp);
711 let mv = sstate.get_cur_blk4(bx / 4 + by + 4).mv[0];
712 if let Some(ref_id) = frame_refs.get_ref_id(0, mb_info.ref_l0[part].index()) {
713 wait_for_mb(disp, sstate, xpos + bx + 8, ypos + by + 8, mv, ref_id)?;
714 }
715 do_p_mc(frm, xpos + bx, ypos + by + 4, 8, 4, mv, rpic, weight, mc_dsp);
716 },
717 SubMBType::P4x8 => {
718 if let Some(ref_id) = frame_refs.get_ref_id(0, mb_info.ref_l0[part].index()) {
719 wait_for_mb(disp, sstate, xpos + bx + 4, ypos + by + 8, mv, ref_id)?;
720 }
721 do_p_mc(frm, xpos + bx, ypos + by, 4, 8, mv, rpic.clone(), weight, mc_dsp);
722 let mv = sstate.get_cur_blk4(bx / 4 + by + 1).mv[0];
723 if let Some(ref_id) = frame_refs.get_ref_id(0, mb_info.ref_l0[part].index()) {
724 wait_for_mb(disp, sstate, xpos + bx + 8, ypos + by + 8, mv, ref_id)?;
725 }
726 do_p_mc(frm, xpos + bx + 4, ypos + by, 4, 8, mv, rpic, weight, mc_dsp);
727 },
728 SubMBType::P4x4 => {
729 for sb_no in 0..4 {
730 let sxpos = xpos + bx + (sb_no & 1) * 4;
731 let sypos = ypos + by + (sb_no & 2) * 2;
732 let sblk_no = (bx / 4 + (sb_no & 1)) + ((by / 4) + (sb_no >> 1)) * 4;
733 let mv = sstate.get_cur_blk4(sblk_no).mv[0];
734 if let Some(ref_id) = frame_refs.get_ref_id(0, mb_info.ref_l0[part].index()) {
735 wait_for_mb(disp, sstate, sxpos + 4, sypos + 4, mv, ref_id)?;
736 }
737 do_p_mc(frm, sxpos, sypos, 4, 4, mv, rpic.clone(), weight, mc_dsp);
738 }
739 },
740 _ => unreachable!(),
741 };
742 }
743 },
744 MBType::B16x16(mode) => {
745 let mv0 = sstate.get_cur_blk4(0).mv[0];
746 let rpic0 = frame_refs.select_ref_pic(0, mb_info.ref_l0[0].index());
747 let mv1 = sstate.get_cur_blk4(0).mv[1];
748 let rpic1 = frame_refs.select_ref_pic(1, mb_info.ref_l1[0].index());
749 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, mode, weight_mode, mb_info.ref_l0[0], mb_info.ref_l1[0]);
750 wait_b_mc(disp, sstate, frame_refs, [mv0, mv1], [mb_info.ref_l0[0], mb_info.ref_l1[0]], xpos, ypos, 16, 16)?;
751 do_b_mc(frm, mode, xpos, ypos, 16, 16, mv0, rpic0, &weight0, mv1, rpic1, &weight1, mc_dsp);
752 },
753 MBType::B16x8(mode0, mode1) | MBType::B8x16(mode0, mode1) => {
754 let (pw, ph) = mb_info.mb_type.size();
755 let (px, py) = (pw & 8, ph & 8);
756 let modes = [mode0, mode1];
757 let (mut bx, mut by) = (0, 0);
758 for part in 0..2 {
759 let blk = if part == 0 { 0 } else { (px / 4) + py };
760 let mv0 = sstate.get_cur_blk4(blk).mv[0];
761 let rpic0 = frame_refs.select_ref_pic(0, mb_info.ref_l0[part].index());
762 let mv1 = sstate.get_cur_blk4(blk).mv[1];
763 let rpic1 = frame_refs.select_ref_pic(1, mb_info.ref_l1[part].index());
764 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, modes[part], weight_mode, mb_info.ref_l0[part], mb_info.ref_l1[part]);
765 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)?;
766 do_b_mc(frm, modes[part], xpos + bx, ypos + by, pw, ph, mv0, rpic0, &weight0, mv1, rpic1, &weight1, mc_dsp);
767 bx += px;
768 by += py;
769 }
770 },
771 MBType::Direct | MBType::BSkip => {
772 if let Some(ref_id) = frame_refs.get_ref_id(1, mb_info.ref_l1[0].index()) {
773 wait_for_mb(disp, sstate, xpos, ypos, ZERO_MV, ref_id)?;
774 }
775 let colo_mb_type = frame_refs.get_colocated_info(sstate.mb_x, sstate.mb_y).0.mb_type;
776 let is_16x16 = colo_mb_type.is_16x16_ref();
777
778 if is_16x16 {
779 let mv = sstate.get_cur_blk4(0).mv;
780 let ref_idx = sstate.get_cur_blk8(0).ref_idx;
781 let rpic0 = frame_refs.select_ref_pic(0, ref_idx[0].index());
782 let rpic1 = frame_refs.select_ref_pic(1, ref_idx[1].index());
783 if let Some(ref_id) = frame_refs.get_ref_id(0, mb_info.ref_l0[0].index()) {
784 wait_for_mb(disp, sstate, xpos + 16, ypos + 16, mv[0], ref_id)?;
785 }
786 if let Some(ref_id) = frame_refs.get_ref_id(1, mb_info.ref_l1[0].index()) {
787 wait_for_mb(disp, sstate, xpos + 16, ypos + 16, mv[1], ref_id)?;
788 }
789 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, BMode::Bi, weight_mode, ref_idx[0], ref_idx[1]);
790 wait_b_mc(disp, sstate, frame_refs, mv, ref_idx, xpos, ypos, 16, 16)?;
791 do_b_mc(frm, BMode::Bi, xpos, ypos, 16, 16, mv[0], rpic0, &weight0, mv[1], rpic1, &weight1, mc_dsp);
792 } else {
793 for blk4 in 0..16 {
794 let mv = sstate.get_cur_blk4(blk4).mv;
795 let ref_idx = sstate.get_cur_blk8(blk4_to_blk8(blk4)).ref_idx;
796 if let Some(ref_id) = frame_refs.get_ref_id(0, ref_idx[0].index()) {
797 wait_for_mb(disp, sstate, xpos + 16, ypos + 16, mv[0], ref_id)?;
798 }
799 if let Some(ref_id) = frame_refs.get_ref_id(1, ref_idx[1].index()) {
800 wait_for_mb(disp, sstate, xpos + 16, ypos + 16, mv[1], ref_id)?;
801 }
802 let rpic0 = frame_refs.select_ref_pic(0, ref_idx[0].index());
803 let rpic1 = frame_refs.select_ref_pic(1, ref_idx[1].index());
804 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, BMode::Bi, weight_mode, ref_idx[0], ref_idx[1]);
805 wait_b_mc(disp, sstate, frame_refs, mv, ref_idx, xpos + (blk4 & 3) * 4, ypos + (blk4 >> 2) * 4, 4, 4)?;
806 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);
807 }
808 }
809 sstate.apply_to_blk8(|blk8| { blk8.ref_idx[0].set_direct(); blk8.ref_idx[1].set_direct(); });
810 },
811 MBType::B8x8 => {
812 for part in 0..4 {
813 let ridx = sstate.get_cur_blk8(part).ref_idx;
814 let rpic0 = frame_refs.select_ref_pic(0, ridx[0].index());
815 let rpic1 = frame_refs.select_ref_pic(1, ridx[1].index());
816 let subtype = mb_info.sub_mb_type[part];
817 let blk8 = (part & 1) * 2 + (part & 2) * 4;
818 let mut bx = (part & 1) * 8;
819 let mut by = (part & 2) * 4;
820 match subtype {
821 SubMBType::Direct8x8 => {
822 for blk in 0..4 {
823 let mv = sstate.get_cur_blk4(bx / 4 + (by / 4) * 4).mv;
824 let ref_idx = sstate.get_cur_blk8(bx / 8 + (by / 8) * 2).ref_idx;
825 let rpic0 = frame_refs.select_ref_pic(0, ref_idx[0].index());
826 let rpic1 = frame_refs.select_ref_pic(1, ref_idx[1].index());
827 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, BMode::Bi, weight_mode, ref_idx[0], ref_idx[1]);
828 wait_b_mc(disp, sstate, frame_refs, mv, ref_idx, xpos + bx, ypos + by, 4, 4)?;
829 do_b_mc(frm, BMode::Bi, xpos + bx, ypos + by, 4, 4, mv[0], rpic0, &weight0, mv[1], rpic1, &weight1, mc_dsp);
830 bx += 4;
831 if blk == 1 {
832 bx -= 8;
833 by += 4;
834 }
835 }
836 sstate.get_cur_blk8(part).ref_idx[0].set_direct();
837 sstate.get_cur_blk8(part).ref_idx[1].set_direct();
838 },
839 SubMBType::B8x8(mode) => {
840 let mv = sstate.get_cur_blk4(blk8).mv;
841 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, mode, weight_mode, ridx[0], ridx[1]);
842 wait_b_mc(disp, sstate, frame_refs, mv, ridx, xpos + bx, ypos + by, 8, 8)?;
843 do_b_mc(frm, mode, xpos + bx, ypos + by, 8, 8, mv[0], rpic0, &weight0, mv[1], rpic1, &weight1, mc_dsp);
844 },
845 SubMBType::B8x4(mode) | SubMBType::B4x8(mode) => {
846 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, mode, weight_mode, ridx[0], ridx[1]);
847 let (pw, ph) = subtype.size();
848 let mv = sstate.get_cur_blk4(blk8).mv;
849 wait_b_mc(disp, sstate, frame_refs, mv, ridx, xpos + bx, ypos + by, pw, ph)?;
850 do_b_mc(frm, mode, xpos + bx, ypos + by, pw, ph, mv[0], rpic0.clone(), &weight0, mv[1], rpic1.clone(), &weight1, mc_dsp);
851 let addr2 = blk8 + (pw & 4) / 4 + (ph & 4);
852 let mv = sstate.get_cur_blk4(addr2).mv;
853 wait_b_mc(disp, sstate, frame_refs, mv, ridx, xpos + bx + (pw & 4), ypos + by + (ph & 4), pw, ph)?;
854 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);
855 },
856 SubMBType::B4x4(mode) => {
857 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, mode, weight_mode, ridx[0], ridx[1]);
858 for i in 0..4 {
859 let addr2 = blk8 + (i & 1) + (i & 2) * 2;
860 let mv = sstate.get_cur_blk4(addr2).mv;
861 wait_b_mc(disp, sstate, frame_refs, mv, ridx, xpos + bx, ypos + by, 4, 4)?;
862 do_b_mc(frm, mode, xpos + bx, ypos + by, 4, 4, mv[0], rpic0.clone(), &weight0, mv[1], rpic1.clone(), &weight1, mc_dsp);
863 bx += 4;
864 if i == 1 {
865 bx -= 8;
866 by += 4;
867 }
868 }
869 },
870 _ => unreachable!(),
871 };
872 }
873 },
874 };
875 if !mb_info.mb_type.is_skip() {
876 if mb_info.mb_type != MBType::Intra4x4 && mb_info.mb_type != MBType::Intra8x8 {
877 add_luma(frm, sstate, mb_info);
878 }
879 add_chroma(frm, sstate, mb_info);
880 }
881 Ok(())
882}