Use caching reader to packetize FLAC efficiently
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
DataHoarder 2022-08-01 17:31:01 +02:00
parent a7d06f5eea
commit 3dbf436742
Signed by: DataHoarder
SSH key fingerprint: SHA256:OLTRf6Fl87G52SiR7sWLGNzlJt4WOX+tfI2yxo0z7xk

View file

@ -9,10 +9,6 @@ import (
"io"
)
func NewFLACPacketizer(reader io.Reader) *FLACPacketizer {
return &FLACPacketizer{br: bitio.NewReader(bufio.NewReaderSize(reader, 4096))}
}
type FLACHeaderPacket struct {
Capture [4]byte
MinimumBlockSize uint16
@ -137,7 +133,7 @@ func readFlacHeader(br *bitio.Reader) *FLACHeaderPacket {
return hdr
}
func readFlacFrame(hdr *FLACHeaderPacket, br *bitio.Reader) *FLACPacket {
func readFlacFrame(hdr *FLACHeaderPacket, br *bitio.Reader, bfr *cachedBitReader) *FLACPacket {
if sync, err := br.ReadBits(14); err != nil || sync != 0b11111111111110 {
return nil
}
@ -336,11 +332,9 @@ func readFlacFrame(hdr *FLACHeaderPacket, br *bitio.Reader) *FLACPacket {
blockSize := int(p.getBlockSize())
buf := bytes.NewBuffer(hdr.buf[:0])
bfr.ResetBuffer()
bw := bitio.NewWriter(buf)
var padding, subframeType, wastedBitsFlag, wastedBits uint64
var subframeType, wastedBitsFlag, wastedBits uint64
//TODO: remove error checking here, given we get proper input and a check will happen later
for channelNumber := 0; channelNumber < channelCount; channelNumber++ {
bps := p.getBitsPerSample()
@ -351,7 +345,8 @@ func readFlacFrame(hdr *FLACHeaderPacket, br *bitio.Reader) *FLACPacket {
bps++
}
if padding, err = br.ReadBits(1); err != nil {
//var padding uint64
if _, err = br.ReadBits(1); err != nil {
return nil
}
if subframeType, err = br.ReadBits(6); err != nil {
@ -370,11 +365,11 @@ func readFlacFrame(hdr *FLACHeaderPacket, br *bitio.Reader) *FLACPacket {
wastedBits = 0
}
_ = bw.WriteBits(padding, 1)
_ = bw.WriteBits(subframeType, 6)
_ = bw.WriteBits(wastedBitsFlag, 1)
//_ = bw.WriteBits(padding, 1)
//_ = bw.WriteBits(subframeType, 6)
//_ = bw.WriteBits(wastedBitsFlag, 1)
if wastedBitsFlag == 1 {
_ = writeUnary(bw, wastedBits)
//_ = writeUnary(bw, wastedBits)
bps -= uint8(wastedBits) + 1
}
@ -382,17 +377,17 @@ func readFlacFrame(hdr *FLACHeaderPacket, br *bitio.Reader) *FLACPacket {
switch {
case subframeType == 0: //Constant
var constantSample uint64
if constantSample, err = br.ReadBits(bps); err != nil {
//var constantSample uint64
if _, err = br.ReadBits(bps); err != nil {
return nil
}
_ = bw.WriteBits(constantSample, bps)
//_ = bw.WriteBits(constantSample, bps)
case subframeType == 1: //Verbatim
var verbatimData []byte
if verbatimData, err = readManyBits(br, blockSize*int(bps)); err != nil {
//var verbatimData []byte
if _, err = readManyBits(br, blockSize*int(bps)); err != nil {
return nil
}
_ = writeManyBits(bw, verbatimData, blockSize*int(bps))
//_ = writeManyBits(bw, verbatimData, blockSize*int(bps))
case subframeType < 8: //reserved
return nil
case subframeType < 16: //Fixed
@ -402,30 +397,30 @@ func readFlacFrame(hdr *FLACHeaderPacket, br *bitio.Reader) *FLACPacket {
return nil
}
var warmupData []byte
if warmupData, err = readManyBits(br, order*int(bps)); err != nil {
//var warmupData []byte
if _, err = readManyBits(br, order*int(bps)); err != nil {
return nil
}
_ = writeManyBits(bw, warmupData, order*int(bps))
//_ = writeManyBits(bw, warmupData, order*int(bps))
if err = decodeResidual(br, bw, blockSize, order); err != nil {
if err = decodeResidual(br, blockSize, order); err != nil {
return nil
}
case subframeType < 32: //reserved
return nil
default: //FIR
order := int(subframeType&0x1F) + 1
var warmupData []byte
if warmupData, err = readManyBits(br, order*int(bps)); err != nil {
//var warmupData []byte
if _, err = readManyBits(br, order*int(bps)); err != nil {
return nil
}
_ = writeManyBits(bw, warmupData, order*int(bps))
//_ = writeManyBits(bw, warmupData, order*int(bps))
var coefficientPrecisionLen, quantizationLevel uint64
var coefficientPrecisionLen uint64
if coefficientPrecisionLen, err = br.ReadBits(4); err != nil {
return nil
}
_ = bw.WriteBits(coefficientPrecisionLen, 4)
//_ = bw.WriteBits(coefficientPrecisionLen, 4)
if coefficientPrecisionLen == 0xF {
return nil
@ -433,35 +428,30 @@ func readFlacFrame(hdr *FLACHeaderPacket, br *bitio.Reader) *FLACPacket {
precision := int(coefficientPrecisionLen) + 1
if quantizationLevel, err = br.ReadBits(5); err != nil {
//var quantizationLevel uint64
if _, err = br.ReadBits(5); err != nil {
return nil
}
_ = bw.WriteBits(quantizationLevel, 5)
//_ = bw.WriteBits(quantizationLevel, 5)
var coefficientData []byte
if coefficientData, err = readManyBits(br, order*precision); err != nil {
//var coefficientData []byte
if _, err = readManyBits(br, order*precision); err != nil {
return nil
}
_ = writeManyBits(bw, coefficientData, order*precision)
//_ = writeManyBits(bw, coefficientData, order*precision)
if err = decodeResidual(br, bw, blockSize, order); err != nil {
if err = decodeResidual(br, blockSize, order); err != nil {
return nil
}
}
}
if n := br.Align(); n > 0 {
_ = bw.WriteBits(0, n)
if n, err = bw.Align(); err != nil || n != 0 {
//Alignment mismatch!
return nil
}
}
br.Align()
_ = bw.Close()
buf := bfr.GetBuffer()
p.FrameData = make([]byte, buf.Len())
copy(p.FrameData, buf.Bytes())
p.FrameData = make([]byte, len(buf))
copy(p.FrameData, buf)
if p.CRC16, err = br.ReadBits(16); err != nil {
return nil
@ -470,12 +460,12 @@ func readFlacFrame(hdr *FLACHeaderPacket, br *bitio.Reader) *FLACPacket {
return p
}
func decodeResidual(br *bitio.Reader, bw *bitio.Writer, blockSize, predictorOrder int) (err error) {
func decodeResidual(br *bitio.Reader, blockSize, predictorOrder int) (err error) {
var entropyCodingMethod, partitionOrder uint64
if entropyCodingMethod, err = br.ReadBits(2); err != nil {
return err
}
_ = bw.WriteBits(entropyCodingMethod, 2)
//_ = bw.WriteBits(entropyCodingMethod, 2)
paramSize := 0
@ -491,7 +481,7 @@ func decodeResidual(br *bitio.Reader, bw *bitio.Writer, blockSize, predictorOrde
if partitionOrder, err = br.ReadBits(4); err != nil {
return err
}
_ = bw.WriteBits(partitionOrder, 4)
//_ = bw.WriteBits(partitionOrder, 4)
partitions := 1 << partitionOrder
@ -500,7 +490,7 @@ func decodeResidual(br *bitio.Reader, bw *bitio.Writer, blockSize, predictorOrde
if riceParameter, err = br.ReadBits(uint8(paramSize)); err != nil {
return err
}
_ = bw.WriteBitsUnsafe(riceParameter, uint8(paramSize))
//_ = bw.WriteBitsUnsafe(riceParameter, uint8(paramSize))
var nsamples int
if partition != 0 {
@ -517,36 +507,36 @@ func decodeResidual(br *bitio.Reader, bw *bitio.Writer, blockSize, predictorOrde
if riceParameter2, err = br.ReadBits(5); err != nil {
return err
}
_ = bw.WriteBitsUnsafe(riceParameter2, 5)
//_ = bw.WriteBitsUnsafe(riceParameter2, 5)
if riceParameter2 > 0 {
var sampleData []byte
if sampleData, err = readManyBits(br, nsamples*int(riceParameter2)); err != nil {
//var sampleData []byte
if _, err = readManyBits(br, nsamples*int(riceParameter2)); err != nil {
return err
}
_ = writeManyBits(bw, sampleData, nsamples*int(riceParameter2))
//_ = writeManyBits(bw, sampleData, nsamples*int(riceParameter2))
}
} else {
//TODO: optimize this!
var high, low uint64
//var high, low uint64
if riceParameter == 0 {
for j := 0; j < nsamples; j++ {
if high, err = readUnary(br); err != nil {
if _, err = readUnary(br); err != nil {
return err
}
_ = writeUnary(bw, high)
//_ = writeUnary(bw, high)
}
} else {
for j := 0; j < nsamples; j++ {
if high, err = readUnary(br); err != nil {
if _, err = readUnary(br); err != nil {
return err
}
_ = writeUnary(bw, high)
if low, err = br.ReadBits(uint8(riceParameter)); err != nil {
//_ = writeUnary(bw, high)
if _, err = br.ReadBits(uint8(riceParameter)); err != nil {
return err
}
_ = bw.WriteBitsUnsafe(low, uint8(riceParameter))
//_ = bw.WriteBitsUnsafe(low, uint8(riceParameter))
}
}
}
@ -934,12 +924,64 @@ func (p *FLACPacket) GetDataOffset(offset int64) []byte {
return buf.Bytes()
}
type cachedBitReader struct {
r *bufio.Reader
originalBuf []byte
buf []byte
byteBuf []byte
}
func newCachedBitReader(reader io.Reader, bufSize int) *cachedBitReader {
r := &cachedBitReader{
r: bufio.NewReaderSize(reader, bufSize),
buf: make([]byte, 0, bufSize),
byteBuf: make([]byte, 1),
}
r.originalBuf = r.buf[:]
return r
}
func (r *cachedBitReader) Read(p []byte) (n int, err error) {
n, err = r.r.Read(p)
if n > 0 {
r.buf = append(r.buf, p[:n]...)
}
return
}
func (r *cachedBitReader) ReadByte() (byte, error) {
n, err := r.r.Read(r.byteBuf)
if n > 0 {
r.buf = append(r.buf, r.byteBuf[0])
}
return r.byteBuf[0], err
}
func (r *cachedBitReader) GetBuffer() []byte {
return r.buf
}
func (r *cachedBitReader) ResetBuffer() {
r.buf = r.originalBuf
}
type FLACPacketizer struct {
bfr *cachedBitReader
br *bitio.Reader
hdr *FLACHeaderPacket
}
func NewFLACPacketizer(reader io.Reader) *FLACPacketizer {
p := &FLACPacketizer{
bfr: newCachedBitReader(reader, 1024*32),
}
p.br = bitio.NewReader(p.bfr)
return p
}
func (o *FLACPacketizer) GetPacket() Packet {
o.bfr.ResetBuffer()
if o.hdr == nil {
o.hdr = readFlacHeader(o.br)
if o.hdr == nil {
@ -948,7 +990,7 @@ func (o *FLACPacketizer) GetPacket() Packet {
return o.hdr
}
packet := readFlacFrame(o.hdr, o.br)
packet := readFlacFrame(o.hdr, o.br, o.bfr)
if packet == nil {
return nil
}