Packetize FLAC using libFLAC for faster parsing
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
DataHoarder 2022-07-17 01:15:57 +02:00
parent e899166ec4
commit 44d93971c5
Signed by: DataHoarder
SSH key fingerprint: SHA256:OLTRf6Fl87G52SiR7sWLGNzlJt4WOX+tfI2yxo0z7xk
6 changed files with 119 additions and 59 deletions

View file

@ -27,15 +27,15 @@ Collection of audio utilities for decoding/encoding files and streams.
Only output from Kirika's own encoders is supported.
| Container | Packetizer | Keep Mode | Sample Numbers | Offset | Notes |
|:---------:|:----------:|:---------:|:--------------:|:------:|:---------------------------------------------------------------------------------------------------------------------------------------|
| **FLAC** | ✅ | ✅ | ✅ | ❌ | Uses [mewkiz/flac](https://github.com/mewkiz/flac) for parsing streams. |
| **TTA** | ❌ | - | - | - | |
| **MP3** | ✅ | ✅ | ✅ | ✅ | Uses [sssgun/mp3](https://github.com/sssgun/mp3) as a frame parser. |
| **Ogg** | ✅ | ✅ | ✅* | ✅ | *Sample numbers (absolute granule position in Ogg) depend on underlying codec implementing it.<br/>Has been tested as working for Opus |
| **ADTS** | ✅ | ✅ | ✅ | ✅ | Uses [edgeware/mp4ff](https://github.com/edgeware/mp4ff) for its ADTS frame parser. |
| **MP4** | ❌ | - | - | - | |
| **ADIF** | ❌ | - | - | - | |
| Container | Packetizer | Keep Mode | Sample Numbers | Offset | Notes |
|:---------:|:----------:|:---------:|:--------------:|:------:|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **FLAC** | ✅ | ✅ | ✅ | ❌ | Uses [libFLAC](https://github.com/xiph/flac) via [goflac](https://git.gammaspectra.live/S.O.N.G/goflac) for parsing streams.<br/>If not available, [mewkiz/flac](https://github.com/mewkiz/flac) will be used. |
| **TTA** | ❌ | - | - | - | |
| **MP3** | ✅ | ✅ | ✅ | ✅ | Uses [sssgun/mp3](https://github.com/sssgun/mp3) as a frame parser. |
| **Ogg** | ✅ | ✅ | ✅* | ✅ | *Sample numbers (absolute granule position in Ogg) depend on underlying codec implementing it.<br/>Has been tested as working for Opus |
| **ADTS** | ✅ | ✅ | ✅ | ✅ | Uses [edgeware/mp4ff](https://github.com/edgeware/mp4ff) for its ADTS frame parser. |
| **MP4** | ❌ | - | - | - | |
| **ADIF** | ❌ | - | - | - | |
## Dependencies
### Go >= 1.18
@ -136,7 +136,7 @@ If this tag is enabled, yet `aac` support remains enabled, an AAC encoder (but n
### disable_codec_libflac
This tag disables the [libFLAC](https://gitlab.xiph.org/xiph/flac) support for decoding/encoding FLAC.
This tag disables the [libFLAC](https://gitlab.xiph.org/xiph/flac) support for decoding/encoding/packetizing FLAC.
If this tag is enabled, yet `flac` support remains enabled, [mewkiz/flac](https://github.com/mewkiz/flac) FLAC decoder (but not encoder) will be used.

View file

@ -2,19 +2,9 @@ package packetizer
import (
"bufio"
flac_parser "github.com/mewkiz/flac"
"io"
)
type FLACPacketizer struct {
reader io.Reader
stream *flac_parser.Stream
offset int64
samples int64
bytesRead int64
buffer []byte
}
type FLACPacket struct {
mode KeepMode
sampleNumber int64
@ -47,8 +37,8 @@ func NewFLACPacketizer(reader io.Reader) *FLACPacketizer {
}
func (o *FLACPacketizer) Read(p []byte) (n int, err error) {
n, err = io.ReadFull(o.reader, p)
if err == nil {
n, err = o.reader.Read(p)
if n > 0 {
o.buffer = append(o.buffer, p[:n]...)
}
o.bytesRead += int64(n)
@ -62,45 +52,13 @@ func (o *FLACPacketizer) Seek(offset int64, whence int) (int64, error) {
return 0, io.ErrNoProgress
}
func (o *FLACPacketizer) Close() error {
return nil
}
func (o *FLACPacketizer) getBuffer() (buf []byte) {
buf = make([]byte, len(o.buffer))
copy(buf, o.buffer)
o.buffer = o.buffer[:0]
return
}
func (o *FLACPacketizer) GetPacket() (packet Packet) {
var err error
if o.stream == nil {
o.stream, err = flac_parser.NewSeek(o)
if err != nil {
return nil
}
packet = &FLACPacket{
mode: Keep,
sampleNumber: 0,
endSampleNumber: 0,
data: o.getBuffer(),
}
return
}
frame, err := o.stream.ParseNext()
if err != nil {
return nil
}
sampleNumber := int64(frame.Num)
if frame.HasFixedBlockSize {
sampleNumber *= int64(frame.BlockSize)
}
packet = &FLACPacket{
mode: Discard,
sampleNumber: sampleNumber,
endSampleNumber: sampleNumber + int64(frame.Subframes[0].NSamples),
data: o.getBuffer(),
}
return
}

View file

@ -0,0 +1,50 @@
//go:build !disable_format_flac && !disable_codec_libflac && cgo
package packetizer
import (
libflac "git.gammaspectra.live/S.O.N.G/goflac"
"io"
)
type FLACPacketizer struct {
reader io.Reader
stream *libflac.Decoder
offset int64
samples int64
bytesRead int64
buffer []byte
}
func (o *FLACPacketizer) GetPacket() Packet {
var err error
if o.stream == nil {
o.stream, err = libflac.NewDecoderReader(o)
if err != nil {
return nil
}
return &FLACPacket{
mode: Keep,
sampleNumber: 0,
endSampleNumber: 0,
data: o.getBuffer(),
}
}
frame, err := o.stream.ReadFrame()
if err != nil {
return nil
}
sampleNumber := o.samples
nsamples := int64(len(frame.Buffer)) / int64(frame.Channels)
o.samples += nsamples
return &FLACPacket{
mode: Discard,
sampleNumber: sampleNumber,
endSampleNumber: sampleNumber + nsamples,
data: o.getBuffer(),
}
}

View file

@ -0,0 +1,50 @@
//go:build disable_format_flac || disable_codec_libflac || !cgo
package packetizer
import (
flac_parser "github.com/mewkiz/flac"
"io"
)
type FLACPacketizer struct {
reader io.Reader
stream *flac_parser.Stream
offset int64
samples int64
bytesRead int64
buffer []byte
}
func (o *FLACPacketizer) GetPacket() Packet {
var err error
if o.stream == nil {
o.stream, err = flac_parser.NewSeek(o)
if err != nil {
return nil
}
return &FLACPacket{
mode: Keep,
sampleNumber: 0,
endSampleNumber: 0,
data: o.getBuffer(),
}
}
frame, err := o.stream.ParseNext()
if err != nil {
return nil
}
sampleNumber := int64(frame.Num)
if frame.HasFixedBlockSize {
sampleNumber *= int64(frame.BlockSize)
}
return &FLACPacket{
mode: Discard,
sampleNumber: sampleNumber,
endSampleNumber: sampleNumber + int64(frame.Subframes[0].NSamples),
data: o.getBuffer(),
}
}

View file

@ -87,7 +87,9 @@ func TestPacketizeOggOffset(t *testing.T) {
break
}
packetCount++
packetBytes += len(packet.GetDataOffset(1000))
if offsetablePacket, ok := packet.(OffsetablePacket); ok {
packetBytes += len(offsetablePacket.GetDataOffset(1000))
}
}
if packetCount != 395 {
t.Errorf("Wrong Packet Count %d != %d", packetCount, 395)