init: 自 zomaintain/backend/rdplib 平移独立成库; module path 从上游 github.com/nakagami/grdp 改为 git.zeroonesoft.cn/golib/rdplib
This commit is contained in:
@@ -0,0 +1,452 @@
|
||||
package rdpgfx
|
||||
|
||||
// RLGR1/RLGR3 (Run-Length Golomb-Rice) decoder for RFX codec.
|
||||
// Reference: MS-RDPRFX 3.1.8.1.7.3 RLGR1/RLGR3 Pseudocode
|
||||
// Matches FreeRDP's rfx_rlgr.c implementation.
|
||||
|
||||
import "math/bits"
|
||||
|
||||
const (
|
||||
rlgrLSGR = 3 // shift count to convert kp to k
|
||||
rlgrKPMax = 80 // max value for kp or krp
|
||||
rlgrUPGR = 4 // increase in kp after a zero run in RL mode
|
||||
rlgrDNGR = 6 // decrease in kp after a nonzero symbol in RL mode
|
||||
rlgrUQGR = 3 // increase in kp after zero symbol in GR mode
|
||||
rlgrDQGR = 3 // decrease in kp after nonzero symbol in GR mode
|
||||
)
|
||||
|
||||
// rlgr1Decode decodes RLGR1-encoded data into signed 16-bit DWT coefficients.
|
||||
// If dst is non-nil and has sufficient capacity, it is reused (zeroed first).
|
||||
func rlgr1Decode(data []byte, outputSize int, dst []int16) []int16 {
|
||||
var output []int16
|
||||
if cap(dst) >= outputSize {
|
||||
output = dst[:outputSize]
|
||||
clear(output)
|
||||
} else {
|
||||
output = make([]int16, outputSize)
|
||||
}
|
||||
br := &rlgrBitReader{data: data}
|
||||
cnt := 0
|
||||
|
||||
k := uint32(1)
|
||||
kp := uint32(1 << rlgrLSGR) // 8
|
||||
kr := uint32(1)
|
||||
krp := uint32(1 << rlgrLSGR) // 8
|
||||
|
||||
for br.remaining() > 0 && cnt < outputSize {
|
||||
if k > 0 {
|
||||
// RL (Run-Length) Mode
|
||||
|
||||
// Count leading 0-bits → number of full run groups
|
||||
vk := br.countLeadingZeros()
|
||||
|
||||
// Each leading 0 adds (1 << k) to run, with k adapting upward
|
||||
run := uint32(0)
|
||||
for range vk {
|
||||
run += 1 << k
|
||||
kp += rlgrUPGR
|
||||
if kp > rlgrKPMax {
|
||||
kp = rlgrKPMax
|
||||
}
|
||||
k = kp >> rlgrLSGR
|
||||
}
|
||||
|
||||
// Read k bits for run remainder
|
||||
if k > 0 {
|
||||
run += br.readBits(int(k))
|
||||
}
|
||||
|
||||
// Read sign bit for the non-zero value
|
||||
sign := br.readBits(1)
|
||||
|
||||
// Decode non-zero magnitude using GR code with leading 1-bits
|
||||
vk2 := br.countLeadingOnes()
|
||||
|
||||
// Read kr bits for code remainder
|
||||
code := uint32(0)
|
||||
if kr > 0 {
|
||||
code = br.readBits(int(kr))
|
||||
}
|
||||
code |= vk2 << kr
|
||||
|
||||
// Update kr/krp
|
||||
if vk2 == 0 {
|
||||
if krp > 2 {
|
||||
krp -= 2
|
||||
} else {
|
||||
krp = 0
|
||||
}
|
||||
kr = krp >> rlgrLSGR
|
||||
} else if vk2 != 1 {
|
||||
krp += vk2
|
||||
if krp > rlgrKPMax {
|
||||
krp = rlgrKPMax
|
||||
}
|
||||
kr = krp >> rlgrLSGR
|
||||
}
|
||||
|
||||
// Update k/kp (decrease after non-zero)
|
||||
if kp > rlgrDNGR {
|
||||
kp -= rlgrDNGR
|
||||
} else {
|
||||
kp = 0
|
||||
}
|
||||
k = kp >> rlgrLSGR
|
||||
|
||||
// Compute magnitude (code + 1, guaranteed non-zero)
|
||||
mag := int16(code + 1)
|
||||
if sign != 0 {
|
||||
mag = -mag
|
||||
}
|
||||
|
||||
// Output: run zeros (already 0 from init), then the non-zero value
|
||||
runEnd := min(cnt+int(run), outputSize)
|
||||
cnt = runEnd
|
||||
if cnt < outputSize {
|
||||
output[cnt] = mag
|
||||
cnt++
|
||||
}
|
||||
|
||||
} else {
|
||||
// GR (Golomb-Rice) Mode
|
||||
|
||||
// Count leading 1-bits
|
||||
vk := br.countLeadingOnes()
|
||||
|
||||
// Read kr bits for code remainder
|
||||
code := uint32(0)
|
||||
if kr > 0 {
|
||||
code = br.readBits(int(kr))
|
||||
}
|
||||
code |= vk << kr
|
||||
|
||||
// Update kr/krp
|
||||
if vk == 0 {
|
||||
if krp > 2 {
|
||||
krp -= 2
|
||||
} else {
|
||||
krp = 0
|
||||
}
|
||||
kr = krp >> rlgrLSGR
|
||||
} else if vk != 1 {
|
||||
krp += vk
|
||||
if krp > rlgrKPMax {
|
||||
krp = rlgrKPMax
|
||||
}
|
||||
kr = krp >> rlgrLSGR
|
||||
}
|
||||
|
||||
// RLGR1: sign embedded in code as code = 2*magnitude - sign
|
||||
if code == 0 {
|
||||
kp += rlgrUQGR
|
||||
if kp > rlgrKPMax {
|
||||
kp = rlgrKPMax
|
||||
}
|
||||
k = kp >> rlgrLSGR
|
||||
|
||||
if cnt < outputSize {
|
||||
cnt++ // zero already set from init
|
||||
}
|
||||
} else {
|
||||
if kp > rlgrDQGR {
|
||||
kp -= rlgrDQGR
|
||||
} else {
|
||||
kp = 0
|
||||
}
|
||||
k = kp >> rlgrLSGR
|
||||
|
||||
var mag int16
|
||||
if code&1 != 0 {
|
||||
// odd code → negative
|
||||
mag = -int16((code + 1) >> 1)
|
||||
} else {
|
||||
// even code → positive
|
||||
mag = int16(code >> 1)
|
||||
}
|
||||
if cnt < outputSize {
|
||||
output[cnt] = mag
|
||||
cnt++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
// rlgr3Decode decodes RLGR3-encoded data into signed 16-bit DWT coefficients.
|
||||
// RLGR3 differs from RLGR1 only in GR mode: it encodes/decodes TWO values
|
||||
// per GR code by encoding their sum then splitting.
|
||||
// Reference: MS-RDPRFX 3.1.8.1.7.3, FreeRDP rfx_rlgr.c
|
||||
func rlgr3Decode(data []byte, outputSize int, dst []int16) []int16 {
|
||||
var output []int16
|
||||
if cap(dst) >= outputSize {
|
||||
output = dst[:outputSize]
|
||||
clear(output)
|
||||
} else {
|
||||
output = make([]int16, outputSize)
|
||||
}
|
||||
br := &rlgrBitReader{data: data}
|
||||
cnt := 0
|
||||
|
||||
k := uint32(1)
|
||||
kp := uint32(1 << rlgrLSGR)
|
||||
kr := uint32(1)
|
||||
krp := uint32(1 << rlgrLSGR)
|
||||
|
||||
for br.remaining() > 0 && cnt < outputSize {
|
||||
if k > 0 {
|
||||
// RL Mode — identical to RLGR1
|
||||
vk := br.countLeadingZeros()
|
||||
|
||||
run := uint32(0)
|
||||
for range vk {
|
||||
run += 1 << k
|
||||
kp += rlgrUPGR
|
||||
if kp > rlgrKPMax {
|
||||
kp = rlgrKPMax
|
||||
}
|
||||
k = kp >> rlgrLSGR
|
||||
}
|
||||
|
||||
if k > 0 {
|
||||
run += br.readBits(int(k))
|
||||
}
|
||||
|
||||
sign := br.readBits(1)
|
||||
|
||||
vk2 := br.countLeadingOnes()
|
||||
|
||||
code := uint32(0)
|
||||
if kr > 0 {
|
||||
code = br.readBits(int(kr))
|
||||
}
|
||||
code |= vk2 << kr
|
||||
|
||||
if vk2 == 0 {
|
||||
if krp > 2 {
|
||||
krp -= 2
|
||||
} else {
|
||||
krp = 0
|
||||
}
|
||||
kr = krp >> rlgrLSGR
|
||||
} else if vk2 != 1 {
|
||||
krp += vk2
|
||||
if krp > rlgrKPMax {
|
||||
krp = rlgrKPMax
|
||||
}
|
||||
kr = krp >> rlgrLSGR
|
||||
}
|
||||
|
||||
if kp > rlgrDNGR {
|
||||
kp -= rlgrDNGR
|
||||
} else {
|
||||
kp = 0
|
||||
}
|
||||
k = kp >> rlgrLSGR
|
||||
|
||||
mag := int16(code + 1)
|
||||
if sign != 0 {
|
||||
mag = -mag
|
||||
}
|
||||
|
||||
runEnd3 := min(cnt+int(run), outputSize)
|
||||
cnt = runEnd3
|
||||
if cnt < outputSize {
|
||||
output[cnt] = mag
|
||||
cnt++
|
||||
}
|
||||
|
||||
} else {
|
||||
// GR Mode — RLGR3 variant: decode TWO values from one GR code
|
||||
vk := br.countLeadingOnes()
|
||||
|
||||
code := uint32(0)
|
||||
if kr > 0 {
|
||||
code = br.readBits(int(kr))
|
||||
}
|
||||
code |= vk << kr
|
||||
|
||||
if vk == 0 {
|
||||
if krp > 2 {
|
||||
krp -= 2
|
||||
} else {
|
||||
krp = 0
|
||||
}
|
||||
kr = krp >> rlgrLSGR
|
||||
} else if vk != 1 {
|
||||
krp += vk
|
||||
if krp > rlgrKPMax {
|
||||
krp = rlgrKPMax
|
||||
}
|
||||
kr = krp >> rlgrLSGR
|
||||
}
|
||||
|
||||
// RLGR3: code = val1 + val2 (sum of two 2*mag-sign encoded values)
|
||||
// Read nIdx bits to split: nIdx = bit-length of code
|
||||
nIdx := uint32(0)
|
||||
if code != 0 {
|
||||
nIdx = uint32(bits.Len(uint(code)))
|
||||
}
|
||||
|
||||
if br.remaining() < int(nIdx) {
|
||||
break
|
||||
}
|
||||
val1 := uint32(0)
|
||||
if nIdx > 0 {
|
||||
val1 = br.readBits(int(nIdx))
|
||||
}
|
||||
val2 := code - val1
|
||||
|
||||
// Update k/kp based on both values
|
||||
if val1 != 0 && val2 != 0 {
|
||||
if kp > 2*rlgrDQGR {
|
||||
kp -= 2 * rlgrDQGR
|
||||
} else {
|
||||
kp = 0
|
||||
}
|
||||
k = kp >> rlgrLSGR
|
||||
} else if val1 == 0 && val2 == 0 {
|
||||
kp += 2 * rlgrUQGR
|
||||
if kp > rlgrKPMax {
|
||||
kp = rlgrKPMax
|
||||
}
|
||||
k = kp >> rlgrLSGR
|
||||
}
|
||||
|
||||
// Decode val1 as 2*mag-sign
|
||||
var mag1 int16
|
||||
if val1&1 != 0 {
|
||||
mag1 = -int16((val1 + 1) >> 1)
|
||||
} else {
|
||||
mag1 = int16(val1 >> 1)
|
||||
}
|
||||
if cnt < outputSize {
|
||||
output[cnt] = mag1
|
||||
cnt++
|
||||
}
|
||||
|
||||
// Decode val2 as 2*mag-sign
|
||||
var mag2 int16
|
||||
if val2&1 != 0 {
|
||||
mag2 = -int16((val2 + 1) >> 1)
|
||||
} else {
|
||||
mag2 = int16(val2 >> 1)
|
||||
}
|
||||
if cnt < outputSize {
|
||||
output[cnt] = mag2
|
||||
cnt++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
// rlgrBitReader reads bits MSB-first from a byte slice.
|
||||
//
|
||||
// To minimise the per-bit cost on the RLGR hot path we keep a 64-bit
|
||||
// shift-register (`acc`, MSB-aligned with `bitsInAcc` valid bits at the top)
|
||||
// fed from `data[bytePos:]`. Reads up to 32 bits are a shift+mask, and runs
|
||||
// of identical bits are extracted with a single `bits.LeadingZeros64`.
|
||||
//
|
||||
// Invariant: bits consumed == bytePos*8 - bitsInAcc, so
|
||||
//
|
||||
// remaining() == (len(data)-bytePos)*8 + bitsInAcc
|
||||
//
|
||||
// which lets us drop the separate `total` and `read` counters entirely.
|
||||
type rlgrBitReader struct {
|
||||
data []byte
|
||||
bytePos int // next byte to load into acc
|
||||
acc uint64 // bits aligned to MSB
|
||||
bitsInAcc int // number of valid bits in acc (MSB-aligned)
|
||||
}
|
||||
|
||||
func (br *rlgrBitReader) remaining() int {
|
||||
return (len(br.data)-br.bytePos)*8 + br.bitsInAcc
|
||||
}
|
||||
|
||||
// fill loads bytes into the high end of acc until at least `need` bits are
|
||||
// buffered or the input is exhausted. need must be <= 56.
|
||||
func (br *rlgrBitReader) fill(need int) {
|
||||
for br.bitsInAcc < need && br.bytePos < len(br.data) {
|
||||
br.acc |= uint64(br.data[br.bytePos]) << uint(56-br.bitsInAcc)
|
||||
br.bytePos++
|
||||
br.bitsInAcc += 8
|
||||
}
|
||||
}
|
||||
|
||||
// readBits extracts n bits (n > 0) from the accumulator.
|
||||
// Inlinable: when bitsInAcc is already sufficient the slow path is never
|
||||
// compiled into the call site; when fill is also inlinable the whole hot
|
||||
// path reduces to a shift + mask without a call frame.
|
||||
func (br *rlgrBitReader) readBits(n int) uint32 {
|
||||
if br.bitsInAcc < n {
|
||||
br.fill(n)
|
||||
if br.bitsInAcc < n {
|
||||
// EOF (bytePos == len(data)): zero bitsInAcc so remaining()
|
||||
// returns 0 and the decode loop terminates cleanly.
|
||||
br.bitsInAcc = 0
|
||||
return 0
|
||||
}
|
||||
}
|
||||
val := uint32(br.acc >> uint(64-n))
|
||||
br.acc <<= uint(n)
|
||||
br.bitsInAcc -= n
|
||||
return val
|
||||
}
|
||||
|
||||
// countLeadingZeros counts consecutive 0-bits and consumes the first 1-bit terminator.
|
||||
func (br *rlgrBitReader) countLeadingZeros() uint32 {
|
||||
count := uint32(0)
|
||||
for {
|
||||
if br.bitsInAcc < 56 && br.bytePos < len(br.data) {
|
||||
br.fill(56)
|
||||
}
|
||||
if br.bitsInAcc == 0 {
|
||||
return count
|
||||
}
|
||||
lz := bits.LeadingZeros64(br.acc)
|
||||
if lz >= br.bitsInAcc {
|
||||
count += uint32(br.bitsInAcc)
|
||||
br.acc = 0
|
||||
br.bitsInAcc = 0
|
||||
continue
|
||||
}
|
||||
count += uint32(lz)
|
||||
consume := lz + 1
|
||||
br.acc <<= uint(consume)
|
||||
br.bitsInAcc -= consume
|
||||
return count
|
||||
}
|
||||
}
|
||||
|
||||
// countLeadingOnes counts consecutive 1-bits and consumes the first 0-bit terminator.
|
||||
func (br *rlgrBitReader) countLeadingOnes() uint32 {
|
||||
count := uint32(0)
|
||||
for {
|
||||
if br.bitsInAcc < 56 && br.bytePos < len(br.data) {
|
||||
br.fill(56)
|
||||
}
|
||||
if br.bitsInAcc == 0 {
|
||||
return count
|
||||
}
|
||||
lo := bits.LeadingZeros64(^br.acc)
|
||||
if lo >= br.bitsInAcc {
|
||||
count += uint32(br.bitsInAcc)
|
||||
br.acc = 0
|
||||
br.bitsInAcc = 0
|
||||
continue
|
||||
}
|
||||
count += uint32(lo)
|
||||
consume := lo + 1
|
||||
br.acc <<= uint(consume)
|
||||
br.bitsInAcc -= consume
|
||||
return count
|
||||
}
|
||||
}
|
||||
|
||||
// DecodeRLGR3ForDebug exposes the RLGR3 decoder for offline verification.
|
||||
func DecodeRLGR3ForDebug(data []byte, outputSize int) []int16 {
|
||||
return rlgr3Decode(data, outputSize, nil)
|
||||
}
|
||||
Reference in New Issue
Block a user