nx_webpprobe.nx source
↩ module page · 142 lines · 5248 B
1// nx_webpprobe.nx -- DIAGNOSTIC: which WebP variant is actually on the wire?
2//
3// Our webp_decode() searches for the VP8L (lossless) fourcc and returns 0 for anything else, so wiring it
4// in blind would fix an unknown fraction of the gap. RIFF layout: 'RIFF' <size> 'WEBP' <fourcc> -- so the
5// variant is bytes 12..15. This walks a directory and reports the split, which decides whether closing the
6// WebP gap is a WIRING job (VP8L) or a CODEC job (VP8 lossy intra).
7//
8// usage: nx_webpprobe <dir>
9
10import "nx_str.nx"
11import "nx_syscalls.nx"
12import "nx_dir.nx"
13import "nx_webp.nx"
14
15const WP_MAXROWS: i64 = 4096
16const WP_ARENA: i64 = 1048576
17const WP_PATH: i64 = 4096
18
19func wp_puts(s: *u8) -> i64 { sys_write(1, s, nx_str_len(s)); return 0 }
20
21func wp_pi(v: i64) -> i64 {
22 let t: *u8 = sys_mmap(32)
23 let o: *u8 = sys_mmap(32)
24 var m: i64 = v
25 var k: i64 = 0
26 if m < 0 { m = 0 - m; sys_write(1, "-" as *u8, 1) }
27 if m == 0 { t[0] = 48; k = 1 }
28 while m > 0 { t[k] = 48 + (m % 10); m = m / 10; k = k + 1 }
29 var i: i64 = 0
30 while i < k { o[i] = t[k - 1 - i]; i = i + 1 }
31 sys_write(1, o, k)
32 return 0
33}
34
35func wp_cat(dst: *u8, off: i64, s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { dst[off+i] = s[i]; i = i + 1 } return off + i }
36
37func wp_fourcc_is(b: *u8, off: i64, a: i64, c: i64, d: i64, e: i64) -> i64 {
38 if (b[off] as i64) != a { return 0 }
39 if (b[off+1] as i64) != c { return 0 }
40 if (b[off+2] as i64) != d { return 0 }
41 if (b[off+3] as i64) != e { return 0 }
42 return 1
43}
44
45func main(argc: i64, argv: *i64) -> i64 {
46 var dir: *u8 = "knowledge/media/julia_kyoka" as *u8
47 if argc >= 2 { dir = argv[1] as *u8 }
48
49 let rows: *NxDirRow = sys_mmap(NX_DIR_ROW_BYTES * WP_MAXROWS) as *NxDirRow
50 let arena: *u8 = sys_mmap(WP_ARENA)
51 let res: *NxDirResult = sys_mmap(NX_DIR_RESULT_BYTES) as *NxDirResult
52 let lrc: i64 = nx_dir_list(dir, rows, WP_MAXROWS, arena, WP_ARENA, 0, res)
53 wp_puts("=== nx_webpprobe dir=" as *u8); wp_puts(dir)
54 wp_puts(" entries=" as *u8); wp_pi(res.n_filled); wp_puts(" list_rc=" as *u8); wp_pi(lrc); wp_puts("\n" as *u8)
55
56 let path: *u8 = sys_mmap(WP_PATH)
57 let lenbox: *i64 = sys_mmap(16) as *i64
58 let wh: *i64 = sys_mmap(32) as *i64
59
60 var n_webp: i64 = 0
61 var n_vp8: i64 = 0
62 var n_vp8l: i64 = 0
63 var n_vp8x: i64 = 0
64 var n_other: i64 = 0
65 var n_gif: i64 = 0
66 var dec_ok: i64 = 0
67 var dec_fail: i64 = 0
68
69 var i: i64 = 0
70 while i < res.n_filled {
71 let row: *NxDirRow = nx_dir_row_at(rows, i)
72 var st: i64 = 0
73 if nx_dir_row_is_regular_file(row) != 1 { st = 1 }
74
75 if st == 0 {
76 var po: i64 = wp_cat(path, 0, dir)
77 po = wp_cat(path, po, "/" as *u8)
78 var c: i64 = 0
79 while c < row.name_len { path[po + c] = row.name_ptr[c]; c = c + 1 }
80 path[po + row.name_len] = 0 as u8
81 }
82
83 var buf: *u8 = 0 as *u8
84 if st == 0 {
85 buf = sys_read_file(path, lenbox)
86 if buf == 0 as *u8 { st = 1 }
87 }
88 if st == 0 { if lenbox[0] < 20 { st = 1 } }
89
90 // GIF87a / GIF89a
91 if st == 0 {
92 if wp_fourcc_is(buf, 0, 71, 73, 70, 56) == 1 { n_gif = n_gif + 1; st = 1 }
93 }
94
95 // RIFF ....WEBP
96 var iswebp: i64 = 0
97 if st == 0 {
98 if wp_fourcc_is(buf, 0, 82, 73, 70, 70) == 1 {
99 if wp_fourcc_is(buf, 8, 87, 69, 66, 80) == 1 { iswebp = 1 }
100 }
101 if iswebp == 0 { st = 1 }
102 }
103
104 if st == 0 {
105 n_webp = n_webp + 1
106 var kind: *u8 = "OTHER" as *u8
107 if wp_fourcc_is(buf, 12, 86, 80, 56, 76) == 1 { kind = "VP8L" as *u8; n_vp8l = n_vp8l + 1 }
108 else { if wp_fourcc_is(buf, 12, 86, 80, 56, 88) == 1 { kind = "VP8X" as *u8; n_vp8x = n_vp8x + 1 }
109 else { if wp_fourcc_is(buf, 12, 86, 80, 56, 32) == 1 { kind = "VP8 " as *u8; n_vp8 = n_vp8 + 1 }
110 else { n_other = n_other + 1 } } }
111
112 wh[0] = 0
113 wh[1] = 0
114 let argb: *i64 = webp_decode(buf, lenbox[0], wh)
115 var ok: i64 = 0
116 if argb != 0 as *i64 { if wh[0] > 0 { ok = 1 } }
117 if ok == 1 { dec_ok = dec_ok + 1 } else { dec_fail = dec_fail + 1 }
118
119 wp_puts(" " as *u8); wp_puts(kind)
120 wp_puts(" decode=" as *u8); wp_pi(ok)
121 wp_puts(" w=" as *u8); wp_pi(wh[0])
122 wp_puts(" h=" as *u8); wp_pi(wh[1])
123 wp_puts(" bytes=" as *u8); wp_pi(lenbox[0])
124 wp_puts(" " as *u8); sys_write(1, row.name_ptr, row.name_len); wp_puts("\n" as *u8)
125 }
126
127 i = i + 1
128 }
129
130 wp_puts("{\"tool\":\"nx_webpprobe\",\"entries\":" as *u8); wp_pi(res.n_filled)
131 wp_puts(",\"webp\":" as *u8); wp_pi(n_webp)
132 wp_puts(",\"vp8l_lossless\":" as *u8); wp_pi(n_vp8l)
133 wp_puts(",\"vp8_lossy\":" as *u8); wp_pi(n_vp8)
134 wp_puts(",\"vp8x_extended\":" as *u8); wp_pi(n_vp8x)
135 wp_puts(",\"other_fourcc\":" as *u8); wp_pi(n_other)
136 wp_puts(",\"gif\":" as *u8); wp_pi(n_gif)
137 wp_puts(",\"webp_decode_ok\":" as *u8); wp_pi(dec_ok)
138 wp_puts(",\"webp_decode_fail\":" as *u8); wp_pi(dec_fail)
139 wp_puts("}\nWEBPPROBE-OK\n" as *u8)
140 sys_exit(0)
141 return 0
142}