本文所给的是一个简单的FFmpeg音频编码示例:
输入的PCM文件格式信息:采样率为48000、双通道、32位
输出的AAC文件格式信息:采样率为44100、双通道、16位
受项目的限制,FFmpeg的版本为2.4.6
如果是需要在新版本上开发,可以用做参考,整体的思路不会有太大的变化。
整体思路是先进行重采样,然后再进行编码。
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswresample/swresample.h"
#include "libavutil/opt.h"
};
#define INBUF_SIZE 1024
#define IN_SAMPLE_RATE 48000
#define OUT_SAMPLE_RATE 44100
#define CHANNEL 2 //通道数
#define BITPERSAMPLE 4 //每个样本点的字节数,例如S16为2,FLT为4
int main()
{
SwrContext *swr;
swr = swr_alloc();
swr = swr_alloc_set_opts(swr, AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_S16, OUT_SAMPLE_RATE, //输出的音频参数
AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_FLT, IN_SAMPLE_RATE, //输入的音频参数
0, 0);
if (!swr) {
fprintf(stderr, "Could not allocate resample context\n");
return 0;
}
if (swr_init(swr) < 0) {
fprintf(stderr, "Could not open resample context\n");
swr_free(&swr);
return 0;
}
uint8_t *samples = (uint8_t *)av_malloc(INBUF_SIZE * CHANNEL * BITPERSAMPLE);
FILE *in_file = fopen("test.pcm", "rb");
FILE *out_file = fopen("Convert_test.aac", "wb");
const int out_num_samples = av_rescale_rnd(
swr_get_delay(swr, IN_SAMPLE_RATE) + INBUF_SIZE, OUT_SAMPLE_RATE,
IN_SAMPLE_RATE, AV_ROUND_UP);
uint8_t* outputBuffer = (uint8_t *)av_malloc(out_num_samples * CHANNEL * BITPERSAMPLE);
avcodec_register_all();
AVCodec* pCodec = avcodec_find_encoder(AV_CODEC_ID_AAC);
AVCodecContext* pCodecCtx = avcodec_alloc_context3(pCodec);
pCodecCtx->sample_rate = OUT_SAMPLE_RATE;
pCodecCtx->sample_fmt = AV_SAMPLE_FMT_S16;
pCodecCtx->channels = 2;
pCodecCtx->codec_type = AVMEDIA_TYPE_AUDIO; //声道类型
pCodecCtx->channel_layout = AV_CH_LAYOUT_STEREO; //输入音频的channel layout
pCodecCtx->bit_rate = 64000; // 音频码率 Bit(码率)
int ret = avcodec_open2(pCodecCtx, pCodec, nullptr);
if (ret < 0) {
char errbuf[128] = { 0 };
const char *errbuf_ptr = errbuf;
if (av_strerror(ret, errbuf, sizeof(errbuf)) < 0)
strerror_s(errbuf, AVUNERROR(ret));
return false;
}
AVFrame* pFrame = av_frame_alloc();
pFrame->format = pCodecCtx->sample_fmt;
pFrame->channels = pCodecCtx->channels;
pFrame->channel_layout = pCodecCtx->channel_layout;
pFrame->sample_rate = pCodecCtx->sample_rate;
pFrame->nb_samples = pCodecCtx->frame_size;
ret = avcodec_fill_audio_frame(pFrame, pCodecCtx->channels, pCodecCtx->sample_fmt,
(const uint8_t*)outputBuffer, out_num_samples * CHANNEL * BITPERSAMPLE, 0);
if (ret < 0) {
fprintf(stderr, "Could not setup audio frame\n");
exit(1);
}
AVPacket pkt;
int got_pkt = 0;
while(1) {
if (fread(samples, 1, INBUF_SIZE * CHANNEL * BITPERSAMPLE, in_file) <= 0) {
printf("Failed to read raw data! \n");
return 0;
}
else if (feof(in_file)) {
break;
}
swr_convert(swr, &outputBuffer, out_num_samples, (const uint8_t**)(&samples), INBUF_SIZE);
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
ret = avcodec_encode_audio2(pCodecCtx, &pkt, pFrame, &got_pkt);
if (ret < 0 || got_pkt != 1) {
av_packet_unref(&pkt);
return false;
}
fwrite(pkt.data, 1, pkt.size, out_file);
}
av_packet_unref(&pkt);
av_freep(&outputBuffer[0]);
av_freep(&samples[0]);
swr_free(&swr);
fclose(in_file);
fclose(out_file);
printf("Successful encoding of PCM format to AAC format! \n");
system("pause");
return 0;
}
参考文档:
https://blog.csdn.net/leixiaohua1020/article/details/25430449
https://blog.csdn.net/vnanyesheshou/article/details/54560684
https://github.com/FFmpeg/FFmpeg/blob/n2.4.6/doc/examples/decoding_encoding.c