AV_SAMPLE_FMT_S16 使用16位 两个字节
AV_SAMPLE_FMT_FLTP 使用32位 四字节 fLOAT
播放pcm文件 :
./ffplay.exe -ar 16000 -channels 1 -f s16le -i device_check_voice.pcm
新建工程:
附加依赖项:
avcodec.lib
swresample.lib
avutil.lib
avformat.lib
ffmpeg是由C语言写的,在c++中使用,需要extern "C"
#include <iostream>
using namespace std;
extern "C"
{
#include <libavcodec/avcodec.h> //编解码
#include <libavformat/avformat.h> //格式
#include <libavutil/avutil.h>
#include <libswresample/swresample.h> //重采样
}
//添加静态库
#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"swresample.lib")
int main()
{
// av_register_all(); 弃用
// avcodec_register_all();
int ret = 0;
char inputfile[] = "audio.pcm";
char outputfile[] = "audio.aac";
//注册编码器 acc
AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
if (!codec)
{
cout << "avcodec_find_encoder failed" << endl;
return -1;
}
//配置编码器上下文 初始化编码器上下文,主要通道数,采样率,采样格式
AVCodecContext* ac = avcodec_alloc_context3(codec);
if (!ac) {
cout << "avcodec_alloc_context3 failed" << endl;
return -1;
}
//设置参数
ac->sample_rate = 44100;
ac->channels = 2;
ac->channel_layout = AV_CH_LAYOUT_STEREO;//立体声
ac->sample_fmt = AV_SAMPLE_FMT_FLTP;//AAC 支持float类型
ac->bit_rate = 64000;
ac->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;//音频帧设置头部
//打开音频编码器
ret = avcodec_open2(ac, codec, NULL);
if (ret < 0)
{
cout << "avcodec_open2 failed" << endl;
return -1;
}
//创建输出上下文结构体
AVFormatContext* oc = NULL;
avformat_alloc_output_context2(&oc, NULL, NULL, outputfile);//初始化结构体
if (!oc)
{
cout << "avformat_alloc_output_context2 failed" << endl;
return -1;
}
//创建音频流
AVStream* st = avformat_new_stream(oc, NULL);
st->codecpar->codec_tag = 0;//在一个文件中,音频流 视频流 字幕流的下标分别为 0 1 2
//将配置的编解码器上下文拷贝到st
avcodec_parameters_from_context(st->codecpar, ac);
//打印信息 上下文 流下标 输出文件名 是否输出1 输出;
av_dump_format(oc, 0, outputfile, 1);
//打开输出文件流
ret = avio_open(&oc->pb, outputfile, AVIO_FLAG_WRITE);
if (ret < 0)
{
cout << "avio_open failed" << endl;
return -1;
}
avformat_write_header(oc, NULL);//写入头部信息
//重采样上下文
SwrContext* ctx = NULL;
//配置重采样 参数
ctx = swr_alloc_set_opts(ctx, ac->channel_layout, ac->sample_fmt, ac->sample_rate,//输出的音频参数
AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_S16, 44100,//输入的pcm的声道布局
0, 0
);
if (!ctx)
{
cout << "swr_alloc_set_opts failed" << endl;
return -1;
}
ret = swr_init(ctx);
if (ret < 0)
{
cout << "swr_init failed" << endl;
return -1;
}
//创建AVFrame 结构体 :是一帧样本:1024个
AVFrame* frame = av_frame_alloc();//分配空间
frame->format = AV_SAMPLE_FMT_FLTP;//四字节 acc只支持fltp
frame->channels = 2;
frame->channel_layout = AV_CH_LAYOUT_STEREO;
frame->nb_samples = 1024;//一帧音频的样本数量
ret = av_frame_get_buffer(frame, 0);//设置frame 缓存空间
if (ret < 0) {
cout << "av_frame_get_buffer failed" << endl;
return -1;
}
int readSize = frame->nb_samples * 2 * 2;//每一次读取的数据 双声道 * 两字节
char* pcms = new char[readSize];
//打开输入的文件
FILE* fp = fopen(inputfile, "rb");
if (fp == nullptr)
{
std::cout << "open inputfile error" << std::endl;
return -1;
}
for (;;)
{
int len = fread(pcms, 1, readSize, fp);
if (len <= 0)
{
break;
}
//强制类型转换
const uint8_t* data[1];
data[0] = (uint8_t*)pcms;
//重采样 接收 样本数量
len = swr_convert(ctx, frame->data, frame->nb_samples, //重采样之后的数据
data, frame->nb_samples //重采样之前的数据
);
if (len <= 0)
{
break;
}
//AVFrame 存储原始数据 AVPacket存放编码后的数据 存放到aac文件中
AVPacket pkt;
av_init_packet(&pkt);//初始化
//重采样之后的数据进行编码
//重采样之后的数据发送到编码线程 todo
ret = avcodec_send_frame(ac, frame);
if (ret != 0) {
continue;
}
//接收编码之后的数据
ret = avcodec_receive_packet(ac, &pkt);
if (ret != 0)
{
continue;
}
//编码后的数据写入acc文件中
pkt.stream_index = 0;//音频流 0
pkt.dts = 0;//
pkt.pts = 0;
av_interleaved_write_frame(oc, &pkt);
cout << len << ",";
}
delete pcms;
pcms = NULL;
//写入音频的索引
av_write_trailer(oc);
//关闭打开的文件io流
avio_close(oc->pb);
//关闭编码器
avcodec_close(ac);
//清理在编码器设置的参数
avcodec_free_context(&ac);
//清理封装的上下文
avformat_free_context(oc);
return 0;
}
编译:出现关于fopen报错_CRT_SECURE_NO_WARNINGS:配置