snapshot of https://github.com/livekit/livekit.git @ 08c5433449c106943231037d0b892895f6e92d3b (2026-09-15)
This commit is contained in:
132
pkg/sfu/rtpextension/dependencydescriptor/bitstreamwriter.go
Normal file
132
pkg/sfu/rtpextension/dependencydescriptor/bitstreamwriter.go
Normal file
@@ -0,0 +1,132 @@
|
||||
// Copyright 2023 LiveKit, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package dependencydescriptor
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type BitStreamWriter struct {
|
||||
buf []byte
|
||||
pos int
|
||||
bitOffset int // bit offset in the current byte
|
||||
}
|
||||
|
||||
func NewBitStreamWriter(buf []byte) *BitStreamWriter {
|
||||
return &BitStreamWriter{buf: buf}
|
||||
}
|
||||
|
||||
func (w *BitStreamWriter) RemainingBits() int {
|
||||
return (len(w.buf)-w.pos)*8 - w.bitOffset
|
||||
}
|
||||
|
||||
func (w *BitStreamWriter) WriteBits(val uint64, bitCount int) error {
|
||||
if bitCount > w.RemainingBits() {
|
||||
return errors.New("insufficient space")
|
||||
}
|
||||
|
||||
totalBits := bitCount
|
||||
|
||||
// push bits to the highest bits of uint64
|
||||
val <<= 64 - bitCount
|
||||
|
||||
buf := w.buf[w.pos:]
|
||||
|
||||
// The first byte is relatively special; the bit offset to write to may put us
|
||||
// in the middle of the byte, and the total bit count to write may require we
|
||||
// save the bits at the end of the byte.
|
||||
remainingBitsInCurrentByte := 8 - w.bitOffset
|
||||
bitsInFirstByte := bitCount
|
||||
if bitsInFirstByte > remainingBitsInCurrentByte {
|
||||
bitsInFirstByte = remainingBitsInCurrentByte
|
||||
}
|
||||
|
||||
buf[0] = w.writePartialByte(uint8(val>>56), bitsInFirstByte, buf[0], w.bitOffset)
|
||||
|
||||
if bitCount <= remainingBitsInCurrentByte {
|
||||
// no bit left to write
|
||||
return w.consumeBits(totalBits)
|
||||
}
|
||||
|
||||
// write the rest of the bits
|
||||
val <<= bitsInFirstByte
|
||||
buf = buf[1:]
|
||||
bitCount -= bitsInFirstByte
|
||||
for bitCount >= 8 {
|
||||
buf[0] = uint8(val >> 56)
|
||||
buf = buf[1:]
|
||||
val <<= 8
|
||||
bitCount -= 8
|
||||
}
|
||||
|
||||
// write the last bits
|
||||
if bitCount > 0 {
|
||||
buf[0] = w.writePartialByte(uint8(val>>56), bitCount, buf[0], 0)
|
||||
}
|
||||
return w.consumeBits(totalBits)
|
||||
}
|
||||
|
||||
func (w *BitStreamWriter) consumeBits(bitCount int) error {
|
||||
if bitCount > w.RemainingBits() {
|
||||
return errors.New("insufficient space")
|
||||
}
|
||||
|
||||
w.pos += (w.bitOffset + bitCount) / 8
|
||||
w.bitOffset = (w.bitOffset + bitCount) % 8
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *BitStreamWriter) writePartialByte(source uint8, sourceBitCount int, target uint8, targetBitOffset int) uint8 {
|
||||
// if !(targetBitOffset < 8 && sourceBitCount <= (8-targetBitOffset)) {
|
||||
// return fmt.Errorf("invalid argument, source %d, sourceBitCount %d, target %d, targetBitOffset %d", source, sourceBitCount, target, targetBitOffset)
|
||||
// }
|
||||
|
||||
// generate mask for bits to overwrite, shift source bits to highest bits, then position to target bit offset
|
||||
mask := uint8(0xff<<(8-sourceBitCount)) >> uint8(targetBitOffset)
|
||||
|
||||
// clear target bits and write source bits
|
||||
return (target & ^mask) | (source >> targetBitOffset)
|
||||
}
|
||||
|
||||
func (w *BitStreamWriter) WriteNonSymmetric(val, numValues uint32) error {
|
||||
if val >= numValues || numValues > 1<<31 {
|
||||
return fmt.Errorf("invalid argument, val %d, numValues %d", val, numValues)
|
||||
}
|
||||
if numValues == 1 {
|
||||
// When there is only one possible value, it requires zero bits to store it.
|
||||
// But WriteBits doesn't support writing zero bits.
|
||||
return nil
|
||||
}
|
||||
|
||||
countBits := bitwidth(numValues)
|
||||
numMinBitsValues := (uint32(1) << countBits) - numValues
|
||||
if val < numMinBitsValues {
|
||||
return w.WriteBits(uint64(val), countBits-1)
|
||||
} else {
|
||||
return w.WriteBits(uint64(val+numMinBitsValues), countBits)
|
||||
}
|
||||
}
|
||||
|
||||
func SizeNonSymmetricBits(val, numValues uint32) int {
|
||||
countBits := bitwidth(numValues)
|
||||
numMinBitsValues := (uint32(1) << countBits) - numValues
|
||||
if val < numMinBitsValues {
|
||||
return countBits - 1
|
||||
} else {
|
||||
return countBits
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user