Qt项目-安防监控系统(解码编码转码)

目录

FFMPEG音视频处理

14.Decode.h .cpp

15.Decode_Replay.h .cpp

16.EncodeToH264.h .cpp

17.FTranceTomp4.h .cpp


FFMPEG音视频处理

Qt项目-安防监控系统(解码编码转码)_第1张图片

 Qt项目-安防监控系统(解码编码转码)_第2张图片

 Qt项目-安防监控系统(解码编码转码)_第3张图片

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文件
    //发送一帧像素数据-->编码器 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;
}

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->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;
}

你可能感兴趣的:(Qt学习之路,qt,音视频,开发语言)