blob: 94c8c06745c4684176783aaa157f11ee5110e633 [file]
// Copyright 2026 The Wuffs Authors.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
// --------
// RFC 6386 Section 13. DCT Coefficient Decoding.
//
// and
//
// RFC 6386 Section 13.2. Coding of Individual Coefficient Values.
pri func decoder.decode_coefficients!(
workbuf: slice base.u8,
mbx: base.u32[..= 0x3FF],
mby: base.u32[..= 0x3FF],
seg: base.u32[..= 3],
luma_mode: base.u32[..= 4]) base.u32[..= 1] {
var bc : base.u32
var by : base.u32
var bx : base.u32
var b : base.u32[..= 23]
var plane : base.u32[..= 3]
var lnz : base.u32[..= 1]
var tnz : base.u32[..= 1]
var bit : base.u32[..= 1]
this.mb_dc_nz = 0
this.mb_ac_nz = 0
this.initialize_mb_coeffs!()
// Handle "intra16x16 prediction".
plane = 3 // Plane 3: Y beginning at coefficient 0.
if args.luma_mode < 4 {
lnz = 1 & (this.mb_states_left >> 23)
this.mb_states_left &= 0xFF7F_FFFF
tnz = 1 & (this.mb_states_top[args.mbx] >> 23)
this.mb_states_top[args.mbx] &= 0xFF7F_FFFF
lnz = this.decode_subblock_coefficients!(
workbuf: args.workbuf,
mby: args.mby,
seg: args.seg,
b: 24,
plane: 1, // Plane 1: Y2.
context: lnz + tnz)
this.mb_states_top[args.mbx] |= lnz << 23
this.mb_states_left |= lnz << 23
this.inverse_wht!()
plane = 0 // Plane 0: Y beginning at coefficient 1.
}
// Parse Luma coefficients.
by = 0
while by < 4 {
lnz = 1 & (this.mb_states_left >> (24 + by))
this.mb_states_left &= 0xFFFF_FFFF ^ ((1 as base.u32) << (24 + by))
bx = 0
while bx < 4,
inv by < 4,
{
tnz = 1 & (this.mb_states_top[args.mbx] >> (24 + bx))
this.mb_states_top[args.mbx] &= 0xFFFF_FFFF ^ ((1 as base.u32) << (24 + bx))
b = (4 * by) + bx
lnz = this.decode_subblock_coefficients!(
workbuf: args.workbuf,
mby: args.mby,
seg: args.seg,
b: b,
plane: plane,
context: lnz + tnz)
bit = 0
if this.mb_coeffs[b][0] <> 0 {
bit = 1
}
this.mb_dc_nz |= bit << b
this.mb_ac_nz |= lnz << b
this.mb_states_top[args.mbx] |= lnz << (24 + bx)
bx += 1
}
this.mb_states_left |= lnz << (24 + by)
by += 1
}
// Parse Chroma coefficients.
bc = 0
while bc <= 2 {
by = 0
while by < 2,
inv bc <= 2,
{
lnz = 1 & (this.mb_states_left >> (28 + bc + by))
this.mb_states_left &= 0xFFFF_FFFF ^ ((1 as base.u32) << (28 + bc + by))
bx = 0
while bx < 2,
inv bc <= 2,
inv by < 2,
{
tnz = 1 & (this.mb_states_top[args.mbx] >> (28 + bc + bx))
this.mb_states_top[args.mbx] &= 0xFFFF_FFFF ^ ((1 as base.u32) << (28 + bc + bx))
b = (2 * bc) + (2 * by) + bx + 16
lnz = this.decode_subblock_coefficients!(
workbuf: args.workbuf,
mby: args.mby,
seg: args.seg,
b: b,
plane: 2, // Plane 2: U or V.
context: lnz + tnz)
this.mb_states_top[args.mbx] |= lnz << (28 + bc + bx)
bit = 0
if this.mb_coeffs[b][0] <> 0 {
bit = 1
}
this.mb_dc_nz |= bit << b
this.mb_ac_nz |= lnz << b
bx += 1
}
this.mb_states_left |= lnz << (28 + bc + by)
by += 1
}
bc += 2
}
if (this.mb_dc_nz == 0) and (this.mb_ac_nz == 0) {
return 1
}
return 0
}
pri func decoder.initialize_mb_coeffs!() {
var i : base.u32
var j : base.u32
i = 0
while i < 25 {
j = 0
while j < 16,
inv i < 25,
{
this.mb_coeffs[i][j] = 0
j += 1
}
i += 1
}
}
pri func decoder.decode_subblock_coefficients!(
workbuf: slice base.u8,
mby: base.u32[..= 0x3FF],
seg: base.u32[..= 3],
b: base.u32[..= 24],
plane: base.u32[..= 3],
context: base.u32[..= 2]) base.u32[..= 1] {
var q1 : base.u32[..= 2]
var q2 : base.u32[..= 1]
var quant : base.u32
var i : base.u32
var part : base.u32[..= 8]
var prob_base : base.u32[..= 1045]
var v1 : base.u32[..= 1]
var value : base.u32
q1 = 0
if args.b == 24 {
q1 = 1
} else if args.b >= 16 {
q1 = 2
}
i = 0
assert i <= 1
if args.plane == 0 {
i = 1
assert i <= 1
}
part = 1 + (args.mby & this.num_other_partitions_m1)
prob_base = (args.plane * (8 * 3 * 11)) + COEFF_BANDS_33[i] + (args.context * 11)
v1 = this.read_bit!(workbuf: args.workbuf, part: part,
prob: this.coeff_probs[prob_base + 0] as base.u32)
if v1 == 0 {
return 0
}
while true,
pre i < 16,
{
v1 = this.read_bit!(workbuf: args.workbuf, part: part,
prob: this.coeff_probs[prob_base + 1] as base.u32)
if v1 == 0 {
i += 1
if i >= 16 {
break
}
prob_base = (args.plane * (8 * 3 * 11)) + COEFF_BANDS_33[i + 0] + (0 * 11)
continue
}
v1 = this.read_bit!(workbuf: args.workbuf, part: part,
prob: this.coeff_probs[prob_base + 2] as base.u32)
if v1 == 0 {
value = 1
prob_base = (args.plane * (8 * 3 * 11)) + COEFF_BANDS_33[i + 1] + (1 * 11)
} else {
value = this.decode_large_value!(
workbuf: args.workbuf,
part: part,
prob_base: prob_base)
prob_base = (args.plane * (8 * 3 * 11)) + COEFF_BANDS_33[i + 1] + (2 * 11)
}
v1 = this.read_bit!(workbuf: args.workbuf, part: part, prob: 128)
if v1 <> 0 {
value = 0 ~mod- value
}
q2 = 0
if i <> 0 {
q2 = 1
}
quant = this.dequants[args.seg][q1][q2] as base.u32
this.mb_coeffs[args.b][ZIGZAG[i]] = ((value ~mod* quant) & 0xFFFF) as base.u16
if i >= 15 {
break
}
v1 = this.read_bit!(workbuf: args.workbuf, part: part,
prob: this.coeff_probs[prob_base + 0] as base.u32)
if v1 == 0 {
break
}
i += 1
}
return 1
}
pri func decoder.decode_large_value!(
workbuf: slice base.u8,
part: base.u32[..= 8],
prob_base: base.u32[..= 1045]) base.u32[2 ..= 2114] {
var v1 : base.u32[..= 1]
var w1 : base.u32[..= 1]
var category : base.u32[..= 3]
var value : base.u32
var i : base.u32[..= 15]
v1 = this.read_bit!(workbuf: args.workbuf, part: args.part,
prob: this.coeff_probs[args.prob_base + 3] as base.u32)
if v1 == 0 {
v1 = this.read_bit!(workbuf: args.workbuf, part: args.part,
prob: this.coeff_probs[args.prob_base + 4] as base.u32)
if v1 == 0 {
return 2
}
v1 = this.read_bit!(workbuf: args.workbuf, part: args.part,
prob: this.coeff_probs[args.prob_base + 5] as base.u32)
return 3 + v1
}
v1 = this.read_bit!(workbuf: args.workbuf, part: args.part,
prob: this.coeff_probs[args.prob_base + 6] as base.u32)
if v1 == 0 {
v1 = this.read_bit!(workbuf: args.workbuf, part: args.part,
prob: this.coeff_probs[args.prob_base + 7] as base.u32)
if v1 == 0 {
// Category 1.
v1 = this.read_bit!(workbuf: args.workbuf, part: args.part,
prob: 159)
return 5 + v1
}
// Category 2.
v1 = this.read_bit!(workbuf: args.workbuf, part: args.part,
prob: 165)
w1 = this.read_bit!(workbuf: args.workbuf, part: args.part,
prob: 145)
return 7 + (2 * v1) + w1
}
// Categories 3, 4, 5, 6.
v1 = this.read_bit!(workbuf: args.workbuf, part: args.part,
prob: this.coeff_probs[args.prob_base + 8] as base.u32)
w1 = this.read_bit!(workbuf: args.workbuf, part: args.part,
prob: this.coeff_probs[args.prob_base + 9 + v1] as base.u32)
category = (2 * v1) + w1
// Read 3, 4, 5 or 11 extra bits, depending on the category.
value = 0
i = 0
while true {
v1 = this.read_bit!(workbuf: args.workbuf, part: args.part,
prob: CATEGORY_PROBS[category][i] as base.u32)
value ~mod<<= 1
value ~mod+= v1
i = (i + 1) & 15
if CATEGORY_PROBS[category][i] == 0 {
break
}
}
return (value & 0x7FF) + ((8 as base.u32) << category) + 3
}