欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

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

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

然后進(jìn)行項(xiàng)目的創(chuàng)建。

得到的項(xiàng)目沒有pro文件,而是CMakeLists.txt。

二、引入ffmpeg

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

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

1、復(fù)制頭文件和lib

在項(xiàng)目內(nèi)創(chuàng)建一個文件夾,我這里起名叫l(wèi)ib,然后在lib文件夾下創(chuàng)建了ffmpeg文件夾,然后將上面下載的壓縮包內(nèi)的include和lib文件夾復(fù)制到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、復(fù)制bin文件

將下面的dll文件復(fù)制到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);

運(yùn)行,會看到如下消息窗口,其中顯示的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) {
 
        // 迭代結(jié)束后釋放 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ū)結(jié)束了,那么也要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);
 
                // 圖像轉(zhuǎn)換
                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);
            }
        }
 
        // 因?yàn)槊恳淮巫x取的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先縮放后轉(zhuǎn)為QPixmap的方式在圖像比較小時耗時少,圖片越大耗時遠(yuǎn)大
        QPixmap pixmap = QPixmap::fromImage(m_image.scaled(this->size(), Qt::KeepAspectRatio));
        // 先將QImage轉(zhuǎn)換為QPixmap再進(jìn)行縮放則耗時比較少,并且穩(wěn)定,不會因?yàn)榭s放圖片大小而產(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的設(shè)計(jì)界面,拖一個Widget到主界面,然后在Widget上點(diǎn)擊右鍵,然后選擇提升為,在提升的類名稱處輸入上面自定義控件的類名。

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

4、開啟線程,進(jìn)行視頻解析

(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)繪制結(jié)果

差不多下面這個樣子。

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

相關(guān)文章

  • C++ 中的異常拋出和捕獲方式

    C++ 中的異常拋出和捕獲方式

    這篇文章主要介紹了C++ 中的異常拋出和捕獲方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • MFC程序執(zhí)行過程深入剖析

    MFC程序執(zhí)行過程深入剖析

    這篇文章主要介紹了MFC程序執(zhí)行過程,包括對MFC執(zhí)行流程的分析以及斷點(diǎn)調(diào)試分析出的SDI程序執(zhí)行流程,需要的朋友可以參考下
    2014-09-09
  • C++ 淺談emplace_back及使用誤區(qū)

    C++ 淺談emplace_back及使用誤區(qū)

    這篇文章主要介紹了C++ 淺談emplace_back及使用誤區(qū),具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • c語言swap(a,b)值交換的4種實(shí)現(xiàn)方法

    c語言swap(a,b)值交換的4種實(shí)現(xiàn)方法

    c語言swap(a,b)值交換的4種實(shí)現(xiàn)方法,這么好的東西,盡管簡單,但值得發(fā)表,以此共享。
    2013-02-02
  • C++深入講解引用的特點(diǎn)及與指針的區(qū)別

    C++深入講解引用的特點(diǎn)及與指針的區(qū)別

    引用是C++一個很重要的特性,顧名思義是某一個變量或?qū)ο蟮膭e名,對引用的操作與對其所綁定的變量或?qū)ο蟮牟僮魍耆葍r(jià),這篇文章主要給大家總結(jié)介紹了C++中引用的相關(guān)知識點(diǎn),需要的朋友可以參考下
    2022-05-05
  • Qt與Web混合開發(fā)實(shí)現(xiàn)雙向通信的示例

    Qt與Web混合開發(fā)實(shí)現(xiàn)雙向通信的示例

    本文主要介紹了Qt與Web混合開發(fā)實(shí)現(xiàn)雙向通信的示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • C++語言實(shí)現(xiàn)線性表之?dāng)?shù)組實(shí)例

    C++語言實(shí)現(xiàn)線性表之?dāng)?shù)組實(shí)例

    這篇文章主要介紹了C++語言實(shí)現(xiàn)線性表之?dāng)?shù)組,實(shí)例分析了C++實(shí)現(xiàn)數(shù)組形式線性表的原理與方法,需要的朋友可以參考下
    2015-04-04
  • C++語言實(shí)現(xiàn)拼圖游戲詳解

    C++語言實(shí)現(xiàn)拼圖游戲詳解

    這篇文章主要為大家詳細(xì)介紹了C++基于EasyX庫實(shí)現(xiàn)拼圖小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • C/C++實(shí)現(xiàn)快速排序算法的思路及原理解析

    C/C++實(shí)現(xiàn)快速排序算法的思路及原理解析

    這篇文章主要介紹了C/C++實(shí)現(xiàn)快速排序算法的思路及原理解析,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01
  • C語言調(diào)用攝像頭實(shí)現(xiàn)生成yuv未壓縮圖片

    C語言調(diào)用攝像頭實(shí)現(xiàn)生成yuv未壓縮圖片

    這篇文章主要為大家詳細(xì)介紹了C語言如何調(diào)用攝像頭實(shí)現(xiàn)生成yuv未壓縮圖片,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以參考一下
    2023-11-11

最新評論