forked from ktysakura/rtmp_media
-
Notifications
You must be signed in to change notification settings - Fork 1
/
aacencoder.cpp
213 lines (182 loc) · 5.11 KB
/
aacencoder.cpp
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
#include "aacencoder.h"
#include "dlog.h"
/**
* @brief AACEncoder::AACEncoder
* @param properties
* key value
* sample_fmt 默认AV_SAMPLE_FMT_FLTP
* samplerate 默认 48000
* ch_layout 默认AV_CH_LAYOUT_STEREO
* bitrate 默认out_samplerate*3
*/
AACEncoder::AACEncoder()
{
}
AACEncoder::~AACEncoder()
{
if (ctx_)
avcodec_free_context(&ctx_);
if (frame_)
av_frame_free(&frame_);
}
RET_CODE AACEncoder::Init(const Properties &properties)
{
// 获取参数
sample_rate_ = properties.GetProperty("sample_rate", 48000);
bitrate_ = properties.GetProperty("bitrate", 128*1024);
channels_ = properties.GetProperty("channels", 2);
channel_layout_ = properties.GetProperty("channel_layout",
(int)av_get_default_channel_layout(channels_));
int ret;
type_ = AudioCodec::AAC;
// 读取默认的aac encoder
codec_ = avcodec_find_encoder(AV_CODEC_ID_AAC);
if(!codec_)
{
LogError("AAC: No encoder found\n");
return RET_ERR_MISMATCH_CODE;
}
ctx_ = avcodec_alloc_context3(codec_);
if (ctx_ == NULL)
{
LogError("AAC: could not allocate context.\n");
return RET_ERR_OUTOFMEMORY;
}
//Set params
ctx_->channels = channels_;
ctx_->channel_layout = channel_layout_;
ctx_->sample_fmt = AV_SAMPLE_FMT_FLTP;
ctx_->sample_rate = sample_rate_;
ctx_->bit_rate = bitrate_;
ctx_->thread_count = 1;
//Allow experimental codecs
ctx_->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
if (avcodec_open2(ctx_, codec_, NULL) < 0)
{
LogError("AAC: could not open codec\n");
return RET_FAIL;
}
frame_byte_size_ = av_get_bytes_per_sample(ctx_->sample_fmt)
* ctx_->channels * ctx_->frame_size;
//Create frame
frame_ = av_frame_alloc();
//Set defaults
frame_->nb_samples = ctx_->frame_size;
frame_->format = ctx_->sample_fmt;
frame_->channel_layout = ctx_->channel_layout;
frame_->sample_rate = ctx_->sample_rate;
//分配data buf
ret = av_frame_get_buffer(frame_, 0);
//Log
LogInfo("AAC: Encoder open with frame sample size %d.\n", ctx_->frame_size);
return RET_OK;
}
int AACEncoder::Encode(AVFrame *frame,uint8_t* out,int out_len)
{
AVPacket pkt;
int got_output;
int ret;
if (!frame)
return 0;
if (ctx_ == NULL)
{
LogError("AAC: no context.\n");
return -1;
}
//Reset packet
av_init_packet(&pkt);
//Set output
pkt.data = out;
pkt.size = out_len;
//Encode audio
if (avcodec_encode_audio2(ctx_, &pkt, frame, &got_output)<0)
{
LogError("AAC: could not encode audio frame\n");
return -1;
}
//Check if we got output
if (!got_output)
{
LogError("AAC: could not get output packet\n");
return -1;
}
//Return encoded size
return pkt.size;
}
/**
* @brief 每次需要输入足够进行一次编码的数据
* @param in
* @param size
* @return
*/
RET_CODE AACEncoder::EncodeInput(const uint8_t *in, const uint32_t size)
{
RET_CODE ret_code = RET_OK;
if(in)
{
uint32_t need_size = av_get_bytes_per_sample(ctx_->sample_fmt) * ctx_->channels *
ctx_->frame_size;
if(size != need_size)
{
LogError("need size:%u, but the size:%u", need_size, size);
return RET_ERR_PARAMISMATCH;
}
AVFrame *frame = av_frame_alloc();
frame->nb_samples = ctx_->frame_size;
avcodec_fill_audio_frame(frame, ctx_->channels, ctx_->sample_fmt, in, size, 0);
ret_code = EncodeInput(frame);
av_frame_free(&frame); // 释放自己申请的数据
return ret_code;
}
else // 为null时flush编码器
{
return EncodeInput(NULL);
}
}
RET_CODE AACEncoder::EncodeInput(const AVFrame *frame)
{
int ret = avcodec_send_frame(ctx_, frame);
if(ret != 0)
{
if(AVERROR(EAGAIN) == ret)
{
LogWarn("please receive packet then send frame");
return RET_ERR_EAGAIN;
}
else if(AVERROR_EOF == ret)
{
LogWarn("if you wan continue use it, please new one decoder again");
}
return RET_FAIL;
}
return RET_OK;
}
RET_CODE AACEncoder::EncodeOutput(AVPacket *pkt)
{
int ret = avcodec_receive_packet(ctx_, pkt);
if(ret != 0)
{
if(AVERROR(EAGAIN) == ret)
{
LogWarn("output is not available in the current state - user must try to send input");
return RET_ERR_EAGAIN;
}
else if(AVERROR_EOF == ret)
{
LogWarn("the encoder has been fully flushed, and there will be no more output packets");
return RET_ERR_EOF;
}
return RET_FAIL;
}
return RET_OK;
}
RET_CODE AACEncoder::EncodeOutput(uint8_t *out, uint32_t &size)
{
AVPacket pkt;
av_init_packet(&pkt);
pkt.data = out;
pkt.size = size;
RET_CODE ret = EncodeOutput(&pkt);
size = pkt.size; // 实际编码后的数据长度
return ret;
}