nx_video_frame.nx source
↩ module page · 133 lines · 4466 B
1// nx_video_frame.nx -- wire frame format for Nishi sovereign video.
2//
3// Magic "NXVD" (Nishi Video), hash-chained header just like
4// nx_voice_frame. Carries one I-frame as a sequence of 8x8 DCT
5// blocks. Future P-frame support will reuse the same envelope with
6// a different flag.
7//
8// Wire layout (little-endian):
9// [0..3] magic "NXVD"
10// [4] version major (1)
11// [5] tier hint (NX_HW_TIER_*)
12// [6..7] width_blocks (each block is 8 pixels)
13// [8..9] height_blocks
14// [10] frame_kind (1 = I-frame; 2 = P-frame queued)
15// [11] quant_step (1..64; per-frame uniform quantisation)
16// [12..15] sequence
17// [16..47] prev_frame_hash (32 bytes; FNV 4-lane shared with voice)
18// [48..49] payload_bytes (= width_blocks * height_blocks * 64 * 2)
19// [50..] payload: per block, 64 quantised coefficients as int16 LE
20//
21// Per-frame size for a 16x16 I-frame (2x2 blocks of 8x8):
22// header 50 + payload 4 * 64 * 2 = 50 + 512 = 562 bytes.
23// At 30 fps that's 16.86 kbps for 16x16 -- proof of concept.
24//
25// genealogy_id: nx_voice_frame_q10 + jpeg_iso_10918 + h264_iso_14496_10 +
26// nx_dct8_q10
27// lineage_id: nishi_video_frame_q10
28
29// nx_safety_envelope:
30// intended_use: AUTO_APPLIED -- primitive-specific tuning queued
31// sil_target: SIL1
32// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail]
33// verdict: NOT_YET_EVALUATED
34
35import "nx_syscalls.nx"
36
37// Sealed verdict.
38const NX_VID_VERDICT_UNKNOWN: i64 = 0
39const NX_VID_VERDICT_OK: i64 = 1
40const NX_VID_VERDICT_BAD_MAGIC: i64 = 2
41const NX_VID_VERDICT_VERSION_MISMATCH: i64 = 3
42const NX_VID_VERDICT_TRUNCATED: i64 = 4
43const NX_VID_VERDICT_CHAIN_BROKEN: i64 = 5
44const NX_VID_VERDICT_BAD_PARAMS: i64 = 6
45const NX_VID_VERDICT_N: i64 = 7
46
47const NX_VID_KIND_I: i64 = 1
48const NX_VID_KIND_P: i64 = 2
49
50const NX_VID_HEADER_BYTES: i64 = 50
51
52func nx_vid_build_header(
53 out: *u8, out_cap: i64,
54 tier: i64,
55 width_blocks: i64, height_blocks: i64,
56 frame_kind: i64,
57 quant_step: i64,
58 sequence: i64,
59 prev_hash: *u8,
60 payload_bytes: i64
61) -> i64 {
62 if out_cap < NX_VID_HEADER_BYTES + payload_bytes { return -1 }
63 if width_blocks < 1 { return -1 }
64 if height_blocks < 1 { return -1 }
65 if quant_step < 1 { return -1 }
66 if quant_step > 255 { return -1 }
67
68 out[0]=78; out[1]=88; out[2]=86; out[3]=68 // "NXVD"
69 out[4]=1
70 out[5]=tier & 0xff
71 out[6]=width_blocks & 0xff
72 out[7]=(width_blocks >> 8) & 0xff
73 out[8]=height_blocks & 0xff
74 out[9]=(height_blocks >> 8) & 0xff
75 out[10]=frame_kind & 0xff
76 out[11]=quant_step & 0xff
77 out[12]=sequence & 0xff
78 out[13]=(sequence >> 8) & 0xff
79 out[14]=(sequence >> 16) & 0xff
80 out[15]=(sequence >> 24) & 0xff
81 var i: i64 = 0
82 while i < 32 {
83 out[16 + i] = prev_hash[i]
84 i = i + 1
85 }
86 out[48] = payload_bytes & 0xff
87 out[49] = (payload_bytes >> 8) & 0xff
88 return NX_VID_HEADER_BYTES
89}
90
91func nx_vid_parse_header(
92 buf: *u8, buf_len: i64,
93 expected_prev_hash: *u8,
94 out_width_blocks: *i64, out_height_blocks: *i64,
95 out_frame_kind: *i64, out_quant: *i64, out_sequence: *i64,
96 out_payload_off: *i64, out_payload_len: *i64
97) -> i64 {
98 if buf_len < NX_VID_HEADER_BYTES { return NX_VID_VERDICT_TRUNCATED }
99 if buf[0] != 78 { return NX_VID_VERDICT_BAD_MAGIC }
100 if buf[1] != 88 { return NX_VID_VERDICT_BAD_MAGIC }
101 if buf[2] != 86 { return NX_VID_VERDICT_BAD_MAGIC }
102 if buf[3] != 68 { return NX_VID_VERDICT_BAD_MAGIC }
103 if buf[4] != 1 { return NX_VID_VERDICT_VERSION_MISMATCH }
104
105 *out_width_blocks = buf[6] | (buf[7] << 8)
106 *out_height_blocks = buf[8] | (buf[9] << 8)
107 *out_frame_kind = buf[10]
108 *out_quant = buf[11]
109 *out_sequence = buf[12] | (buf[13] << 8) | (buf[14] << 16) | (buf[15] << 24)
110
111 let plen: i64 = buf[48] | (buf[49] << 8)
112 if NX_VID_HEADER_BYTES + plen > buf_len { return NX_VID_VERDICT_TRUNCATED }
113
114 if (expected_prev_hash as i64) != 0 {
115 var i: i64 = 0
116 var bad: i64 = 0
117 while i < 32 {
118 if buf[16 + i] != expected_prev_hash[i] { bad = 1 }
119 i = i + 1
120 }
121 if bad == 1 { return NX_VID_VERDICT_CHAIN_BROKEN }
122 }
123
124 *out_payload_off = NX_VID_HEADER_BYTES
125 *out_payload_len = plen
126 return NX_VID_VERDICT_OK
127}
128
129func nx_vid_verdict_is_valid(v: i64) -> i64 {
130 if v < 0 { return 0 }
131 if v >= NX_VID_VERDICT_N { return 0 }
132 return 1
133}