Kirika/audio/format/aac/aac.go

217 lines
3.8 KiB
Go

package aac
import (
"errors"
"fmt"
"git.gammaspectra.live/S.O.N.G/Kirika/audio"
"git.gammaspectra.live/S.O.N.G/Kirika/audio/packetizer"
"git.gammaspectra.live/S.O.N.G/Kirika/cgo"
"git.gammaspectra.live/S.O.N.G/go-fdkaac/fdkaac"
"io"
"unsafe"
)
type Format struct {
}
func NewFormat() Format {
return Format{}
}
func decodeFrame(decoder *fdkaac.AacDecoder, p *packetizer.AdtsPacketizer) ([]float32, error) {
pcm, err := decoder.Decode()
if err != nil {
return nil, err
}
if pcm != nil {
return cgo.Int32ToFloat32(cgo.BytesToInt32(pcm, 16), 16), nil
}
packet := p.GetPacket()
if packet == nil {
return nil, errors.New("error decoding")
}
_, err = decoder.Fill(packet.GetData())
if err != nil {
return nil, err
}
return decodeFrame(decoder, p)
}
func (f Format) Open(r io.ReadSeekCloser) (audio.Source, error) {
decoder := fdkaac.NewAacDecoder()
err := decoder.InitAdts()
if err != nil {
return audio.Source{}, err
}
p := packetizer.NewAdtsPacketizer(r)
buf, err := decodeFrame(decoder, p)
if err != nil {
decoder.Close()
return audio.Source{}, err
}
newChannel := make(chan []float32)
go func() {
defer close(newChannel)
defer decoder.Close()
if len(buf) > 0 {
newChannel <- buf
}
for {
buf, err = decodeFrame(decoder, p)
if err != nil {
return
}
if len(buf) > 0 {
newChannel <- buf
}
}
}()
return audio.Source{
Channels: decoder.NumChannels(),
SampleRate: decoder.SampleRate(),
Blocks: newChannel,
}, nil
}
func (f Format) Encode(source audio.Source, writer io.WriteCloser, options map[string]interface{}) error {
var bitrate = 128
var isHEv2 bool
if options != nil {
var val interface{}
var ok bool
var intVal int
var strVal string
if val, ok = options["bitrate"]; ok {
if strVal, ok = val.(string); ok {
switch strVal {
case "320k":
bitrate = 320
case "256k":
bitrate = 256
case "192k":
bitrate = 192
case "128k":
bitrate = 128
default:
return fmt.Errorf("unknown setting bitrate=%s", strVal)
}
} else if intVal, ok = val.(int); ok {
bitrate = intVal
}
}
if val, ok = options["mode"]; ok {
if strVal, ok = val.(string); ok {
switch strVal {
case "lc":
isHEv2 = false
case "hev2":
isHEv2 = true
default:
return fmt.Errorf("unknown setting mode=%s", strVal)
}
}
}
}
encoder := fdkaac.NewAacEncoder()
if isHEv2 {
err := encoder.InitHEv2(source.Channels, source.SampleRate, bitrate*1024)
if err != nil {
return err
}
} else {
err := encoder.InitLc(source.Channels, source.SampleRate, bitrate*1024)
if err != nil {
return err
}
}
defer encoder.Close()
frameSize := encoder.FrameSize() * encoder.Channels()
var buffer []int16
for block := range source.Blocks {
buffer = append(buffer, cgo.Float32ToInt16(block)...)
for len(buffer) >= frameSize {
sl := buffer[:frameSize]
buf, err := encoder.Encode(unsafe.Slice((*byte)(unsafe.Pointer(&sl[0])), len(sl)*2))
if err != nil {
return err
}
if len(buf) > 0 {
_, err = writer.Write(buf)
if err != nil {
return err
}
}
buffer = buffer[frameSize:]
}
}
if len(buffer) > 0 {
//pad
buffer = append(buffer, make([]int16, frameSize-len(buffer))...)
buf, err := encoder.Encode(unsafe.Slice((*byte)(unsafe.Pointer(&buffer[0])), len(buffer)*2))
if err != nil {
return err
}
if len(buf) > 0 {
_, err = writer.Write(buf)
if err != nil {
return err
}
}
}
//Do flush
for {
buf, err := encoder.Flush()
if err != nil {
return err
}
if len(buf) > 0 {
_, err = writer.Write(buf)
if err != nil {
return err
}
} else {
break
}
}
return nil
}
func (f Format) Identify(peek []byte, extension string) bool {
return extension == "aac" || extension == "adts"
}