目录
FFMPEG音视频处理
14.Decode.h .cpp
15.Decode_Replay.h .cpp
16.EncodeToH264.h .cpp
17.FTranceTomp4.h .cpp
FFMPEG音视频处理
文章图片
文章图片
文章图片
14.Decode.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();
}
15.Decode_Replay.h .cpp
#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;
}
16.EncodeToH264.h .cpp
#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文件
//发送一帧像素数据-->编码器 frameYUV像素数据
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;
}
17.FTranceTomp4.h .cpp
#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->pts【Qt学习之路|Qt项目-安防监控系统(解码编码转码)】dts)
{
//时间基小于解码时间基
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;
}
推荐阅读
- QT|QT---创建对话框3(形状可变对话框的实现)
- Qt探索之旅|Qt实现思维导图功能(二)
- QT|Qt状态机的使用
- C++|Qt-Q_OBJECT宏及控件提升导致的类重定义问题
- Qt学习之路|Qt项目-安防监控系统(欢迎登录注册)
- Qt学习之路|Qt项目-安防监控系统(MVC设计模式)
- C和指针|C和指针 第6章 指针 6.4 间接访问操作符
- C++学习笔记|C++11常用特性
- 前端学习笔记|3.8 JavaScript-DOM节点