//
// Created by bytedance on 2022/1/20.
//
#include "main.h"
#include <iostream>
#include <unistd.h>
using namespace std;
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavutil/log.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(){
int ret =0;
// 样本格式 sample_size AV_SAMPLE_FMT_S16(16位字节存储) AV_SAMPLE_FMT_FLTP(浮点数存储 4个字节32位存储)
// 样本类型 planar AV_SAMPLE_FMT_S16 在内存中的格式为c1/c2/c1/c2
// 样本类型 planar AV_SAMPLE_FMT_S16P 在内存中的格式为c1/c1/c1/...c2/c2/c2
av_register_all(); // 注册所有的解码器
avcodec_register_all(); // 注册所有的编解码
// 输入和输出都是字符数组
char inputFile[] = "../audio.pcm";
char outFile[] = "../audio.aac";
// 1、找到指定的编码器
AVCodec * codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
if (!codec) {
cout<<"avcodec_find_encoder failed"<<endl;
return -1;
}
// 2、根据编码器拿到编码器的上下文(输入的上下文)
AVCodecContext* avCodecContext = avcodec_alloc_context3(codec);
if (!avCodecContext) {
cout<<"avcodec_alloc_context3 failed"<<endl;
return -1;
}
// 3、将音频的参数设置到编辑器的上下文中
avCodecContext->sample_rate = 44100;
avCodecContext->channels = 2;
// 声道类型是立体声
avCodecContext->channel_layout =AV_CH_LAYOUT_STEREO;
// 设置样本格式
avCodecContext->sample_fmt = AV_SAMPLE_FMT_FLTP;
avCodecContext->bit_rate = 64000;
// 设置文件头部
avCodecContext->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
// 4、打开音频编码器
ret =avcodec_open2(avCodecContext, codec, NULL);
if(ret < 0) {
return -1;
}
// 5、创建一个输出的结构体
AVFormatContext * oc =NULL;
avformat_alloc_output_context2(&oc, NULL, NULL, outFile);
if(!oc) {
return -1;
}
// 6、 创建音频流
AVStream * st = avformat_new_stream(oc, NULL);
st->codecpar->codec_tag = 0;
// 拷贝音频输入设置的那些参数
avcodec_parameters_from_context(st->codecpar, avCodecContext);
// 打印设置的信息
av_dump_format(oc, 0, outFile, 1);
// 7、打开音频文件
ret = avio_open(&oc->pb, outFile, AVIO_FLAG_READ_WRITE);
if (ret < 0) {
return -1;
}
avformat_write_header(oc, NULL); // 生成一个aac的文件
// 8、设置重采样
SwrContext * ctx = NULL;
ctx = swr_alloc_set_opts(ctx, avCodecContext->channel_layout,avCodecContext->sample_fmt, avCodecContext-> sample_rate, // 输出的音频参数
AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_S16, 44100, // 输入的音频参数
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;
}
// 一帧一帧的读取PCM数据,进行重采样,然后写入到aac文件
// 9、创建接收帧数据的结构体
AVFrame *frame = av_frame_alloc();
frame->format = AV_SAMPLE_FMT_FLTP;
frame->channels =2;
frame->channel_layout = AV_CH_LAYOUT_STEREO;
frame->nb_samples = 1024; //一帧音频的采样数量
ret = av_frame_get_buffer(frame, 0);
if(ret < 0)
{
cout<<"av_frame_get_buffer failed"<<endl;
return -1;
}
// 10、创建缓存空间
int readSize = frame->nb_samples*2*2; // 16位 代表两个字节
char *pcms = new char[readSize];
// 11、打开输入的音频文件
FILE *flp = fopen(inputFile, "rb");
if (flp == nullptr)
{
cout<<"fopen failed"<<endl;
return -1;
}
for(;;)
{
int len = fread(pcms, 1, readSize, flp);
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;
}
// 12、重载样之后的数据重新编码后写入aac文件
AVPacket pkt;
av_init_packet(&pkt); // avpacket 一般作为需要重新编码的数据容器
// 将数据发送给编码线程
ret = avcodec_send_frame(avCodecContext, frame);
if(ret != 0)
{
continue;
}
ret = avcodec_receive_packet(avCodecContext, &pkt);
if(ret != 0)
{
continue;
}
// 0标识音频流
pkt.stream_index = 0;
pkt.dts = 0; //重置解码时间
pkt.pts = 0; //重置播放时间
// 将文件写入到输出文件
av_interleaved_write_frame(oc, &pkt);
cout<<len+"单词读取的样本个数"<<endl;
}
delete pcms;
pcms = NULL;
// 写入视频的索引
av_write_trailer(oc);
// 、关闭文件流、编码器
avio_close(oc->pb);
// 关闭编码器
avcodec_close(avCodecContext);
// 清理设置的编码器参数
avcodec_free_context(&avCodecContext);
// 清理结构体上下文
avformat_free_context(oc);
std::cout<<"main.cpp"<<endl;
return 0;
}
音频转aac格式
于 2022-02-09 21:38:40 首次发布