资源准备
- 本地pcm文件 ->采样率44100 双通道 AV_SAMPLE_FMT_S16格式
- 压缩后的aac ->采样率44100 双通道 AV_SAMPLE_FMT_FLTP格式
实现思路
- 创建输出上下文 avformat_alloc_output_context2();
- 查找编码器 avcodec_find_encoder();
- 创建编码器上下文 avcodec_alloc_context3();
- 设置编码器具体参数
- 打开编码器
- 创建流
- 打开输出文件
- 写入头文件
- 初始化重采样相关
- 初始化AVFrame,AVPacket
- 计算每次读取pcm一帧的样本大小以及创建缓存空间
- 打开输入文件
- 开始循环读取,进行重采样然后写入本地文件
- 读取完毕后写入文件索引
- 释放资源
代码
AVFormatContext *audioFmtCtx;
AVCodec *audioCodec;
AVCodecContext *audioCtx;
AVStream *audioStream;
SwrContext *swrCtx;
AVFrame *audioFrame;
void PcmToAac::PcmToAacInit() {
const char *inFile = "/sdcard/aaa/test.pcm";
const char *outFile = "/sdcard/aaa/test.aac";
int ret = 0;
ret = avformat_alloc_output_context2(&audioFmtCtx, NULL, NULL, outFile);
if (ret < 0) {
LOGE("创建输出上下文失败");
}
audioCodec = avcodec_find_encoder(AV_CODEC_ID_AAC);
if (!audioCodec) {
LOGE("AAC编码器寻找失败");
}
audioCtx = avcodec_alloc_context3(audioCodec);
if (!audioCtx) {
LOGE("AAC编码器上下文创建失败");
}
audioCtx->channels = 2;
audioCtx->channel_layout = AV_CH_LAYOUT_STEREO;
audioCtx->sample_rate = 44100;
audioCtx->sample_fmt = AV_SAMPLE_FMT_FLTP;
audioCtx->bit_rate = 64000;
audioCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
ret = avcodec_open2(audioCtx, audioCodec, NULL);
if (ret != 0) {
LOGE("打开编码器失败");
}
audioStream = avformat_new_stream(audioFmtCtx, NULL);
audioStream->codecpar->codec_tag = 0;
avcodec_parameters_from_context(audioStream->codecpar, audioCtx);
ret = avio_open(&audioFmtCtx->pb, outFile, AVIO_FLAG_WRITE);
if (ret < 0) {
LOGE("打开输出文件失败");
}
avformat_write_header(audioFmtCtx, NULL);
swrCtx = swr_alloc_set_opts(swrCtx, audioCtx->channel_layout,
audioCtx->sample_fmt, audioCtx->sample_rate,
AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_S16,
44100, 0, 0);
if (!swrCtx) {
LOGE("SwrContext参数设置失败");
}
ret = swr_init(swrCtx);
if (ret < 0) {
LOGE("SwrContext初始化失败");
}
audioFrame = av_frame_alloc();
audioFrame->format = AV_SAMPLE_FMT_FLTP;
audioFrame->channels = 2;
audioFrame->channel_layout = AV_CH_LAYOUT_STEREO;
audioFrame->nb_samples = 1024;
ret = av_frame_get_buffer(audioFrame, 0);
if (ret < 0) {
LOGE("audioFrame创建失败");
}
int readSize = audioFrame->nb_samples * 2 * 2;
char *pcmBuffer = new char[readSize];
FILE *file = fopen(inFile, "rb");
for (;;) {
int len = fread(pcmBuffer, 1, readSize, file);
if (len <= 0) {
LOGE("文件读取完毕");
break;
}
const uint8_t *pcmData[1];
pcmData[0] = (uint8_t *) pcmBuffer;
swr_convert(swrCtx, audioFrame->data, audioFrame->nb_samples,
pcmData, 1024);
AVPacket pkt;
av_init_packet(&pkt);
int ret;
ret = avcodec_send_frame(audioCtx, audioFrame);
if (ret != 0) continue;
ret = avcodec_receive_packet(audioCtx,&pkt);
if (ret != 0) continue;
pkt.stream_index = audioStream->index;
pkt.pts = 0;
pkt.dts = 0;
av_interleaved_write_frame(audioFmtCtx,&pkt);
LOGE("写入本地文件成功");
}
delete pcmBuffer;
pcmBuffer = NULL;
av_write_trailer(audioFmtCtx);
avio_close(audioFmtCtx->pb);
avcodec_close(audioCtx);
avcodec_free_context(&audioCtx);
avformat_free_context(audioFmtCtx);
}
文章评论