Use caching reader to packetize FLAC efficiently
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
a7d06f5eea
commit
3dbf436742
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue