Kirika/audio/packetizer/flac.go
DataHoarder b7ce508d50
Some checks failed
continuous-integration/drone/push Build is failing
Expose internal structure of packets on packetizer
2022-11-07 14:02:07 +01:00

945 lines
20 KiB
Go

package packetizer
import (
"bufio"
"bytes"
"errors"
"fmt"
"github.com/icza/bitio"
"golang.org/x/exp/slices"
"io"
)
type FLACHeaderPacket struct {
Capture [4]byte
MinimumBlockSize uint16
MaximumBlockSize uint16
MinimumFrameSize uint32
MaximumFrameSize uint32
SampleRate uint32
ChannelCount uint8
BitsPerSample uint8
TotalSamples uint64
Hash [128 / 8]byte
MetadataBlocks [][]byte
}
func (p *FLACHeaderPacket) KeepMode() KeepMode {
return Keep
}
func (p *FLACHeaderPacket) GetStartSampleNumber() int64 {
return 0
}
func (p *FLACHeaderPacket) GetEndSampleNumber() int64 {
return 0
}
func (p *FLACHeaderPacket) GetData() []byte {
data := bytes.NewBuffer(make([]byte, 0, 1024))
buf := bitio.NewWriter(data)
if _, err := buf.Write(p.Capture[:]); err != nil {
return nil
}
for _, b := range p.MetadataBlocks {
if buf.WriteByte(b[0]) != nil {
return nil
}
if err := buf.WriteBits(uint64(len(b)-1), 24); err != nil {
return nil
}
if _, err := buf.Write(b[1:]); err != nil {
return nil
}
}
_ = buf.Close()
return data.Bytes()
}
func (p *FLACHeaderPacket) Category() int64 {
return 0
}
const invalidMetadataBlock = 127
func readFlacMetadataBlock(br *bitio.Reader) (block byte, data []byte) {
var err error
if block, err = br.ReadByte(); err != nil {
return invalidMetadataBlock, nil
}
var lengthInBytes uint64
if lengthInBytes, err = br.ReadBits(24); err != nil {
return invalidMetadataBlock, nil
}
data = make([]byte, lengthInBytes)
if _, err = io.ReadFull(br, data); err != nil {
return invalidMetadataBlock, nil
}
return
}
func readFlacHeader(br *bitio.Reader) *FLACHeaderPacket {
hdr := &FLACHeaderPacket{}
if _, err := br.Read(hdr.Capture[:]); err != nil || bytes.Compare(hdr.Capture[:], []byte("fLaC")) != 0 {
return nil
}
block, data := readFlacMetadataBlock(br)
if (block&0x7F) != 0 || len(data) < ((16+16+24+24+20+3+5+36+128)/8) { //StreamInfo
return nil
}
hdr.MetadataBlocks = append(hdr.MetadataBlocks, append([]byte{block}, data...))
sbr := bitio.NewReader(bytes.NewBuffer(data))
var n uint64
n, _ = sbr.ReadBits(16)
hdr.MinimumBlockSize = uint16(n)
n, _ = sbr.ReadBits(16)
hdr.MaximumBlockSize = uint16(n)
n, _ = sbr.ReadBits(24)
hdr.MinimumFrameSize = uint32(n)
n, _ = sbr.ReadBits(24)
hdr.MaximumFrameSize = uint32(n)
n, _ = sbr.ReadBits(20)
hdr.SampleRate = uint32(n)
n, _ = sbr.ReadBits(3)
hdr.ChannelCount = uint8(n) + 1
n, _ = sbr.ReadBits(5)
hdr.BitsPerSample = uint8(n) + 1
_, _ = sbr.Read(hdr.Hash[:])
for {
if (block & (1 << 7)) > 0 { //if last
break
}
block, data = readFlacMetadataBlock(br)
if block == invalidMetadataBlock {
return nil
}
hdr.MetadataBlocks = append(hdr.MetadataBlocks, append([]byte{block}, data...))
}
return hdr
}
func readFlacFrame(hdr *FLACHeaderPacket, br *bitio.Reader, bfr *cachedBitReader) *FLACPacket {
if sync, err := br.ReadBits(14); err != nil || sync != 0b11111111111110 {
return nil
}
if reserved, err := br.ReadBits(1); err != nil || reserved != 0 {
return nil
}
p := &FLACPacket{
hdr: hdr,
mode: Discard,
}
var err error
if p.BlockingStrategy, err = br.ReadBits(1); err != nil {
return nil
}
if p.BlockSizeRaw, err = br.ReadBits(4); err != nil {
return nil
}
if p.SampleRateRaw, err = br.ReadBits(4); err != nil {
return nil
}
if p.ChannelAssignment, err = br.ReadBits(4); err != nil {
return nil
}
if p.BitsPerSample, err = br.ReadBits(3); err != nil {
return nil
}
if reserved, err := br.ReadBits(1); err != nil || reserved != 0 {
return nil
}
if p.Number, err = func(r io.ByteReader) (x uint64, err error) {
const (
tx = 0x80 // 1000 0000
t2 = 0xC0 // 1100 0000
t3 = 0xE0 // 1110 0000
t4 = 0xF0 // 1111 0000
t5 = 0xF8 // 1111 1000
t6 = 0xFC // 1111 1100
t7 = 0xFE // 1111 1110
t8 = 0xFF // 1111 1111
maskx = 0x3F // 0011 1111
mask2 = 0x1F // 0001 1111
mask3 = 0x0F // 0000 1111
mask4 = 0x07 // 0000 0111
mask5 = 0x03 // 0000 0011
mask6 = 0x01 // 0000 0001
rune1Max = 1<<7 - 1
rune2Max = 1<<11 - 1
rune3Max = 1<<16 - 1
rune4Max = 1<<21 - 1
rune5Max = 1<<26 - 1
rune6Max = 1<<31 - 1
rune7Max = 1<<36 - 1
)
c0, err := r.ReadByte()
if err != nil {
return 0, err
}
// 1-byte, 7-bit sequence?
if c0 < tx {
// if c0 == 0xxxxxxx
// total: 7 bits (7)
return uint64(c0), nil
}
// unexpected continuation byte?
if c0 < t2 {
// if c0 == 10xxxxxx
return 0, errors.New("unexpected continuation byte")
}
// get number of continuation bytes and store bits from c0.
var l int
switch {
case c0 < t3:
// if c0 == 110xxxxx
// total: 11 bits (5 + 6)
l = 1
x = uint64(c0 & mask2)
case c0 < t4:
// if c0 == 1110xxxx
// total: 16 bits (4 + 6 + 6)
l = 2
x = uint64(c0 & mask3)
case c0 < t5:
// if c0 == 11110xxx
// total: 21 bits (3 + 6 + 6 + 6)
l = 3
x = uint64(c0 & mask4)
case c0 < t6:
// if c0 == 111110xx
// total: 26 bits (2 + 6 + 6 + 6 + 6)
l = 4
x = uint64(c0 & mask5)
case c0 < t7:
// if c0 == 1111110x
// total: 31 bits (1 + 6 + 6 + 6 + 6 + 6)
l = 5
x = uint64(c0 & mask6)
case c0 < t8:
// if c0 == 11111110
// total: 36 bits (0 + 6 + 6 + 6 + 6 + 6 + 6)
l = 6
x = 0
}
// store bits from continuation bytes.
for i := 0; i < l; i++ {
x <<= 6
c, err := r.ReadByte()
if err != nil {
if err == io.EOF {
return 0, io.ErrUnexpectedEOF
}
return 0, err
}
if c < tx || t2 <= c {
// if c != 10xxxxxx
return 0, errors.New("expected continuation byte")
}
x |= uint64(c & maskx)
}
// check if number representation is larger than necessary.
switch l {
case 1:
if x <= rune1Max {
return 0, fmt.Errorf("larger number representation than necessary; x (%d) stored in %d bytes, could be stored in %d bytes", x, l+1, l)
}
case 2:
if x <= rune2Max {
return 0, fmt.Errorf("larger number representation than necessary; x (%d) stored in %d bytes, could be stored in %d bytes", x, l+1, l)
}
case 3:
if x <= rune3Max {
return 0, fmt.Errorf("larger number representation than necessary; x (%d) stored in %d bytes, could be stored in %d bytes", x, l+1, l)
}
case 4:
if x <= rune4Max {
return 0, fmt.Errorf("larger number representation than necessary; x (%d) stored in %d bytes, could be stored in %d bytes", x, l+1, l)
}
case 5:
if x <= rune5Max {
return 0, fmt.Errorf("larger number representation than necessary; x (%d) stored in %d bytes, could be stored in %d bytes", x, l+1, l)
}
case 6:
if x <= rune6Max {
return 0, fmt.Errorf("larger number representation than necessary; x (%d) stored in %d bytes, could be stored in %d bytes", x, l+1, l)
}
}
return x, nil
}(br); err != nil {
return nil
}
if p.BlockSizeRaw == 0x6 {
if p.BlockSizeExtra, err = br.ReadBits(8); err != nil {
return nil
}
} else if p.BlockSizeRaw == 0x7 {
if p.BlockSizeExtra, err = br.ReadBits(16); err != nil {
return nil
}
}
if p.SampleRateRaw == 0xC {
if p.SampleRateExtra, err = br.ReadBits(8); err != nil {
return nil
}
} else if p.SampleRateRaw == 0xD || p.SampleRateRaw == 0xE {
if p.SampleRateExtra, err = br.ReadBits(16); err != nil {
return nil
}
}
if p.CRC8, err = br.ReadBits(8); err != nil {
return nil
}
channelCount := int(p.ChannelAssignment) + 1
if p.ChannelAssignment == 0x8 || p.ChannelAssignment == 0x9 || p.ChannelAssignment == 0xA {
channelCount = 2
}
blockSize := int(p.getBlockSize())
bfr.ResetBuffer()
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()
if p.ChannelAssignment == 0x9 && channelNumber == 0 {
bps++
} else if (p.ChannelAssignment == 0x8 || p.ChannelAssignment == 0xA) && channelNumber == 1 {
bps++
}
//var padding uint64
if _, err = br.ReadBits(1); err != nil {
return nil
}
if subframeType, err = br.ReadBits(6); err != nil {
return nil
}
if wastedBitsFlag, err = br.ReadBits(1); err != nil {
return nil
}
if wastedBitsFlag == 1 {
if wastedBits, err = readUnary(br); err != nil {
return nil
}
} else {
wastedBits = 0
}
if wastedBitsFlag == 1 {
bps -= uint8(wastedBits) + 1
}
switch {
case subframeType == 0: //Constant
//var constantSample uint64
if _, err = br.ReadBits(bps); err != nil {
return nil
}
case subframeType == 1: //Verbatim
//var verbatimData []byte
if _, err = readManyBits(br, blockSize*int(bps)); err != nil {
return nil
}
case subframeType < 8: //reserved
return nil
case subframeType < 16: //Fixed
order := int(subframeType & 0x07)
if order > 4 {
return nil
}
//var warmupData []byte
if _, err = readManyBits(br, order*int(bps)); err != nil {
return 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 _, err = readManyBits(br, order*int(bps)); err != nil {
return nil
}
var coefficientPrecisionLen uint64
if coefficientPrecisionLen, err = br.ReadBits(4); err != nil {
return nil
}
if coefficientPrecisionLen == 0xF {
return nil
}
precision := int(coefficientPrecisionLen) + 1
//var quantizationLevel uint64
if _, err = br.ReadBits(5); err != nil {
return nil
}
//var coefficientData []byte
if _, err = readManyBits(br, order*precision); err != nil {
return nil
}
if err = decodeResidual(br, blockSize, order); err != nil {
return nil
}
}
}
br.Align()
p.FrameData = slices.Clone(bfr.GetBuffer())
if p.CRC16, err = br.ReadBits(16); err != nil {
return nil
}
return p
}
func decodeResidual(br *bitio.Reader, blockSize, predictorOrder int) (err error) {
var entropyCodingMethod, partitionOrder uint64
if entropyCodingMethod, err = br.ReadBits(2); err != nil {
return err
}
paramSize := 0
switch entropyCodingMethod {
case 0x0:
paramSize = 4
case 0x1:
paramSize = 5
default:
return errors.New("wrong method")
}
if partitionOrder, err = br.ReadBits(4); err != nil {
return err
}
partitions := 1 << partitionOrder
var riceParameter uint64
for partition := 0; partition < partitions; partition++ {
if riceParameter, err = br.ReadBits(uint8(paramSize)); err != nil {
return err
}
var nsamples int
if partition != 0 {
nsamples = blockSize / partitions
} else {
nsamples = blockSize/partitions - predictorOrder
}
if (paramSize == 4 && riceParameter == 0xF) || (paramSize == 5 && riceParameter == 0x1F) {
// 1111 or 11111: Escape code, meaning the partition is in unencoded
// binary form using riceParameter2 bits per sample; riceParameter2 follows as a 5-bit number.
var riceParameter2 uint64
if riceParameter2, err = br.ReadBits(5); err != nil {
return err
}
if riceParameter2 > 0 {
//var sampleData []byte
if _, err = readManyBits(br, nsamples*int(riceParameter2)); err != nil {
return err
}
}
} else {
//TODO: optimize this!
//var high, low uint64
if riceParameter == 0 {
for j := 0; j < nsamples; j++ {
if _, err = readUnary(br); err != nil {
return err
}
}
} else {
for j := 0; j < nsamples; j++ {
if _, err = readUnary(br); err != nil {
return err
}
if _, err = br.ReadBits(uint8(riceParameter)); err != nil {
return err
}
}
}
}
}
return nil
}
func readManyBits(br *bitio.Reader, bits int) (data []byte, err error) {
dataLen := bits / 8
if (bits % 8) != 0 {
dataLen++
}
data = make([]byte, dataLen)
for i := 0; i < (bits / 8); i++ {
if data[i], err = br.ReadByte(); err != nil {
return nil, err
}
}
if (bits % 8) != 0 {
var b uint64
if b, err = br.ReadBits(uint8(bits % 8)); err != nil {
return nil, err
}
data[len(data)-1] = byte(b)
}
return
}
func readUnary(br *bitio.Reader) (x uint64, err error) {
var bit uint64
for {
if bit, err = br.ReadBits(1); err != nil {
return 0, err
}
if bit == 1 {
break
}
x++
}
return x, nil
}
type FLACPacket struct {
mode KeepMode
hdr *FLACHeaderPacket
BlockingStrategy uint64
BlockSizeRaw uint64
SampleRateRaw uint64
ChannelAssignment uint64
BitsPerSample uint64
Number uint64
BlockSizeExtra uint64
SampleRateExtra uint64
CRC8 uint64
FrameData []byte
buf []byte
CRC16 uint64
}
func (p *FLACPacket) KeepMode() KeepMode {
return p.mode
}
func (p *FLACPacket) GetStartSampleNumber() int64 {
if p.BlockingStrategy == 0 { //fixed-blocksize
return int64(p.Number * uint64(p.hdr.MinimumBlockSize))
}
return int64(p.Number)
}
func (p *FLACPacket) GetEndSampleNumber() int64 {
return p.GetStartSampleNumber() + int64(p.getBlockSize())
}
func (p *FLACPacket) GetData() []byte {
return p.GetDataOffset(0)
}
func (p *FLACPacket) Category() int64 {
return 0
}
func (p *FLACPacket) getBlockSize() uint16 {
n := p.BlockSizeRaw
x := p.BlockSizeExtra
switch {
case n == 0x0:
// 0000: reserved.
return 0
case n == 0x1:
// 0001: 192 samples.
return 192
case n >= 0x2 && n <= 0x5:
// 0010-0101: 576 * 2^(n-2) samples.
return 576 * (1 << (n - 2))
case n == 0x6:
// 0110: get 8 bit (block size)-1 from the end of the header.
return uint16(x + 1)
case n == 0x7:
// 0111: get 16 bit (block size)-1 from the end of the header.
return uint16(x + 1)
default:
// 1000-1111: 256 * 2^(n-8) samples.
return 256 * (1 << (n - 8))
}
}
func (p *FLACPacket) getSampleRate() uint32 {
switch p.SampleRateRaw {
case 0x0:
// 0000: unknown sample rate; get from StreamInfo.
return p.hdr.SampleRate
case 0x1:
// 0001: 88.2 kHz.
return 88200
case 0x2:
// 0010: 176.4 kHz.
return 176400
case 0x3:
// 0011: 192 kHz.
return 192000
case 0x4:
// 0100: 8 kHz.
return 8000
case 0x5:
// 0101: 16 kHz.
return 16000
case 0x6:
// 0110: 22.05 kHz.
return 22050
case 0x7:
// 0111: 24 kHz.
return 24000
case 0x8:
// 1000: 32 kHz.
return 32000
case 0x9:
// 1001: 44.1 kHz.
return 44100
case 0xA:
// 1010: 48 kHz.
return 48000
case 0xB:
// 1011: 96 kHz.
return 96000
case 0xC:
// 1100: get 8 bit sample rate (in kHz) from the end of the header.
return uint32(p.SampleRateExtra * 1000)
case 0xD:
// 1101: get 16 bit sample rate (in Hz) from the end of the header.
return uint32(p.SampleRateExtra)
case 0xE:
// 1110: get 16 bit sample rate (in daHz) from the end of the header.
return uint32(p.SampleRateExtra * 10)
default:
// 1111: invalid.
return 0
}
}
func (p *FLACPacket) getBitsPerSample() uint8 {
switch p.BitsPerSample {
case 0x0:
// 000: unknown bits-per-sample; get from StreamInfo.
return p.hdr.BitsPerSample
case 0x1:
// 001: 8 bits-per-sample.
return 8
case 0x2:
// 010: 12 bits-per-sample.
return 12
case 0x4:
// 100: 16 bits-per-sample.
return 16
case 0x5:
// 101: 20 bits-per-sample.
return 20
case 0x6:
// 110: 24 bits-per-sample.
return 24
default:
// 011: reserved.
// 111: reserved.
return 0
}
}
func (p *FLACPacket) GetDataOffset(offset int64) []byte {
//TODO: reserve proper amount
buf := bytes.NewBuffer(make([]byte, 0, len(p.FrameData)+64))
bw := bitio.NewWriter(buf)
//sync
_ = bw.WriteBits(0b11111111111110, 14)
//reserved
_ = bw.WriteBits(0, 1)
_ = bw.WriteBits(p.BlockingStrategy, 1)
_ = bw.WriteBits(p.BlockSizeRaw, 4)
_ = bw.WriteBits(p.SampleRateRaw, 4)
_ = bw.WriteBits(p.ChannelAssignment, 4)
_ = bw.WriteBits(p.BitsPerSample, 3)
//reserved
_ = bw.WriteBits(0, 1)
number := int64(p.Number)
if offset != 0 {
if p.BlockingStrategy == 1 {
number -= offset
if number < 0 {
return nil
}
} else {
number -= offset / int64(p.hdr.MinimumBlockSize)
if number < 0 {
return nil
}
}
}
var err error
if err = func(w io.ByteWriter, x uint64) error {
const (
tx = 0x80 // 1000 0000
t2 = 0xC0 // 1100 0000
t3 = 0xE0 // 1110 0000
t4 = 0xF0 // 1111 0000
t5 = 0xF8 // 1111 1000
t6 = 0xFC // 1111 1100
t7 = 0xFE // 1111 1110
t8 = 0xFF // 1111 1111
maskx = 0x3F // 0011 1111
mask2 = 0x1F // 0001 1111
mask3 = 0x0F // 0000 1111
mask4 = 0x07 // 0000 0111
mask5 = 0x03 // 0000 0011
mask6 = 0x01 // 0000 0001
rune1Max = 1<<7 - 1
rune2Max = 1<<11 - 1
rune3Max = 1<<16 - 1
rune4Max = 1<<21 - 1
rune5Max = 1<<26 - 1
rune6Max = 1<<31 - 1
rune7Max = 1<<36 - 1
)
// 1-byte, 7-bit sequence?
if x <= rune1Max {
if err := w.WriteByte(byte(x)); err != nil {
return err
}
return nil
}
// get number of continuation bytes and store bits of c0.
var (
// number of continuation bytes.,
l int
// bits of c0.
bits uint64
)
switch {
case x <= rune2Max:
// if c0 == 110xxxxx
// total: 11 bits (5 + 6)
l = 1
bits = t2 | (x>>6)&mask2
case x <= rune3Max:
// if c0 == 1110xxxx
// total: 16 bits (4 + 6 + 6)
l = 2
bits = t3 | (x>>(6*2))&mask3
case x <= rune4Max:
// if c0 == 11110xxx
// total: 21 bits (3 + 6 + 6 + 6)
l = 3
bits = t4 | (x>>(6*3))&mask4
case x <= rune5Max:
// if c0 == 111110xx
// total: 26 bits (2 + 6 + 6 + 6 + 6)
l = 4
bits = t5 | (x>>(6*4))&mask5
case x <= rune6Max:
// if c0 == 1111110x
// total: 31 bits (1 + 6 + 6 + 6 + 6 + 6)
l = 5
bits = t6 | (x>>(6*5))&mask6
case x <= rune7Max:
// if c0 == 11111110
// total: 36 bits (0 + 6 + 6 + 6 + 6 + 6 + 6)
l = 6
bits = 0
}
// Store bits of c0.
if err := w.WriteByte(byte(bits)); err != nil {
return err
}
// Store continuation bytes.
for i := l - 1; i >= 0; i-- {
bits = tx | (x>>uint(6*i))&maskx
if err := w.WriteByte(byte(bits)); err != nil {
return err
}
}
return nil
}(bw, uint64(number)); err != nil {
return nil
}
if p.BlockSizeRaw == 0x6 {
_ = bw.WriteBits(p.BlockSizeExtra, 8)
} else if p.BlockSizeRaw == 0x7 {
_ = bw.WriteBits(p.BlockSizeExtra, 16)
}
if p.SampleRateRaw == 0xC {
_ = bw.WriteBits(p.SampleRateExtra, 8)
} else if p.SampleRateRaw == 0xD || p.SampleRateRaw == 0xE {
_ = bw.WriteBits(p.SampleRateExtra, 16)
}
_, _ = bw.Align()
_ = bw.WriteBits(uint64(flacCrc8(buf.Bytes())), 8)
_, _ = bw.Write(p.FrameData)
_, _ = bw.Align()
_ = bw.WriteBits(uint64(flacCrc16(buf.Bytes())), 16)
_ = bw.Close()
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 {
return nil
}
return o.hdr
}
packet := readFlacFrame(o.hdr, o.br, o.bfr)
if packet == nil {
return nil
}
return packet
}