chinese直男口爆体育生外卖, 99久久er热在这里只有精品99, 又色又爽又黄18禁美女裸身无遮挡, gogogo高清免费观看日本电视,私密按摩师高清版在线,人妻视频毛茸茸,91论坛 兴趣闲谈,欧美 亚洲 精品 8区,国产精品久久久久精品免费

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

【干貨分享】基于QT和ffmpeg硬解碼的多路攝像頭取流

電子發(fā)燒友論壇 ? 2025-07-29 08:05 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

目前QT和ffmpeg都已經(jīng)安裝好了,接下來將會使用QT和ffmpeg來進行編程。

https://bbs.elecfans.com/jishu_2496310_1_1.html



前言

其實官方為我們已經(jīng)提供了三個官方實例,我打開學習了一下,QT實例雖然也用到了信號槽,是點擊按鈕的信號槽,我覺的QT妙就妙在了信號槽和多線程,而且官方的是QT5;多路攝像頭取流案例使用的是采流使用的是GStreamer,UI采用的是GTK庫;所以我做了一個QT6+多線程+ffmpeg的多路攝像頭取流案例供參考。


代碼編寫

test.pro 這個地方比較重要的改動主要在于添加ffmpeg要使用的庫


QT += core guigreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsCONFIG += c++17# You can make your code fail to compile if it uses deprecated APIs.# In order to do so, uncomment the following line.#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0SOURCES += \ camera.cpp \ main.cpp \ mainwindow.cppHEADERS += \ camera.h \ mainwindow.hFORMS += \ mainwindow.uiLIBS += -lavdevice \-lavformat \-ldrm \-lavfilter \-lavcodec \-lavutil \-lswresample \-lswscale \-lm \-lrga \-lpthread \-lrt \-lrockchip_mpp \-lz# Default rules for deployment.qnx: target.path = /tmp/$${TARGET}/binelse: unix target.path = /opt/$${TARGET}/bin!isEmpty(target.path): INSTALLS += target



camera.h:采集線程的頭文件,無需多言

#ifndefCAMERA_H#defineCAMERA_H// 顯示畫面的大小#defineDISPLAY_WIDTH 640#defineDISPLAY_HEIGHT 360#include#include#includeextern"C"{#include"libavdevice/avdevice.h"#include"libavcodec/avcodec.h"#include"libavdevice/avdevice.h"#include"libavfilter/avfilter.h"#include"libavfilter/buffersink.h"#include"libavfilter/buffersrc.h"#include"libavformat/avformat.h"#include"libavutil/pixdesc.h"#include"libavutil/opt.h"#include"libavutil/avassert.h"#include"libavutil/imgutils.h"#include"libavutil/avutil.h"#include"libavutil/audio_fifo.h"#include"libavutil/file.h"#include"libavutil/imgutils.h"#include"libavutil/mathematics.h"#include"libavutil/pixfmt.h"#include"libavutil/time.h"#include"libswscale/swscale.h"#include"libswresample/swresample.h"#include"libavutil/hwcontext.h"#include"libavutil/hwcontext_drm.h"#include#include#include#include#include}classCamera:publicQThread { Q_OBJECTpublic: Camera(QObject *parent =0); virtual~Camera(); voidset_para(intindex,constchar*rtsp_str);signals: voidupdate_video_label(int, QImage *);protected: virtualvoidrun();private: intindex; char*rtsp_str =nullptr; uint8_t*dst_data_main[4]; intdst_linesize_main[4]; QImage *p_image_main =nullptr;};#endif// CAMERA_H



camera.cpp這部分是代碼的關(guān)鍵,是取流的線程,具體的解釋已經(jīng)寫好在注釋里

#include"camera.h"Camera::Camera(QObject *parent) : QThread(parent) { // 創(chuàng)建顯示圖像的內(nèi)存 av_image_alloc(dst_data_main, dst_linesize_main, DISPLAY_WIDTH, DISPLAY_HEIGHT,AV_PIX_FMT_RGB24,1); p_image_main = new QImage(dst_data_main[0], DISPLAY_WIDTH, DISPLAY_HEIGHT, QImage::Format_RGB888);}Camera::~Camera() {}voidCamera::set_para(intindex,constchar*rtsp_str) { // 配置線程的參數(shù) this->index = index; this->rtsp_str = newchar[255]; strcpy(this->rtsp_str, rtsp_str);}voidCamera::run() { // 線程執(zhí)行函數(shù) intsrc_width, src_height; AVFormatContext*av_fmt_ctx =NULL; AVStream*av_stream =NULL; AVCodecContext* av_codec_ctx; // 設置RTSP連接參數(shù) AVDictionary*options =NULL; av_dict_set(&options,"rtsp_transport","tcp",0); av_dict_set(&options,"buffer_size","1024000",0); av_dict_set(&options,"stimeout","2000000",0); av_dict_set(&options,"max_delay","500000",0); // 創(chuàng)建AVFormatContext av_fmt_ctx = avformat_alloc_context(); if(avformat_open_input(&av_fmt_ctx, rtsp_str,NULL, &options) !=0) { qDebug() <nb_streams; i++) { if(av_fmt_ctx->streams[i]->codecpar->codec_type ==AVMEDIA_TYPE_VIDEO) { av_stream = av_fmt_ctx->streams[i]; break; } } if(av_stream ==NULL) { qDebug() <codecpar->codec_id); constAVCodec*av_codec = avcodec_find_decoder_by_name("h264_rkmpp"); if(av_codec == nullptr) { qDebug() <codecpar); // 打開解碼器 if(avcodec_open2(av_codec_ctx, av_codec,NULL) long_name <name; src_width = av_codec_ctx->width; src_height = av_codec_ctx->height; // 創(chuàng)建AVFrame和AVPacket供解碼使用 AVFrame*av_frame = av_frame_alloc(); AVPacket*av_packet = (AVPacket*)av_malloc(sizeof(AVPacket)); // 創(chuàng)建SwsContext,將解碼出來的YUV格式,轉(zhuǎn)換成供界面顯示的RGB格式,同時對圖像進行縮放,縮放成顯示大小 structSwsContext* img_ctx = sws_getContext(src_width, src_height, av_codec_ctx->pix_fmt, DISPLAY_WIDTH, DISPLAY_HEIGHT,AV_PIX_FMT_RGB24, SWS_BILINEAR,0,0,0); while(true) { // 解碼流程 if(av_read_frame(av_fmt_ctx, av_packet) >=0){ avcodec_send_packet(av_codec_ctx, av_packet); while(avcodec_receive_frame(av_codec_ctx, av_frame) ==0) { // 轉(zhuǎn)換畫面 sws_scale(img_ctx, (constuint8_t*const*)av_frame->data, av_frame->linesize,0, src_height, dst_data_main, dst_linesize_main); // 發(fā)送信號,將QImage圖像地址發(fā)送到主線程,供更新界面 // 一般情況下,界面的更新都不允許在子線程進行 // 同時,一些耗時長的操作也一般不允許在主線程進行,例如網(wǎng)絡操作,IO操作以及解碼等,防止主線程卡死,畫面卡頓 emit update_video_label(index, p_image_main); } av_frame_unref(av_frame); av_packet_unref(av_packet); }else{ msleep(10); } } return;}


mainwindow.h 這個文件也不必多說,button的點擊事件是自動添加的,增加4個采集線程和4個狀態(tài)。

#ifndefMAINWINDOW_H#defineMAINWINDOW_H#include#include"camera.h"QT_BEGIN_NAMESPACEnamespaceUi {classMainWindow; }QT_END_NAMESPACEclassMainWindow:publicQMainWindow{ Q_OBJECTpublic: MainWindow(QWidget *parent =nullptr); ~MainWindow();publicslots: voidupdate_video_label(intindex, QImage *image);privateslots: voidon_pushButton_1_clicked(); voidon_pushButton_2_clicked(); voidon_pushButton_3_clicked(); voidon_pushButton_4_clicked();private: Ui::MainWindow *ui; Camera **camera =newCamera*[4]; boolstatus[4] = {false};};#endif// MAINWINDOW_H



mainwindow.cpp 對采集線程進行初始化并綁定更新視圖槽

#include"mainwindow.h"#include"ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(newUi::MainWindow) { ui->setupUi(this); // 對采集線程進行初始化并綁定更新視圖槽 camera[0] =newCamera(); camera[1] =newCamera(); camera[2] =newCamera(); camera[3] =newCamera(); connect(camera[0],SIGNAL(update_video_label(int, QImage *)),this,SLOT(update_video_label(int, QImage *))); connect(camera[1],SIGNAL(update_video_label(int, QImage *)),this,SLOT(update_video_label(int, QImage *))); connect(camera[2],SIGNAL(update_video_label(int, QImage *)),this,SLOT(update_video_label(int, QImage *))); connect(camera[3],SIGNAL(update_video_label(int, QImage *)),this,SLOT(update_video_label(int, QImage *)));}MainWindow::~MainWindow() { deleteui;}voidMainWindow::on_pushButton_1_clicked(){ // 如果已經(jīng)開始播放,那么就不必繼續(xù)了,后期可以添加先停止原鏈接采集再開啟新鏈接采集 if(status[0]) { return; } status[0] =true; camera[0]->set_para(0, ui->lineEdit_1->text().toStdString().c_str()); // 啟動采集 camera[0]->start();}voidMainWindow::on_pushButton_2_clicked(){ // 同button1的點擊事件處理 if(status[1]) { return; } status[1] =true; camera[1]->set_para(1, ui->lineEdit_2->text().toStdString().c_str()); camera[1]->start();}voidMainWindow::on_pushButton_3_clicked(){ // 同button1的點擊事件處理 if(status[2]) { return; } status[2] =true; camera[2]->set_para(2, ui->lineEdit_3->text().toStdString().c_str()); camera[2]->start();}voidMainWindow::on_pushButton_4_clicked(){ // 同button1的點擊事件處理 if(status[3]) { return; } status[3] =true; camera[3]->set_para(3, ui->lineEdit_4->text().toStdString().c_str()); camera[3]->start();}voidMainWindow::update_video_label(intcode, QImage *image){ // 將采集回來的畫面顯示到對應的界面 switch(code) { case0: ui->label_video_1->setPixmap(QPixmap::fromImage(*image)); break; case1: ui->label_video_2->setPixmap(QPixmap::fromImage(*image)); break; case2: ui->label_video_3->setPixmap(QPixmap::fromImage(*image)); break; case3: ui->label_video_4->setPixmap(QPixmap::fromImage(*image)); break; default: break; }}


還需要更改的地方

首先第一個更改的地方是吧QT編譯的線程降低一些,線程太多容易搞死機,我這里改成了1,可以像我這樣修改,就可以了。

c9e83ea6-6c0f-11f0-9080-92fbcf53809c.png
第二個問題,讓我整整花費了一整天進行修改,我在安裝自己編譯的ffmpeg前就已經(jīng)測試過ffmpeg板子沒有安裝,所以我就默認ffmpeg的庫也沒有安裝,等到我編譯完成后總是無法找到h264_rkmpp的解碼器,但是偏偏使用ffmpeg來查看時,卻擁有h264_rkmpp的解碼器,我整整找了一天的問題關(guān)鍵所在。首先,我懷疑的是不是ffmpeg需要開啟 --enable-shared 進行動態(tài)編譯,于是按照猜想執(zhí)行

./configure --prefix=/usr --enable-gpl --enable-version3 --enable-libdrm --enable-rkmpp --enable-rkrga --enable-sharedmake -j 6sudo make install

但是執(zhí)行完畢后,依舊沒有解決問題,直到花了一天的時間后,我再次使用ldd test的時候突然發(fā)現(xiàn)一個問題,明明我的安裝路徑是在/usr,理論上動態(tài)連接庫應該是在/usr/lib當中,但是為何是在/lib/aarch64-linux-gnu/下面呢?于是我懷疑雖然沒有安裝ffmpeg,但是很有可能把ffmpeg的庫已經(jīng)安裝上了,所以使用apt search ffmpeg搜索,然后就看到avformat avcodec avutil等庫都已經(jīng)安裝好了,所以有時候不要想當然,當把該排除的都排除了,那可能就是最簡單的原因,簡單到壓根都想不起來的程度,發(fā)現(xiàn)問題那就解決問題吧。

第一種解決辦法,把自帶的ffmpeg卸載掉,缺點是依賴比較多,卸載起來還是比較麻煩,但是強烈推薦。

sudoapt remove libavformat-dev libopencv-dev libgstreamer-plugins-bad1.0-dev libcheese-dev libcheese-gtk-dev libopencv-highgui-dev libopencv-contrib-dev libopencv-features2d-dev libopencv-objdetect-dev libopencv-calib3d-dev libopencv-stitching-dev libopencv-videostab-dev libavcodec-dev libavutil-dev libavdevice-dev libswresample-dev libswscale-dev libswresample4 libswscale6 libavutil57 libavformat59 libavcodec59 libchromaprint1 libfreerdp2-2libopencv-videoio406 gstreamer1.0-plugins-bad libopencv-superres406 libopencv-videoio-dev libopencv-videostab406 libweston-10-0gnome-video-effects gstreamer1.0-plugins-bad-apps gstreamer1.0-plugins-bad-dbgsym libcheese8 libgstrtspserver-1.0-0 libopencv-superres-dev libweston-10-0-dbgsym libweston-10-dev weston cheese gir1.2-cheese-3.0gir1.2-gst-rtsp-server-1.0 gstreamer1.0-plugins-bad-apps-dbgsym libcheese-gtk25 libcheese8-dbgsym libgstrtspserver-1.0-dev weston-dbgsym cheese-dbgsym libcheese-gtk25-dbgsym


如果你需要里面的很多庫,比如像測試官方的案例,那么就試試第二種解決辦法:
首先,我們不能讓qt編譯時選擇默認的include和lib路徑,這也就是為什么在.pro中沒有寫路徑也可以找到ffmpeg的頭文件和庫文件,我們需要添加路徑,修改test.pro文件如下:

QT += core guigreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsCONFIG += c++17# You can make your code fail to compile if it uses deprecated APIs.# In order to do so, uncomment the following line.#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0SOURCES += \ camera.cpp \ main.cpp \ mainwindow.cppHEADERS += \ camera.h \ mainwindow.hFORMS += \ mainwindow.uiINCLUDEPATH += /usr/includeLIBS += -L/usr/lib \-lavdevice \-lavformat \-ldrm \-lavfilter \-lavcodec \-lavutil \-lswresample \-lswscale \-lm \-lrga \-lpthread \-lrt \-lrockchip_mpp \-lz# Default rules for deployment.qnx: target.path = /tmp/$${TARGET}/binelse: unix target.path = /opt/$${TARGET}/bin!isEmpty(target.path): INSTALLS += target

這樣我們就強制讓qt使用我們指定的ffmpeg的頭文件和庫文件了,但是僅僅有這些還不夠,我們還需要在編譯后,運行時指定動態(tài)鏈接庫:

LD_LIBRARY_PATH=/usr/lib ./test


運行,對比及分析

首先我們嘗試使用軟解碼來看看接入4路1080P 25FPS RTSP流,顯示畫面如下:

c9f904e8-6c0f-11f0-9080-92fbcf53809c.png
CPU占用:
ca2e9b4e-6c0f-11f0-9080-92fbcf53809c.png

然后我們看看用硬解碼接入相同的碼流,甚至清晰度還要好過軟解碼:
ca425f9e-6c0f-11f0-9080-92fbcf53809c.png

CPU占用:
ca552fd4-6c0f-11f0-9080-92fbcf53809c.png


可以看到硬解碼接入后直接降低至少一般的CPU占用率,其實降低的要遠遠超過一半,因為從GPU把解碼后的視頻數(shù)據(jù)拷貝到內(nèi)存當中、對圖像進行縮放以及顯示圖像都是CPU占用率極高的地方,所以這也是后期優(yōu)化的方向。


ca63141e-6c0f-11f0-9080-92fbcf53809c.png聲明:本文由電子發(fā)燒友社區(qū)發(fā)布,轉(zhuǎn)載請注明以上來源。如需平臺(包括:試用+專欄+企業(yè)號+學院+技術(shù)直播+共建社區(qū))合作及入群交流,請咨詢18925255684(微信同號:elecfans123),謝謝!

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 攝像頭
    +關(guān)注

    關(guān)注

    61

    文章

    5024

    瀏覽量

    101482
  • Qt
    Qt
    +關(guān)注

    關(guān)注

    2

    文章

    317

    瀏覽量

    39871
  • ffmpeg
    +關(guān)注

    關(guān)注

    0

    文章

    49

    瀏覽量

    7797
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點推薦

    基于FFMPEG采集攝像頭圖像編碼MP4視頻+時間水印

    基于FFMPEG采集攝像頭圖像編碼MP4視頻+時間水印
    的頭像 發(fā)表于 09-29 15:46 ?4600次閱讀
    基于<b class='flag-5'>FFMPEG</b>采集<b class='flag-5'>攝像頭</b>圖像編碼MP4視頻+時間水印

    《深入理解FFmpeg閱讀體驗》FFmpeg攝像頭測試

    better, run \'man ffmpeg\' OK的。 二、連接攝像頭 我用的是手頭的???20P USB攝像頭。 插進去后系統(tǒng)自動識別。 [ 1812.860609] uvcvideo
    發(fā)表于 04-17 19:06

    【EASY EAI Orin Nano開發(fā)板試用體驗】05-基于QTffmpeg解碼多路攝像頭

    使用的是GStreamer,UI采用的是GTK庫;所以我做了一個QT6+多線程+ffmpeg多路攝像頭
    發(fā)表于 07-25 19:24

    LabVIEW獲取網(wǎng)絡攝像頭方法

    。 *****************************************************************************************2015年9月28日 更新如果攝像頭的數(shù)據(jù)是http,那就
    發(fā)表于 04-14 23:36

    nanopi m1最新rom支持攝像頭模塊CAM500A

    `http://wiki.friendlyarm.com/wiki/index.php/NanoPi_M1/zhDebian和Ubuntu-Core with Qt-Embedded系統(tǒng)支持攝像頭
    發(fā)表于 09-08 16:09

    ESM6802支持Qt攝像頭應用

    版本。使用Qt的multimedia模塊可以方便快捷的進行攝像頭應用的開發(fā),本文使用Qt源碼中提供的camera例程進行展示,例程代碼可從Qt源碼中獲取或者向我們工程師索要?! ∥覀兪?/div>
    發(fā)表于 10-20 10:33

    安防攝像頭的過保護

    ,分配給攝像頭負載。無論是開關(guān)電源還是火牛電源供電,都是一個公用電源的多路供電系統(tǒng),這是目前普遍采用的方法。 而在這種供電系統(tǒng)中,會存在一個致命的問題,那就是當其中某個攝像頭負載有短路或過
    發(fā)表于 12-29 14:10

    labview如何連接多路網(wǎng)絡攝像頭采集視頻

    想知道怎么實現(xiàn)labview連接多路網(wǎng)絡攝像頭采集視頻,怎么實現(xiàn)通訊都不太清楚。
    發(fā)表于 12-26 23:39

    在RK3288主板Debian 9.13系統(tǒng)上如何調(diào)用CPU解進行網(wǎng)絡攝像頭視頻解碼

    在RK3288主板Debian 9.13系統(tǒng)上如何調(diào)用CPU解進行網(wǎng)絡攝像頭視頻解碼?
    發(fā)表于 03-03 06:47

    Android解碼如何去實現(xiàn)呢

    很簡單,右下角是攝像頭的預覽窗口,中間的經(jīng)過硬編解碼顯示出來的數(shù)據(jù)。logcat顯示:從logcat可以看出1280*720的preview數(shù)據(jù)長度是1280*720*3/2=1382400;編碼后數(shù)據(jù)長度是et 大概在500
    發(fā)表于 04-11 14:39

    RV1126通過v4l2拉usb攝像頭mjpeg解碼耗時很長如何解決

    在rv1126上拉usb攝像頭1080p分辨率的視頻的時候,默認情況下拉的是yuv格式的,并且拉1080p的時候幀率是5fps,如果
    發(fā)表于 11-23 16:32

    QT上構(gòu)建ffmpeg環(huán)境實現(xiàn)音頻的解碼

    QT上構(gòu)建ffmpeg環(huán)境,實現(xiàn)音頻的解碼
    發(fā)表于 06-09 09:05 ?1608次閱讀
    在<b class='flag-5'>QT</b>上構(gòu)建<b class='flag-5'>ffmpeg</b>環(huán)境實現(xiàn)音頻的<b class='flag-5'>解碼</b>

    嵌入式Qt-簡易網(wǎng)絡監(jiān)控攝像頭

    本篇介紹了如何用Qt實現(xiàn)一個網(wǎng)絡攝像頭功能,通過服務端將USB攝像頭轉(zhuǎn)換為一個IP攝像頭,Linux板子中的客戶端來連接服務器,將攝像頭的實
    的頭像 發(fā)表于 09-14 08:52 ?2435次閱讀
    嵌入式<b class='flag-5'>Qt</b>-簡易網(wǎng)絡監(jiān)控<b class='flag-5'>攝像頭</b>

    基于RV1126開發(fā)板實現(xiàn)多路網(wǎng)絡攝像頭方案

    在RV1126上實現(xiàn)多路網(wǎng)絡攝像頭方案
    的頭像 發(fā)表于 04-11 15:57 ?719次閱讀
    基于RV1126開發(fā)板實現(xiàn)<b class='flag-5'>多路</b>網(wǎng)絡<b class='flag-5'>攝像頭</b><b class='flag-5'>取</b><b class='flag-5'>流</b>方案

    基于RV1126開發(fā)板實現(xiàn)多路網(wǎng)絡攝像頭方案

    在RV1126上實現(xiàn)多路網(wǎng)絡攝像頭方案
    的頭像 發(fā)表于 04-21 14:39 ?49次閱讀
    基于RV1126開發(fā)板實現(xiàn)<b class='flag-5'>多路</b>網(wǎng)絡<b class='flag-5'>攝像頭</b><b class='flag-5'>取</b><b class='flag-5'>流</b>方案