-
Notifications
You must be signed in to change notification settings - Fork 11
/
encode.go
129 lines (104 loc) · 2.52 KB
/
encode.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// Package aac provides AAC codec encoder based on VisualOn AAC encoder library.
package aac
//#include <stdlib.h>
import "C"
import (
"errors"
"fmt"
"io"
"unsafe"
"github.com/gen2brain/aac-go/aacenc"
)
// 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 {
w io.Writer
insize int
inbuf []byte
outbuf []byte
}
// NewEncoder returns new AAC encoder.
func NewEncoder(w io.Writer, opts *Options) (*Encoder, error) {
e := &Encoder{}
e.w = w
if opts.BitRate == 0 {
opts.BitRate = 64000
}
ret := aacenc.Init(aacenc.VoAudioCodingAac)
err := aacenc.ErrorFromResult(ret)
if err != nil {
return nil, fmt.Errorf("aac: %w", err)
}
var params aacenc.Param
params.SampleRate = int32(opts.SampleRate)
params.BitRate = int32(opts.BitRate)
params.NChannels = int16(opts.NumChannels)
params.AdtsUsed = 1
ret = aacenc.SetParam(aacenc.VoPidAacEncparam, unsafe.Pointer(¶ms))
err = aacenc.ErrorFromResult(ret)
if err != nil {
return nil, fmt.Errorf("aac: %w", err)
}
e.insize = opts.NumChannels * 2 * 1024
e.inbuf = make([]byte, e.insize)
e.outbuf = make([]byte, 20480)
return e, nil
}
// Encode encodes data from reader.
func (e *Encoder) Encode(r io.Reader) error {
inputEmpty := false
for !inputEmpty {
n, err := r.Read(e.inbuf)
if err != nil {
if !errors.Is(err, io.EOF) {
return fmt.Errorf("aac: %w", err)
}
inputEmpty = true
}
if n < e.insize {
inputEmpty = true
}
var outinfo aacenc.VoAudioOutputinfo
var input, output aacenc.VoCodecBuffer
input.Buffer = C.CBytes(e.inbuf)
input.Length = uint64(n)
ret := aacenc.SetInputData(&input)
err = aacenc.ErrorFromResult(ret)
if err != nil {
return fmt.Errorf("aac: %w", err)
}
outputEmpty := false
for !outputEmpty {
output.Buffer = C.CBytes(e.outbuf)
output.Length = uint64(len(e.outbuf))
ret = aacenc.GetOutputData(&output, &outinfo)
err = aacenc.ErrorFromResult(ret)
if err != nil {
if !errors.Is(err, aacenc.ErrInputBufferSmall) {
return fmt.Errorf("aac: %w", err)
}
outputEmpty = true
}
_, err = e.w.Write(C.GoBytes(output.Buffer, C.int(output.Length)))
if err != nil {
return fmt.Errorf("aac: %w", err)
}
C.free(output.Buffer)
}
C.free(input.Buffer)
}
return nil
}
// Close closes encoder.
func (e *Encoder) Close() error {
ret := aacenc.Uninit()
return aacenc.ErrorFromResult(ret)
}