1 use nihav_core::codecs::{DecoderResult, DecoderError};
2 use nihav_core::frame::*;
3 use nihav_codec_support::codecs::{MV, ZERO_MV};
4 use super::{CurrentMBInfo, I4X4_SCAN, Shareable};
5 use super::dispatch::{ThreadDispatcher, FrameDecodingStatus};
7 use super::pic_ref::SliceRefs;
8 use super::slice::{SliceHeader, WeightInfo, DEF_WEIGHT_INFO};
11 fn 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) {
17 } else if !sstate.has_top && !sstate.has_left {
19 } else if !sstate.has_left {
24 IPRED_FUNCS16X16[id](&mut frm.data[yoff..], frm.stride[0], &sstate.top_line_y[sstate.mb_x * 16..], &sstate.left_y);
27 let mut ictx = IPred8Context::new();
29 let x = (part & 1) * 2;
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();
40 } else if !has_top && !has_left {
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 {
52 &sstate.top_line_y[sstate.mb_x * 16 + x * 4..]
54 &frm.data[cur_yoff - frm.stride[0]..]
56 let mut left_buf = [0; 9];
57 let left = if x == 0 {
58 &sstate.left_y[y * 4..]
62 left_buf[0] = sstate.top_line_y[sstate.mb_x * 16 + x * 4 - 1];
64 left_buf[0] = frm.data[cur_yoff - 1 - frm.stride[0]];
68 for (dst, src) in left_buf[1..].iter_mut().zip(frm.data[cur_yoff - 1..].chunks(frm.stride[0])) {
74 ictx.fill(top, left, has_top, has_top && !noright, has_left, has_tl);
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);
83 for &(x,y) in I4X4_SCAN.iter() {
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();
93 } else if !has_top && !has_left {
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]]
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]]
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]]
117 let mut top = [128; 4];
118 let mut left = [128; 9];
121 top.copy_from_slice(&sstate.top_line_y[sstate.mb_x * 16 + x * 4..][..4]);
124 top.copy_from_slice(&frm.data[cur_yoff - frm.stride[0]..][..4]);
128 for (dst, &src) in left.iter_mut().zip(sstate.left_y[y * 4..].iter()) {
135 left[0] = sstate.left_y[y * 4];
137 left[0] = sstate.top_line_y[sstate.mb_x * 16 + x * 4 - 1];
140 left[0] = frm.data[cur_yoff - frm.stride[0] - 1];
142 for (dst, row) in left[1..].iter_mut().zip(frm.data[cur_yoff - 1..].chunks(frm.stride[0])) {
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]);
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 {
158 } else if !sstate.has_left {
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]);
170 fn 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 {
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]);
179 yoff += frm.stride[0] * 4;
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);
188 yoff += frm.stride[0] * 8;
193 fn add_chroma(frm: &mut NASimpleVideoFrame<u8>, sstate: &SliceState, mb_info: &CurrentMBInfo) {
195 let mut off = frm.offset[chroma] + sstate.mb_x * 8 + sstate.mb_y * 8 * frm.stride[chroma];
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]);
203 off += frm.stride[chroma] * 4;
208 fn 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) {
209 if let Some(buf) = ref_pic {
210 if !weight.is_weighted() {
211 mc_dsp.do_mc(frm, buf, xpos, ypos, w, h, mv);
213 let mut ytmp = [0; 16 * 16];
214 let mut utmp = [0; 16 * 16];
215 let mut vtmp = [0; 16 * 16];
216 mc_dsp.mc_blocks(&mut ytmp, &mut utmp, &mut vtmp, buf, xpos, ypos, w, h, mv);
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]
224 let wmode = match w {
230 (mc_dsp.put_block_weighted[wmode])(&mut frm.data[yoff..], frm.stride[0], &ytmp, h, yw);
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]
240 let csrc = if chroma == 0 { &utmp } else { &vtmp };
241 (mc_dsp.put_block_weighted[wmode - 1])(&mut frm.data[coff..], cstride, csrc, h / 2, cw);
245 mc_dsp.gray_block(frm, xpos, ypos, w, h);
249 #[allow(clippy::match_like_matches_macro)]
250 fn 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) {
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,
260 if let Some(buf) = ref_pic0 {
261 mc_dsp.do_mc(frm, buf, xpos, ypos, w, h, mv0);
263 mc_dsp.gray_block(frm, xpos, ypos, w, h);
267 if let Some(buf) = ref_pic1 {
268 mc_dsp.do_mc(frm, buf, xpos, ypos, w, h, mv1);
270 mc_dsp.gray_block(frm, xpos, ypos, w, h);
274 match (ref_pic0, ref_pic1) {
275 (Some(buf0), Some(buf1)) => {
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);
279 (Some(buf0), None) => {
280 mc_dsp.do_mc(frm, buf0, xpos, ypos, w, h, mv0);
282 (None, Some(buf1)) => {
283 mc_dsp.do_mc(frm, buf1, xpos, ypos, w, h, mv1);
286 mc_dsp.gray_block(frm, xpos, ypos, w, h);
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) };
301 mc_dsp.mc_blocks(&mut ytmp0, &mut utmp0, &mut vtmp0, buf, xpos, ypos, w, h, mv);
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]
309 let wmode = match w {
315 (mc_dsp.put_block_weighted[wmode])(&mut frm.data[yoff..], frm.stride[0], &ytmp0, h, yw);
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]
325 let csrc = if chroma == 0 { &utmp0 } else { &vtmp0 };
326 (mc_dsp.put_block_weighted[wmode - 1])(&mut frm.data[coff..], cstride, csrc, h / 2, cw);
329 (BMode::Bi, Some(buf0), Some(buf1)) => { // do both and avg
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);
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],
340 let wmode = match w {
346 (mc_dsp.put_block_weighted2[wmode])(&mut frm.data[yoff..], frm.stride[0], &ytmp0, &ytmp1, h, yw);
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],
361 let csrc0 = if chroma == 0 { &utmp0 } else { &vtmp0 };
362 let csrc1 = if chroma == 0 { &utmp1 } else { &vtmp1 };
363 (mc_dsp.put_block_weighted2[wmode - 1])(&mut frm.data[coff..], cstride, csrc0, csrc1, h / 2, cw);
367 mc_dsp.gray_block(frm, xpos, ypos, w, h);
373 fn get_weights(slice_hdr: &SliceHeader, frame_refs: &SliceRefs, mode: BMode, weight_mode: u8, ref_l0: PicRef, ref_l1: PicRef) -> (WeightInfo, WeightInfo) {
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);
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);
393 let w1 = (scale >> 2) as i8;
396 let weight0 = WeightInfo {
401 chroma_weighted: true,
402 chroma_weight: [w0; 2],
403 chroma_offset: [0; 2],
406 let weight1 = WeightInfo {
411 chroma_weighted: true,
412 chroma_weight: [w1; 2],
413 chroma_offset: [0; 2],
419 (DEF_WEIGHT_INFO, DEF_WEIGHT_INFO)
423 pub 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) {
424 let xpos = sstate.mb_x * 16;
425 let ypos = sstate.mb_y * 16;
427 match mb_info.mb_type {
428 MBType::Intra16x16(_, _, _) => {
429 pred_intra(frm, sstate, mb_info);
431 MBType::Intra4x4 | MBType::Intra8x8 => {
432 pred_intra(frm, sstate, mb_info);
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);
439 do_p_mc(frm, xpos, ypos, 16, 16, mv, rpic, weight, mc_dsp);
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());
445 do_p_mc(frm, xpos, ypos, 16, 16, mv, rpic, weight, mc_dsp);
447 MBType::P16x8 | MBType::P8x16 => {
448 let (bw, bh, bx, by) = if mb_info.mb_type == MBType::P16x8 {
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());
456 do_p_mc(frm, xpos, ypos, bw, bh, mv, rpic, weight, mc_dsp);
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());
460 do_p_mc(frm, xpos + bx, ypos + by, bw, bh, mv, rpic, weight, mc_dsp);
462 MBType::P8x8 | MBType::P8x8Ref0 => {
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());
470 match mb_info.sub_mb_type[part] {
472 do_p_mc(frm, xpos + bx, ypos + by, 8, 8, mv, rpic, weight, mc_dsp);
475 do_p_mc(frm, xpos + bx, ypos + by, 8, 4, mv, rpic.clone(), weight, mc_dsp);
476 let mv = sstate.get_cur_blk4(bx / 4 + by + 4).mv[0];
477 do_p_mc(frm, xpos + bx, ypos + by + 4, 8, 4, mv, rpic, weight, mc_dsp);
480 do_p_mc(frm, xpos + bx, ypos + by, 4, 8, mv, rpic.clone(), weight, mc_dsp);
481 let mv = sstate.get_cur_blk4(bx / 4 + by + 1).mv[0];
482 do_p_mc(frm, xpos + bx + 4, ypos + by, 4, 8, mv, rpic, weight, mc_dsp);
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];
490 do_p_mc(frm, sxpos, sypos, 4, 4, mv, rpic.clone(), weight, mc_dsp);
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]);
503 do_b_mc(frm, mode, xpos, ypos, 16, 16, mv0, rpic0, &weight0, mv1, rpic1, &weight1, mc_dsp);
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);
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]);
517 do_b_mc(frm, modes[part], xpos + bx, ypos + by, pw, ph, mv0, rpic0, &weight0, mv1, rpic1, &weight1, mc_dsp);
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();
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]);
532 do_b_mc(frm, BMode::Bi, xpos, ypos, 16, 16, mv[0], rpic0, &weight0, mv[1], rpic1, &weight1, mc_dsp);
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]);
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);
543 sstate.apply_to_blk8(|blk8| { blk8.ref_idx[0].set_direct(); blk8.ref_idx[1].set_direct(); });
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;
555 SubMBType::Direct8x8 => {
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]);
562 do_b_mc(frm, BMode::Bi, xpos + bx, ypos + by, 4, 4, mv[0], rpic0, &weight0, mv[1], rpic1, &weight1, mc_dsp);
569 sstate.get_cur_blk8(part).ref_idx[0].set_direct();
570 sstate.get_cur_blk8(part).ref_idx[1].set_direct();
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]);
575 do_b_mc(frm, mode, xpos + bx, ypos + by, 8, 8, mv[0], rpic0, &weight0, mv[1], rpic1, &weight1, mc_dsp);
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;
581 do_b_mc(frm, mode, xpos + bx, ypos + by, pw, ph, mv[0], rpic0.clone(), &weight0, mv[1], rpic1.clone(), &weight1, mc_dsp);
582 let addr2 = blk8 + (pw & 4) / 4 + (ph & 4);
583 let mv = sstate.get_cur_blk4(addr2).mv;
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);
586 SubMBType::B4x4(mode) => {
587 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, mode, weight_mode, ridx[0], ridx[1]);
589 let addr2 = blk8 + (i & 1) + (i & 2) * 2;
590 let mv = sstate.get_cur_blk4(addr2).mv;
591 do_b_mc(frm, mode, xpos + bx, ypos + by, 4, 4, mv[0], rpic0.clone(), &weight0, mv[1], rpic1.clone(), &weight1, mc_dsp);
604 if !mb_info.mb_type.is_skip() {
605 if mb_info.mb_type != MBType::Intra4x4 && mb_info.mb_type != MBType::Intra8x8 {
606 add_luma(frm, sstate, mb_info);
608 add_chroma(frm, sstate, mb_info);
612 pub 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;
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),
626 std::thread::yield_now();
630 fn 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)?;
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)?;
640 pub 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;
644 match mb_info.mb_type {
645 MBType::Intra16x16(_, _, _) => {
646 pred_intra(frm, sstate, mb_info);
648 MBType::Intra4x4 | MBType::Intra8x8 => {
649 pred_intra(frm, sstate, mb_info);
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)?;
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);
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)?;
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);
670 MBType::P16x8 | MBType::P8x16 => {
671 let (bw, bh, bx, by) = if mb_info.mb_type == MBType::P16x8 {
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)?;
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)?;
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);
691 MBType::P8x8 | MBType::P8x8Ref0 => {
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());
699 match mb_info.sub_mb_type[part] {
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)?;
704 do_p_mc(frm, xpos + bx, ypos + by, 8, 8, mv, rpic, weight, mc_dsp);
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)?;
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)?;
715 do_p_mc(frm, xpos + bx, ypos + by + 4, 8, 4, mv, rpic, weight, mc_dsp);
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)?;
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)?;
726 do_p_mc(frm, xpos + bx + 4, ypos + by, 4, 8, mv, rpic, weight, mc_dsp);
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)?;
737 do_p_mc(frm, sxpos, sypos, 4, 4, mv, rpic.clone(), weight, mc_dsp);
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);
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);
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);
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)?;
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();
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)?;
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)?;
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);
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)?;
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)?;
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);
809 sstate.apply_to_blk8(|blk8| { blk8.ref_idx[0].set_direct(); blk8.ref_idx[1].set_direct(); });
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;
821 SubMBType::Direct8x8 => {
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);
836 sstate.get_cur_blk8(part).ref_idx[0].set_direct();
837 sstate.get_cur_blk8(part).ref_idx[1].set_direct();
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);
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);
856 SubMBType::B4x4(mode) => {
857 let (weight0, weight1) = get_weights(slice_hdr, frame_refs, mode, weight_mode, ridx[0], ridx[1]);
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);
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);
879 add_chroma(frm, sstate, mb_info);