nx_vp8_kf.nx source
↩ module page · 589 lines · 22501 B
1// nx_vp8_kf.nx -- VP8 lossy KEYFRAME decoder (intra-only): the C3 rung.
2//
3// Entropy half + driver. Bitstream order and all probability plumbing ported
4// against RFC 6386 reference decoder (dixie.c / modemv.c / tokens.c):
5// partition-1 header: colorspace(2b, must be 0) -> segmentation ->
6// loopfilter (parsed, v1 does not filter) -> token partition count+sizes ->
7// quantizer -> refresh_entropy -> 1056 coeff prob updates -> skip prob.
8// Then one mode pass over all MBs (partition 1), then per-row token decode
9// (partitions cycle by row) + reconstruction.
10//
11// THE LOOP FILTER IS DELIBERATELY ABSENT (fingerprint-grade output): it
12// smooths block edges for display but does not feed back into intra
13// prediction of the same frame, so omitting it perturbs pixels only locally.
14// The gate bounds the perturbation against an independent oracle.
15//
16// TOKEN CONTEXT RULES (the three easy-to-lose ones, from tokens.c):
17// - EOB is NOT tested for the token following a ZERO token.
18// - After a token, the next context is 0/1/2 for zero/one/bigger.
19// - A skipped MB zeroes its left+above contexts EXCEPT Y2 when the mode
20// has no Y2 block (B_PRED), which PRESERVES the stored Y2 context.
21//
22// genealogy_id: vp8_rfc6386
23// lineage_id: nx_vp8_kf_v1
24// license_tier: ORIGINAL
25
26import "nx_syscalls.nx"
27import "nx_vp8.nx"
28import "nx_vp8_tables.nx"
29import "nx_vp8_pred.nx"
30const NX_MAGIC_1056: i64 = 1056
31
32// out box slots
33const NX_VP8KF_OUT_Y: i64 = 0
34const NX_VP8KF_OUT_U: i64 = 1
35const NX_VP8KF_OUT_V: i64 = 2
36const NX_VP8KF_OUT_W: i64 = 3
37const NX_VP8KF_OUT_H: i64 = 4
38const NX_VP8KF_OUT_YS: i64 = 5
39const NX_VP8KF_OUT_UVS: i64 = 6
40
41// small-table arena slots (i64 entries)
42const NX_VP8KF_BANDS: i64 = 0
43const NX_VP8KF_ZZ: i64 = 16
44const NX_VP8KF_LIDX: i64 = 32
45const NX_VP8KF_AIDX: i64 = 57
46const NX_VP8KF_TREE: i64 = 82
47const NX_VP8KF_CATB: i64 = 100
48const NX_VP8KF_CATL: i64 = 107
49const NX_VP8KF_CATP: i64 = 120
50const NX_VP8KF_AR_N: i64 = 200
51
52func vp8kf_arena() -> *i64 {
53 let ar: *i64 = sys_mmap(NX_VP8KF_AR_N * 8 + 64) as *i64
54 // coefficient bands per position
55 ar[0]=0; ar[1]=1; ar[2]=2; ar[3]=3; ar[4]=6; ar[5]=4; ar[6]=5; ar[7]=6
56 ar[8]=6; ar[9]=6; ar[10]=6; ar[11]=6; ar[12]=6; ar[13]=6; ar[14]=6; ar[15]=7
57 // zigzag
58 ar[16]=0; ar[17]=1; ar[18]=4; ar[19]=8; ar[20]=5; ar[21]=2; ar[22]=3; ar[23]=6
59 ar[24]=9; ar[25]=12; ar[26]=13; ar[27]=10; ar[28]=7; ar[29]=11; ar[30]=14; ar[31]=15
60 // left context index per block 0..24
61 ar[32]=0; ar[33]=0; ar[34]=0; ar[35]=0; ar[36]=1; ar[37]=1; ar[38]=1; ar[39]=1
62 ar[40]=2; ar[41]=2; ar[42]=2; ar[43]=2; ar[44]=3; ar[45]=3; ar[46]=3; ar[47]=3
63 ar[48]=4; ar[49]=4; ar[50]=5; ar[51]=5; ar[52]=6; ar[53]=6; ar[54]=7; ar[55]=7
64 ar[56]=8
65 // above context index per block 0..24
66 ar[57]=0; ar[58]=1; ar[59]=2; ar[60]=3; ar[61]=0; ar[62]=1; ar[63]=2; ar[64]=3
67 ar[65]=0; ar[66]=1; ar[67]=2; ar[68]=3; ar[69]=0; ar[70]=1; ar[71]=2; ar[72]=3
68 ar[73]=4; ar[74]=5; ar[75]=4; ar[76]=5; ar[77]=6; ar[78]=7; ar[79]=6; ar[80]=7
69 ar[81]=8
70 // b_mode_tree (RFC modemv_data.h), leaves negated mode ids
71 ar[82]=0; ar[83]=2; ar[84]=0-1; ar[85]=4; ar[86]=0-2; ar[87]=6
72 ar[88]=8; ar[89]=12; ar[90]=0-3; ar[91]=10; ar[92]=0-5; ar[93]=0-6
73 ar[94]=0-4; ar[95]=14; ar[96]=0-7; ar[97]=16; ar[98]=0-8; ar[99]=0-9
74 // DCT category bases and top extra-bit index (index by category 1..6)
75 ar[100]=0; ar[101]=5; ar[102]=7; ar[103]=11; ar[104]=19; ar[105]=35; ar[106]=67
76 ar[107]=0; ar[108]=0; ar[109]=1; ar[110]=2; ar[111]=3; ar[112]=4; ar[113]=10
77 // category extra-bit probs at 120+cat*12+bitpos (read from top bit down)
78 ar[120+12]=159
79 ar[120+24]=145; ar[120+25]=165
80 ar[120+36]=140; ar[120+37]=148; ar[120+38]=173
81 ar[120+48]=135; ar[120+49]=140; ar[120+50]=155; ar[120+51]=176
82 ar[120+60]=130; ar[120+61]=134; ar[120+62]=141; ar[120+63]=157; ar[120+64]=180
83 ar[120+72]=129; ar[120+73]=130; ar[120+74]=133; ar[120+75]=140; ar[120+76]=153
84 ar[120+77]=177; ar[120+78]=196; ar[120+79]=230; ar[120+80]=243; ar[120+81]=254
85 ar[120+82]=254
86 return ar
87}
88
89// the 4x4 subblock mode tree in its own allocation (indexed, never offset)
90func vp8kf_btree() -> *i64 {
91 let t: *i64 = sys_mmap(18 * 8 + 64) as *i64
92 t[0]=0; t[1]=2; t[2]=0-1; t[3]=4; t[4]=0-2; t[5]=6
93 t[6]=8; t[7]=12; t[8]=0-3; t[9]=10; t[10]=0-5; t[11]=0-6
94 t[12]=0-4; t[13]=14; t[14]=0-7; t[15]=16; t[16]=0-8; t[17]=0-9
95 return t
96}
97
98// generic tree read (RFC 8.1 semantics; leaves are negated values)
99func vp8kf_tree_read(bd: *NxVp8Bool, tree: *i64, probs: *u8) -> i64 {
100 var i: i64 = tree[nx_vp8_bool_get(bd, (probs[0] as i64) & 255)]
101 while i > 0 {
102 i = tree[i + nx_vp8_bool_get(bd, (probs[i >> 1] as i64) & 255)]
103 }
104 return 0 - i
105}
106
107// kf_y_mode_tree {-B_PRED,2,4,6,-DC,-V,-H,-TM} probs {145,156,163,128}
108// returns 0=DC 1=V 2=H 3=TM 4=B_PRED
109func vp8kf_read_ymode(bd: *NxVp8Bool) -> i64 {
110 if nx_vp8_bool_get(bd, 145) == 0 { return 4 }
111 if nx_vp8_bool_get(bd, 156) == 0 {
112 if nx_vp8_bool_get(bd, 163) == 0 { return 0 }
113 return 1
114 }
115 if nx_vp8_bool_get(bd, 128) == 0 { return 2 }
116 return 3
117}
118
119// uv_mode_tree {-DC,2,-V,4,-H,-TM} probs {142,114,183}
120func vp8kf_read_uvmode(bd: *NxVp8Bool) -> i64 {
121 if nx_vp8_bool_get(bd, 142) == 0 { return 0 }
122 if nx_vp8_bool_get(bd, 114) == 0 { return 1 }
123 if nx_vp8_bool_get(bd, 183) == 0 { return 2 }
124 return 3
125}
126
127func vp8kf_read_segid(bd: *NxVp8Bool, tp: *u8) -> i64 {
128 if nx_vp8_bool_get(bd, (tp[0] as i64) & 255) == 1 {
129 return 2 + nx_vp8_bool_get(bd, (tp[2] as i64) & 255)
130 }
131 return nx_vp8_bool_get(bd, (tp[1] as i64) & 255)
132}
133
134// implied subblock mode of a non-B_PRED macroblock, for bmode context
135func vp8kf_implied_b(ymode: i64) -> i64 {
136 if ymode == 1 { return 2 }
137 if ymode == 2 { return 3 }
138 if ymode == 3 { return 1 }
139 return 0
140}
141
142// ===== one 4x4 coefficient block ==================================
143// tp: runtime coeff probs (4*8*3*11 bytes); toff: type*264.
144// Returns the final position c; (c != firstc) means the block has data.
145
146func vp8kf_decode_block(bd: *NxVp8Bool, tp: *u8, toff: i64, ctx0: i64,
147 firstc: i64, dqdc: i64, dqac: i64,
148 ar: *i64, cf: *i64, cfb: i64) -> i64 {
149 var c: i64 = firstc
150 var cx: i64 = ctx0
151 var check: i64 = 1
152 var go: i64 = 1
153 while go == 1 {
154 if c > 15 { go = 0 } else {
155 let po: i64 = toff + ar[NX_VP8KF_BANDS + c]*33 + cx*11
156 var fin: i64 = 0
157 if check == 1 {
158 if nx_vp8_bool_get(bd, (tp[po] as i64) & 255) == 0 { go = 0; fin = 1 }
159 }
160 if fin == 0 {
161 if nx_vp8_bool_get(bd, (tp[po+1] as i64) & 255) == 0 {
162 // ZERO token: advance, context 0, and no EOB test next
163 cx = 0
164 check = 0
165 c = c + 1
166 if c > 15 { go = 0 }
167 } else {
168 var val: i64 = 0
169 if nx_vp8_bool_get(bd, (tp[po+2] as i64) & 255) == 0 {
170 val = 1
171 cx = 1
172 } else {
173 cx = 2
174 if nx_vp8_bool_get(bd, (tp[po+3] as i64) & 255) == 0 {
175 if nx_vp8_bool_get(bd, (tp[po+4] as i64) & 255) == 0 { val = 2 } else {
176 if nx_vp8_bool_get(bd, (tp[po+5] as i64) & 255) == 0 { val = 3 } else { val = 4 }
177 }
178 } else {
179 var cat: i64 = 0
180 if nx_vp8_bool_get(bd, (tp[po+6] as i64) & 255) == 0 {
181 if nx_vp8_bool_get(bd, (tp[po+7] as i64) & 255) == 0 { cat = 1 } else { cat = 2 }
182 } else {
183 if nx_vp8_bool_get(bd, (tp[po+8] as i64) & 255) == 0 {
184 if nx_vp8_bool_get(bd, (tp[po+9] as i64) & 255) == 0 { cat = 3 } else { cat = 4 }
185 } else {
186 if nx_vp8_bool_get(bd, (tp[po+10] as i64) & 255) == 0 { cat = 5 } else { cat = 6 }
187 }
188 }
189 val = ar[NX_VP8KF_CATB + cat]
190 var bi: i64 = ar[NX_VP8KF_CATL + cat]
191 while bi >= 0 {
192 val = val + (nx_vp8_bool_get(bd, ar[NX_VP8KF_CATP + cat*12 + bi]) << bi)
193 bi = bi - 1
194 }
195 }
196 }
197 var v: i64 = val
198 if nx_vp8_bool_bit(bd) == 1 { v = 0 - val }
199 var q: i64 = dqac
200 if c == 0 { q = dqdc }
201 cf[cfb + ar[NX_VP8KF_ZZ + c]] = v * q
202 c = c + 1
203 check = 1
204 }
205 }
206 }
207 }
208 return c
209}
210
211// ===== all 24/25 blocks of one macroblock =========================
212// lctx: 9 bytes (this partition's row-left contexts)
213// actx: 9 bytes (this column's above contexts)
214// dq: 6 factors y1dc,y1ac,y2dc,y2ac,uvdc,uvac
215
216func vp8kf_mb_tokens(bd: *NxVp8Bool, tp: *u8, has_y2: i64,
217 lctx: *u8, actx: *u8, cf: *i64, ar: *i64,
218 dq: *i64, dqb: i64) -> i64 {
219 if has_y2 == 1 {
220 let t24: i64 = ((lctx[8] as i64) & 255) + ((actx[8] as i64) & 255)
221 let ce: i64 = vp8kf_decode_block(bd, tp, 264, t24, 0, dq[dqb+2], dq[dqb+3], ar, cf, 384)
222 var had: i64 = 0
223 if ce != 0 { had = 1 }
224 lctx[8] = had as u8
225 actx[8] = had as u8
226 }
227 var toff: i64 = 792
228 var firstc: i64 = 0
229 if has_y2 == 1 { toff = 0; firstc = 1 }
230 var b: i64 = 0
231 while b < 16 {
232 let li: i64 = ar[NX_VP8KF_LIDX + b]
233 let ai: i64 = ar[NX_VP8KF_AIDX + b]
234 let t: i64 = ((lctx[li] as i64) & 255) + ((actx[ai] as i64) & 255)
235 let ce: i64 = vp8kf_decode_block(bd, tp, toff, t, firstc, dq[dqb], dq[dqb+1], ar, cf, b*16)
236 var had: i64 = 0
237 if ce != firstc { had = 1 }
238 lctx[li] = had as u8
239 actx[ai] = had as u8
240 b = b + 1
241 }
242 b = 16
243 while b < 24 {
244 let li: i64 = ar[NX_VP8KF_LIDX + b]
245 let ai: i64 = ar[NX_VP8KF_AIDX + b]
246 let t: i64 = ((lctx[li] as i64) & 255) + ((actx[ai] as i64) & 255)
247 let ce: i64 = vp8kf_decode_block(bd, tp, 528, t, 0, dq[dqb+4], dq[dqb+5], ar, cf, b*16)
248 var had: i64 = 0
249 if ce != 0 { had = 1 }
250 lctx[li] = had as u8
251 actx[ai] = had as u8
252 b = b + 1
253 }
254 return 0
255}
256
257// skipped MB: zero contexts, except Y2 stays when the mode has no Y2
258func vp8kf_skip_ctx(lctx: *u8, actx: *u8, has_y2: i64) -> i64 {
259 var i: i64 = 0
260 while i < 8 { lctx[i] = 0 as u8; actx[i] = 0 as u8; i = i + 1 }
261 if has_y2 == 1 { lctx[8] = 0 as u8; actx[8] = 0 as u8 }
262 return 0
263}
264
265// ===== the keyframe decoder =======================================
266// Returns 1 and fills outp (Y/U/V plane pointers + dims + strides), or 0.
267
268func nx_vp8_kf_decode(raw: *u8, n: i64, outp: *i64) -> i64 {
269 let fld: *i64 = sys_mmap(80) as *i64
270 if nx_vp8_frame_parse(raw, n, fld) == 0 { return 0 }
271 if fld[NX_VP8_FLD_KEYFRAME] != 1 { return 0 }
272 let w: i64 = fld[NX_VP8_FLD_WIDTH]
273 let h: i64 = fld[NX_VP8_FLD_HEIGHT]
274 let part0: i64 = fld[NX_VP8_FLD_PART1LEN]
275 if part0 <= 0 { return 0 }
276 if 10 + part0 > n { return 0 }
277 let mbw: i64 = (w + 15) >> 4
278 let mbh: i64 = (h + 15) >> 4
279
280 let bd: *NxVp8Bool = nx_vp8_bool_init(raw, 10 + part0, 10)
281 if bd == (0 as *NxVp8Bool) { return 0 }
282
283 // colorspace + clamping: reference refuses nonzero
284 if nx_vp8_bool_literal(bd, 2) != 0 { return 0 }
285
286 // ---- segmentation header ----
287 var seg_en: i64 = 0
288 var seg_upd_map: i64 = 0
289 var seg_abs: i64 = 0
290 let seg_q: *i64 = sys_mmap(64) as *i64
291 let seg_tp: *u8 = sys_mmap(16)
292 seg_tp[0] = 255 as u8
293 seg_tp[1] = 255 as u8
294 seg_tp[2] = 255 as u8
295 seg_en = nx_vp8_bool_bit(bd)
296 if seg_en == 1 {
297 seg_upd_map = nx_vp8_bool_bit(bd)
298 let upd_data: i64 = nx_vp8_bool_bit(bd)
299 if upd_data == 1 {
300 seg_abs = nx_vp8_bool_bit(bd)
301 var i: i64 = 0
302 while i < 4 { seg_q[i] = nx_vp8_bool_maybe_signed(bd, 7); i = i + 1 }
303 i = 0
304 while i < 4 { nx_vp8_bool_maybe_signed(bd, 6); i = i + 1 }
305 }
306 if seg_upd_map == 1 {
307 var i: i64 = 0
308 while i < 3 {
309 if nx_vp8_bool_bit(bd) == 1 { seg_tp[i] = nx_vp8_bool_literal(bd, 8) as u8 }
310 i = i + 1
311 }
312 }
313 }
314
315 // ---- loop filter header (parsed; v1 does not filter) ----
316 nx_vp8_bool_bit(bd)
317 nx_vp8_bool_literal(bd, 6)
318 nx_vp8_bool_literal(bd, 3)
319 if nx_vp8_bool_bit(bd) == 1 {
320 if nx_vp8_bool_bit(bd) == 1 {
321 var i: i64 = 0
322 while i < 4 { nx_vp8_bool_maybe_signed(bd, 6); i = i + 1 }
323 i = 0
324 while i < 4 { nx_vp8_bool_maybe_signed(bd, 6); i = i + 1 }
325 }
326 }
327
328 // ---- token partitions ----
329 let nparts: i64 = 1 << nx_vp8_bool_literal(bd, 2)
330 let pbase: i64 = 10 + part0
331 let sztab: i64 = 3 * (nparts - 1)
332 if pbase + sztab > n { return 0 }
333 let pdec: *i64 = sys_mmap(8 * 8 + 64) as *i64
334 var cursor: i64 = pbase + sztab
335 var pi: i64 = 0
336 var pok: i64 = 1
337 while pi < nparts {
338 var psz: i64 = n - cursor
339 if pi < nparts - 1 {
340 let so: i64 = pbase + pi*3
341 psz = ((raw[so] as i64) & 255) | (((raw[so+1] as i64) & 255) << 8) | (((raw[so+2] as i64) & 255) << 16)
342 }
343 if psz < 2 { pok = 0 }
344 if cursor + psz > n { pok = 0 }
345 if pok == 1 {
346 let pb: *NxVp8Bool = nx_vp8_bool_init(raw, cursor + psz, cursor)
347 if pb == (0 as *NxVp8Bool) { pok = 0 } else { pdec[pi] = pb as i64 }
348 }
349 cursor = cursor + psz
350 pi = pi + 1
351 }
352 if pok == 0 { return 0 }
353
354 // ---- quantizer header ----
355 let qi: i64 = nx_vp8_bool_literal(bd, 7)
356 let dq_y1dc: i64 = nx_vp8_bool_maybe_signed(bd, 4)
357 let dq_y2dc: i64 = nx_vp8_bool_maybe_signed(bd, 4)
358 let dq_y2ac: i64 = nx_vp8_bool_maybe_signed(bd, 4)
359 let dq_uvdc: i64 = nx_vp8_bool_maybe_signed(bd, 4)
360 let dq_uvac: i64 = nx_vp8_bool_maybe_signed(bd, 4)
361
362 // refresh_entropy (keyframe reference header reads exactly this one bit)
363 nx_vp8_bool_bit(bd)
364
365 // ---- coefficient probabilities: defaults + transmitted updates ----
366 let tabs_dcq: *u8 = sys_mmap(NX_VP8T_DCQ_BYTES + 64)
367 let tabs_acq: *u8 = sys_mmap(NX_VP8T_ACQ_BYTES + 64)
368 let tabs_kfb: *u8 = sys_mmap(NX_VP8T_KFB_BYTES + 64)
369 let tabs_cup: *u8 = sys_mmap(NX_VP8T_CUP_BYTES + 64)
370 let tp: *u8 = sys_mmap(NX_VP8T_CDP_BYTES + 64)
371 vp8t_fill_dcq(tabs_dcq)
372 vp8t_fill_acq(tabs_acq)
373 vp8t_fill_kfb(tabs_kfb)
374 vp8t_fill_cup(tabs_cup)
375 vp8t_fill_cdp(tp)
376 var ui: i64 = 0
377 while ui < NX_MAGIC_1056 {
378 if nx_vp8_bool_get(bd, (tabs_cup[ui] as i64) & 255) == 1 {
379 tp[ui] = nx_vp8_bool_literal(bd, 8) as u8
380 }
381 ui = ui + 1
382 }
383
384 // ---- macroblock skip probability ----
385 let skip_en: i64 = nx_vp8_bool_bit(bd)
386 var skip_prob: i64 = 0
387 if skip_en == 1 { skip_prob = nx_vp8_bool_literal(bd, 8) }
388
389 // the header must not have consumed past its partition
390 if bd.overflow != 0 { return 0 }
391
392 // ---- dequantization factors per segment ----
393 let dqf: *i64 = sys_mmap(4 * 6 * 8 + 64) as *i64
394 var s: i64 = 0
395 while s < 4 {
396 var q: i64 = qi
397 if seg_en == 1 {
398 if seg_abs == 1 { q = seg_q[s] } else { q = qi + seg_q[s] }
399 }
400 var qc: i64 = q + dq_y1dc
401 if qc < 0 { qc = 0 }
402 if qc > 127 { qc = 127 }
403 dqf[s*6] = vp8t_u16(tabs_dcq, qc)
404 qc = q
405 if qc < 0 { qc = 0 }
406 if qc > 127 { qc = 127 }
407 dqf[s*6+1] = vp8t_u16(tabs_acq, qc)
408 qc = q + dq_y2dc
409 if qc < 0 { qc = 0 }
410 if qc > 127 { qc = 127 }
411 dqf[s*6+2] = vp8t_u16(tabs_dcq, qc) * 2
412 qc = q + dq_y2ac
413 if qc < 0 { qc = 0 }
414 if qc > 127 { qc = 127 }
415 var y2ac: i64 = (vp8t_u16(tabs_acq, qc) * 155) / 100
416 if y2ac < 8 { y2ac = 8 }
417 dqf[s*6+3] = y2ac
418 qc = q + dq_uvdc
419 if qc < 0 { qc = 0 }
420 if qc > 127 { qc = 127 }
421 var uvdc: i64 = vp8t_u16(tabs_dcq, qc)
422 if uvdc > 132 { uvdc = 132 }
423 dqf[s*6+4] = uvdc
424 qc = q + dq_uvac
425 if qc < 0 { qc = 0 }
426 if qc > 127 { qc = 127 }
427 dqf[s*6+5] = vp8t_u16(tabs_acq, qc)
428 s = s + 1
429 }
430
431 // ---- MB info grids ((mbh+1) x (mbw+1), origin at +1,+1) ----
432 let gw: i64 = mbw + 1
433 let gn: i64 = (mbh + 1) * gw
434 let g_ym: *u8 = sys_mmap(gn + 64)
435 let g_uv: *u8 = sys_mmap(gn + 64)
436 let g_seg: *u8 = sys_mmap(gn + 64)
437 let g_skip: *u8 = sys_mmap(gn + 64)
438 let g_bm: *u8 = sys_mmap(gn * 16 + 64)
439 // zero the border row and column explicitly (DC_PRED / B_DC_PRED)
440 var zi: i64 = 0
441 while zi < gw {
442 g_ym[zi] = 0 as u8
443 var zb: i64 = 0
444 while zb < 16 { g_bm[zi*16+zb] = 0 as u8; zb = zb + 1 }
445 zi = zi + 1
446 }
447 zi = 0
448 while zi < mbh + 1 {
449 g_ym[zi*gw] = 0 as u8
450 var zb: i64 = 0
451 while zb < 16 { g_bm[(zi*gw)*16+zb] = 0 as u8; zb = zb + 1 }
452 zi = zi + 1
453 }
454
455 let ar: *i64 = vp8kf_arena()
456 let btree: *i64 = vp8kf_btree()
457
458 // ---- pass 1: modes for every MB, from partition 1 ----
459 var r: i64 = 0
460 while r < mbh {
461 var c: i64 = 0
462 while c < mbw {
463 let gi: i64 = (r+1)*gw + (c+1)
464 var sid: i64 = 0
465 if seg_upd_map == 1 { sid = vp8kf_read_segid(bd, seg_tp) }
466 g_seg[gi] = sid as u8
467 var sk: i64 = 0
468 if skip_en == 1 { sk = nx_vp8_bool_get(bd, skip_prob) }
469 g_skip[gi] = sk as u8
470 let ym: i64 = vp8kf_read_ymode(bd)
471 g_ym[gi] = ym as u8
472 if ym == 4 {
473 let agi: i64 = r*gw + (c+1)
474 let lgi: i64 = (r+1)*gw + c
475 var b: i64 = 0
476 while b < 16 {
477 var am: i64 = 0
478 if b < 4 {
479 am = (g_bm[agi*16 + b + 12] as i64) & 255
480 } else {
481 am = (g_bm[gi*16 + b - 4] as i64) & 255
482 }
483 var lm: i64 = 0
484 if (b & 3) == 0 {
485 lm = (g_bm[lgi*16 + b + 3] as i64) & 255
486 } else {
487 lm = (g_bm[gi*16 + b - 1] as i64) & 255
488 }
489 let bm: i64 = vp8kf_tree_read(bd, btree, tabs_kfb + (am*10 + lm)*9)
490 g_bm[gi*16 + b] = bm as u8
491 b = b + 1
492 }
493 } else {
494 let ib: i64 = vp8kf_implied_b(ym)
495 var b: i64 = 0
496 while b < 16 { g_bm[gi*16 + b] = ib as u8; b = b + 1 }
497 }
498 g_uv[gi] = vp8kf_read_uvmode(bd) as u8
499 c = c + 1
500 }
501 r = r + 1
502 }
503
504 // ---- frame planes with borders (left/top 16, right 16; chroma 8) ----
505 let ys: i64 = 16 + mbw*16 + 16
506 let yh: i64 = 16 + mbh*16
507 let uvs: i64 = 8 + mbw*8 + 16
508 let uvh: i64 = 8 + mbh*8
509 let py: *u8 = sys_mmap(ys*yh + 64)
510 let pu: *u8 = sys_mmap(uvs*uvh + 64)
511 let pv: *u8 = sys_mmap(uvs*uvh + 64)
512 let yo: i64 = 16*ys + 16
513 let uvo: i64 = 8*uvs + 8
514
515 // ---- pass 2: tokens + reconstruction, row by row ----
516 let actx: *u8 = sys_mmap(mbw*9 + 64)
517 var az: i64 = 0
518 while az < mbw*9 { actx[az] = 0 as u8; az = az + 1 }
519 let lctx: *u8 = sys_mmap(16)
520 let cf: *i64 = sys_mmap(400 * 8 + 64) as *i64
521 let tmp: *i64 = sys_mmap(16 * 8 + 64) as *i64
522 let y2t: *i64 = sys_mmap(16 * 8 + 64) as *i64
523
524 r = 0
525 while r < mbh {
526 let tbd: *NxVp8Bool = pdec[r % nparts] as *NxVp8Bool
527 var li: i64 = 0
528 while li < 9 { lctx[li] = 0 as u8; li = li + 1 }
529
530 // left-edge fixup uses the first MB's modes
531 let gi0: i64 = (r+1)*gw + 1
532 vp8p_fixup_left(py, yo + r*16*ys, 16, ys, r, (g_ym[gi0] as i64) & 255)
533 vp8p_fixup_left(pu, uvo + r*8*uvs, 8, uvs, r, (g_uv[gi0] as i64) & 255)
534 vp8p_fixup_left(pv, uvo + r*8*uvs, 8, uvs, r, (g_uv[gi0] as i64) & 255)
535 if r == 0 { py[yo - ys - 1] = 127 as u8 }
536
537 var c: i64 = 0
538 while c < mbw {
539 let gi: i64 = (r+1)*gw + (c+1)
540 let ym: i64 = (g_ym[gi] as i64) & 255
541 let uvm: i64 = (g_uv[gi] as i64) & 255
542 var has_y2: i64 = 1
543 if ym == 4 { has_y2 = 0 }
544
545 // zero this MB's coefficients
546 var k: i64 = 0
547 while k < 400 { cf[k] = 0; k = k + 1 }
548
549 if ((g_skip[gi] as i64) & 255) == 1 {
550 vp8kf_skip_ctx(lctx, actx + c*9, has_y2)
551 } else {
552 vp8kf_mb_tokens(tbd, tp, has_y2, lctx, actx + c*9, cf, ar,
553 dqf, ((g_seg[gi] as i64) & 255) * 6)
554 }
555
556 let yoff: i64 = yo + r*16*ys + c*16
557 let uoff: i64 = uvo + r*8*uvs + c*8
558 if r == 0 {
559 vp8p_fixup_above(py, yoff, 16, ys, c, ym)
560 vp8p_fixup_above(pu, uoff, 8, uvs, c, uvm)
561 vp8p_fixup_above(pv, uoff, 8, uvs, c, uvm)
562 }
563
564 if has_y2 == 1 {
565 vp8p_walsh(cf, 384, y2t)
566 var d: i64 = 0
567 while d < 16 { cf[d*16] = y2t[d]; d = d + 1 }
568 }
569 vp8p_recon_luma(py, yoff, ys, ym, g_bm + gi*16, cf, tmp)
570 vp8p_recon_chroma(pu, uoff, pv, uoff, uvs, uvm, cf, tmp)
571 c = c + 1
572 }
573
574 // extend the row's last pixel row 4px right, for above-right prediction
575 let ext: i64 = yo + r*16*ys + mbw*16 + 15*ys
576 let ev: u8 = py[ext - 1]
577 py[ext] = ev; py[ext+1] = ev; py[ext+2] = ev; py[ext+3] = ev
578 r = r + 1
579 }
580
581 outp[NX_VP8KF_OUT_Y] = (py as i64) + yo
582 outp[NX_VP8KF_OUT_U] = (pu as i64) + uvo
583 outp[NX_VP8KF_OUT_V] = (pv as i64) + uvo
584 outp[NX_VP8KF_OUT_W] = w
585 outp[NX_VP8KF_OUT_H] = h
586 outp[NX_VP8KF_OUT_YS] = ys
587 outp[NX_VP8KF_OUT_UVS] = uvs
588 return 1
589}