code wiki / (root) / nx_vid_dur_lib.nx

nx_vid_dur_lib.nx source

↩ module page · 105 lines · 5451 B

1// nx_vid_dur_lib.nx -- SOVEREIGN container-duration parsers (no main -> build the _gate). Reads the raw 2// container bytes (no external tool): mp4/mov/m4v via the moov->mvhd movie header (timescale + duration, 3// integer), and mkv/webm via EBML Info->Duration (an IEEE float in TimecodeScale ticks). Returns dur in ms, 4// or -1 if not found in the given window. Composes into nx_ts_dur so EVERY video format gets a runtime. 5// license_tier: ORIGINAL 6import "nx_syscalls.nx" 7const K_MAGIC_86400000: i64 = 86400000 8const K_MAGIC_1000000: i64 = 1000000 9 10// first offset in buf[0..n) where the plen-byte pattern matches, else -1. 11func vd_find(buf: *u8, n: i64, pat: *u8, plen: i64) -> i64 { 12 var i: i64 = 0 13 while i + plen <= n { 14 var j: i64 = 0; var ok: i64 = 1 15 while j < plen { if buf[i + j] != pat[j] { ok = 0; j = plen } else { j = j + 1 } } 16 if ok == 1 { return i } 17 i = i + 1 18 } 19 return 0 - 1 20} 21func vd_u32(buf: *u8, off: i64) -> i64 { return ((buf[off] as i64) << 24) | ((buf[off+1] as i64) << 16) | ((buf[off+2] as i64) << 8) | (buf[off+3] as i64) } 22func vd_u64(buf: *u8, off: i64) -> i64 { var v: i64 = 0; var k: i64 = 0; while k < 8 { v = (v << 8) | (buf[off+k] as i64); k = k + 1 } return v } 23 24// ---- MP4 / MOV / M4V: moov -> mvhd movie header ---- 25// mvhd layout after the 4-byte type: version(1) flags(3); v0: [create4][mod4][timescale4][duration4]; 26// v1: [create8][mod8][timescale4][duration8]. dur_ms = duration * 1000 / timescale. 27func vd_mp4_dur(buf: *u8, n: i64) -> i64 { 28 let m: i64 = vd_find(buf, n, "mvhd" as *u8, 4) 29 if m < 0 { return 0 - 1 } 30 let d: i64 = m + 4 31 if d + 4 > n { return 0 - 1 } 32 let ver: i64 = buf[d] as i64 33 var tsoff: i64 = d + 12; var duroff: i64 = d + 16; var is64: i64 = 0; var durlen: i64 = 4 34 if ver == 1 { tsoff = d + 20; duroff = d + 24; is64 = 1; durlen = 8 } 35 if duroff + durlen > n { return 0 - 1 } 36 let ts: i64 = vd_u32(buf, tsoff) 37 if ts <= 0 { return 0 - 1 } 38 var dur: i64 = 0 39 if is64 == 1 { dur = vd_u64(buf, duroff) } else { dur = vd_u32(buf, duroff) } 40 if dur < 0 { return 0 - 1 } 41 let r: i64 = dur * 1000 / ts 42 if r > K_MAGIC_86400000 { return 0 - 1 } // >24h = a false "mvhd" match / mis-parse, not a real recording 43 return r 44} 45 46// ---- IEEE 754 big-endian float -> truncated integer (NishiLang is integer-only) ---- 47func vd_ieee64(buf: *u8, off: i64) -> i64 { 48 let b0: i64 = buf[off] as i64 49 let exp: i64 = ((b0 & 0x7F) << 4) | ((buf[off+1] as i64) >> 4) 50 if exp == 0 { return 0 } 51 var mant: i64 = ((buf[off+1] as i64) & 0xF) << 48 52 mant = mant | ((buf[off+2] as i64) << 40) | ((buf[off+3] as i64) << 32) | ((buf[off+4] as i64) << 24) | ((buf[off+5] as i64) << 16) | ((buf[off+6] as i64) << 8) | (buf[off+7] as i64) 53 let full: i64 = mant | (1 << 52) 54 let e: i64 = exp - 1023 - 52 55 if e >= 0 { if e >= 12 { return 0 } return full << e } 56 let sh: i64 = 0 - e 57 if sh >= 63 { return 0 } 58 return full >> sh 59} 60func vd_ieee32(buf: *u8, off: i64) -> i64 { 61 let b0: i64 = buf[off] as i64 62 let exp: i64 = ((b0 & 0x7F) << 1) | ((buf[off+1] as i64) >> 7) 63 if exp == 0 { return 0 } 64 var mant: i64 = ((buf[off+1] as i64) & 0x7F) << 16 65 mant = mant | ((buf[off+2] as i64) << 8) | (buf[off+3] as i64) 66 let full: i64 = mant | (1 << 23) 67 let e: i64 = exp - 127 - 23 68 if e >= 0 { if e >= 40 { return 0 } return full << e } 69 let sh: i64 = 0 - e 70 if sh >= 31 { return 0 } 71 return full >> sh 72} 73 74// ---- MKV / WEBM: EBML Info -> Duration (float, ticks) * TimecodeScale (ns/tick, default 1e6) / 1e6 ms ---- 75// Duration element = ID 44 89, then a 1-byte size VINT (84=4-byte float / 88=8-byte float), then the float. 76// TimecodeScale = ID 2A D7 B1, then a size VINT, then a big-endian uint (default 1000000 if absent). 77func vd_mkv_dur(buf: *u8, n: i64) -> i64 { 78 var tcs: i64 = K_MAGIC_1000000 79 let tci: *u8 = sys_mmap(8); tci[0] = 0x2A as u8; tci[1] = 0xD7 as u8; tci[2] = 0xB1 as u8 80 let tp: i64 = vd_find(buf, n, tci, 3) 81 if tp >= 0 { let szb: i64 = (buf[tp+3] as i64) & 0x7F; if szb >= 1 { if szb <= 8 { if tp + 4 + szb <= n { 82 var v: i64 = 0; var k: i64 = 0; while k < szb { v = (v << 8) | (buf[tp+4+k] as i64); k = k + 1 } 83 if v > 0 { tcs = v } 84 } } } } 85 // Duration: search for "44 89 84" (4-byte float) or "44 89 88" (8-byte float) 86 let d4: *u8 = sys_mmap(8); d4[0] = 0x44 as u8; d4[1] = 0x89 as u8; d4[2] = 0x84 as u8 87 let d8: *u8 = sys_mmap(8); d8[0] = 0x44 as u8; d8[1] = 0x89 as u8; d8[2] = 0x88 as u8 88 var ticks: i64 = 0 - 1 89 let p8: i64 = vd_find(buf, n, d8, 3) 90 if p8 >= 0 { if p8 + 11 <= n { ticks = vd_ieee64(buf, p8 + 3) } } 91 if ticks < 0 { let p4: i64 = vd_find(buf, n, d4, 3); if p4 >= 0 { if p4 + 7 <= n { ticks = vd_ieee32(buf, p4 + 3) } } } 92 if ticks < 0 { return 0 - 1 } 93 let r: i64 = ticks * tcs / K_MAGIC_1000000 94 if r > K_MAGIC_86400000 { return 0 - 1 } // >24h = a false "44 89 8x"/TimecodeScale match, not a real recording 95 return r 96} 97 98// sniff: 1 = mp4-family (ftyp/moov present), 2 = mkv/webm (EBML magic), 0 = other (TS / unknown). 99func vd_sniff(buf: *u8, n: i64) -> i64 { 100 let eb: *u8 = sys_mmap(8); eb[0] = 0x1A as u8; eb[1] = 0x45 as u8; eb[2] = 0xDF as u8; eb[3] = 0xA3 as u8 101 if vd_find(buf, n, eb, 4) >= 0 { return 2 } 102 if vd_find(buf, n, "ftyp" as *u8, 4) >= 0 { return 1 } 103 if vd_find(buf, n, "moov" as *u8, 4) >= 0 { return 1 } 104 return 0 105}