一種用於voip客戶端多窗口視頻渲染的實現思路

在我以往的opengl渲染視頻的使用經驗中,是由opengl渲染環境管理窗口句柄,將作爲界面層傳入的窗口句柄的子窗口嵌入其中進行視頻圖像顯示。現在介紹的一種實現方式與此大相徑庭:渲染的窗口句柄由上層界面管理,每個窗口句柄綁定一個opengl渲染環境進行視頻的渲染,opengl渲染環境一旦創建就不再銷燬(在此描述的只是客戶端界面窗口與opengl渲染環境的關聯的一種思路,並非描述opengl渲染的方法)

背景

最近有一個項目,客戶端運行環境是麒麟x86系統,客戶端點播監控圖像,客戶端的界面是用QT做的,圖像顯示時是分屏模式,最大分屏數爲9分屏(包括4分屏,6分屏等),分屏模式間可以相互切換。每個分屏顯示一路圖像。9分屏如下圖所示:

image
界面業務:

  1. 界面層是不會進行具體的圖像渲染的,在點播會話建立成功後,界面層會將對應要顯示圖像的窗口句柄傳入媒體庫進行渲染
  2. 界面上針對單個分屏,是有放大,全屏,縮小功能的
  3. 會對監控進行輪詢,一次自動點播指定分屏數量的監控圖像,下次再自動點播其他監控的圖像,自動輪詢
  4. 可一鍵點播多路監控圖像

媒體庫渲染的實現:

  1. 渲染採用的是opengl,媒體庫將opengl的渲染流程封裝到一個叫Render的對象中
  2. 每次點播會話建立成功將會創建一個新的Render對象,結束會話會銷燬Render對象
  3. 界面傳入的句柄會傳入Render對象用於渲染的顯示

問題

對多路圖像進行輪詢點播時,媒體庫會隨機崩潰(有時候輪詢一次就會崩潰,有時候輪詢很長時間都不會崩潰),根據core文件中的堆棧信息,是崩潰在opengl渲染的API中

解決

分析

Render對象是對opengl渲染流程的封裝,

  1. 每次會話建立後會創建一個Render對象,會話掛斷時會被銷燬,Render銷燬是異步釋放(會話被掛斷銷燬,Render可能正在釋放)
  2. Render在Init時會根據傳入的句柄,在窗口上創建opengl渲染環境,在銷燬時會在close函數中銷燬opengl渲染環境
  3. 每路圖像渲染爲一個線程,所以一個渲染線程中,有一個Render對象,一個窗口句柄,一個opengl的渲染環境
  4. 同一個Render對象中opengl渲染流程都是串行的

實現思路

因爲崩潰的堆棧信息顯示在opengl的渲染API上,所以最開始的時候懷疑是opengl不支持多窗口渲染(以往的opengl使用經驗都是通過渲染模塊自己創建窗口,然後將窗口作爲子窗口嵌入界面指定的父窗口中,所以opengl渲染環境只有一個),在與界面的開發人員討論解決方案時,得知界面分屏的實現機制:固定創建最大數目的窗口(這裏是9分屏),不管分屏怎麼變換,窗口是不會被銷燬的。

然而對負責渲染的Render對象它是與會話綁定的,會話創建時它會創建,會話掛斷時它會被銷燬,但界面分屏窗口是恆存在的(顯然同一個窗口上顯示的不同的會話的圖像,對不同的會話傳入同一個窗口句柄),但是在掛斷會話後,Render對象會被異步銷燬,假如在同一個分屏窗口上點播一路視頻,那麼新的Render對象與正在被銷燬的Render對象可能會使用的是同一個窗口句柄,如果被銷燬的Render對象在釋放opengl的渲染環境,而新的Render對象正在渲染,此時就會造成崩潰

按照這種思路,對渲染實現方式進行修改:Render對象只創建(不再銷燬,按照業務的需求最大也就同時點9路,所以最多會產生9個Render對象)在界面傳入窗口句柄時,傳入一個index標識分屏序號。最終,每個分屏窗口都固定綁定了一個Render對象,Render對象不會被銷燬。如此修改了,輪詢點播時不再崩潰。

本質

  1. 問題的本質

崩潰的本質是不同的Render對象對同一個窗口句柄存在競爭關係,沒做不同Render對象間的同步,必然會導致崩潰。

  1. 本質關係

會話,分屏窗口,Render對象,opengl環境的本質關係:會話掛斷,分屏與Render對象還存在,這時Render對象的中的opengl渲染環境並沒有被釋放,而只是沒有圖像數據,不渲染圖像罷了,該分屏上再建立另外一路會話,對Render對象來說只有又了圖像數據,可以進行渲染。所以本質上,Render與opengl環境根本不需要與會話關聯。

理清楚本質關係,其實並不需要對Render對象間進行同步,如果進行同步,必然會影響視頻圖像的幀率。

注意點

按照上面所說的實現方式有幾點需要注意:

  1. 每路會話中,圖像的分辨率可能會不一致,在渲染需要做判斷,如果分辨率變化,需要重新分配紋理的空間
  2. 因爲窗口句柄有上層界面掌握,在掛斷後,界面後重新刷新窗口的背景色,這個時候opengl環境可能會變化,在渲染時需再重新設置窗口的渲染環境
  3. 分屏窗口會放大,縮小,此時需要改變渲染時的視口大小

總結

關鍵點,理清會話,分屏,Render對象(opengl渲染環境)之間的關係,Render對象應該與分屏綁定,不同會話圖像的渲染對Render對象來說只是圖像數據不同。

實現方式:Render對象只創建不銷燬,通過Index標識與分屏窗口綁定,在分辨率變化時,紋理對象需重新分配,在分屏大小變化時,視口需變化

補充: Render對象對opengl的封裝是基於 GLX庫進行

GLX庫資料

Xlib手冊

GLX_and_Xlib

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章