code wiki / (root) / nx_ts_dur.nx

nx_ts_dur.nx source

↩ module page · 102 lines · 4510 B

1// nx_ts_dur.nx -- MPEG-TS total duration via FIRST + LAST PCR (no full-file scan; reads only an 2// 8 MB window at each end). PCR lives in the adaptation field (afc>=2, PCR_flag bit 0x10), a 33-bit 3// base clock @ 90 kHz. Also reports the PCR endpoints so the daemon can do proportional time<->byte 4// seeking (byte ~= start + (T-first)/(last-first)*size). Usage: nx_ts_dur <in.ts> 5// Prints: size=<n> first_pcr90=<n> last_pcr90=<n> dur_ms=<n>. license_tier: ORIGINAL 6import "nx_syscalls.nx" 7import "nx_vid_dur_lib.nx" // sovereign mp4/mov + mkv/webm container-duration parsers (so EVERY format gets a runtime) 8const K_MAGIC_8589934592: i64 = 8589934592 9 10const WIN: i64 = 8388608 11 12func tp_p(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 13func tp_n(v: i64) -> i64 { 14 var m: i64=v; var neg: i64=0; if m<0 { neg=1; m=0-m } 15 let b: *u8=sys_mmap(32); var i: i64=32 16 if m==0 { i=i-1; b[i]=(48 as u8) } 17 while m>0 { let q: i64=m/10; i=i-1; b[i]=((48+(m-q*10)) as u8); m=q } 18 if neg==1 { i=i-1; b[i]=(45 as u8) } 19 return sys_write(1, ((b as i64)+i) as *u8, 32-i) 20} 21 22// scan buf[0..n) for PCRs; set fp[0] to the first seen (if still -1), lp[0] to the last seen. returns count. 23func scan_pcr(buf: *u8, n: i64, fp: *i64, lp: *i64) -> i64 { 24 var i: i64 = 0; var cnt: i64 = 0 25 while i + 188 <= n { 26 if buf[i] != (0x47 as u8) { i = i + 1 } else { 27 let afc: i64 = ((buf[i+3] as i64)>>4)&3 28 if afc>=2 { 29 let afl: i64 = buf[i+4] as i64 30 if afl > 0 { 31 let flags: i64 = buf[i+5] as i64 32 if ((flags>>4)&1)==1 { 33 let base: i64 = ((buf[i+6] as i64)<<25)|((buf[i+7] as i64)<<17)|((buf[i+8] as i64)<<9)|((buf[i+9] as i64)<<1)|((buf[i+10] as i64)>>7) 34 if fp[0] < 0 { fp[0] = base } 35 lp[0] = base 36 cnt = cnt + 1 37 } 38 } 39 } 40 i = i + 188 41 } 42 } 43 return cnt 44} 45 46func read_window(fd: i64, buf: *u8, cap: i64) -> i64 { 47 var got: i64 = 0; var go: i64 = 1 48 while go==1 { if got>=cap { go=0 } else { let r: i64=sys_read(fd, ((buf as i64)+got) as *u8, cap-got); if r<=0 { go=0 } else { got=got+r } } } 49 return got 50} 51 52func main(argc: i64, argv: *i64) -> i64 { 53 if argc < 2 { tp_p("usage: nx_ts_dur <in.ts>\n" as *u8); return 2 } 54 let path: *u8 = argv[1] as *u8 55 let fd: i64 = sys_openat_rd(path) 56 if fd < 0 { tp_p("ERROR open failed\n" as *u8); return 1 } 57 let size: i64 = sys_lseek(fd, 0, 2) 58 let buf: *u8 = sys_mmap(WIN + 16) 59 let fp: *i64 = sys_mmap(16) as *i64; fp[0] = 0 - 1 60 let lp: *i64 = sys_mmap(16) as *i64; lp[0] = 0 - 1 61 // start window -> first PCR 62 sys_lseek(fd, 0, 0) 63 let g1: i64 = read_window(fd, buf, WIN) 64 // sniff the container: mp4/mov (moov->mvhd) or mkv/webm (EBML Duration) -> direct duration, no PCR scan. 65 let sf: i64 = vd_sniff(buf, g1) 66 if sf == 1 { 67 var dms: i64 = vd_mp4_dur(buf, g1) 68 if dms < 0 { var es: i64 = size - WIN; if es < 0 { es = 0 } sys_lseek(fd, es, 0); let ge: i64 = read_window(fd, buf, WIN); dms = vd_mp4_dur(buf, ge) } 69 if dms < 0 { dms = 0 } 70 sys_close(fd) 71 tp_p("size=" as *u8); tp_n(size); tp_p(" first_pcr90=0 last_pcr90=0 dur_ms=" as *u8); tp_n(dms); tp_p("\n" as *u8) 72 return 0 73 } 74 if sf == 2 { 75 var dms2: i64 = vd_mkv_dur(buf, g1); if dms2 < 0 { dms2 = 0 } 76 sys_close(fd) 77 tp_p("size=" as *u8); tp_n(size); tp_p(" first_pcr90=0 last_pcr90=0 dur_ms=" as *u8); tp_n(dms2); tp_p("\n" as *u8) 78 return 0 79 } 80 scan_pcr(buf, g1, fp, lp) 81 let first_pcr: i64 = fp[0] 82 // end window -> last PCR 83 let fp2: *i64 = sys_mmap(16) as *i64; fp2[0] = 0 - 1 84 let lp2: *i64 = sys_mmap(16) as *i64; lp2[0] = 0 - 1 85 var estart: i64 = size - WIN; if estart < 0 { estart = 0 } 86 sys_lseek(fd, estart, 0) 87 let g2: i64 = read_window(fd, buf, WIN) 88 scan_pcr(buf, g2, fp2, lp2) 89 let last_pcr: i64 = lp2[0] 90 sys_close(fd) 91 var dur90: i64 = 0 92 if first_pcr >= 0 { if last_pcr >= 0 { 93 dur90 = last_pcr - first_pcr 94 if dur90 < 0 { dur90 = dur90 + K_MAGIC_8589934592 } // 33-bit PCR wrap (2^33) 95 } } 96 tp_p("size=" as *u8); tp_n(size) 97 tp_p(" first_pcr90=" as *u8); tp_n(first_pcr) 98 tp_p(" last_pcr90=" as *u8); tp_n(last_pcr) 99 tp_p(" dur_ms=" as *u8); tp_n(dur90/90) 100 tp_p("\n" as *u8) 101 return 0 102}