nx_h264_mvpred.nx source
↩ module page · 83 lines · 3656 B
1// nx_h264_mvpred.nx -- H.264 motion-vector prediction (spec 8.4.1.3 / 8.4.1.3.1).
2// The predicted MV mvp for a partition from its neighbours A(left) B(top) C(top-right; D=top-left
3// substitutes when C unavailable). mv = mvp + mvd. Unavailable neighbour: ref = -1, mv = (0,0).
4// rule (8.4.1.3.1): if exactly ONE of A,B,C has refIdxN == refIdx -> mvp = that mvN;
5// else mvp = component-wise MEDIAN(mvA,mvB,mvC).
6// availability sub: if B and C both unavailable but A available -> B := A, C := A.
7// directional (8.4.1.3): P_16x8 top->B / bottom->A ; P_8x16 left->A / right->C, when ref matches.
8// genealogy_id: itu_t_h264_sec8_4_1_3_mv_prediction
9// lineage_id: median_predictor + ref_match_special_case + directional_partition
10// license_tier: ORIGINAL
11import "nx_syscalls.nx"
12
13func nx_mv_min3(a: i64, b: i64, c: i64) -> i64 {
14 var m: i64 = a
15 if b < m { m = b }
16 if c < m { m = c }
17 return m
18}
19func nx_mv_max3(a: i64, b: i64, c: i64) -> i64 {
20 var m: i64 = a
21 if b > m { m = b }
22 if c > m { m = c }
23 return m
24}
25// median of three = a+b+c - min - max
26func nx_mv_median(a: i64, b: i64, c: i64) -> i64 {
27 return a + b + c - nx_mv_min3(a, b, c) - nx_mv_max3(a, b, c)
28}
29
30// Core 8.4.1.3.1 predictor. Neighbour N = (mvNx, mvNy, refN); refN<0 == unavailable.
31// Writes out[0]=mvp_x, out[1]=mvp_y.
32func nx_h264_mvp(mvAx: i64, mvAy: i64, refA: i64,
33 mvBx: i64, mvBy: i64, refB: i64,
34 mvCx: i64, mvCy: i64, refC: i64,
35 refIdx: i64, out: *i64) -> i64 {
36 // availability substitution: B and C both unavailable but A available -> B:=A, C:=A
37 var ax: i64 = mvAx
38 var ay: i64 = mvAy
39 var ra: i64 = refA
40 var bx: i64 = mvBx
41 var by: i64 = mvBy
42 var rb: i64 = refB
43 var cx: i64 = mvCx
44 var cy: i64 = mvCy
45 var rc: i64 = refC
46 if rb < 0 { if rc < 0 { if ra >= 0 { bx = ax; by = ay; rb = ra; cx = ax; cy = ay; rc = ra } } }
47 // count ref matches
48 var ma: i64 = 0
49 if ra == refIdx { ma = 1 }
50 var mb: i64 = 0
51 if rb == refIdx { mb = 1 }
52 var mc: i64 = 0
53 if rc == refIdx { mc = 1 }
54 if ma + mb + mc == 1 {
55 if ma == 1 { out[0] = ax; out[1] = ay }
56 if mb == 1 { out[0] = bx; out[1] = by }
57 if mc == 1 { out[0] = cx; out[1] = cy }
58 return 0
59 }
60 out[0] = nx_mv_median(ax, bx, cx)
61 out[1] = nx_mv_median(ay, by, cy)
62 return 0
63}
64
65// Directional predictor for a partition (8.4.1.3). part_shape: 0=16x16, 1=16x8, 2=8x16.
66// part_idx: which partition (0/1). For 16x8: part0(top)->mvB if refB==refIdx; part1(bottom)->mvA if
67// refA==refIdx. For 8x16: part0(left)->mvA if refA==refIdx; part1(right)->mvC if refC==refIdx.
68// Otherwise falls through to the median predictor. Writes out[0..1].
69func nx_h264_mvp_directional(part_shape: i64, part_idx: i64,
70 mvAx: i64, mvAy: i64, refA: i64,
71 mvBx: i64, mvBy: i64, refB: i64,
72 mvCx: i64, mvCy: i64, refC: i64,
73 refIdx: i64, out: *i64) -> i64 {
74 if part_shape == 1 { // 16x8
75 if part_idx == 0 { if refB == refIdx { out[0] = mvBx; out[1] = mvBy; return 0 } }
76 if part_idx == 1 { if refA == refIdx { out[0] = mvAx; out[1] = mvAy; return 0 } }
77 }
78 if part_shape == 2 { // 8x16
79 if part_idx == 0 { if refA == refIdx { out[0] = mvAx; out[1] = mvAy; return 0 } }
80 if part_idx == 1 { if refC == refIdx { out[0] = mvCx; out[1] = mvCy; return 0 } }
81 }
82 return nx_h264_mvp(mvAx, mvAy, refA, mvBx, mvBy, refB, mvCx, mvCy, refC, refIdx, out)
83}