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