code wiki / (root) / nx_vp8_kf.nx

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}