最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

QT+ffmpeg實現(xiàn)視頻解析的示例詳解

 更新時間:2022年09月07日 08:50:51   作者:坐望云起  
這篇文章主要為大家詳細介紹了如何利用QT+ffmpeg實現(xiàn)視頻解析功能,文中的示例代碼講解詳細,對我們學習Qt有一定幫助,需要的可以參考一下

一、創(chuàng)建QT項目

首先安裝了最新的Community版本,Creator是8.0.1版本了。

然后進行項目的創(chuàng)建。

得到的項目沒有pro文件,而是CMakeLists.txt。

二、引入ffmpeg

從下面下載的ffmpeg-5.0.1-full_build-shared.7z。

https://www.gyan.dev/ffmpeg/builds/

1、復制頭文件和lib

在項目內(nèi)創(chuàng)建一個文件夾,我這里起名叫l(wèi)ib,然后在lib文件夾下創(chuàng)建了ffmpeg文件夾,然后將上面下載的壓縮包內(nèi)的include和lib文件夾復制到ffmpeg文件夾下。

然后修改CMakeLists.txt,添加如下的內(nèi)容。

include_directories(${CMAKE_SOURCE_DIR}/lib/ffmpeg/include)
 
target_link_libraries(QtFFmpegApp1 PRIVATE ${CMAKE_SOURCE_DIR}/lib/ffmpeg/lib/avcodec.lib
                                           ${CMAKE_SOURCE_DIR}/lib/ffmpeg/lib/avdevice.lib
                                           ${CMAKE_SOURCE_DIR}/lib/ffmpeg/lib/avfilter.lib
                                           ${CMAKE_SOURCE_DIR}/lib/ffmpeg/lib/avformat.lib
                                           ${CMAKE_SOURCE_DIR}/lib/ffmpeg/lib/avutil.lib
                                           ${CMAKE_SOURCE_DIR}/lib/ffmpeg/lib/postproc.lib
                                          ${CMAKE_SOURCE_DIR}/lib/ffmpeg/lib/swresample.lib
                                           ${CMAKE_SOURCE_DIR}/lib/ffmpeg/lib/swscale.lib
                                       )

2、復制bin文件

將下面的dll文件復制到build-QtFFmpegApp1-Desktop_Qt_6_3_1_MinGW_64_bit-Debug文件夾下。

3、簡單測試

在mainwindow.h文件內(nèi)添加以下引用

extern "C"
{
#include "libavformat/avformat.h"
#include "libavformat/avio.h"
#include "libavcodec/avcodec.h"
#include "libavutil/buffer.h"
#include "libavutil/error.h"
#include "libavutil/mem.h"
#include "libavutil/imgutils.h"
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>
#include <libavfilter/avfilter.h>
}

在mainwindow.cpp文件內(nèi)的MainWindow::MainWindow方法內(nèi)添加

std::string s = avcodec_configuration();
QString dlgTitle = "information消息框";
QString strInfo = QString::fromStdString(s);
QMessageBox::information(this, dlgTitle, strInfo, QMessageBox::Ok, QMessageBox::NoButton);

運行,會看到如下消息窗口,其中顯示的ffmpeg的編譯參數(shù),看到這個就表明ffmpeg引入成功。

三、視頻解析

1、創(chuàng)建線程

(1)MyThread.h文件

#ifndef MYTHREAD_H
#define MYTHREAD_H
 
 
#include <QObject>
#include <QThread>
#include <QImage>
 
#include <iostream>
#include <fstream>
extern "C"
{
#include "libavformat/avformat.h"
#include "libavformat/avio.h"
#include "libavcodec/avcodec.h"
#include "libavutil/buffer.h"
#include "libavutil/error.h"
#include "libavutil/mem.h"
#include "libavutil/imgutils.h"
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>
#include <libavfilter/avfilter.h>
}
 
 
class MyThread : public QThread
{
    Q_OBJECT
public:
    MyThread();
protected:
    void run() override;
signals:
    void minNumToamin(int min);
    void getPicFromFrame(QImage image);
};
 
#endif // MYTHREAD_H

(2)MyThread.cpp文件

#include <MyThread.h>
#include <QDebug>
 
#define INBUF_SIZE 4096
 
MyThread::MyThread()
{
 
}
 
void MyThread::run()
{
    const char* filename, * outfilename;
    const AVCodec* codec;
    AVCodecParserContext* parser;
    AVCodecContext* c = NULL;
    FILE* f;
    AVFrame* frame;
    AVFrame* pFrameBGR;
    uint8_t inbuf[INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
    uint8_t* data;
    size_t   data_size;
    int ret;
    AVPacket* pkt;
    AVFormatContext* inFmtCtx = NULL;
    int video_in_stream_index = -1, audio_in_stream_index = -1;
    AVCodecID src_video_id = AVCodecID::AV_CODEC_ID_NONE, src_audio_id = AVCodecID::AV_CODEC_ID_NONE;
    SwsContext* sws_ctx;
    uint8_t* buffer = nullptr;
 
    //文件路徑
    filename = "C:\\Users\\zyh\\Desktop\\2.mp4";
    outfilename = "";
 
    pkt = av_packet_alloc();
    if (!pkt)
        exit(1);
 
 
    // 打開輸入文件
    if ((ret = avformat_open_input(&inFmtCtx, filename, NULL, NULL)) < 0) {
        //LOGD("avformat_open_input() fail");
        //releaseSources();
        return;
    }
    if ((ret = avformat_find_stream_info(inFmtCtx, NULL)) < 0) {
        //LOGD("avformat_find_stream_info fail %d", ret);
        //releaseSources();
        return;
    }
    // 輸出輸入文件信息
    av_dump_format(inFmtCtx, 0, filename, 0);
 
    for (int i = 0; i < inFmtCtx->nb_streams; i++) {
        AVCodecParameters* codecpar = inFmtCtx->streams[i]->codecpar;
        if (codecpar->codec_type == AVMEDIA_TYPE_VIDEO && video_in_stream_index == -1) {
            src_video_id = codecpar->codec_id;
            video_in_stream_index = i;
        }
        if (codecpar->codec_type == AVMEDIA_TYPE_AUDIO && audio_in_stream_index == -1) {
            src_audio_id = codecpar->codec_id;
            audio_in_stream_index = i;
        }
    }
 
 
    /* set end of buffer to 0 (this ensures that no overreading happens for damaged MPEG streams) */
    memset(inbuf + INBUF_SIZE, 0, AV_INPUT_BUFFER_PADDING_SIZE);
 
    /* find the MPEG-1 video decoder */
    codec = avcodec_find_decoder(src_video_id);
    if (!codec) {
        fprintf(stderr, "Codec not found\n");
        exit(1);
    }
 
    parser = av_parser_init(codec->id);
    if (!parser) {
        fprintf(stderr, "parser not found\n");
        exit(1);
    }
 
    c = avcodec_alloc_context3(codec);
    if (!c) {
        fprintf(stderr, "Could not allocate video codec context\n");
        exit(1);
    }
 
    AVCodecParameters* codecpar = inFmtCtx->streams[video_in_stream_index]->codecpar;
    if ((ret = avcodec_parameters_to_context(c, codecpar)) < 0) {
        //LOGD("avcodec_parameters_to_context fail %d", ret);
        //releaseSources();
        return;
    }
 
    /* For some codecs, such as msmpeg4 and mpeg4, width and height
       MUST be initialized there because this information is not
       available in the bitstream. */
    /* open it */
    if (avcodec_open2(c, codec, NULL) < 0) {
        fprintf(stderr, "Could not open codec\n");
        exit(1);
    }
 
    f = fopen(filename, "rb");
    if (!f) {
        fprintf(stderr, "Could not open %s\n", filename);
        exit(1);
    }
 
    frame = av_frame_alloc();
    pFrameBGR = av_frame_alloc();
 
    if (!frame) {
        fprintf(stderr, "Could not allocate video frame\n");
        exit(1);
    }
 
    int index = 0;
    while (av_read_frame(inFmtCtx, pkt) >= 0) {
 
        // 迭代結束后釋放 av_read_frame 分配的 packet 內(nèi)存
        //std::shared_ptr<AVPacket> packetDeleter(&pkt, av_packet_unref);
 
        if(index >0) break;
        // 說明讀取的視頻數(shù)據(jù)
        if (pkt->stream_index == video_in_stream_index) {
            if ((ret = avcodec_send_packet(c, pkt)) < 0) {
                //LOGD("video avcodec_send_packet fail %s", av_err2str(ret));
                //releaseSources();
                return;
            }
            while (true) {
                // 從解碼緩沖區(qū)接收解碼后的數(shù)據(jù)
                if ((ret = avcodec_receive_frame(c, frame)) < 0) {
                    if (ret == AVERROR_EOF) {
                        exit(1);
                        // 解碼緩沖區(qū)結束了,那么也要flush編碼緩沖區(qū)
                        //doEncodeVideo(NULL);
                    }
                    break;
                }
 
                int numBytes = av_image_get_buffer_size(AV_PIX_FMT_RGB24, c->width, c->height, 1);
                if(buffer == nullptr) buffer = (uint8_t*)av_malloc(numBytes * sizeof(uint8_t));
                av_image_fill_arrays(pFrameBGR->data, pFrameBGR->linesize, buffer, AV_PIX_FMT_RGB24,  c->width, c->height, 1);
 
 
                sws_ctx = sws_getContext(codecpar->width, codecpar->height, (enum AVPixelFormat)codecpar->format,
                    frame->width, frame->height, AV_PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
 
                sws_scale(sws_ctx, frame->data, frame->linesize, 0, c->height, pFrameBGR->data, pFrameBGR->linesize);
 
                // 圖像轉換
                sws_scale(sws_ctx, frame->data, frame->linesize, 0, c->height, pFrameBGR->data, pFrameBGR->linesize);
                
                // 得到QImage
                QImage tempImage((uchar*)pFrameBGR->data[0], c->width, c->height, QImage::Format_RGB888);
                // 對于qt還是不是很熟悉,理解是傳遞給主線程
                getPicFromFrame(tempImage);
            }
        }
 
        // 因為每一次讀取的AVpacket的數(shù)據(jù)大小不一樣,所以用完之后要釋放
        av_packet_unref(pkt);
    }
 
    fclose(f);
 
    av_parser_close(parser);
    avcodec_free_context(&c);
    av_frame_free(&frame);
    av_packet_free(&pkt);
}

2、創(chuàng)建自定義繪制控件

(1)PlayImage.h

#ifndef PLAYIMAGE_H
#define PLAYIMAGE_H
 
#include <QWidget>
 
class PlayImage : public QWidget
{
    Q_OBJECT
public:
    explicit PlayImage(QWidget *parent = nullptr);
 
    void updateImage(const QImage& image);
    void updatePixmap(const QPixmap& pixmap);
 
signals:
 
protected:
    void paintEvent(QPaintEvent *event) override;
 
private:
    QPixmap m_pixmap;
};
 
#endif // PLAYIMAGE_H

(2)PlayImage.cpp

#include "playimage.h"
 
#include <QPainter>
 
PlayImage::PlayImage(QWidget *parent) : QWidget(parent)
{
 
}
 
/**
 * @brief        傳入Qimage圖片顯示
 * @param image
 */
void PlayImage::updateImage(const QImage& image)
{
    updatePixmap(QPixmap::fromImage(image));
}
 
/**
 * @brief        傳入QPixmap圖片
 * @param pixmap
 */
void PlayImage::updatePixmap(const QPixmap &pixmap)
{
    m_pixmap = pixmap;
    update();
}
 
/**
 * @brief        使用Qpainter顯示圖片
 * @param event
 */
void PlayImage::paintEvent(QPaintEvent *event)
{
    if(!m_pixmap.isNull())
    {
        QPainter painter(this);
#if 0
        // 經(jīng)過粗略測試,QImage先縮放后轉為QPixmap的方式在圖像比較小時耗時少,圖片越大耗時遠大
        QPixmap pixmap = QPixmap::fromImage(m_image.scaled(this->size(), Qt::KeepAspectRatio));
        // 先將QImage轉換為QPixmap再進行縮放則耗時比較少,并且穩(wěn)定,不會因為縮放圖片大小而產(chǎn)生太大影響
        QPixmap pixmap1 = QPixmap::fromImage(m_image).scaled(this->size(), Qt::KeepAspectRatio);
#endif
        QPixmap pixmap = m_pixmap.scaled(this->size(), Qt::KeepAspectRatio);
        int x = (this->width() - pixmap.width()) / 2;
        int y = (this->height() - pixmap.height()) / 2;
        painter.drawPixmap(x, y, pixmap);
    }
    QWidget::paintEvent(event);
}

3、使用自定義控件

在mainwindow.ui的設計界面,拖一個Widget到主界面,然后在Widget上點擊右鍵,然后選擇提升為,在提升的類名稱處輸入上面自定義控件的類名。

如果選擇下面的全局包含,就不用再單獨包含頭文件了。

4、開啟線程,進行視頻解析

(1)mainwindow.cpp

開啟線程

m_thread  =  new MyThread;
connect(m_thread,&MyThread::getPicFromFrame,this,&MainWindow::getPicfromThread);
m_thread->start();

接收并繪制圖片

void MainWindow::getPicfromThread(QImage image)
{
    ui->widget->updateImage(image);
}

(2)繪制結果

差不多下面這個樣子。

到此這篇關于QT+ffmpeg實現(xiàn)視頻解析的示例詳解的文章就介紹到這了,更多相關QT ffmpeg視頻解析內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • VC++實現(xiàn)程序開機啟動運行的方法

    VC++實現(xiàn)程序開機啟動運行的方法

    這篇文章主要介紹了VC++實現(xiàn)程序開機啟動運行的方法,很實用的功能,需要的朋友可以參考下
    2014-08-08
  • C++?STL容器與函數(shù)謂詞示例分析講解

    C++?STL容器與函數(shù)謂詞示例分析講解

    這篇文章主要介紹了C++?STL容器與函數(shù)謂詞示例,STL是“Standard?Template?Library”的縮寫,中文譯為“標準模板庫”。STL是C++標準庫的一部分,不用單獨安裝
    2022-11-11
  • C語言實現(xiàn)學生學籍管理系統(tǒng)程序設計

    C語言實現(xiàn)學生學籍管理系統(tǒng)程序設計

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)學生學籍管理系統(tǒng)程序設計,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • C++模擬實現(xiàn)string類的實例代碼

    C++模擬實現(xiàn)string類的實例代碼

    這篇文章主要給大家介紹了C++如何模擬實現(xiàn)string類,文章通過代碼示例講解的非常詳細,有完整的實現(xiàn)過程,具有一定的參考價值,需要的朋友可以參考下
    2023-08-08
  • C++中虛表是什么意思(概念及示例)

    C++中虛表是什么意思(概念及示例)

    虛函數(shù)表,以及虛函數(shù)指針是實現(xiàn)多態(tài)性(Polymorphism)的關鍵機制,這篇文章主要介紹了C++中虛表是什么意思(概念及示例),需要的朋友可以參考下
    2024-03-03
  • C++稀疏矩陣的各種基本運算并實現(xiàn)加法乘法

    C++稀疏矩陣的各種基本運算并實現(xiàn)加法乘法

    今天小編就為大家分享一篇關于C++稀疏矩陣的各種基本運算并實現(xiàn)加法乘法,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-02-02
  • C 語言環(huán)境設置詳細講解

    C 語言環(huán)境設置詳細講解

    本文主要介紹C 語言環(huán)境設置,在不同的系統(tǒng)平臺上,C語言的環(huán)境設置不同,這里幫大家整理了Liunx, UNIX,Windows 上安裝C語言環(huán)境,有開始學習C語言的朋友可以參考下
    2016-08-08
  • Qt物聯(lián)網(wǎng)管理平臺之實現(xiàn)數(shù)據(jù)查詢導出打印

    Qt物聯(lián)網(wǎng)管理平臺之實現(xiàn)數(shù)據(jù)查詢導出打印

    這篇文章主要為大家介紹了如何利用Qt編寫物聯(lián)網(wǎng)管理平臺中數(shù)據(jù)查詢導出打印的功能,文字的示例代碼講解詳細,感興趣的可以了解一下
    2022-07-07
  • opencv3/C++ PHash算法圖像檢索詳解

    opencv3/C++ PHash算法圖像檢索詳解

    今天小編就為大家分享一篇opencv3/C++ PHash算法圖像檢索詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-12-12
  • Qt鍵盤事件實現(xiàn)圖片在窗口上下左右移動

    Qt鍵盤事件實現(xiàn)圖片在窗口上下左右移動

    這篇文章主要為大家詳細介紹了Qt鍵盤事件實現(xiàn)圖片在窗口上下左右移動,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08

最新評論

正镶白旗| 来安县| 郯城县| 东海县| 濮阳县| 祥云县| 苗栗县| 墨竹工卡县| 开封县| 壶关县| 钦州市| 岫岩| 石柱| 多伦县| 舞阳县| 城固县| 莲花县| 莎车县| 上蔡县| 乌拉特中旗| 深水埗区| 南皮县| 汉寿县| 聂拉木县| 浮梁县| 高尔夫| 区。| 恩平市| 清流县| 卢氏县| 湖口县| 曲阳县| 惠水县| 江北区| 泾川县| 元江| 马尔康县| 汉阴县| 苍溪县| 崇阳县| 丰镇市|