将 PCM 数据编码为AAC格式
1.将mp3文件转换为pcm文件
ffmpeg -i test.mp3 -f s16le test.pcm
2.贴上代码
aac.c
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswresample/swresample.h>
#include <stdio.h>
#include <stdbool.h>
SwrContext *g_swr_ctx = NULL;
static int audio_resampling_2(AVFrame *dst, const AVFrame *src)
{
int ret = 0;
if (!dst || !src)
{
av_log(NULL, AV_LOG_ERROR, "frame pointer is null\n");
return -1;
}
//创建swr对象
if (!g_swr_ctx)
{
g_swr_ctx = swr_alloc();
if (!g_swr_ctx)
{
av_log(NULL, AV_LOG_ERROR, "swr contex alloc failed\n");
return -1;
}
printf("in_channel_layout = %d\n", src->channel_layout);
printf("in_sample_rate = %d\n", src->sample_rate);
printf("in_format = %d\n", src->format);
printf("out_channel_layout = %d\n", dst->channel_layout);
printf("out_sample_rate = %d\n", dst->sample_rate);
printf("out_format = %d\n", dst->format);
//设置转换参数
av_opt_set_int(g_swr_ctx, "in_channel_layout", src->channel_layout, 0);
av_opt_set_int(g_swr_ctx, "in_sample_rate", src->sample_rate, 0);
av_opt_set_sample_fmt(g_swr_ctx, "in_sample_fmt", src->format, 0);
av_opt_set_int(g_swr_ctx, "out_channel_layout", dst->channel_layout, 0);
av_opt_set_int(g_swr_ctx, "out_sample_rate", dst->sample_rate, 0);
av_opt_set_sample_fmt(g_swr_ctx, "out_sample_fmt", dst->format, 0);
//初始化swr对象
if ((ret = swr_init(g_swr_ctx)) < 0)
{
av_log(NULL, AV_LOG_ERROR, "init swr contex failed\n");
swr_free(&g_swr_ctx);
return -1;
}
}
//估算输出的采样数
dst->nb_samples = FFMAX(av_rescale_rnd(swr_get_delay(g_swr_ctx, src->sample_rate) + src->nb_samples,
dst->sample_rate, src->sample_rate, AV_ROUND_UP),
av_rescale_rnd(src->nb_samples, dst->sample_rate, src->sample_rate, AV_ROUND_UP));
//分配样本空间
ret = av_samples_alloc(dst->data, &dst->linesize[0], dst->channels,
dst->nb_samples, dst->format, 0);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "samples alloc failed\n");
swr_free(&g_swr_ctx);
return -1;
}
//进行重采样,并且把缓存的样本flush掉
ret = swr_convert(g_swr_ctx, dst->data, dst->nb_samples, (const uint8_t **)src->data, src->nb_samples)
+ swr_convert(g_swr_ctx, dst->data, dst->nb_samples, 0, 0);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "resample failed\n");
swr_free(&g_swr_ctx);
return -1;
}
//重新设置输出采样数
dst->nb_samples = ret;
return 0;
}
int flush_encoder(AVFormatContext *fmt_ctx, unsigned int stream_index)
{
int ret = 0;
int got_frame = 0;
AVPacket enc_pkt;
if(!(fmt_ctx->streams[stream_index]->codec->codec->capabilities &
CODEC_CAP_DELAY))
{
return 0;
}
while(1)
{
enc_pkt.data = NULL;
enc_pkt.size = 0;
av_init_packet(&enc_pkt);
ret = avcodec_encode_audio2(fmt_ctx->streams[stream_index]->codec, &enc_pkt, NULL, &got_frame);
if(ret < 0)
{
break;
}
if(!got_frame)
{
ret = 0;
break;
}
ret = av_write_frame(fmt_ctx, &enc_pkt);
if(ret < 0)
{
break;
}
}
return ret;
}
void usage(void)
{
printf("./aac input_file output_file.aac\n");
}
int main(int argc, char *argv[])
{
if(argc != 3)
{
usage();
return -1;
}
char *input_file = argv[1];
char *output_file = argv[2];
AVFormatContext *pFormatCtx = NULL;
AVOutputFormat *ofmt = NULL;
AVStream *audio_stream = NULL;
AVCodecContext *pCodecCtx = NULL;
AVCodec *pCodec = NULL;
uint8_t *frame_buf = NULL;
AVFrame *pFrame = NULL;
AVPacket pkt;
int got_frame = 0;
int ret = 0;
int size = 0;
int i = 0;
FILE *fp = fopen(input_file, "rb");
av_register_all();
avformat_alloc_output_context2(&pFormatCtx, NULL, NULL, output_file);
ofmt = pFormatCtx->oformat;
if(avio_open(&pFormatCtx->pb, output_file, AVIO_FLAG_READ_WRITE) < 0)
{
printf("Error: call avio_open failed!\n");
return -1;
}
audio_stream = avformat_new_stream(pFormatCtx, 0);
if(!audio_stream)
{
return -1;
}
//初始化编码器
pCodecCtx = audio_stream->codec;
pCodecCtx->codec_id = ofmt->audio_codec;
pCodecCtx->codec_type = AVMEDIA_TYPE_AUDIO;
pCodecCtx->sample_fmt = AV_SAMPLE_FMT_FLTP;
pCodecCtx->channel_layout = AV_CH_LAYOUT_STEREO;
pCodecCtx->channels = av_get_channel_layout_nb_channels(pCodecCtx->channel_layout);
pCodecCtx->sample_rate = 44100;
pCodecCtx->bit_rate = 192000;
pCodecCtx->frame_size = 1024;
AVFrame *src_frame = NULL;
AVFrame *dst_frame = NULL;
src_frame = av_frame_alloc();
src_frame->nb_samples = 1024;
src_frame->sample_rate = 44100;
src_frame->format= AV_SAMPLE_FMT_S16;
src_frame->channel_layout = AV_CH_LAYOUT_STEREO;
src_frame->channels = av_get_channel_layout_nb_channels(src_frame->channel_layout);
//重采样
dst_frame = av_frame_alloc();
dst_frame->sample_rate = 44100;
dst_frame->format = AV_SAMPLE_FMT_FLTP;
dst_frame->channel_layout = AV_CH_LAYOUT_STEREO;
dst_frame->channels = av_get_channel_layout_nb_channels(dst_frame->channel_layout);
pCodec = avcodec_find_encoder(pCodecCtx->codec_id);
//pCodec = avcodec_find_encoder_by_name("aac");
if(!pCodec)
{
printf("Error: call avcodec_find_encoder failed!\n");
return -1;
}
if(avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
{
printf("Error: call avcodec_open2 failed!\n");
return -1;
}
int sr_size = 0;
sr_size = av_samples_get_buffer_size(NULL, src_frame->channels, src_frame->nb_samples, src_frame->format, 1);
frame_buf = (uint8_t *)av_malloc(sr_size);
if(!frame_buf)
{
printf("Error: call av_malloc failed, sr_size = %d\n", sr_size);
return -1;
}
if(av_sample_fmt_is_planar(src_frame->format))
{
avcodec_fill_audio_frame(src_frame, src_frame->channels, src_frame->format, (const uint8_t *)frame_buf, sr_size * src_frame->channels, 1 );
}
else
{
avcodec_fill_audio_frame(src_frame, src_frame->channels, src_frame->format, (const uint8_t *)frame_buf, sr_size, 0 );
}
//Write Header
if(avformat_write_header(pFormatCtx,NULL) < 0)
{
printf("Error: call avformat_write_header..\n");
return -1;
}
AVPacket *packet = (AVPacket *)av_malloc(sizeof(AVPacket));
av_init_packet(packet);
dst_frame->pts = 0;
while(fread(frame_buf, 1, sr_size, fp) > 0)
{
//printf("Read a frame..\n");
got_frame = 0;
if(audio_resampling_2(dst_frame, src_frame) < 0)
{
printf("Error: call audio_resampling_2\n");
return -1;
}
ret = avcodec_encode_audio2(pCodecCtx, packet, dst_frame, &got_frame);
if(ret < 0)
{
printf("Error: call avcodec_encode_audio2\n");
return -1;
}
i++;
dst_frame->pts = i * 100;
if(1 == got_frame)
{
packet->stream_index = audio_stream->index;
ret = av_write_frame(pFormatCtx, packet);
if(ret < 0)
{
printf("Error: call av_write_frame..\n");
}
av_free_packet(packet);
}
if(dst_frame->data[0])
{
av_free(dst_frame->data[0]);
}
}
//flush encoder
ret = flush_encoder(pFormatCtx, 0);
if(ret < 0)
{
printf("Error: call flush_encoder failed!\n");
return -1;
}
if(av_write_trailer(pFormatCtx) < 0)
{
printf("Error: call av_write_trailer..\n");
return -1;
}
if(audio_stream)
{
avcodec_close(audio_stream->codec);
av_frame_free(&dst_frame);
av_frame_free(&src_frame);
av_free(frame_buf);
}
av_free(packet);
avio_close(pFormatCtx->pb);
avformat_free_context(pFormatCtx);
fclose(fp);
printf("Encode Audio End...\n");
return 0;
}
3.编译
gcc -g mp2.c -o mp2 -lavformat -lavcodec -lavutil -lswresample
4.执行
./mp2 test.pcm test.aac