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}