code wiki / (root) / nx_h264_mvpred.nx

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}