code wiki / (root) / nx_h264_mvgrid.nx

nx_h264_mvgrid.nx source

↩ module page · 93 lines · 4847 B

1// nx_h264_mvgrid.nx -- H.264 per-4x4 motion-vector grid + neighbour gathering (8.4.1.3). 2// Maintains three parallel grids over the whole picture (lbW x lbH 4x4 blocks): 3// gref[idx] : reference index of the block. -2 == NOT-YET-DECODED or out-of-picture (geometrically 4// unavailable -> triggers D-substitution for the C neighbour); -1 == DECODED but intra 5// (available, refIdxN=-1, mvN=0); >=0 == inter reference index. Distinguishing -2 from -1 6// matters only for sub-partition (8x8) neighbours whose top-right may be undecoded. 7// gmvx/gmvy : the block's L0 motion vector (quarter-pel units). 8// Gathering A(left)/B(top)/C(top-right; D=top-left substitutes when C unavailable) for a partition 9// then calling the median/directional predictor (nx_h264_mvp / _directional). Reusable by the P-frame 10// reconstructor. genealogy_id: itu_t_h264_sec8_4_1_3_mvgrid license_tier: ORIGINAL 11import "nx_syscalls.nx" 12import "nx_h264_mvpred.nx" 13 14// Read block (bx,by); out[0]=ref out[1]=mvx out[2]=mvy. Out-of-picture -> ref=-1,mv=0. 15func nx_mvg_get(gref: *i64, gmvx: *i64, gmvy: *i64, lbW: i64, lbH: i64, bx: i64, by: i64, out: *i64) -> i64 { 16 if bx < 0 { out[0] = 0 - 2; out[1] = 0; out[2] = 0; return 0 } 17 if by < 0 { out[0] = 0 - 2; out[1] = 0; out[2] = 0; return 0 } 18 if bx >= lbW { out[0] = 0 - 2; out[1] = 0; out[2] = 0; return 0 } 19 if by >= lbH { out[0] = 0 - 2; out[1] = 0; out[2] = 0; return 0 } 20 let idx: i64 = by * lbW + bx 21 out[0] = gref[idx] 22 out[1] = gmvx[idx] 23 out[2] = gmvy[idx] 24 return 0 25} 26 27// Fill the pw x ph block rectangle at (px,py) with (ref,mvx,mvy). 28func nx_mvg_fill(gref: *i64, gmvx: *i64, gmvy: *i64, lbW: i64, 29 px: i64, py: i64, pw: i64, ph: i64, ref: i64, mvx: i64, mvy: i64) -> i64 { 30 var yy: i64 = 0 31 while yy < ph { 32 var xx: i64 = 0 33 while xx < pw { 34 let idx: i64 = (py + yy) * lbW + (px + xx) 35 gref[idx] = ref 36 gmvx[idx] = mvx 37 gmvy[idx] = mvy 38 xx = xx + 1 39 } 40 yy = yy + 1 41 } 42 return 0 43} 44 45// Compute the predicted MV (mvp) for a partition whose top-left 4x4 block is (px,py) and width pw 46// (in 4x4 units). part_shape: 0=16x16/sub (plain median), 1=16x8, 2=8x16 (directional). Writes out[0,1]. 47func nx_mvg_part_mvp(gref: *i64, gmvx: *i64, gmvy: *i64, lbW: i64, lbH: i64, 48 px: i64, py: i64, pw: i64, refIdx: i64, 49 part_shape: i64, part_idx: i64, out: *i64) -> i64 { 50 let na: *i64 = sys_mmap(32) as *i64 51 let nb: *i64 = sys_mmap(32) as *i64 52 let ncv: *i64 = sys_mmap(32) as *i64 53 nx_mvg_get(gref, gmvx, gmvy, lbW, lbH, px - 1, py, na) // A = left 54 nx_mvg_get(gref, gmvx, gmvy, lbW, lbH, px, py - 1, nb) // B = top 55 // C = top-right (px+pw, py-1). It is "available" only if in-picture AND already DECODED (gref != -2). 56 // A not-yet-decoded slot (e.g. a sub-partition whose top-right is a later sub-block, or the next MB) 57 // is NOT available -> D = top-left (px-1, py-1) substitutes (8.4.1.3 / decode-order availability). 58 var cAvail: i64 = 0 59 if py > 0 { if px + pw < lbW { 60 nx_mvg_get(gref, gmvx, gmvy, lbW, lbH, px + pw, py - 1, ncv) 61 if ncv[0] != (0 - 2) { cAvail = 1 } 62 } } 63 if cAvail == 0 { nx_mvg_get(gref, gmvx, gmvy, lbW, lbH, px - 1, py - 1, ncv) } 64 if part_shape == 0 { 65 nx_h264_mvp(na[1], na[2], na[0], nb[1], nb[2], nb[0], ncv[1], ncv[2], ncv[0], refIdx, out) 66 return 0 67 } 68 nx_h264_mvp_directional(part_shape, part_idx, 69 na[1], na[2], na[0], nb[1], nb[2], nb[0], ncv[1], ncv[2], ncv[0], refIdx, out) 70 return 0 71} 72 73// P_Skip MV derivation (8.4.1.1): mv=(0,0) if the LEFT or TOP macroblock is not available (outside the 74// picture) or if either neighbour is a zero-MV ref-0 block; otherwise the plain median predictor with 75// refIdx 0. NOTE an INTRA neighbour is "available" (refIdxN=-1, mvN=0) and does NOT force zero -- only a 76// macroblock outside the picture does (mbX==0 / mbY==0 here, single-slice). Writes out[0,1]. 77func nx_mvg_skip_mv(gref: *i64, gmvx: *i64, gmvy: *i64, lbW: i64, lbH: i64, 78 mbX: i64, mbY: i64, out: *i64) -> i64 { 79 let px: i64 = mbX * 4 80 let py: i64 = mbY * 4 81 let na: *i64 = sys_mmap(32) as *i64 82 let nb: *i64 = sys_mmap(32) as *i64 83 nx_mvg_get(gref, gmvx, gmvy, lbW, lbH, px - 1, py, na) 84 nx_mvg_get(gref, gmvx, gmvy, lbW, lbH, px, py - 1, nb) 85 var zero: i64 = 0 86 if mbX == 0 { zero = 1 } 87 if mbY == 0 { zero = 1 } 88 if na[0] == 0 { if na[1] == 0 { if na[2] == 0 { zero = 1 } } } 89 if nb[0] == 0 { if nb[1] == 0 { if nb[2] == 0 { zero = 1 } } } 90 if zero == 1 { out[0] = 0; out[1] = 0; return 0 } 91 nx_mvg_part_mvp(gref, gmvx, gmvy, lbW, lbH, px, py, 4, 0, 0, 0, out) 92 return 0 93}