code wiki / _hdl_build / nx_movie_probe.nx

nx_movie_probe.nx source

↩ module page · 301 lines · 19216 B

1// nx_movie_probe.nx -- MOVIE LIVENESS PROBE (operator 2026-07-04: "broken movies where i cant see the start, 2// finish, chapters, the dead air, the performance"). The video rung of the media-liveness plane (serving != working). 3// A SOVEREIGN ISO-BMFF (MP4/M4V/MOV) box parser: reads ONLY the small `moov` metadata box (seeks past the huge 4// `mdat` -- never loads GB of media) and reports: structural completeness (ftyp/moov/mdat present, not truncated), 5// duration (start->finish), video WxH + codec, audio presence + codec, chapters, embedded cover(thumbnail), fast- 6// start(moov-before-mdat = seekable/streamable), and bitrate (performance). Verdict OK|DEGRADED|BROKEN. 7// HONEST SCOPE: MKV/WebM(EBML) detected + flagged as a TODO rung; true DEAD-AIR(silence) + keyframe-thumbnail-gen 8// need audio/H.264 DECODE (separate rungs) -- we report hasAudio + hasThumbnail, not silence spans. license_tier: ORIGINAL 9// expect_exit: 0 10import "nx_syscalls.nx" 11const R_MAGIC_4096: i64 = 4096 12const R_MAGIC_8192: i64 = 8192 13const R_MAGIC_67108864: i64 = 67108864 14const R_MAGIC_2048: i64 = 2048 15const R_MAGIC_1048576: i64 = 1048576 16const R_MAGIC_4095: i64 = 4095 17const R_MAGIC_1048000: i64 = 1048000 18 19// result slots 20const R_TS: i64=0 const R_DUR: i64=1 const R_W: i64=2 const R_H: i64=3 21const R_VID: i64=4 const R_AUD: i64=5 const R_VCC: i64=6 const R_ACC: i64=7 22const R_CHP: i64=8 const R_COVR: i64=9 const R_NTRAK: i64=10 const R_FTYP: i64=11 23const R_MOOV: i64=12 const R_MDAT: i64=13 const R_TRUNC: i64=14 const R_FAST: i64=15 24const R_SIZE: i64=16 const R_MKV: i64=17 const R_MOOVSZ: i64=18 const R_POSTER: i64=19 25const R_TSFMT: i64=20 const R_FLV: i64=21 26 27func pw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 28func pn(v: i64) -> i64 { let b: *u8=sys_mmap(24); var m: i64=v; if m<0{pw("-" as *u8);m=0-m} let t: *u8=sys_mmap(24); var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 } 29func p4(buf: *u8, o: i64) -> i64 { sys_write(1,(buf as i64+o) as *u8,4); return 0 } 30func be32(buf: *u8, o: i64) -> i64 { return ((buf[o] as i64)<<24)|((buf[o+1] as i64)<<16)|((buf[o+2] as i64)<<8)|(buf[o+3] as i64) } 31func be64(buf: *u8, o: i64) -> i64 { return (be32(buf,o)<<32)|be32(buf,o+4) } 32func fcc(buf: *u8, o: i64, a: i64, b: i64, c: i64, d: i64) -> i64 { if (buf[o] as i64)!=a {return 0} if (buf[o+1] as i64)!=b {return 0} if (buf[o+2] as i64)!=c {return 0} if (buf[o+3] as i64)!=d {return 0} return 1 } 33func sys_lseek(fd: i64, off: i64, whence: i64) -> i64 { return __syscall(8, fd, off, whence, 0, 0, 0) } 34func mp_read_at(fd: i64, off: i64, buf: *u8, n: i64) -> i64 { 35 sys_lseek(fd, off, 0) 36 var got: i64=0 37 while got < n { let r: i64=sys_read(fd, (buf as i64+got) as *u8, n-got); if r<=0 {return got} got=got+r } 38 return got 39} 40// is `type4` at buf[o] one of the standard ISO CONTAINER boxes we should recurse into? 41func mp_iscontainer(buf: *u8, o: i64) -> i64 { 42 if fcc(buf,o,109,111,111,118)==1 {return 1} // moov 43 if fcc(buf,o,116,114,97,107)==1 {return 1} // trak 44 if fcc(buf,o,109,100,105,97)==1 {return 1} // mdia 45 if fcc(buf,o,109,105,110,102)==1 {return 1} // minf 46 if fcc(buf,o,115,116,98,108)==1 {return 1} // stbl 47 if fcc(buf,o,117,100,116,97)==1 {return 1} // udta 48 if fcc(buf,o,101,100,116,115)==1 {return 1} // edts 49 if fcc(buf,o,100,105,110,102)==1 {return 1} // dinf 50 if fcc(buf,o,105,108,115,116)==1 {return 1} // ilst 51 return 0 52} 53// find first box whose type == (a,b,c,d) within buf[start,end); return CONTENT offset (after box header) or -1. 54func mp_find(buf: *u8, start: i64, end: i64, a: i64, b: i64, c: i64, d: i64, depth: i64) -> i64 { 55 if depth > 8 { return 0-1 } 56 var pos: i64 = start; var guard: i64 = 0 57 while pos + 8 <= end { 58 guard = guard + 1; if guard > R_MAGIC_4096 { return 0-1 } 59 var bs: i64 = be32(buf, pos); var hl: i64 = 8 60 if bs == 1 { bs = be64(buf, pos+8); hl = 16 } 61 if bs == 0 { bs = end - pos } 62 if bs < hl { return 0-1 } 63 var ie: i64 = pos + bs; if ie > end { ie = end } 64 if fcc(buf,pos+4,a,b,c,d) == 1 { return pos + hl } 65 if mp_iscontainer(buf, pos+4) == 1 { 66 var cs: i64 = pos + hl 67 if fcc(buf,pos+4,109,101,116,97)==1 { cs = cs + 4 } // meta is a FullBox (defensive; not in our set but safe) 68 let r: i64 = mp_find(buf, cs, ie, a, b, c, d, depth+1) 69 if r >= 0 { return r } 70 } 71 pos = pos + bs 72 } 73 return 0-1 74} 75// parse one trak subtree [start,end): tkhd(w,h) + hdlr(type) + stsd(codec) -> commit to res 76func mp_trak(buf: *u8, start: i64, end: i64, res: *i64) -> i64 { 77 res[R_NTRAK] = res[R_NTRAK] + 1 78 // hdlr type: content+8 = handler fourcc 79 let hd: i64 = mp_find(buf, start, end, 104,100,108,114, 0) // hdlr 80 var isvid: i64 = 0; var isaud: i64 = 0 81 if hd >= 0 { if fcc(buf, hd+8, 118,105,100,101)==1 { isvid=1 } // 'vide' 82 if fcc(buf, hd+8, 115,111,117,110)==1 { isaud=1 } } // 'soun' 83 // stsd codec: content+12 = first sample-entry format fourcc 84 let sd: i64 = mp_find(buf, start, end, 115,116,115,100, 0) // stsd 85 // tkhd w/h (16.16 fixed at version-dependent offset) 86 let tk: i64 = mp_find(buf, start, end, 116,107,104,100, 0) // tkhd 87 if isvid == 1 { 88 res[R_VID] = 1 89 if sd >= 0 { res[R_VCC] = be32(buf, sd + 12) } // packed codec fourcc (stsd: ver/flags(4)+count(4)+entrysize(4)+format(4)) 90 if tk >= 0 { let ver: i64 = buf[tk] as i64 91 var woff: i64 = tk + 76; if ver == 1 { woff = tk + 88 } // v0: 4(ver/flags)+24(fields)+8(reserved2)+8(layer/alt/vol/res)+36(matrix)=76 -> width; +4 -> height 92 res[R_W] = be32(buf, woff) >> 16 93 res[R_H] = be32(buf, woff+4) >> 16 } 94 } 95 if isaud == 1 { res[R_AUD] = 1; if sd >= 0 { res[R_ACC] = be32(buf, sd + 12) } } 96 return 0 97} 98 99// parse moov buffer [0,moovlen) -> res. buf holds the moov CONTENT (after moov header). 100func mp_probe_moov(buf: *u8, moovlen: i64, res: *i64) -> i64 { 101 let mv: i64 = mp_find(buf, 0, moovlen, 109,118,104,100, 0) // mvhd 102 if mv >= 0 { let ver: i64 = buf[mv] as i64 103 if ver == 1 { res[R_TS] = be32(buf, mv+20); res[R_DUR] = be64(buf, mv+24) } 104 else { res[R_TS] = be32(buf, mv+12); res[R_DUR] = be32(buf, mv+16) } } 105 // direct trak children 106 var pos: i64 = 0; var guard: i64 = 0 107 while pos + 8 <= moovlen { 108 guard = guard + 1; if guard > R_MAGIC_4096 { pos = moovlen } else { 109 var bs: i64 = be32(buf, pos); var hl: i64 = 8 110 if bs == 1 { bs = be64(buf, pos+8); hl = 16 } 111 if bs == 0 { bs = moovlen - pos } 112 if bs < hl { pos = moovlen } else { 113 if fcc(buf, pos+4, 116,114,97,107)==1 { var ie: i64=pos+bs; if ie>moovlen {ie=moovlen} mp_trak(buf, pos+hl, ie, res) } 114 pos = pos + bs 115 } 116 } 117 } 118 if mp_find(buf, 0, moovlen, 99,104,112,108, 0) >= 0 { res[R_CHP] = 1 } // chpl (Nero chapters) 119 if mp_find(buf, 0, moovlen, 99,111,118,114, 0) >= 0 { res[R_COVR] = 1 } // covr (embedded cover art) 120 return 0 121} 122 123// top-level probe of `path` into res. returns verdict 2=OK 1=DEGRADED 0=BROKEN. 124func mp_probe(path: *u8, res: *i64) -> i64 { 125 var i: i64=0; while i<24 { res[i]=0; i=i+1 } 126 let fd: i64 = sys_openat_rd(path) 127 if fd < 0 { return 0 } 128 let size: i64 = sys_lseek(fd, 0, 2) 129 res[R_SIZE] = size 130 if size < 16 { sys_close(fd); return 0 } 131 // container sniff (read 200 bytes): EBML(mkv/webm) 1A45DFA3 · MPEG-TS 0x47 sync at 0 AND 188 · FLV magic 132 let sn: *u8 = sys_mmap(256); let sniffn: i64 = mp_read_at(fd, 0, sn, 200) 133 if (sn[0] as i64)==0x1a { if (sn[1] as i64)==0x45 { if (sn[2] as i64)==0xdf { if (sn[3] as i64)==0xa3 { res[R_MKV]=1 } } } } 134 if sniffn > 188 { if (sn[0] as i64)==0x47 { if (sn[188] as i64)==0x47 { res[R_TSFMT]=1 } } } // MPEG-TS (188-byte packets) 135 if (sn[0] as i64)==0x46 { if (sn[1] as i64)==0x4c { if (sn[2] as i64)==0x56 { res[R_FLV]=1 } } } // "FLV" 136 // top-level box walk (header-only seeks; never read mdat payload) 137 let hdr: *u8 = sys_mmap(16) 138 var pos: i64 = 0; var moovoff: i64 = 0-1; var moovsz: i64 = 0 139 var seen_mdat: i64 = 0; var corrupt: i64 = 0; var ntop: i64 = 0 140 while pos + 8 <= size { 141 if mp_read_at(fd, pos, hdr, 16) < 8 { corrupt = 1; pos = size } else { 142 var bs: i64 = be32(hdr, 0); var hl: i64 = 8 143 if bs == 1 { bs = be64(hdr, 8); hl = 16 } 144 if bs == 0 { bs = size - pos } 145 if bs < hl { corrupt = 1; pos = size } else { 146 if fcc(hdr,4,102,116,121,112)==1 { res[R_FTYP]=1 } // ftyp 147 if fcc(hdr,4,109,111,111,118)==1 { res[R_MOOV]=1; moovoff=pos+hl; moovsz=bs-hl; if seen_mdat==0 { res[R_FAST]=1 } } // moov 148 if fcc(hdr,4,109,100,97,116)==1 { res[R_MDAT]=1; seen_mdat=1 } // mdat 149 pos = pos + bs; ntop = ntop + 1 150 if ntop > R_MAGIC_8192 { pos = size } 151 } 152 } 153 } 154 if pos > size { res[R_TRUNC] = 1 } // last box claims bytes beyond EOF -> truncated 155 // read + parse moov (bounded to 64MiB; moov is metadata) 156 if res[R_MOOV] == 1 { if moovsz > 0 { 157 var cap: i64 = moovsz; if cap > R_MAGIC_67108864 { cap = R_MAGIC_67108864 } 158 let mbuf: *u8 = sys_mmap(cap + 16) 159 let got: i64 = mp_read_at(fd, moovoff, mbuf, cap) 160 res[R_MOOVSZ] = got 161 if got >= 8 { mp_probe_moov(mbuf, got, res) } 162 } } 163 sys_close(fd) 164 if res[R_TSFMT]==1 { res[R_TRUNC]=0 } if res[R_FLV]==1 { res[R_TRUNC]=0 } if res[R_MKV]==1 { res[R_TRUNC]=0 } // box-walk trunc is meaningless for non-BMFF 165 res[R_POSTER] = mp_has_poster(path) // sidecar thumbnail the gallery serves at /vidthumb 166 var thumb: i64 = 0; if res[R_COVR]==1 { thumb=1 } if res[R_POSTER]==1 { thumb=1 } 167 // recognized-but-not-deep-verified containers (TS/FLV/MKV are sync-valid real streams the gallery remuxes) -> 168 // usable IF they have a thumbnail; else DEGRADED (no preview). deep A/V verify = the TS/MKV rung (TODO). 169 if res[R_TSFMT]==1 { if thumb==1 { return 2 } return 1 } 170 if res[R_FLV]==1 { if thumb==1 { return 2 } return 1 } 171 if res[R_MKV]==1 { if thumb==1 { return 2 } return 1 } 172 // MP4/ISO-BMFF deep verify 173 if res[R_FTYP] == 0 { if res[R_MOOV] == 0 { return 0 } } // not any recognized container -> BROKEN 174 if res[R_MOOV] == 0 { return 0 } // no metadata -> unplayable 175 if res[R_MDAT] == 0 { return 0 } // no media data 176 if res[R_TRUNC] == 1 { return 1 } // truncated -> degraded 177 if res[R_TS] <= 0 { return 1 } // no/zero duration -> degraded 178 if res[R_VID] == 0 { if res[R_AUD] == 0 { return 0 } } // no A/V tracks -> broken 179 if thumb == 0 { return 1 } // playable but no thumbnail -> blank tile -> DEGRADED 180 return 2 181} 182 183// gallery serves the sidecar <path-without-ext>-poster.jpg for /vidthumb; missing = blank tile = "no thumbnail". 184func mp_has_poster(path: *u8) -> i64 { 185 var pl: i64=0; while path[pl]!=(0 as u8){pl=pl+1} 186 var dot: i64 = pl; var i: i64 = 0 187 while i < pl { if (path[i] as i64)==46 { dot = i } i = i + 1 } // last '.' 188 let pp: *u8 = sys_mmap(R_MAGIC_2048); var o: i64 = 0 189 var j: i64 = 0; while j < dot { pp[o]=path[j]; o=o+1; j=j+1 } 190 let suf: *u8 = "-poster.jpg" as *u8; var k: i64=0; while suf[k]!=(0 as u8){pp[o]=suf[k];o=o+1;k=k+1} pp[o]=0 as u8 191 let fd: i64 = sys_openat_rd(pp); if fd < 0 { return 0 } sys_close(fd); return 1 192} 193func mp_vstr(v: i64) -> *u8 { if v==2 {return "OK"} if v==1 {return "DEGRADED"} return "BROKEN" } 194// print a packed fourcc (4 bytes) as ascii, or '-' if 0 195func mp_p4(v: i64) -> i64 { if v==0 { pw("-" as *u8); return 0 } let b: *u8=sys_mmap(4); b[0]=((v>>24)&0xff) as u8; b[1]=((v>>16)&0xff) as u8; b[2]=((v>>8)&0xff) as u8; b[3]=(v&0xff) as u8; sys_write(1,b,4); return 0 } 196 197// append NUL-term s into dst[o..]; return new o 198func mp_js(dst: *u8, o: i64, s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8){dst[o]=s[i];o=o+1;i=i+1} return o } 199// decimal into dst (report builder) 200func mp_dec(dst: *u8, o: i64, v: i64) -> i64 { var m: i64=v; if m<0{dst[o]=45 as u8;o=o+1;m=0-m} let t: *u8=sys_mmap(24); var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var i: i64=0; while i<k{dst[o]=t[k-1-i];o=o+1;i=i+1} return o } 201// append path bytes with JSON-escaping (" and \ -> escaped; drop <0x20); return new o 202func mp_jesc(dst: *u8, o: i64, s: *u8, cap: i64) -> i64 { var i: i64=0; while s[i]!=(0 as u8){ let c: i64=s[i] as i64; if c==34 { if o<cap-2 {dst[o]=92 as u8;dst[o+1]=34 as u8;o=o+2} } else { if c==92 { if o<cap-2 {dst[o]=92 as u8;dst[o+1]=92 as u8;o=o+2} } else { if c>=32 { if o<cap-1 {dst[o]=s[i] as u8;o=o+1} } } } i=i+1 } return o } 203 204// SWEEP mode: read a catalog (one path per line, first \t-field = path), probe up to `max`, tally + collect the 205// NOT-OK issues into a JSON health report at outpath. Honest: logs swept-of-total; caps the issue list + says so. 206func mp_sweep(catalog: *u8, outpath: *u8, max: i64) -> i64 { 207 let box: *i64 = sys_mmap(16) as *i64 208 let buf: *u8 = sys_read_file(catalog, box) 209 if (buf as i64)==0 { pw("SWEEP: cannot read catalog " as *u8); pw(catalog); pw("\n" as *u8); return 1 } 210 let n: i64 = box[0] 211 let rep: *u8 = sys_mmap(R_MAGIC_1048576); var ro: i64 = 0 // report JSON 212 ro = mp_js(rep, ro, "{\"scope\":\"video\",\"issues\":[" as *u8) 213 let res: *i64 = sys_mmap(32*8) as *i64 214 let path: *u8 = sys_mmap(R_MAGIC_4096) 215 var total: i64=0; var swept: i64=0; var ok: i64=0; var deg: i64=0; var brk: i64=0; var nothumb: i64=0 216 var issues: i64=0; let ISS_CAP: i64=400 217 var i: i64=0 218 while i < n { 219 // phase 1: copy path = bytes until '\t' or '\n' or EOF (skip '\r') 220 var po: i64=0 221 var stop1: i64=0 222 while stop1==0 { if i>=n { stop1=1 } else { let c: i64=buf[i] as i64; if c==9 { stop1=1 } else { if c==10 { stop1=1 } else { if c==13 { i=i+1 } else { if po<R_MAGIC_4095 { path[po]=buf[i]; po=po+1 } i=i+1 } } } } } 223 // phase 2: skip to just past the next '\n' 224 while i < n { let c: i64=buf[i] as i64; i=i+1; if c==10 { break } } 225 if po > 0 { 226 path[po]=0 as u8 227 total=total+1 228 if swept < max { 229 swept=swept+1 230 if swept - (swept/250)*250 == 0 { pw(" ..swept " as *u8); pn(swept); pw("\n" as *u8) } // keep-alive + progress 231 let v: i64 = mp_probe(path, res) 232 if v==2 { ok=ok+1 } else { if v==1 { deg=deg+1 } else { brk=brk+1 } } 233 if res[R_POSTER]==0 { if res[R_COVR]==0 { nothumb=nothumb+1 } } 234 if v != 2 { if issues < ISS_CAP { 235 if issues>0 { rep[ro]=44 as u8; ro=ro+1 } 236 issues=issues+1 237 ro=mp_js(rep,ro,"{\"path\":\"" as *u8); ro=mp_jesc(rep,ro,path,R_MAGIC_1048000) 238 ro=mp_js(rep,ro,"\",\"verdict\":\"" as *u8); ro=mp_js(rep,ro,mp_vstr(v)) 239 // reason = most-severe first (corrupt > truncated > no-thumbnail) 240 var reason: *u8 = "other" as *u8 241 if res[R_POSTER]==0 { if res[R_COVR]==0 { reason="no_thumbnail" as *u8 } } 242 if res[R_TRUNC]==1 { reason="truncated" as *u8 } 243 if res[R_MOOV]==0 { if res[R_TSFMT]==0 { if res[R_MKV]==0 { if res[R_FLV]==0 { reason="unrecognized/corrupt" as *u8 } } } } 244 ro=mp_js(rep,ro,"\",\"reason\":\"" as *u8); ro=mp_js(rep,ro,reason); ro=mp_js(rep,ro,"\"}" as *u8) 245 } } 246 } 247 } 248 } 249 ro=mp_js(rep,ro,"],\"total\":" as *u8); ro=mp_dec(rep,ro,total) 250 ro=mp_js(rep,ro,",\"swept\":" as *u8); ro=mp_dec(rep,ro,swept) 251 ro=mp_js(rep,ro,",\"ok\":" as *u8); ro=mp_dec(rep,ro,ok) 252 ro=mp_js(rep,ro,",\"degraded\":" as *u8); ro=mp_dec(rep,ro,deg) 253 ro=mp_js(rep,ro,",\"broken\":" as *u8); ro=mp_dec(rep,ro,brk) 254 ro=mp_js(rep,ro,",\"no_thumbnail\":" as *u8); ro=mp_dec(rep,ro,nothumb) 255 var capped: i64=0; if issues>=ISS_CAP { capped=1 } 256 ro=mp_js(rep,ro,",\"issues_capped\":" as *u8); ro=mp_dec(rep,ro,capped); ro=mp_js(rep,ro,"}" as *u8) 257 let fd: i64 = sys_openat_wr(outpath, 0x1a4) 258 if fd < 0 { pw("SWEEP: cannot write " as *u8); pw(outpath); pw("\n" as *u8); return 1 } 259 sys_write(fd, rep, ro); sys_close(fd) 260 pw("SWEEP DONE total=" as *u8); pn(total); pw(" swept=" as *u8); pn(swept); pw(" ok=" as *u8); pn(ok) 261 pw(" degraded=" as *u8); pn(deg); pw(" broken=" as *u8); pn(brk); pw(" no_thumbnail=" as *u8); pn(nothumb) 262 pw(" -> " as *u8); pw(outpath); pw("\n" as *u8) 263 if swept < total { pw("SWEEP NOTE: swept " as *u8); pn(swept); pw(" of " as *u8); pn(total); pw(" (raise max to cover all)\n" as *u8) } 264 return 0 265} 266 267func main(argc: i64, argv: *i64) -> i64 { 268 if argc < 2 { pw("usage: nx_movie_probe <file.mp4> [--quiet] | nx_movie_probe --sweep <catalog> <out.json> <max>\n" as *u8); sys_exit(2); return 2 } 269 // sweep mode 270 let a1: *u8 = argv[1] as *u8 271 if a1[0]==45 as u8 { if a1[1]==45 as u8 { if a1[2]==115 as u8 { // "--s"weep 272 if argc < 5 { pw("usage: nx_movie_probe --sweep <catalog> <out.json> <max>\n" as *u8); sys_exit(2); return 2 } 273 var mx: i64=0; var q: i64=0; let ms: *u8=argv[4] as *u8; while ms[q]!=(0 as u8){ let c: i64=ms[q] as i64; if c>=48 { if c<=57 { mx=mx*10+(c-48) } } q=q+1 } 274 let rc: i64 = mp_sweep(argv[2] as *u8, argv[3] as *u8, mx) 275 sys_exit(rc); return rc 276 } } } 277 let path: *u8 = argv[1] as *u8 278 var quiet: i64 = 0; if argc > 2 { quiet = 1 } 279 let res: *i64 = sys_mmap(32*8) as *i64 280 let v: i64 = mp_probe(path, res) 281 // seconds = dur/ts 282 var secs: i64 = 0; if res[R_TS] > 0 { secs = res[R_DUR] / res[R_TS] } 283 var kbps: i64 = 0; if secs > 0 { kbps = (res[R_SIZE] / secs) * 8 / 1000 } 284 // machine line 285 var fmt: *u8 = "none" as *u8 286 if res[R_MOOV]==1 { fmt = "mp4" as *u8 } 287 if res[R_MKV]==1 { fmt = "mkv" as *u8 } 288 if res[R_TSFMT]==1 { fmt = "ts" as *u8 } 289 if res[R_FLV]==1 { fmt = "flv" as *u8 } 290 pw("MOVIE " as *u8); pw(path); pw(" verdict=" as *u8); pw(mp_vstr(v)); pw(" fmt=" as *u8); pw(fmt) 291 pw(" dur=" as *u8); pn(secs/60); pw("m" as *u8); pn(secs%60); pw("s" as *u8) 292 pw(" res=" as *u8); pn(res[R_W]); pw("x" as *u8); pn(res[R_H]) 293 pw(" kbps=" as *u8); pn(kbps) 294 pw(" vcodec=" as *u8); mp_p4(res[R_VCC]); pw(" acodec=" as *u8); mp_p4(res[R_ACC]); pw(" tracks=" as *u8); pn(res[R_NTRAK]) 295 pw(" audio=" as *u8); pn(res[R_AUD]); pw(" chapters=" as *u8); pn(res[R_CHP]) 296 var ht: i64 = 0; if res[R_COVR]==1 { ht=1 } if res[R_POSTER]==1 { ht=1 } 297 pw(" thumb=" as *u8); pn(ht); pw(" poster=" as *u8); pn(res[R_POSTER]); pw(" faststart=" as *u8); pn(res[R_FAST]) 298 pw(" trunc=" as *u8); pn(res[R_TRUNC]); pw(" mkv=" as *u8); pn(res[R_MKV]) 299 pw("\n" as *u8) 300 sys_exit(0); return 0 301}