/*
* 一笑奈何
* cn-yixiaonaihe.blog.csdn.net
*/
#include <iostream>
#include <thread>
extern "C" {
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
}
using namespace std;
static double r2d(AVRational r)
{
return r.den == 0 ? 0 : (double)r.num / (double)r.den;
}
void XSleep(int ms)
{
//c++ 11
chrono::milliseconds du(ms);
this_thread::sleep_for(du);
}
int main(int argc, char *argv[])
{
cout << "Test Demux FFmpeg.club" << endl;
const char *url = "test.pcm";
const char *outfile = "test.aac";
//初始化封装库
av_register_all();
//初始化网络库 (可以打开rtsp rtmp http 协议的流媒体视频)
avformat_network_init();
//注册解码器
avcodec_register_all();
//1 打开音频编码器
AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
if (!codec)
{
cout << "avcodec_find_encoder NO" << endl;
return -1;
}
AVCodecContext *c = avcodec_alloc_context3(codec);
if (!codec)
{
cout << "avcodec_alloc_context3 NO" << endl;
return -1;
}
c->bit_rate = 64000;
c->sample_rate = 44100;
c->sample_fmt = AV_SAMPLE_FMT_FLTP;
c->channel_layout = AV_CH_LAYOUT_STEREO;
c->channels = 2;
c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
int ret = avcodec_open2(c, codec, NULL);
if (ret < 0)
{
cout << "avcodec_open2 NO" << endl;
return -1;
}
cout << "avcodec_open2 OK" << endl;
//2 打开输出封装上下文
AVFormatContext *oc = NULL;
avformat_alloc_output_context2(&oc, NULL,NULL,outfile);
if (!oc)
{
cout << "avformat_alloc_output_context2 NO" << endl;
return -1;
}
AVStream *st = avformat_new_stream(oc, NULL);
st->codecpar->codec_tag = 0;
avcodec_parameters_from_context(st->codecpar, c);
av_dump_format(oc, 0, outfile, 1);
//3 open io & write head
ret=avio_open(&oc->pb, outfile, AVIO_FLAG_WRITE);
if (ret<0)
{
cout << "avio_open NO" << endl;
return -1;
}
ret = avformat_write_header(oc,NULL);
//44100 16位 双通道
//4 创建音频重采样上下文
//音频重采样 上下文初始化
SwrContext *actx = swr_alloc();
actx = swr_alloc_set_opts(actx,
c->channel_layout, //输出格式
c->sample_fmt, //输出样本格式
c->sample_rate, //输出采样率
AV_CH_LAYOUT_STEREO,//输入格式
AV_SAMPLE_FMT_S16,
44100,
0, 0
);
ret = swr_init(actx);
if (ret != 0)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
cout << "swr_init failed! :" << buf << endl;
return -1;
}
//5 打开输入音频文件进行重采样
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 No :" << endl;
return -1;
}
char *pcm = NULL;
int readSize = frame->nb_samples * 2 * 2;
pcm = new char[readSize];
FILE *fp = fopen(url,"rb");
for (;;)
{
int len = fread(pcm, 1, readSize, fp);
if (len <= 0)break;
const uint8_t *data[1];
data[0] = (uint8_t*)pcm;
ret = swr_convert(actx,
frame->data, frame->nb_samples, //输出
data, frame->nb_samples); //输入
if (len <= 0)break;
AVPacket pkt;
av_init_packet(&pkt);
//音频编码
ret=avcodec_send_frame(c, frame);
if (ret != 0)continue;
ret = avcodec_receive_packet(c, &pkt);
if (ret != 0)continue;
//7 音频封装进AAC文件
pkt.stream_index = 0;
pkt.pts = 0;
pkt.dts = 0;
ret = av_interleaved_write_frame(oc, &pkt);
cout << "[" << len << "]";
}
delete pcm;
//写入视频索引尾部信息
av_write_trailer(oc);
//主动关闭后才可以把缓冲区的内容写到文件
avio_close(oc->pb);
//清理空间
av_frame_free(&frame);
//先关闭后释放
swr_close(actx);
swr_free(&actx);
//清理封装输出上下文
avformat_free_context(oc);
//关闭编码器
avcodec_close(c);
//清理编码器上下文
avcodec_free_context(&c);
fclose(fp);
cout << "==================end===============" << endl;
return 0;
}
【FFMPEG应用篇】基于FFmpeg的PCM数据编码为AAC
于 2020-11-01 17:28:55 首次发布