2022-02-28 12:54:17 +00:00
|
|
|
package aac
|
|
|
|
|
|
|
|
/*
|
|
|
|
#cgo CFLAGS: -I"${SRCDIR}/../../../cgo" -march=native -Ofast -std=c99
|
|
|
|
#include "audio.h"
|
|
|
|
*/
|
|
|
|
import "C"
|
|
|
|
import (
|
2022-04-17 17:02:06 +00:00
|
|
|
"errors"
|
2022-02-28 12:54:17 +00:00
|
|
|
"fmt"
|
|
|
|
"git.gammaspectra.live/S.O.N.G/Kirika/audio"
|
2022-04-17 17:02:06 +00:00
|
|
|
"git.gammaspectra.live/S.O.N.G/Kirika/audio/packetizer"
|
2022-02-28 12:54:17 +00:00
|
|
|
"git.gammaspectra.live/S.O.N.G/go-fdkaac/fdkaac"
|
|
|
|
"io"
|
|
|
|
"unsafe"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Format struct {
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewFormat() Format {
|
|
|
|
return Format{}
|
|
|
|
}
|
|
|
|
|
2022-04-17 17:02:06 +00:00
|
|
|
func decodeFrame(decoder *fdkaac.AacDecoder, p *packetizer.AdtsPacketizer) ([]float32, error) {
|
|
|
|
pcm, err := decoder.Decode()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if pcm != nil {
|
|
|
|
n := len(pcm) / 2
|
|
|
|
buf := make([]float32, n)
|
|
|
|
intBuf := make([]int32, n)
|
|
|
|
|
|
|
|
C.audio_bytes_to_int32((*C.int8_t)(unsafe.Pointer(&pcm[0])), C.size_t(len(pcm)), (*C.int32_t)(&intBuf[0]), C.int(16))
|
|
|
|
C.audio_int32_to_float32((*C.int32_t)(&intBuf[0]), C.size_t(n), (*C.float)(&buf[0]), C.int(16))
|
|
|
|
|
|
|
|
return buf, 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
|
|
|
|
}
|
|
|
|
|
2022-02-28 12:54:17 +00:00
|
|
|
func (f Format) Encode(source audio.Source, writer io.WriteCloser, options map[string]interface{}) error {
|
|
|
|
var bitrate = 128
|
2022-02-28 14:47:50 +00:00
|
|
|
var isHEv2 bool
|
2022-02-28 12:54:17 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
2022-02-28 14:47:50 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-02-28 12:54:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
encoder := fdkaac.NewAacEncoder()
|
2022-02-28 14:47:50 +00:00
|
|
|
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
|
|
|
|
}
|
2022-02-28 12:54:17 +00:00
|
|
|
}
|
|
|
|
defer encoder.Close()
|
|
|
|
|
|
|
|
frameSize := encoder.FrameSize() * encoder.Channels()
|
|
|
|
|
|
|
|
var buffer []int16
|
|
|
|
for block := range source.Blocks {
|
|
|
|
samples := make([]int16, len(block))
|
|
|
|
|
|
|
|
C.audio_float32_to_int16((*C.float)(&block[0]), C.size_t(len(block)), (*C.int16_t)(&samples[0]))
|
|
|
|
buffer = append(buffer, samples...)
|
|
|
|
|
|
|
|
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 {
|
2022-03-06 13:52:01 +00:00
|
|
|
return extension == "aac"
|
2022-02-28 12:54:17 +00:00
|
|
|
}
|