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}