我使用的ffmpeg是3.4版本 对应的帮助文档是api文档是
我们还是以项目
中相关项目来学习,其中几乎所有相关功能都和编码有关系,
比如视频剪辑,裁剪,分辨率等,都有。道理相通
av_register_all();
注册混合器注册编解码器
result = avformat_alloc_output_context2(&afc_output, NULL, NULL, outputPath);
开辟一个AVFormatContext(容器)来处理,会根据outputPath来申请不同的容器,比如是sdcard/FFmpeg/test.mp4,就是申请一个mp4容器来处理
avformat_new_stream
Add a new stream to a media file.
添加一个新流到文件中
avcodec_find_encoder(afot->video_codec);
找到对应的编码器(AVCodecID)
申请一个 AVCodecContext
vCtxE = avcodec_alloc_context3(videoCodecE)
然后初始化相关参数
//比如码率,时间基,gop_size(i帧之间的距离),
//数据源格式,最大b帧数,编码器类型,图像的宽,高
vCtxE->bit_rate = 400000;
vCtxE->time_base = (AVRational) {1, 25};
vCtxE->framerate = (AVRational) {25, 1};
vCtxE->gop_size = 10;
vCtxE->max_b_frames = 1;
vCtxE->pix_fmt = AV_PIX_FMT_YUV420P;
vCtxE->codec_type = AVMEDIA_TYPE_VIDEO;
vCtxE->width = width;
vCtxE->height = height;
avcodec_parameters_from_context(videoOutStream->codecpar, vCtxE);
把数据copy数据流相关结构体中
avcodec_open2(vCtxE, videoCodecE, NULL);
初始化AVCodecContext
音频的操作流程相似,只是初始化音频的参数相关有点出入,比如要初始化采样率,声道,采样大小这些数据
详情去看源码把
或者官方的一些api或者demo都行
然后
avio_open(&afc_output->pb, outputPath, AVIO_FLAG_WRITE);
创建和初始化一个AVIOContext ,io流
然后
avformat_write_header(afc_output, NULL);
写文件头,比如flv,MP4有不同数据流
传入的yuv(视频源)数据,或者pcm(音频源)数据
就要开始编码处理
avcodec_send_frame(vCtxE, frame);
将原始数据送入,然后通过
avcodec_receive_packet(vCtxE, packet);
取出得到的就是编码后的数据
接着就要开始写入数据了,因为音频和视频轨道为了要播放同步,所以音频,视频需要交叉写入文件,av_compare_ts就是为了判断是接下来写入视频相关还是音频相关的数据
av_compare_ts(apts, audioOutStream->time_base, vpts, videoOutStream->time_base)
其中apts,vpts就是你上一帧写入的音频或者视频时间,对应timebase就是时间基。
然后
av_interleaved_write_frame(afc_output, aPkt);
就写入相关avpacket就行了
av_write_trailer(afc_output);
当所有数据都搞定了就写入文件尾,这个文件就搞定了。
然后释放相关结构体就行了,注意要释放干净,不然轻者内存泄漏,重者软件崩溃。
if(vCtxE != NULL){
avcodec_free_context(&vCtxE);
}
if(vCtxD != NULL){
avcodec_free_context(&vCtxD);
}
if (afc_input != NULL) {
avformat_close_input(&afc_input);
}
if (afc_output != NULL) {
avformat_free_context(afc_output);
}
if(path != NULL){
free(path);
}
if(outputPath != NULL){
free(outputPath);
}