首頁 > 軟體

Qt+FFMPEG實現迴圈解碼詳解

2022-08-05 18:02:41

一、結果

可以設定延時函數-----遍歷每一幀的資訊進行列印

25(fps)*30(秒)=750幀

二、解碼準備工作+迴圈解碼相關操作

videodecode.h .cpp

#ifndef VIDEODECODE_H
#define VIDEODECODE_H
 
#include <QObject>
 
//當前C++相容C語言
extern "C"
{
//avcodec:編解碼(最重要的庫)
#include <libavcodec/avcodec.h>
//avformat:封裝格式處理
#include <libavformat/avformat.h>
//swscale:視訊畫素資料格式轉換
#include <libswscale/swscale.h>
//avdevice:各種裝置的輸入輸出
#include <libavdevice/avdevice.h>
//avutil:工具庫(大部分庫都需要這個庫的支援)
#include <libavutil/avutil.h>
}
 
class videoDecode : public QObject
{
    Q_OBJECT
public:
    explicit videoDecode(QObject *parent = 0);
 
     //視訊檔上下文格式
     AVFormatContext* avformat_context;
     //編解碼器上下文格式
     AVCodecContext* avcodec_context;
     //解碼器上下文格式
     AVCodec* avcodec;
 
 
 
signals:
 
public slots:
};
 
#endif // VIDEODECODE_H
#include "videodecode.h"
#include<QDebug>
#include<QCoreApplication>
#include<QThread>
 
//解碼初始化操作
//1.註冊所有元件
//2.開啟視訊輸入檔案
//3.查詢視訊流資訊
//4.查詢解碼器
//5.開啟解碼器
 
videoDecode::videoDecode(QObject *parent) : QObject(parent)
{
    qDebug()<<"1.註冊所有元件";
    av_register_all();
 
    qDebug()<<"2.開啟視訊輸入檔案";
    QString filename = QCoreApplication::applicationDirPath();
    qDebug()<<"獲取程式執行目錄 "<<filename;
    QString cinputFilePath = "test.avi";  //本地視訊檔放入程式執行目錄
    avformat_context = avformat_alloc_context();
    //引數一:封裝格式上下文->AVFormatContext->包含了視訊資訊(視訊格式、大小等等...)
    //引數二:開啟檔案(入口檔案)->url
    int avformat_open_result = avformat_open_input(&avformat_context,cinputFilePath.toStdString().c_str(),NULL,NULL);
    if (avformat_open_result != 0)
    {
        //獲取異常資訊
        char* error_info = new char[32];
        av_strerror(avformat_open_result, error_info, 1024);
        qDebug()<<QString("異常資訊 %1").arg(error_info);
 
    };
 
    qDebug()<<"3.查詢視訊流資訊";
    //引數一:封裝格式上下文->AVFormatContext
    //引數二:設定
    //返回值:0>=返回OK,否則失敗
    int avformat_find_stream_info_result = avformat_find_stream_info(avformat_context, NULL);
    if (avformat_find_stream_info_result < 0){
        //獲取失敗
        char* error_info = new char[32];
        av_strerror(avformat_find_stream_info_result, error_info, 1024);
        qDebug()<<QString("異常資訊 %1").arg(error_info);
    }
 
    qDebug()<<"4.查詢解碼器";
    //第一點:獲取當前解碼器是屬於什麼型別解碼器->找到了視訊流
    //音訊解碼器、視訊解碼器、字幕解碼器等等...
    //獲取視訊解碼器流參照
    int av_stream_index = -1;
    for (int i = 0; i < avformat_context->nb_streams; ++i) {
        //迴圈遍歷每一流
        //視訊流、音訊流、字幕流等等...
        if (avformat_context->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){
            //找到了
            av_stream_index = i;
            break;
        }
    }
    if (av_stream_index == -1)
    {
        qDebug()<<QString("沒有找到視訊流");
    }
    //第二點:根據視訊流->查詢到視訊解碼器上下文->視訊壓縮資料
    //編解碼器上下文
    avcodec_context = avformat_context->streams[av_stream_index]->codec;
 
    //第三點:根據解碼器上下文->獲取解碼器ID
    avcodec = avcodec_find_decoder(avcodec_context->codec_id);
    if (avcodec == NULL)
    {
        qDebug()<<QString("沒有找到視訊解碼器");
    }
 
    qDebug()<<"5.開啟解碼器";
    int avcodec_open2_result = avcodec_open2(avcodec_context,avcodec,NULL);
    if (avcodec_open2_result != 0)
    {
        char* error_info = new char[32];
        av_strerror(avformat_find_stream_info_result, error_info, 1024);
        qDebug()<<QString("異常資訊 %1").arg(error_info);
    }
 
    qDebug()<<"視訊詳細資訊輸出";
    //此函數自動列印輸入或輸出的詳細資訊
    av_dump_format(avformat_context, 0, cinputFilePath.toStdString().c_str(), 0);
    qDebug()<<"----------------解碼準備工作完成-----------------";
    qDebug()<<"----------------開始迴圈解碼操作-----------------";
 
    qDebug()<<"6.迴圈解碼";
 
    //讀取幀資料換成到哪裡->快取到packet裡面
    AVPacket* av_packet = (AVPacket*)av_malloc(sizeof(AVPacket));
    //解碼的狀態型別(0:表示解碼完畢,非0:表示正在解碼)
    int current_frame_index = 0;
 
    //>=0:說明有資料,繼續讀取   <0:說明讀取完畢,結束
    //從視訊檔上下文中讀取包--- 有資料就一直讀取
    while (av_read_frame(avformat_context,av_packet) >= 0)
    {
        //解碼什麼型別流(視訊流、音訊流、字幕流等等...)
        if (av_packet->stream_index == av_stream_index)
        {
                //遍歷每一幀的資訊進行列印
                current_frame_index++;
                //延時操作  1秒顯示25幀--1000/25=40
                QThread::msleep(40);
                qDebug()<<QString("當前遍歷第 %1 幀").arg(current_frame_index);
        }
    }
 
    qDebug()<<"7.關閉所有解碼元件";
    av_packet_free(&av_packet);
    //關閉流
    avcodec_close(avcodec_context);
    avformat_free_context(avformat_context);
}

main.cpp

#include "widget.h"
#include <QApplication>
#include"indexwin.h"
#include<QGraphicsItem>    //圖元
#include<QGraphicsScene>   //場景
#include<QGraphicsView>    //檢視
#include<QTransform>       //變換
#include<QDebug>
#include"myview.h"
#include <QWidget>
#include"usersdata.h"
#include"registerwin.h"
#include"sqlite3.h"
#include"mysqlite.h"//資料庫類
#include"videodecode.h"
 
 
//當前C++相容C語言
extern "C"
{
//avcodec:編解碼(最重要的庫)
#include <libavcodec/avcodec.h>
//avformat:封裝格式處理
#include <libavformat/avformat.h>
//swscale:視訊畫素資料格式轉換
#include <libswscale/swscale.h>
//avdevice:各種裝置的輸入輸出
#include <libavdevice/avdevice.h>
//avutil:工具庫(大部分庫都需要這個庫的支援)
#include <libavutil/avutil.h>
}
 
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
 
    qDebug()<<"sqlite3版本"<<sqlite3_libversion();
 
    qDebug("------------------------------------------------------------------------");
    qDebug("%s", avcodec_configuration());
    qDebug("version: %d", avcodec_version());
    qDebug("------------------------------------------------------------------------");
 
    mySqlite::getInstance("app.db");//建立資料庫
    mySqlite::createUserTable("user");//建立使用者表
 
    videoDecode *p = new videoDecode;
 
    //開機動畫
    myView kaiji;//物件建立
    kaiji.show();//呼叫方法
 
    return a.exec();
}

到此這篇關於Qt+FFMPEG實現迴圈解碼詳解的文章就介紹到這了,更多相關Qt FFMPEG解碼內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com