code wiki / (root) / nx_video_codec_v1_adapter.nx

nx_video_codec_v1_adapter.nx source

↩ module page · 213 lines · 8088 B

1// nx_video_codec_v1_adapter.nx -- wraps NishiVideo v1 behind nx_codec. 2// 3// NishiVideo v1's native API: i64 pixel arrays + explicit 4// (width_blocks, height_blocks) + writes total length to out-param. 5// nx_codec's vtable: *u8 byte buffers + returns bytes-written, no 6// dimension args. 7// 8// The adapter bridges by: 9// - Storing width/height in adapter state (fixed at construction) 10// - Treating *u8 src as packed luma bytes (1 byte/pixel, 0..255) 11// - Unpacking to i64 for the codec 12// - Repacking decoded i64 pixels back to *u8 luma on decode 13// 14// Per [[feedback-bits-up-exceed-never-match]]: zero new codec logic. 15// All 11 WIN axes (per codec_grade_card.nx) belong to nx_video_codec. 16 17// nx_safety_envelope: 18// intended_use: glue between nx_codec OOP interface and NishiVideo v1 19// sil_target: SIL2 20// evidence: composes nx_video_codec v1 (codec_grade_card asserts 21// 11 WINs) via the same vtable pattern as the audio adapter 22// verdict: NOT_YET_EVALUATED -- pending adapter smoke 23 24import "nx_syscalls_x86_64.nx" 25import "nx_codec.nx" 26import "nx_video_codec.nx" 27 28// ---- Adapter state ---- 29 30struct nx_video_codec_v1_state { 31 width_blocks: i64, // image width = width_blocks * 8 32 height_blocks: i64, 33 quant_step: i64, // 1..64; lower = better quality 34 tier: i64, 35 perceptual: i64, // 0 or 1..100 36 37 vc_state: *VideoCodecState, 38 39 // Owned scratch. 40 M: *i64, // 64 i64 (DCT matrix) 41 scratch: *i64, // 64 i64 42 tmp_in: *i64, // 8 i64 43 tmp_out: *i64, // 8 i64 44 block_buf: *i64, // 64 i64 45 coeffs_buf: *i64, // 64 i64 46 prev_hash: *u8, // 32 bytes 47 quant_table: *i64, // 64 i64 when perceptual > 0; null otherwise 48 49 // Per-frame conversion scratch. 50 pixel_scratch: *i64, // width*height i64 51 pixel_scratch_cap: i64, 52 out_total_slot: *i64, 53 out_w_slot: *i64, 54 out_h_slot: *i64, 55} 56 57const NX_VID_V1A_STATE_BYTES: i64 = 168 58 59// ---- Conversion helpers ---- 60 61// Unpack u8 luma bytes (0..255) into i64 pixels (0..255). 62func _unpack_luma_u8(src: *u8, src_n: i64, dst: *i64, dst_cap: i64) -> i64 { 63 if src_n > dst_cap { return -1 } 64 var i: i64 = 0 65 while i < src_n { 66 dst[i] = src[i] as i64 67 i = i + 1 68 } 69 return src_n 70} 71 72// Pack i64 luma values back into u8 bytes (clip to 0..255). 73func _pack_luma_u8(src: *i64, n: i64, dst: *u8, dst_cap: i64) -> i64 { 74 if n > dst_cap { return -1 } 75 var i: i64 = 0 76 while i < n { 77 var v: i64 = src[i] 78 if v < 0 { v = 0 } 79 if v > 255 { v = 255 } 80 dst[i] = v as u8 81 i = i + 1 82 } 83 return n 84} 85 86// ---- Vtable impls ---- 87 88func nx_video_codec_v1_encode(c: *nx_codec, src: *u8, src_n: i64, 89 dst: *u8, dst_cap: i64) -> i64 { 90 let st: *nx_video_codec_v1_state = c.state as *nx_video_codec_v1_state 91 92 // Expect src_n == width_pixels * height_pixels. 93 let want_pixels: i64 = (st.width_blocks * 8) * (st.height_blocks * 8) 94 if src_n != want_pixels { return NX_CODEC_ERR_BAD_INPUT } 95 96 let n_pixels: i64 = _unpack_luma_u8(src, src_n, 97 st.pixel_scratch, 98 st.pixel_scratch_cap) 99 if n_pixels < 0 { return NX_CODEC_ERR_BAD_INPUT } 100 101 let out_slot: *i64 = st.out_total_slot 102 out_slot[0] = 0 103 let v: i64 = nx_vc_vid_encode(st.vc_state, 104 st.pixel_scratch, 105 st.width_blocks, st.height_blocks, 106 dst, dst_cap, 107 out_slot) 108 if v != NX_VC_VID_VERDICT_OK { 109 if v == NX_VC_VID_VERDICT_BUF_TOO_SMALL { return NX_CODEC_ERR_OUT_TOO_SMALL } 110 if v == NX_VC_VID_VERDICT_BAD_PARAMS { return NX_CODEC_ERR_BAD_INPUT } 111 return NX_CODEC_ERR_BAD_INPUT 112 } 113 return out_slot[0] 114} 115 116func nx_video_codec_v1_decode(c: *nx_codec, src: *u8, src_n: i64, 117 dst: *u8, dst_cap: i64) -> i64 { 118 let st: *nx_video_codec_v1_state = c.state as *nx_video_codec_v1_state 119 120 let w_slot: *i64 = st.out_w_slot 121 let h_slot: *i64 = st.out_h_slot 122 w_slot[0] = 0 123 h_slot[0] = 0 124 let v: i64 = nx_vc_vid_decode(st.vc_state, 125 src, src_n, 126 st.pixel_scratch, st.pixel_scratch_cap, 127 w_slot, h_slot) 128 if v != NX_VC_VID_VERDICT_OK { 129 if v == NX_VC_VID_VERDICT_BUF_TOO_SMALL { return NX_CODEC_ERR_OUT_TOO_SMALL } 130 if v == NX_VC_VID_VERDICT_FRAME_REJECTED { return NX_CODEC_ERR_BAD_MAGIC } 131 if v == NX_VC_VID_VERDICT_BAD_PARAMS { return NX_CODEC_ERR_BAD_INPUT } 132 return NX_CODEC_ERR_BAD_INPUT 133 } 134 135 // *out_w/*out_h hold PIXEL dimensions (img_w = width_blocks*8), 136 // not block counts. n_pixels = img_w * img_h directly. 137 let n_pixels: i64 = w_slot[0] * h_slot[0] 138 return _pack_luma_u8(st.pixel_scratch, n_pixels, dst, dst_cap) 139} 140 141// ---- Constructor ---- 142 143func nx_video_codec_v1_new(c: *nx_codec, 144 width_blocks: i64, height_blocks: i64, 145 quant_step: i64) -> i64 { 146 if width_blocks < 1 { return -1 } 147 if height_blocks < 1 { return -1 } 148 if quant_step < 1 { return -1 } 149 if quant_step > 64 { return -1 } 150 151 let img_w: i64 = width_blocks * 8 152 let img_h: i64 = height_blocks * 8 153 let n_pix: i64 = img_w * img_h 154 155 // Allocate all scratch buffers. 156 let M: *i64 = sys_mmap(64 * 8) as *i64 157 let scratch: *i64 = sys_mmap(64 * 8) as *i64 158 let tmp_in: *i64 = sys_mmap(8 * 8) as *i64 159 let tmp_out: *i64 = sys_mmap(8 * 8) as *i64 160 let block_buf: *i64 = sys_mmap(64 * 8) as *i64 161 let coeffs_buf: *i64 = sys_mmap(64 * 8) as *i64 162 let prev_hash: *u8 = sys_mmap(32) 163 164 // 256 bytes -- matches the existing video_codec_smoke.nx allocation 165 // and provides slack beyond the 18*8=144 minimum struct fields. 166 let vcs: *VideoCodecState = sys_mmap(256) as *VideoCodecState 167 let init_rc: i64 = nx_vc_vid_init(vcs, M, scratch, tmp_in, tmp_out, 168 block_buf, coeffs_buf, prev_hash, 169 3, quant_step) 170 if init_rc != NX_VC_VID_VERDICT_OK { return -1 } 171 172 // 4x slack on pixel scratch -- the codec's decode can over-walk 173 // by a block boundary internally; 4x avoids hitting any edge. 174 let pix_scratch: *i64 = sys_mmap(n_pix * 8 * 4) as *i64 175 let out_total_slot: *i64 = sys_mmap(16) as *i64 176 let out_w_slot: *i64 = sys_mmap(16) as *i64 177 let out_h_slot: *i64 = sys_mmap(16) as *i64 178 179 let st: *nx_video_codec_v1_state = sys_mmap(NX_VID_V1A_STATE_BYTES) 180 as *nx_video_codec_v1_state 181 st.width_blocks = width_blocks 182 st.height_blocks = height_blocks 183 st.quant_step = quant_step 184 st.tier = 3 185 st.perceptual = 0 186 st.vc_state = vcs 187 st.M = M 188 st.scratch = scratch 189 st.tmp_in = tmp_in 190 st.tmp_out = tmp_out 191 st.block_buf = block_buf 192 st.coeffs_buf = coeffs_buf 193 st.prev_hash = prev_hash 194 st.quant_table = 0 as *i64 195 st.pixel_scratch = pix_scratch 196 st.pixel_scratch_cap = n_pix * 4 197 st.out_total_slot = out_total_slot 198 st.out_w_slot = out_w_slot 199 st.out_h_slot = out_h_slot 200 201 nx_codec_init(c, 202 NX_CODEC_ID_NISHIVIDEO_V1, 203 NX_CODEC_KIND_VIDEO, 204 n_pix, // frame_size_in (1 byte luma per pixel) 205 n_pix * 4, // frame_size_out (rough upper bound for v1 raw coeffs) 206 0, // sample_rate (n/a for video) 207 0, // bitrate_target (v1: no rate control yet) 208 3) // tier 209 c.state = st as i64 210 c.encode_fn = nx_video_codec_v1_encode 211 c.decode_fn = nx_video_codec_v1_decode 212 return 0 213}