1. 程式人生 > >Qt+libvlc+rtsp:視訊層上繪圖探究

Qt+libvlc+rtsp:視訊層上繪圖探究

一、前言

1.起源

最近負責專案中的一個部分,需要從攝像頭獲取rtsp流,同時作tcp的客戶端收取人臉識別的資訊,用qt顯示視訊並繪製人臉識別框。

2.成果

3.環境

系統環境:windows 10 Qt版本:5.8.0 vlc版本:2.2.4(這裡建議使用libvlc 3以上的版本,3以下很難找到debug庫,windows下自行編譯較麻煩) 開發工具:vs2015

4.致謝與宣告

向本文所有引用的作者表示感謝,也要感謝幫助過我的朋友們,正是他們的分享開源精神幫助我解決了問題。 同時感謝菊花怪,從學習程式設計至今一直互勉,包括本次的程式也是在他的幫助下,深夜解決的。 在此宣告:本文對所引用的所有文章的主觀觀點、言論,均不負法律責任。

二、準備

1.瞭解視訊傳輸的原理

如果你對視訊傳輸充滿興趣,可以參考以下博文:

(1)流媒體客戶端的傳送原理

http://blog.csdn.net/jianren994/article/details/8133395

(2)RTSP/RTP媒體傳輸和控制協議

http://blog.csdn.net/ww506772362/article/details/52609379

(3) RTSP詳解

http://blog.csdn.net/yangzhiloveyou/article/details/10161269

2.為什麼使用vlc

vlc是開源的多媒體播放器及框架,它支援大多數的媒體格式播放,體積雖不算非常精簡,但功能非常強大。 你可以訪問VideoLAN的官方網站,並且下載這款播放器:http://www.videolan.org/ 不僅僅是體驗,這對你的測試工作也非常有幫助。

3.下載並配置libvlc

本文不提供下載地址,不過你可以非常容易找到libvlc的sdk,將include/和lib/放入工程目錄,配置你的專案屬性。 請不要忘記與sdk同目錄下的plugins資料夾,它是libvlc發揮能力的重要基礎,請將它放在程式的輸出目錄下。

三、開始

1.使用庫播放一個rtsp流視訊

首先,你需要這麼幾個變數:
libvlc_instance_t *_inst;			// libvlc的執行例項
libvlc_media_t *_media;				// 用於準備播放的媒體
libvlc_media_player_t *_media_player;		// 用於使用vlc媒體播放器

(1)初始化你的rtsp流媒體

值得注意的是,用於初始化本地媒體與rtsp流媒體所呼叫的api並不相同。
_media = libvlc_media_new_location(_inst, addr);

(2)為播放新增一些配置

(未實測)對於實時的rtsp流可能存在延遲,新增如下程式碼可能會減少延遲。
libvlc_media_add_option(_media, ":network-caching=300 :live-caching=300;");

(3)初始化播放器

_media_player = libvlc_media_player_new_from_media(_media);
記得同時釋放你的媒體:
libvlc_media_release(_melibvlc_media_release(_media);

(4)播放媒體

libvlc_media_player_play(_media_player);

(5)rtsp測試連結

通過上述這些步驟,如果rtsp連結沒有問題的話,你應該可以在桌面上看見媒體啦。 這裡提供幾條rtsp測試連結:

①某路段監控視訊(非實時,1080P)

rtsp://202.104.126.35/demo?from=2017-02-07

②某節目(實時,240P)

rtsp://rtsp-v3-spbtv.msk.spbtv.com/spbtv_v3_1/214_110.sdp

③一段可愛的動畫(非實時,160P)

rtsp://rtsp-v3-spbtv.msk.spbtv.com/spbtv_v3_1/214_110.sdp

2.嵌入播放視窗到你的介面

看到這裡,如果你能成功播放媒體,那說明基本的環境配置都沒有問題,放心大膽地走下去吧。 對於大多數開發者來說,接下來應該把它嵌入到自己的介面中啦!

(1)如果你僅僅是作為播放器

那麼我建議你使用API:
libvlc_media_player_set_hwnd(_media_player, (void*)_wdgPlayer->winId());
這是最方便、快捷,並且穩定的方法,滿足一般的開發需求。 至此,你可以將本文看作一篇libvlc如何連線到rtsp流媒體的簡明小提示,後續內容僅供瞭解即可。

(2)如果你需要對視訊進行二次開發

比如我的例子中添加了人臉識別的邊框,或者類似的標註。更重要的是,如果你想要實現半透明在視訊上提示內容,那麼請繼續向下看。 我嘗試過各種方法,如:設定透明背景、加入QStackLayout、使用QGraphicsscene畫異形視窗啊等等… 與此類似的問題:

①在qt+mplayer播放視訊上層設定半透明窗體,為什麼窗體透明不了,變成黑色了

http://bbs.csdn.net/topics/390482549

②QT中實現多層Widget,而下層播放視訊處於不斷重繪的狀態,怎麼實現?

http://www.qtcn.org/bbs/simple/?t58461.html 相信讀到這裡的大家應該也焦頭爛額,找不到更好的辦法。 我在程式開發時遇到的問題:為了在視訊上新增透明內容,我先建立了一個QWidget,設定為透明,並raise()。執行現象是的確透明瞭,但也確確實實從視訊“穿越”了過去。 這裡看到的背景色是最底層的widget顏色。 可能的解釋是:使用了這段程式碼後,widget的控制代碼交給了windows下的directX繪製。
libvlc_media_player_set_hwnd(_media_player, (void*)_wdgPlayer->winId());
要想解決這個辦法:可以選擇不使用這個api,自行繪製;也可以生成多個hwnd進行繪製(windows下不太瞭解,期間幫助過的朋友曾提過這個解決方案,不知是否可行,還希望能得到驗證)。

3.將繪圖統統交給Qt

那麼,在不使用api的前提下,如何繪製呢?術語不甚瞭解還請見諒,這裡我就說的通俗易懂些: 對於視訊來說,由一幅幅畫面組成,我們將每一張圖稱之為“幀”。每秒鐘傳輸了多少幀(FPS)是評價視訊是否流暢的標準。 不瞭解如何編碼解碼沒關係,libvlc在前面所做的那些工作已經為我們鋪墊好了基礎。既然如此,我們只要取出幀,並且繪製即可。 仔細檢視libvlc的api,發現可取出幀並操作的方法:
void VideoSetCallBacks(IntPtr mediaPlayInstance, VideoLockCB lockCB, VideoUnlockCB unlockCB, VideoDisplayCB displayCB, IntPtr opaque);
IntPtr VideoLockCB(IntPtr opaque, IntPtr planes);
void VideoUnlockCB(IntPtr opaque, IntPtr picture, IntPtr planes);
void VideoDisplayCB(IntPtr opaque, IntPtr picture);
以下是我修改後的一部分程式碼:
typedef struct
{
	QMutex mutex;
	CVLCPainter *painter;
	uchar *pixels;
}callback_param_t;

static void* lock(void* op, void** plane)
{
	callback_param_t *p = (callback_param_t *)op;
	p->mutex.lock();
	*plane = p->pixels;

	return NULL;
}

static void unlock(void* op, void* pic, void* const* plane)
{
	callback_param_t *p = (callback_param_t *)op;
	uchar* pp = (uchar*)*plane;
	unsigned char* data = (unsigned char*)*plane;
	QImage a(data, gWidth, gHeight, QImage::Format_RGBA8888);
	p->painter->updatePic(a);
	p->mutex.unlock();
}

static void display(void* op, void* pic) 
{	

}
初始化影象緩衝區(建議使用其他資料結構代替陣列)
void CVLCPlayer::init_vlc_param()
{
	param = new callback_param_t;
	param->painter = _vlcPainter;
	param->pixels = new uchar[gWidth * gHeight * 4];
	memset(param->pixels, 0, gWidth * gHeight * 4);
}
updatePic函式
void CVLCPainter::updatePic(QImage &img)
{
	_pixmap = QPixmap::fromImage(img);
	_image = img;
	update();
}
在widget中渲染:
void CVLCPainter::paintEvent(QPaintEvent *event)
{
	_mutex.lock();
	QPainter painter(this);
	if (_pixmap.isNull())
	{
		_mutex.unlock();
		return;
	}
	v_width = this->rect().width();
	multi = (float)v_width / (float)gWidth;
	multi = QString::number(multi, 'f', 2).toFloat();
	v_height = (int)((float)gHeight * multi);
	o_height = (this->rect().height() - v_height) / 2;

	painter.drawImage(QRect(0, o_height, v_width, v_height), _image);
	//painter.drawPixmap(QRect(0, o_height, v_width, v_height), _pixmap);

	if (_vecRect.count() > 0 && isFaceDist)
	{
		painter.setPen(Qt::red);
		for (int i = 0; i < _vecRect.count(); ++i)
			painter.drawRect(*_vecRect.at(i));
	}
	_mutex.unlock();
}

以上原理均可檢視博文:http://www.cnblogs.com/smartsensor/p/4343769.html 在這裡提供一篇貼子,並感謝作者提供的原始碼:http://bbs.csdn.net/topics/390817375

三、新問題的出現、解決與再探

使用drawPixmap()繪圖可能導致程式崩潰? 在我的機器上出現了崩潰的問題,由於是release版本只能追蹤到drawPixmap(),替換為drawImage()後問題不再出現。通過對於windows下兩者的差異,可能是由於QImage獨立於硬體,並且它也是一種QPaintDevice,不需要在UI執行緒中處理影象。但這種說法並不能完全立足,如果大家有興趣,也可以告知或推斷可能的原因。 博主的能力有限、經驗尚淺,本文可能存在諸多問題,僅供解決問題的參考方向。如果發現錯誤,也請給予指正,謝謝。

相關推薦

Qt+libvlc+rtsp視訊繪圖探究

一、前言 1.起源 最近負責專案中的一個部分,需要從攝像頭獲取rtsp流,同時作tcp的客戶端收取人臉識別的資訊,用qt顯示視訊並繪製人臉識別框。 2.成果 3.環境 系統環境:windows 10 Qt版本:5.8.0 vlc版本:2.2.4(這裡建議使用libvl

Qt如何在QTabWidget繪圖

  Qt繪圖事件必須在paintEvent事件下繪圖,這樣導致我們在向Qt設計師介面上拖拽的控制元件繪圖時,造成了很大的麻煩。 我們不能在拖拽的控制元件上寫paintEvent函式,但是可以自定義一個類,繼承某一個控制元件,在裡面寫繪圖事件函式,但是這個非常麻煩, 此時我們需要借用Qt事件過濾器函式eve

caffe21天書的例子--qt讀取caffe deply網路

主要功能是讀取deply的層名字,程式碼如下: #include <vector> #include <iostream> #include "caffe/net.hpp" using namespace std; using namespace caff

Qt之在控制元件繪圖

1.總述 Qt的要在當前類對應的視窗上繪圖一般需要重寫paintEvent函式,但是Qt的事件過濾器預設是把父視窗下子控制元件的繪圖事件給過濾了的,因此重寫父視窗的paintEvent函式是無法在子控制元件上進行繪圖的,下面舉一個例子。   1 void MainWindow::m

【TeeChart Pro ActiveX教程】(十三)圖表面板的自定義繪圖

下載TeeChart Pro ActiveX最新版本 TeeChart通過Canvas物件提供廣泛的自定義繪圖工具。使用Canvas,您可以在“Chart Panel”的任何位置新增形狀,線條和文字,並定義其顏色,筆和畫筆樣式。 TeeChart畫布 繪圖順序 使用TeeChart的Canvas方

Qt實用技巧使用QMediaPlayer和Windows自帶元件播放swf、rmvb、mpg、mp4等視訊檔案

需求         做軟體時,點選進入介面需要播放一段視訊,該視訊的格式可相容swf、rmvb、mpg、mp4等視訊檔案。 原理         使用QMediaPlayer播放rmvb、mpg、mp4格式         使用windows Media Player

Qt實用技巧QPainterPath繪圖路徑(多次畫同樣的圖形集合)

需求         根據配置檔案,可不改變程式只調整配置檔案可調整主頁面上的字串。 原理         1.讀取檔案,固定格式(檔案在本文章中省略)         2.寫一串字元,使用QPainterPath         3.注意QPainter的時候,需

iOS播放實時視訊,HLS的大延遲問題如何解決,RTSP 能在iOS 低延遲播放麼

HLS 在實時視訊領域一直沒有很好的表現,但是HLS協議最近幾年的普及率也是越來越高, rfc8216 這是HLS最終的標準。https://datatracker.ietf.org/doc/rfc8216/ HLS能如此普及,得益於在CDN友好支援,由於HLS是基於檔案片的

Qt學習筆記(1)---QT5利用事件過濾器實現在控制元件繪圖

首先,感謝 作者:一去丶二三裡 部落格地址:http://blog.csdn.net/liang19890820   Qt中要在控制元件中繪製圖像,需要重寫paintevent函式,本文通過EventFilter(事件過濾器)來實現在控制元件上的圖形繪製。 .h檔案 #

Oracle數據庫12cR2(項目實戰之一)在Windows安裝Oracle12.2

oracle12c安裝 oracle12cr2安裝 oracle培訓教程 oracle視頻教程 oracle12cr2 oracle數據庫12cR2(項目實戰之二):linux系統安裝Oracle12.2一、課程主題:風哥Oracle數據庫教程12cR2(項目實戰之二):在linux操作系

人工智能VS投資者股票市場誰的勝算更高?

人工智能 華爾街 股票市場 異想天開 股票投資 人工智能研究歷史淵源,當人工智能與資本投資,尤其是股票投資相結合或許聽起來有些異想天開,但正如科幻作家William Gibson所言:“未來已經到來,只是分布不均。”在股票市場上想獲得高於平均水平的回報是非常困難的,事實上,研究顯示即使在華

文件傳三base64編碼

說了 json datetime byte 調試 handle png mage hang 介紹三種上傳方式: 文件上傳一:偽刷新上傳 文件上傳二:FormData上傳 文件上傳三:base64編碼上傳 Flash的方式也玩過,不喜歡不拿來說了。 優點: 1.瀏覽器可以

net3文件傳與圖片顯示以及HiddenField隱藏字段值的使用

pos protect path 來源 file ipa gif sender uri 原文發布時間為:2008-07-29 —— 來源於本人的百度文章 [由搬家工具導入]using System;using System.Data;using System.Configu

ThinkPhp框架文件

load 1-1 method 文檔 文件夾 文件上傳 實例 成功 upload 實現文件上傳功能需要控制器,方法然後是顯示的頁面 1.在Controller下新建一個控制器TestController.class.php 2.創建操作方法 <?php names

Android開發實踐JNI線程回調Java函數示例

lan 並且 進行 img 工程 stat 責任 3.5 jpg 原創作品,允許轉載,轉載時請務必以超鏈接形式標明文章 原始出處 、作者信息和本聲明。否則將追究法律責任。http://ticktick.blog.51cto.com/823160/1358558 JNI是Ja

(轉)第03節在Canvas插入圖片並設置旋轉屬性

doctype script border wid bsp viewport 設置 css樣式 png 我們已經學會了在Canvas上畫簡單的圖形,這節我們就在Canvas上加一張圖片。用到fabric.Image對象把圖片添加到Canvas上。 HTML文件:為了效果更好

穆尼裏奧未派最好點球手;齊達內成功並不意外

兩場 來講 目標 皇馬 洛杉磯 是我 小夥子 等等 有時 出色的上半場“我們訓練的結果很棒,對上一支皇馬這樣的頂級對手,那可以說是一個非常棒的上半場。我想在面對他們的年輕球員的時候我們失去了動力和饑餓感。我認為我們打了下半場的那些小夥子們很失望,因為他們踢的不是皇馬最好的球

算法整數除法取整

nbsp blog res 情況 bin math.h 代碼 方法 bsp 寫代碼會遇到整數除法需要上取整的情況。 1. 整數除法的話,可以自己寫^_^ 1 #!/bin/bash 2 3 num=101 ##被除數 4 pre=10 ##除數 5 6

計算機網絡【八】應用 【轉】

tac 都是 文件共享 編寫 .net pos 遠程 等待 src 轉自:http://blog.chinaunix.net/uid-26275986-id-4110819.html 今天我們來快速地瀏覽一下傳輸層之上的應用層所使用的協議,下面將簡要地列出應用

李笑來老師在《把時間當作朋友》曾說過“所有學習的成功,都只靠兩件事策略和堅持,而堅持本身就應該是最重要的策略之一

tail tin keep each however http can 一次 練習 高效編程=工具+方法+體系+專註 前面根據個人的經驗,分享了一些提高編程效率的個人心得。每個人的經歷經驗不盡相同,相信其實每個人心中都有一份自己的清單。但最最重要的是堅持投入,不斷地練習、