目录
FFMPEG音视频处理
14.Decode.h .cpp
15.Decode_Replay.h .cpp
16.EncodeToH264.h .cpp
17.FTranceTomp4.h .cpp
#ifndef DECODE_H
#define DECODE_H
#include
#include //调试
#include //图像
#include //线程
#include //字符串
#include //摄像头信息
#include //队列
#include "encodetoh264.h"//编码h264
//当前C++兼容C语言
extern "C"
{
//avcodec:编解码(最重要的库)
#include
//avformat:封装格式处理
#include
//swscale:视频像素数据格式转换
#include
//avdevice:各种设备的输入输出
#include
//avutil:工具库(大部分库都需要这个库的支持)
#include
}
class Decode : public QThread
{
Q_OBJECT
public:
Decode();//构造函数
void registerFFmpeg();//注册组件
int open_camera();//打开摄像头
int find_stream();//流媒体数据-查找视频流信息
int find_decoder();//查找解码器
void prepare_image();//像素数据准备
void decode_frame();//读取码流数据
static QList getcamera();//获取摄像头
private:
AVFormatContext *pformatContext; //封装格式上下文结构体,也是统领全局的结构体,保存了视频文件封装格式相关信息
AVCodecContext *codec;//编码器上下文结构体,保存了视频(音频)编解码相关信息
AVCodec *decoder;//每种视频(音频)编解码器(例如H.264解码器)对应一个该结构体
AVPacket *pkt;//存储一帧压缩编码数据
//存储一帧解码后像素(采样)数据
AVFrame *yuvpicture, *picture,*rgbpicture; //picture有损像素数据 yuvpicture去除有损数据的像素数据
SwsContext *swscontentRGB,*swscontentYUV;//图像转换上下文
uint8_t *bufferRGB,*bufferYUV;//缓存区
QImage img;//图像
int videoIndex;//记录视频流下标
int count;//统计
int interval;//间隔
EncodeToH264 *encodeObj;//编码目标h264
QString image_name;//图片名称
protected:
void run();
signals:
void sendImg(QImage img);
public slots:
};
#endif // DECODE_H
#include "decode.h"
//构造
Decode::Decode()
{
this->videoIndex= -1; //记录视频流下标
this->count = 0;
}
//获取摄像头
QList Decode::getcamera()
{
QList cnames;
cnames.clear();
QList cameras = QCameraInfo::availableCameras();
//获取摄像头到list
for(int i=0;ipformatContext=avformat_alloc_context();
//获取摄像头
QList cnames=getcamera();
AVInputFormat *fmt = av_find_input_format("dshow");
char CameraName[256];
sprintf(CameraName, "video=%s", cnames[0].toStdString().c_str());
return avformat_open_input(&pformatContext,CameraName,fmt,nullptr);
}
//查找视频流信息
int Decode::find_stream()
{
//获取视频文件信息、流数据、视频流
int res= avformat_find_stream_info(pformatContext,nullptr);
if(res!=0)
{
return res;
}
//查找是否存在视频流
for(int i=0;ipformatContext->nb_streams;i++)
{
if(pformatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
this->videoIndex = i;//找到视频流下标
break;
}
}
return this->videoIndex;
}
//查找解码器
int Decode::find_decoder()
{
//找编解码器上下文结构体
this->codec = pformatContext->streams[videoIndex]->codec;
//找解码器
this->decoder= avcodec_find_decoder(codec->codec_id);
if(decoder == nullptr)
{
return -1;
}
//打开解码器
return avcodec_open2(codec,decoder,nullptr);
}
//像素数据准备
void Decode::prepare_image()
{
//一帧码流数据
this->pkt=(AVPacket *)malloc(sizeof (AVPacket)); //开空间
//准备像素数据
picture = av_frame_alloc();
yuvpicture = av_frame_alloc(); //yuvpicture去除有损数据的像素数据YUV420
rgbpicture = av_frame_alloc(); //rgbpicture去除有损数据的像素数据RGB32
yuvpicture->width = codec->width;
yuvpicture->height = codec->height;
yuvpicture->format = codec->pix_fmt;
//----------------------RGB32像素数据准备---------------------------//
//一帧图像数据大小
int imgaeBytesRGB = avpicture_get_size(AV_PIX_FMT_RGB32,this->codec->width,this->codec->height);
//动态开辟空间
bufferRGB =(uint8_t *) av_malloc(imgaeBytesRGB *sizeof (uint8_t));
//图片填充
avpicture_fill((AVPicture *)rgbpicture,bufferRGB,AV_PIX_FMT_RGB32,this->codec->width,this->codec->height);
//剔除规则
swscontentRGB = nullptr;
//制订剔除规则 编码格式
swscontentRGB = sws_getContext(this->codec->width,this->codec->height,this->codec->pix_fmt,
this->codec->width,this->codec->height,AV_PIX_FMT_RGB32,
SWS_BICUBIC,nullptr,nullptr,nullptr);
//----------------------YUV420P像素数据准备---------------------------//
//一帧图像数据大小
int imgaeBytesYUV = avpicture_get_size(AV_PIX_FMT_YUV420P,codec->width,codec->height);
//动态开辟空间
bufferYUV =(uint8_t *) av_malloc(imgaeBytesYUV *sizeof (uint8_t));
//图片填充
avpicture_fill((AVPicture *)yuvpicture,bufferYUV,AV_PIX_FMT_YUV420P,codec->width,codec->height);
//剔除规则
swscontentYUV = nullptr;
//制订剔除规则 编码格式
swscontentYUV = sws_getContext(codec->width,codec->height,codec->pix_fmt,
codec->width,codec->height,AV_PIX_FMT_YUV420P,
SWS_BICUBIC,nullptr,nullptr,nullptr);
}
//读取码流数据
void Decode::decode_frame()
{
int mark=0;
this->image_name=encodeObj->getTime();
this->encodeObj = new EncodeToH264();
this->encodeObj->getHeightWidth(codec->width,codec->height);
this->encodeObj->getName(image_name);
this->encodeObj->start();
//一帧帧读取码流数据
while(av_read_frame(pformatContext,pkt)==0)
{
//读取码流数据 pkt
if(videoIndex == pkt->stream_index)
{
int got_picture_ptr = -1;
//解码picture:有损像素数据
avcodec_decode_video2(codec,picture,&got_picture_ptr,pkt);
if(got_picture_ptr!=0)
{
//剔除 得到纯净YUVpicture
sws_scale(swscontentYUV,picture->data,picture->linesize,0,
picture->height,yuvpicture->data,yuvpicture->linesize);
//剔除 得到纯净RGBpicture
sws_scale(swscontentRGB,picture->data,picture->linesize,0,
picture->height,rgbpicture->data,rgbpicture->linesize);
img = QImage((uchar *)bufferRGB,codec->width,codec->height,QImage::Format_RGB32);
//发送信号到播放界面
emit sendImg(img);
//把YUV420P添加到队列中
EncodeToH264::Queue_AVFrame.enqueue(yuvpicture);
this->interval=SetControl::getInstance()->getSetting_interval();
if(count==interval)
{
//这里存放的是video第一帧的图片
//写入数据库--传到另一边一起写入
if(mark==1)
{
this->image_name=encodeObj->getTime();
encodeObj->getName(image_name);
}
mark=1;
QString path=SetControl::getInstance()->getSetting_imagepath()+"/"+image_name+".jpg";
this->count=0;
img.save(path);
}
this->count++;
}
}
//重置pkt
av_packet_unref(pkt);
}
}
//解码线程
void Decode::run()
{
//整个解码操作
//打开摄像头
registerFFmpeg();
if(open_camera()!= 0)
{
return;
}
//流媒体数据
if(find_stream()!= 0)
{
return;
}
//解码器
if(find_decoder()!= 0)
{
return;
}
//读取码流数据
prepare_image();
//解码
decode_frame();
}
#ifndef DECODE_REPLAY_H
#define DECODE_REPLAY_H
#include
#include //调试
#include //图片
#include //线程
#include //字符串
#include //队列
#include //日期
#include "setcontrol.h"//设置控制层
#include "imagecontrol.h"//图像控制层
//当前C++兼容C语言
extern "C"
{
//avcodec:编解码(最重要的库)
#include
//avformat:封装格式处理
#include
//swscale:视频像素数据格式转换
#include
//avdevice:各种设备的输入输出
#include
//avutil:工具库(大部分库都需要这个库的支持)
#include
}
class Decode_Replay : public QThread
{
Q_OBJECT
public:
Decode_Replay(QString path);//构造
~Decode_Replay();//析构
void registerFFmpeg();//注册组件
int open_video();//打开视频
int find_stream();//流媒体数据-查找视频流信息
int find_decoder();//查找解码器
void prepare_image();//准备图片帧-像素数据准备
void decode_frame();//读取码流数据
static QString replay_path;//回放路径
int status;//状态
int screenshots_mark;//截屏标志位
private:
AVFormatContext *pformatContext; //封装格式上下文结构体,也是统领全局的结构体,保存了视频文件封装格式相关信息
AVCodecContext *codec; //编码器上下文结构体,保存了视频(音频)编解码相关信息
AVCodec *decoder; //每种视频(音频)编解码器(例如H.264解码器)对应一个该结构体
AVPacket *pkt;//存储一帧压缩编码数据
AVFrame *picture,*rgbpicture;//picture有损像素数据 yuvpicture去除有损数据的像素数据
SwsContext *swscontentRGB;//图像转换上下文
uint8_t *bufferRGB;//缓存区
QImage img;//图像
int play_speed;//播放速度
int videoIndex;//记录视频流下标
QString getTime();//获取日期时间
protected:
void run();//线程
signals:
void sendImg2(QImage img);//发送图片
public slots:
void setSpeed(QString speed);//速度
};
#endif // DECODE_REPLAY_H
#include "decode_replay.h"
QString Decode_Replay::replay_path=nullptr;
//构造
Decode_Replay::Decode_Replay(QString path)
{
this->videoIndex= -1; //记录视频流下标
this->replay_path = path;
this->play_speed=40;
this->status=0;
this->screenshots_mark=0;
}
//析构
Decode_Replay::~Decode_Replay(){}
//注册组件
void Decode_Replay::registerFFmpeg()
{
av_register_all();
avdevice_register_all();
}
//打开视频
int Decode_Replay::open_video()
{
this->pformatContext=avformat_alloc_context();
//封装格式上下文结构体,视频路径
return avformat_open_input(&pformatContext,replay_path.toStdString().c_str(),nullptr,nullptr);
}
//查找视频流信息
int Decode_Replay::find_stream()
{
//获取视频文件信息、流数据、视频流
int res= avformat_find_stream_info(pformatContext,nullptr);
if(res!=0)
{
return res;
}
//查找是否存在视频流
for(int i=0;ipformatContext->nb_streams;i++)
{
if(pformatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
this->videoIndex = i;//找到视频流下标
break;
}
}
return this->videoIndex;
}
//查找解码器
int Decode_Replay::find_decoder()
{
//找编解码器上下文结构体
this->codec = pformatContext->streams[videoIndex]->codec;
//找解码器
this->decoder= avcodec_find_decoder(codec->codec_id);
if(decoder == nullptr)
{
return -1;
}
//打开解码器
return avcodec_open2(codec,decoder,nullptr);
}
//像素数据准备
void Decode_Replay::prepare_image()
{
//一帧码流数据
this->pkt=(AVPacket *)malloc(sizeof (AVPacket));//开空间
//准备像素数据
picture = av_frame_alloc();
rgbpicture = av_frame_alloc(); //rgbpicture去除有损数据的像素数据RGB32
//----------------------RGB32像素数据准备---------------------------//
//一帧图像数据大小
int imgaeBytesRGB = avpicture_get_size(AV_PIX_FMT_RGB32,this->codec->width,this->codec->height);
//动态开辟空间
bufferRGB =(uint8_t *) av_malloc(imgaeBytesRGB *sizeof (uint8_t));
//图片填充
avpicture_fill((AVPicture *)rgbpicture,bufferRGB,AV_PIX_FMT_RGB32,this->codec->width,this->codec->height);
//剔除规则
swscontentRGB = nullptr;
//制订剔除规则 编码格式
swscontentRGB = sws_getContext(this->codec->width,this->codec->height,this->codec->pix_fmt,
this->codec->width,this->codec->height,AV_PIX_FMT_RGB32,
SWS_BICUBIC,nullptr,nullptr,nullptr);
}
//读取码流数据
void Decode_Replay::decode_frame()
{
//一帧帧读取码流数据
while(av_read_frame(pformatContext,pkt)==0)
{
while (status==1)
{
continue;
}
//读取码流数据 pkt
if(videoIndex == pkt->stream_index)
{
int got_picture_ptr = -1;
//解码picture:有损像素数据
avcodec_decode_video2(codec,picture,&got_picture_ptr,pkt);
if(got_picture_ptr!=0)
{
//剔除 得到纯净RGBpicture
sws_scale(swscontentRGB,picture->data,picture->linesize,0,
picture->height,rgbpicture->data,rgbpicture->linesize);
img = QImage((uchar *)bufferRGB,codec->width,codec->height,QImage::Format_RGB32);
//发送信号到播放界面
msleep(this->play_speed);
emit sendImg2(img);
if(this->screenshots_mark==1)
{
QString image_name=this->getTime();
QString path=SetControl::getInstance()->getSetting_imagepath()+"/"+"shots_"+image_name+".jpg";
img.save(path);
ImageControl::getInstance()->addImagePath(image_name, path);
this->screenshots_mark=0;
}
}
}
//重置pkt
av_packet_unref(pkt);
}
}
//线程
void Decode_Replay::run()
{
//整个解码操作
//打开摄像头
registerFFmpeg();
if(open_video()!= 0)
{
return;
}
//流媒体数据
if(find_stream()!= 0)
{
return;
}
//解码器
if(find_decoder()!= 0)
{
return;
}
//读取码流数据
prepare_image();
decode_frame();
}
void Decode_Replay::setSpeed(QString speed)
{
if(speed.compare("0.5X")==0)
{
this->play_speed=80;
}
else if(speed.compare("1X")==0)
{
this->play_speed=40;
}
else if(speed.compare("1.5X")==0)
{
this->play_speed=20;
}
else
{
this->play_speed=10;
}
}
QString Decode_Replay::getTime()
{
QDateTime currentdatetime = QDateTime::currentDateTime();
QString currentdate = currentdatetime.toString("yyyyMMddHHmmss");
return currentdate;
}
#ifndef ENCODETOH264_H
#define ENCODETOH264_H
#include
#include //调试
#include //线程
#include //链表
#include //队列
#include //日期
#include "setcontrol.h"//设置控制层
#include "videocontrol.h"//视频控制层
//当前C++兼容C语言
extern "C"
{
//avcodec:编解码(最重要的库)
#include
//avformat:封装格式处理
#include
//swscale:视频像素数据格式转换
#include
//avdevice:各种设备的输入输出
#include
//avutil:工具库(大部分库都需要这个库的支持)
#include
}
class EncodeToH264 : public QThread
{
Q_OBJECT
public:
EncodeToH264();//构造
void registerEncode();//注册组件
void guess_format(int width,int height);//猜测需要转换的格式
void encode_frame(AVFrame *yuvpicture);//编码码流数据
void writeTailer();//写尾部
void getHeightWidth(int width,int height);//获取分辨率
void getName(QString name);//获取名字
static int frame_count;//流数
static QQueue Queue_AVFrame;//队列--避免像素数据丢失
QString getTime();//获取日期时间--视频图片命名
QString path;
QString video_path;
static QString name;
static int width;//分辨率
static int height;//分辨率
AVCodec *encoder;//每种视频(音频)编解码器(例如H.264解码器)对应一个该结构体
AVOutputFormat *outformat;//输出文件容器格式
AVStream *newStream;//存储每一个视频/音频流信息的结构体
private:
AVCodecContext *codecContext;//编码器上下文结构体,保存了视频(音频)编解码相关信息
AVFormatContext *pformatContext;//封装格式上下文结构体,也是统领全局的结构体,保存了视频文件封装格式相关信息
AVPacket *pkt;//存储一帧压缩编码数据
int pkt_index;//存储一帧压缩编码数据记录
int interval;//间隔
void run();//线程
signals:
public slots:
};
#endif // ENCODETOH264_H
#include "encodetoh264.h"
int EncodeToH264::frame_count=0;
int EncodeToH264::width=0;
int EncodeToH264::height=0;
QQueue EncodeToH264::Queue_AVFrame;//队列
QString EncodeToH264::name=nullptr;
//构造
EncodeToH264::EncodeToH264()
{
this->pkt_index = 0;
this->interval = 0;
this->registerEncode();
}
//注册编码初始化
void EncodeToH264::registerEncode()
{
av_register_all();
}
//猜测需要转换的格式
void EncodeToH264::guess_format(int width,int height)
{
pkt = av_packet_alloc();
pformatContext = avformat_alloc_context();
this->video_path=SetControl::getInstance()->getSetting_videopath();
this->path =video_path+"/"+name+".h264";
this->interval=SetControl::getInstance()->getSetting_interval();
this->outformat = av_guess_format(nullptr,path.toStdString().c_str(),nullptr);
if(outformat == nullptr )
{
return;
}
//设置输出格式
pformatContext->oformat = outformat;
//打开视频流 输入输出上下文对象 输出文件路径 以写入方式操作
int res=avio_open(&pformatContext->pb,path.toStdString().c_str(),AVIO_FLAG_WRITE);
if(res!=0)
{
return;
}
//创建视频流
this->newStream = avformat_new_stream(pformatContext,nullptr);
if(newStream == nullptr)
{
return;
}
//编解码器上下文结构体
codecContext = newStream->codec;
//设置基本信息 1266 968
codecContext->width=width;
codecContext->height=height;
codecContext->time_base={1,25};//时间基,1s播放帧数
codecContext->bit_rate =400000;//码率
codecContext->framerate={25,1};//帧率
codecContext->gop_size=10;//10帧为一组
//影响清晰度
codecContext->qmax = 51;
codecContext->qmin = 10;
codecContext->max_b_frames = 0;//没有B帧
codecContext->pix_fmt = AV_PIX_FMT_YUV420P;//编码器格式
codecContext->codec_type = AVMEDIA_TYPE_VIDEO;//设置为视频流
codecContext->codec_id = outformat->video_codec;//编码器id
//编码器
this->encoder = avcodec_find_encoder(codecContext->codec_id );
res = avcodec_open2(codecContext,encoder,nullptr);
if(res != 0)
{
return;
}
//写入头部信息,编码器打开成功即可写入编码头部信息,完成编码前所有初始化工作
res = avformat_write_header(pformatContext,nullptr);
if(res != 0)
{
return;
}
}
//编码码流数据
void EncodeToH264::encode_frame(AVFrame *yuvpicture)
{
//yuv420p--->AVpacket--->写入h264文件
//发送一帧像素数据-->编码器 frame YUV像素数据
int res = avcodec_send_frame(codecContext,yuvpicture);
if(res != 0)
{
return;
}
//编码的一帧像素数据给编码器进行编码的时候,可能一个AVPacket放不下,就需要两个AVPacket,循环处理去接收码流数据
while(res >= 0)
{
//接收一帧编码数据AVCodecContext *avctx,AVPacket *avpkt
//显示时间基,保证显示的顺序,定义一个变量,每次加+1,每次开始编码的时候赋值为0
yuvpicture->pts = pkt_index++;//时间基--显示顺序
res = avcodec_receive_packet(codecContext,pkt);
if(res == AVERROR(EAGAIN)|| res == AVERROR_EOF)
{
break;
}
//写入文件就可以写入一帧数据
av_interleaved_write_frame(pformatContext,pkt);
}
//pkt使用完后要重置
av_packet_unref(pkt);
}
//写尾部
void EncodeToH264::writeTailer()
{
av_write_trailer(pformatContext);
//关闭输入流
avio_close(pformatContext->pb);
//释放视频信息
avformat_free_context(pformatContext);
}
//线程
void EncodeToH264::run()
{
this->guess_format(this->width,this->height);
while(1)
{
if(!Queue_AVFrame.isEmpty())
{
//从队列取一帧进行编码,并从队列删除
this->encode_frame(this->Queue_AVFrame.dequeue());
frame_count++;
cout<writeTailer();
this->guess_format(this->width,this->height);
//写入数据库--将视频路径写入到数据库当中
VideoControl::getInstance()->addVideoPath(name+".h264",video_path+"/"+name+".jpg",video_path+"/"+name+".h264");
//初始化
frame_count = 0;
}
}
}
//写尾帧
this->writeTailer();
}
//获取分辨率
void EncodeToH264::getHeightWidth(int width, int height)
{
this->width=width;
this->height=height;
}
//获取名字
void EncodeToH264::getName(QString name)
{
this->name=name;
}
//获取日期时间--视频图片命名
QString EncodeToH264::getTime()
{
QDateTime currentdatetime = QDateTime::currentDateTime();
QString currentdate = currentdatetime.toString("yyyyMMddHHmmss");
return currentdate;
}
#ifndef FTRANCETOMP4_H
#define FTRANCETOMP4_H
#include
#include //调试
#include //字符串
#include //日期
#include //消息框
#include
#include //线程
#include "setcontrol.h"//设置控制层
//当前C++兼容C语言
extern "C"
{
//avcodec:编解码(最重要的库)
#include
//avformat:封装格式处理
#include
//swscale:视频像素数据格式转换
#include
//avdevice:各种设备的输入输出
#include
//avutil:工具库(大部分库都需要这个库的支持)
#include
}
class FTranceTomp4 : public QThread
{
Q_OBJECT
public:
FTranceTomp4();//构造
void openH264File(QString file);//打开编码的h264文件
void coverTomp4();//转码为mp4文件
QString getTime();//获取日期时间--文件命名
private:
AVFormatContext *pFormatContext,*outFormatContext;//封装格式上下文结构体,也是统领全局的结构体,保存了视频文件封装格式相关信息
AVPacket *pkt;//存储一帧压缩编码数据
AVOutputFormat *outformat;//输出文件容器格式
int videoIndex,frameCount;
AVStream *newStream;//存储每一个视频/音频流信息的结构体
signals:
public slots:
};
#endif // FTRANCETOMP4_H
#include "ftrancetomp4.h"
//构造
FTranceTomp4::FTranceTomp4()
{
this->videoIndex =-1;
this->frameCount = 0;
pFormatContext = avformat_alloc_context();
outFormatContext =avformat_alloc_context();
pkt = av_packet_alloc();
}
//打开h264文件
void FTranceTomp4::openH264File(QString file)
{
//注册组件
av_register_all();
QString path=SetControl::getInstance()->getSetting_videopath()+"/"+getTime()+".mp4";
//打开视频文件
int res= avformat_open_input(&pFormatContext,file.toStdString().c_str(),nullptr,nullptr);
if(res!=0)
{
return;
}
//查找视频流
avformat_find_stream_info(pFormatContext,nullptr);
if(res!=0)
{
return;
}
for(int i=0;inb_streams;i++)
{
if(pFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
videoIndex = i;
break;
}
}
if(videoIndex == -1)
{
return;
}
outformat = av_guess_format(nullptr,path.toStdString().c_str(),nullptr);
if(outformat == nullptr )
{
return;
}
//设置输出格式
outFormatContext->oformat = outformat;
//打开视频流 输入输出上下文对象 输出文件路径 以写入方式操作
res=avio_open(&outFormatContext->pb,path.toStdString().c_str(),AVIO_FLAG_WRITE);
if(res!=0)
{
return;
}
//创建视频流
this->newStream = avformat_new_stream(outFormatContext,nullptr);
if(newStream == nullptr)
{
return;
}
//参数设置把输入h264编码器的参数给输出视频流进行使用
//参数1-目标视频流的编码器参数信息结构体,参数2-输入视频流的编码器参数信息结构体
avcodec_parameters_copy(newStream->codecpar,pFormatContext->streams[videoIndex]->codecpar);
//写入头部信息 编码器打开成功即可写入编码头部信息,完成编码钱所有初始化工作
res = avformat_write_header(outFormatContext,nullptr);
if(res != 0)
{
return;
}
}
//转码mp4
void FTranceTomp4::coverTomp4()
{
while(av_read_frame(pFormatContext,pkt)==0)
{
//判断是不是视频流
if(pkt->stream_index == videoIndex)
{
//转码 重新编码 时间基设置 时间间隔
//I帧首帧保存一 帧大部分 的重要的视频信息: P按照I帧: B按照左右两边的解码
//一组一组解码
frameCount++;
//判断有没有设置显示时间基:没有设置的情况下
if(pkt->pts == AV_NOPTS_VALUE)
{
//时间基的转换
AVRational time_base1 = pFormatContext->streams[videoIndex]->time_base;
//计算两帧之前的长度:转换
int64_t duration = (double)AV_TIME_BASE/
av_q2d(pFormatContext->streams[videoIndex]->r_frame_rate);
//计算显示时间基--(当前帧数*两帧之间的长度)/(输入时间基 *AV_TIME_BASE)
pkt->pts=(double)(frameCount*duration)/
(double)(av_q2d(time_base1)*AV_TIME_BASE);
//解码时间基=显示时间基
pkt->dts = pkt->pts;
pkt->duration = duration/(double)(av_q2d(time_base1)*AV_TIME_BASE);
}
else if (pkt->ptsdts)
{
//时间基小于解码时间基
continue;
}
pkt->pts=av_rescale_q_rnd(pkt->pts, pFormatContext->streams[videoIndex]->time_base,
newStream->time_base,
(AVRounding)(AV_ROUND_INF|AV_ROUND_PASS_MINMAX));
//解码时间基的转换
pkt->dts=av_rescale_q_rnd(pkt->dts, pFormatContext->streams[videoIndex]->time_base,
newStream->time_base,
(AVRounding)(AV_ROUND_INF|AV_ROUND_PASS_MINMAX));
//数据的时长,以所属媒体流的时间基准为单位,末知则值为默认值0
pkt->duration=av_rescale_q(pkt->duration, pFormatContext->streams[videoIndex]->time_base,
newStream->time_base);
pkt->pos = -1;
pkt->flags |= AV_PKT_FLAG_KEY;
pkt->stream_index = 0;
//写入数据到输出视频信息结构体汇总
av_interleaved_write_frame(outFormatContext,pkt);
}
//重置pkt
av_packet_unref(pkt);
}
//写入尾帧
av_write_trailer(outFormatContext);
//关闭编码器
avcodec_close(outFormatContext->streams[videoIndex]->codec);
av_free(&outFormatContext->streams[videoIndex]->codec);
//关闭输出流
avio_close(outFormatContext->pb);
//释放输出文件容器格式
av_free(outFormatContext);
//关闭输入流
avformat_close_input(&pFormatContext);
//释放输入视频信息结构体
av_free(pFormatContext);
//释放包
av_packet_free(&pkt);
}
//获取日期时间--视频图片命名
QString FTranceTomp4::getTime()
{
QDateTime currentdatetime = QDateTime::currentDateTime();
QString currentdate = currentdatetime.toString("yyyyMMddHHmmss");
return currentdate;
}