const std::string res_dir = "./x64/Debug/";
const std::string input_file = res_dir + "input_8k16bits.pcm";
const std::string output_file = res_dir + "test.aac";
int AudioEncoder::Run()
{
int ret = 0;
// 创建编码器
const AVCodec* codec;
codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
if (!codec) {
fprintf(stderr, "avcodec_find_encoder failed\n");
return -1;
}
// 配置编码器上下文
AVCodecContext* ac = NULL;
ac = avcodec_alloc_context3(codec);
if (!ac) {
fprintf(stderr, "avcodec_alloc_context3 failed\n");
return -1;
}
// 设置采样率
ac->sample_rate = 64000;
ac->channels = 2;
ac->sample_fmt = AVSampleFormat::AV_SAMPLE_FMT_FLTP;
ac->bit_rate = 64000;
// 设置声道类型
ac->channel_layout = AV_CH_LAYOUT_STEREO;
if (!check_sample_fmt(codec, ac->sample_fmt)) {
fprintf(stderr, "Encoder does not support sample format %s",
av_get_sample_fmt_name(ac->sample_fmt));
return -1;
}
// 打开编码器
ret = avcodec_open2(ac, codec, NULL);
if (ret != 0)
{
fprintf(stderr, "avcodec_open2 failed");
return -1;
}
// 打开pcm 文件
FILE* fp = fopen(input_file.c_str(),"rb");
if (!fp) {
fprintf(stderr, "fopen failed");
return -1;
}
//创建接收pcm 数据的帧,并设置参数
AVFrame* frame = av_frame_alloc();
if (!frame)
{
fprintf(stderr, "av_frame_alloc failed");
return -1;
}
frame->format = ac->sample_fmt;
frame->channels = 2;
frame->channel_layout = ac->channel_layout;
frame->nb_samples = ac->frame_size;
//为frame 分配空间
ret = av_frame_get_buffer(frame, 0);
if (ret < 0) {
fprintf(stderr, "av_frame_get_buffer failed\n");
return -1;
}
// 创建接收编码码数据的packet
AVPacket* pkt = av_packet_alloc();
if (!pkt)
{
fprintf(stderr, "av_packet_alloc failed");
return -1;
}
int read_size = frame->nb_samples * 2;
char* pcms = new char[read_size];
// 创建重采样上下文
SwrContext* swr_ctx = NULL;
swr_ctx = swr_alloc();
if (!swr_ctx) {
fprintf(stderr, "swr_alloc failed\n");
return -1;
}
// 设置重采样上下文输出参数
av_opt_set_int(swr_ctx, "out_channel_layout", ac->channel_layout, 0);
av_opt_set_int(swr_ctx, "out_sample_rate", ac->sample_rate, 0);
av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", ac->sample_fmt, 0);
// 设置重采样上下文输入参数
av_opt_set_int(swr_ctx, "in_channel_layout", AV_CH_LAYOUT_MONO, 0);
av_opt_set_int(swr_ctx, "in_sample_rate", 8000, 0);
av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
// 初始化重采样上下文
if ((ret = swr_init(swr_ctx)) < 0) {
fprintf(stderr, "Failed to initialize the resampling context\n");
return -1;
}
// 创建AVFormatContext,并设置参数
AVFormatContext* oc = NULL;
//初始化输出码流的 AVFormatContext
avformat_alloc_output_context2(&oc, NULL, NULL, output_file.c_str());
if (!oc)
{
fprintf(stderr, "avformat_alloc_output_context2 failed\n");
return -1;
}
//创建AVStream,并与AVFormatContext 进行关联
AVStream* st = avformat_new_stream(oc, NULL);
st->codecpar->codec_tag = 0;
avcodec_parameters_from_context(st->codecpar, ac);
av_dump_format(oc, 0, output_file.c_str(), 1);
ret = avio_open(&oc->pb, output_file.c_str(), AVIO_FLAG_WRITE);
if (ret < 0) {
fprintf(stderr, "avio_open failed\n");
return -1;
}
avformat_write_header(oc, NULL);
for (;;)
{
size_t len = fread(pcms, 1, read_size, fp);
if (len < 0)
break;
// 重采样pcm 数据
const uint8_t* data[1];
data[0] = (uint8_t*)pcms;
ret = swr_convert(swr_ctx, frame->data, frame->nb_samples, (const uint8_t**)data, frame->nb_samples);
if (ret < 0) {
fprintf(stderr, "swr_convert failed\n");
return -1;
}
// 编码并写入文件
Encoder(ac, frame, pkt,oc);
}
// 释放资源
delete[] pcms;
av_write_trailer(oc);
avio_close(oc->pb);
avcodec_close(ac);
avcodec_free_context(&ac);
avformat_free_context(oc);
return 0;
}
bool AudioEncoder::check_sample_fmt(const AVCodec* codec, enum AVSampleFormat sample_fmt)
{
const enum AVSampleFormat* p = codec->sample_fmts;
while (*p != AV_SAMPLE_FMT_NONE) {
if (*p == sample_fmt)
return 1;
p++;
}
return 0;
}
void AudioEncoder::Encoder(AVCodecContext* ctx, AVFrame* frame, AVPacket* pkt,
AVFormatContext* oc)
{
int ret;
// 开始编码
ret = avcodec_send_frame(ctx, frame);
if (ret < 0) {
fprintf(stderr, "Error sending the frame to the encoder\n");
exit(1);
}
// 接收编码出的数据
while (ret >= 0) {
ret = avcodec_receive_packet(ctx, pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
return;
else if (ret < 0) {
fprintf(stderr, "Error encoding audio frame\n");
exit(1);
}
// 写入aac 文件
pkt->stream_index = 0; // 表示音频流
av_interleaved_write_frame(oc, pkt);
av_packet_unref(pkt);
}
}
评论