FFmpeg编码过程
编码流程图
步骤
1:注册组件
2:猜格式编码
3:查找编码器
4:打开编码器
5:写入头帧
6:像素数据编码成码流数据
7:写码流数据
8:结束编码
9:写尾帧
FFmpeg编码函数
av_register_all():注册所有组件。
av_guess_format():已经注册的最合适的输出格式
avcodec_find_encoder():查找一个已经注册的音视频编码器
avcode_open2():打开编码码器
avformat_write_header():把流头信息写入到媒体文件中
av_read_frame():读取一帧压缩数据。
avcodec_send_frame():发送一帧像素数据
avcodec_receive_packet():接受一帧编码数据
av_packet_rescale_ts():时间基转换
av_write_frame():写一帧数据
flush_encoder():将最后一帧写入文件
av_write_trailer():把流尾信息写入文件
av_code_close():关闭流
FF解码代码展示
头文件
这里的头文件需要先引入ffmpeg的相关头文件,这里还需要先配置好ffmpeg库文件的相关环境配置。
环境配置资源链接:https://download.csdn.net/download/weixin_55799469/87788642?spm=1001.2014.3001.5503
头文件代码:
#ifndef ENCODEVIDEO_H
#define ENCODEVIDEO_H
#include<QImage>
#include<QString>
#include<QThread>
#include<QObject>
#include<QDebug>
extern "C"
{
//C语言的引入 C语言编码
#include"libavcodec/avcodec.h"
#include"libavdevice/avdevice.h"
#include"libavfilter/avfilter.h"
#include"libavformat/avformat.h"
#include"libavutil/avutil.h"
#include"libpostproc/postprocess.h"
#include"libswresample/swresample.h"
#include"libswscale/swscale.h"
}
class EncodeVideo
{
public:
EncodeVideo();
void register_all();
void initEncode();
void encodecVideo(AVFrame *frame);
void writeTailer();
private:
AVFormatContext * formatContext;
AVCodecContext * codecContext;
AVPacket * pkt;
int pktIndex;
};
#endif // ENCODEVIDEO_H
.cpp执行文件代码
.cpp文件代码 :
#include "encodevideo.h"
EncodeVideo::EncodeVideo()
{
register_all();
this->formatContext=avformat_alloc_context();//初始化
this->pkt=av_packet_alloc();//初始化
this->pktIndex=0;
}
//注册组件使用
void EncodeVideo::register_all()
{
//初始化注册组件
av_register_all();
}
//初始化编辑器
void EncodeVideo::initEncode()
{
//1:通过文件的后缀得到最佳的输出格式
AVOutputFormat *format=av_guess_format(nullptr,"../fileout/Warcraft3_End.H264",nullptr);
if(format==nullptr)
{
qDebug()<<"format is null";
}
else{
qDebug()<<"format sucess";
}
//1.1赋值 设置格式 为了编码获取文件时候通过这个对象知道是什么格式
this->formatContext->oformat=format;
//2:打开视频流
int res=avio_open(&(this->formatContext->pb),".H264",AVIO_FLAG_WRITE);
if(res<0)
{
qDebug()<<"avio_open error";
}
else{
qDebug()<<"avio_open sucess";
}
//2.1 新建视频流
AVStream *newStream=avformat_new_stream(this->formatContext,nullptr);
if(newStream==nullptr)
{
qDebug()<<"newStream is null";
}
else{
qDebug()<<"newStream sucess";
}
//2.2 设置编码器上下文环境设置信息
this->codecContext = newStream->codec;
//2.3 设置基础信息
this->codecContext->width=800;
this->codecContext->height=368;
this->codecContext->bit_rate=579000;//码率 影响视频的大小
this->codecContext->time_base={1,24};//时间基
this->codecContext->framerate={24,1};//帧率
//2.4 一些高级配置
this->codecContext->gop_size=10;// I/P/B 10帧为一组
this->codecContext->qmax=51;//清晰度
this->codecContext->qmin=10;//清晰度
this->codecContext->max_b_frames=0;//B帧压缩为0
this->codecContext->pix_fmt=AV_PIX_FMT_YUV420P;
this->codecContext->codec_type=AVMEDIA_TYPE_VIDEO;
this->codecContext->codec_id=format->video_codec;
//3:查找编码器
AVCodec *codec=avcodec_find_encoder(this->codecContext->codec_id);
//3.1打开编码器
res=avcodec_open2(this->codecContext,codec,nullptr);
if(res!=0)
{
qDebug()<<"avcodec_open2 error";
}
else{
qDebug()<<"avcodec_open2 sucess";
}
//4.写头信息
res=avformat_write_header(this->formatContext,nullptr);
if(res<0)
{
qDebug()<<"avformat_write_header error";
}
else{
qDebug()<<"avformat_write_header sucess";
}
qDebug()<<"initEncode sucess";
}
//逐帧编码
void EncodeVideo::encodecVideo(AVFrame *frame)
{
//5.发送一帧的像素数据给编码器
int res=avcodec_send_frame(this->codecContext,frame);//发送一帧
if(res!=0)
{
qDebug()<<"avcodec_send_frame error";
return;
}
else{
qDebug()<<"avcodec_send_frame sucess";
}
while(res>=0)
{
frame->pts=this->pktIndex++;
//6.像素数据转换成码流数据
res=avcodec_receive_packet(this->codecContext,this->pkt);
if(res!=0)
{
qDebug()<<"avcodec_receive_packet error";
return ;
}
else{
qDebug()<<"avcodec_receive_packet sucess";
}
//7.写一帧码流数据到avformatContext
res=av_interleaved_write_frame(this->formatContext,this->pkt);
if(res!=0)
{
qDebug()<<"av_interleaved_write_frame error";
return;
}
else{
qDebug()<<"av_interleaved_write_frame sucess";
}
}
av_packet_unref(this->pkt);//释放
}
//写入尾帧
void EncodeVideo::writeTailer()
{
//8.写入尾信息 到 avformatContext
av_write_trailer(this->formatContext);
//9.回收IO资源
avio_close(this->formatContext->pb);
//10.释放avfomatContext
avformat_free_context(this->formatContext);
}
FFmpeg编码的数据结构