voaac-go/encode.go

134 lines
2.5 KiB
Go
Raw Permalink Normal View History

2018-03-06 13:41:36 +00:00
// Package aac provides AAC codec encoder based on [VisualOn AAC encoder](https://github.com/mstorsjo/vo-aacenc) library.
2018-03-06 03:50:55 +00:00
package aac
2019-01-22 12:04:54 +00:00
// #include <stdlib.h>
2018-03-06 03:50:55 +00:00
import "C"
import (
"io"
"unsafe"
"git.gammaspectra.live/S.O.N.G/voaac-go/aacenc"
2018-03-06 03:50:55 +00:00
)
// Options represent encoding options.
type Options struct {
// Audio file sample rate
SampleRate int
// Encoder bit rate in bits/sec
BitRate int
// Number of channels on input (1,2)
NumChannels int
}
// Encoder type.
type Encoder struct {
2018-11-29 06:34:29 +00:00
w io.Writer
aacEnc *aacenc.Encoder
2018-03-06 03:50:55 +00:00
insize int
inbuf []byte
outbuf []byte
}
// NewEncoder returns new AAC encoder.
func NewEncoder(w io.Writer, opts *Options) (e *Encoder, err error) {
e = &Encoder{}
e.w = w
2018-11-29 06:34:29 +00:00
e.aacEnc = aacenc.New()
2018-03-06 03:50:55 +00:00
if opts.BitRate == 0 {
opts.BitRate = 64000
}
2018-11-29 06:34:29 +00:00
ret := e.aacEnc.Init(aacenc.VoAudioCodingAac)
2018-03-06 03:50:55 +00:00
err = aacenc.ErrorFromResult(ret)
if err != nil {
return
}
var params aacenc.AacencParam
params.SampleRate = int32(opts.SampleRate)
params.BitRate = int32(opts.BitRate)
params.NChannels = int16(opts.NumChannels)
params.AdtsUsed = 1
2018-11-29 06:34:29 +00:00
ret = e.aacEnc.SetParam(aacenc.VoPidAacEncparam, unsafe.Pointer(&params))
2018-03-06 03:50:55 +00:00
err = aacenc.ErrorFromResult(ret)
if err != nil {
return
}
e.insize = int(opts.NumChannels) * 2 * 1024
e.inbuf = make([]byte, e.insize)
e.outbuf = make([]byte, 20480)
return
}
// Encode encodes data from reader.
func (e *Encoder) Encode(r io.Reader) (err error) {
2019-01-22 12:04:54 +00:00
var outinfo aacenc.VoAudioOutputinfo
var input, output aacenc.VoCodecBuffer
var n int
var prevRead int
2019-01-22 12:04:54 +00:00
loop:
2018-03-06 03:50:55 +00:00
for {
n, err = r.Read(e.inbuf[prevRead:])
2018-03-06 03:50:55 +00:00
if err != nil {
if err != io.EOF {
return err
}
break
}
prevRead += n
if prevRead < e.insize {
continue
2018-03-06 03:50:55 +00:00
}
n = prevRead
prevRead = 0
2018-03-06 03:50:55 +00:00
input.Buffer = C.CBytes(e.inbuf)
input.Length = uint64(n)
2018-11-29 06:34:29 +00:00
ret := e.aacEnc.SetInputData(&input)
2018-03-06 03:50:55 +00:00
err = aacenc.ErrorFromResult(ret)
if err != nil {
2019-01-22 12:04:54 +00:00
break loop
2018-03-06 03:50:55 +00:00
}
output.Buffer = C.CBytes(e.outbuf)
output.Length = uint64(len(e.outbuf))
2018-11-29 06:34:29 +00:00
ret = e.aacEnc.GetOutputData(&output, &outinfo)
2018-03-06 03:50:55 +00:00
err = aacenc.ErrorFromResult(ret)
if err != nil {
2019-01-22 12:04:54 +00:00
break loop
2018-03-06 03:50:55 +00:00
}
_, err = e.w.Write(C.GoBytes(output.Buffer, C.int(output.Length)))
if err != nil {
2019-01-22 12:04:54 +00:00
break loop
2018-03-06 03:50:55 +00:00
}
2019-01-22 12:04:54 +00:00
C.free(input.Buffer)
input.Buffer = nil
C.free(output.Buffer)
output.Buffer = nil
}
if input.Buffer != nil {
C.free(input.Buffer)
}
if output.Buffer != nil {
C.free(output.Buffer)
2018-03-06 03:50:55 +00:00
}
return nil
}
// Close closes encoder.
func (e *Encoder) Close() error {
2018-11-29 06:34:29 +00:00
ret := e.aacEnc.Uninit()
2018-03-06 03:50:55 +00:00
return aacenc.ErrorFromResult(ret)
}