编码出来的aac播放全是刺耳的噪声
来源:8-8 AAC编码器编码2

慕妹3585395
2024-04-03
问题
重采样结果播放都是很清晰的,但是编码之后就全是噪声了
- ffplay -ar 48000 -ac 1 -f f32le audio_raw.pcm 正常播放
- ffplay -ar 48000 -ac 1 -f s16le audio_resample.pcm 正常播放
- ffplay audio_encode.aac 全是刺耳的噪音
- 备注:虽然我重采样的时候已经是s16了,播放aac的时候显示的fltp(不知道咋来的)
系统默认参数为:
获取的原始PCM为:
编码后的结果如下:
代码如下
打开编码器
static AVCodecContext* open_codec(){
// 1. 查找编码器
AVCodec *codec = avcodec_find_encoder_by_name("libfdk_aac"); // 根据名称查找编码器
if (!codec) {
fprintf(stderr, "avcodec_find_encoder_by_name error!\n");
return NULL;
}
// 2. 创建 codec 上下文,目的是设置codec编码器的参数
AVCodecContext *codec_context = avcodec_alloc_context3(codec);
codec_context->sample_fmt = AV_SAMPLE_FMT_S16; // 输入音频的采样大小
codec_context->channel_layout = AV_CH_LAYOUT_MONO; // 输入音频的channel layout
codec_context->channels = 1; // 输入音频 channel 个数
codec_context->sample_rate = 48000; // 输入音频的采样率
codec_context->bit_rate = 128000; // AAC_LC: 128K, AAC HE: 64K, AAC HE V2: 32K
//codec_context->profile = FF_PROFILE_AAC_HE; // 若内部指定了profile,就是动态码率,就不要指定码率了
// 3. 打开编码器
int ret = avcodec_open2(codec_context, codec, NULL);
if (ret < 0){
print_error(ret, "avcodec_open2 error");
return NULL;
}
return codec_context;
}
读取
while(rec_status) {
// 4. 从格式中读取packet(假设它是编码后的)
AVPacket pkt;
av_init_packet(&pkt);
ret = av_read_frame(format_context, &pkt); // 这个函数会自动给pkt分配内部数据空间
if (ret < 0) {
if (ret == AVERROR(EAGAIN)) {
usleep(10000); //如果设备没有准备好,那就等一小会
continue;
}
print_error(ret, "av_read_frame error");
break;
}
printf("av_read_frame success, pkt.data=%p, pkt.size=%d\n", pkt.data, pkt.size);
// 写入本地
fwrite(pkt.data, 1, pkt.size, out_file_raw);
fflush(out_file_raw);
// 5. 如果格式是语音文件的话,这里还要解码,但是这里不用
// 6. 对av_packet(其实就是av_frame)进行重采样
memcpy((void*)src_data[0], (void*)pkt.data, pkt.size); // 将采样前的av_frame拷贝到重采样的输入缓冲中
ret = swr_convert(swr_context, // 重采样的上下文
dst_data, // 输出结果缓冲区
512, // 输出每个通道的采样数
(const uint8_t **)src_data, // 输入缓冲区
512); // 输入单个通道的采样数
if (ret < 0) {
print_error(ret, "swr_convert error");
break;
}
printf("swr_convert success!dst_linesize=%d\n", dst_linesize);
// 写入本地
fwrite(dst_data[0], 1, dst_linesize, out_file_resample);
fflush(out_file_resample);
memcpy((void *)frame->data[0], dst_data[0], dst_linesize); // 将重采样的输出缓冲(av_frame)拷贝到 frame 中
// 7. 对av_frame编码
encode(codec_context, frame, newpkt, out_file_encode);
//
av_packet_unref(&pkt); //release pkt
}
编码
static void encode(AVCodecContext *codec_context,
AVFrame *frame,
AVPacket *newpkt,
FILE *out_file_encode){
//将数据送编码器
int ret = avcodec_send_frame(codec_context, frame);
if (ret < 0) {
print_error(ret, "avcodec_send_frame error");
return;
}
printf("avcodec_send_frame success!\n");
// 如果ret>=0说明数据设置成功
while(ret >= 0) {
// 获取编码后的音频数据,如果成功,需要重复获取,直到失败为止
ret = avcodec_receive_packet(codec_context, newpkt);
if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF){
return;
} else if( ret < 0){
print_error(ret, "avcodec_receive_packet error");
exit(-1);
}
printf("avcodec_receive_packet success!\n");
// write file
fwrite(newpkt->data, 1, newpkt->size, out_file_encode);
fflush(out_file_encode);
}
return;
}
重采样上下文
static
SwrContext* init_swr(void){
// 创建重采样上下文
SwrContext *swr_context = swr_alloc_set_opts(NULL,
AV_CH_LAYOUT_MONO, // 输出channel布局
AV_SAMPLE_FMT_S16, // 输出的采样格式
48000, // 输出的采样率
AV_CH_LAYOUT_MONO, // 输入channel布局
AV_SAMPLE_FMT_FLT, // 输入的采样格式
48000, // 输入的采样率
0, NULL);
if(!swr_context){
print_error2("swr_alloc_set_opts error");
return NULL;
}
// 初始化重采样上下文
int ret = swr_init(swr_context);
if(ret < 0){
print_error(ret, "swr_init error");
return NULL;
}
return swr_context;
}
重采样分配
static
int alloc_data_4_resample(uint8_t ***src_data,
int *src_linesize,
uint8_t *** dst_data,
int *dst_linesize){
//创建输入缓冲区 2048 / 4 / 1 = 512
int ret = av_samples_alloc_array_and_samples(src_data, //输出缓冲区地址
src_linesize, //缓冲区的大小
1, //通道个数
512, //单通道采样个数
AV_SAMPLE_FMT_FLT, //采样格式
0);
if (ret < 0) {
print_error(ret, "av_samples_alloc_array_and_samples error");
return ret;
}
//创建输出缓冲区
ret = av_samples_alloc_array_and_samples(dst_data, //输出缓冲区地址
dst_linesize, //缓冲区的大小
1, //通道个数
512, //单通道采样个数
AV_SAMPLE_FMT_S16, //采样格式
0);
if (ret < 0) {
print_error(ret, "av_samples_alloc_array_and_samples error");
return ret;
}
return 0;
}
重采样执行
ret = swr_convert(swr_context, // 重采样的上下文
dst_data, // 输出结果缓冲区
512, // 输出每个通道的采样数
(const uint8_t **)src_data, // 输入缓冲区
512); // 输入单个通道的采样数
写回答
1回答
-
李超
2024-04-04
把你重采样后的采样率设置成44100 试试
042024-04-04
相似问题