2011-05-13 23 views
4

正如您可能從問題標題中推測的那樣,我們需要同時解碼和顯示多個(例如八個)H.264編碼視頻(並保留所有視頻時間同步,但這是另一個問題)。視頻通常爲25 FPS,分辨率爲640x480。同時解碼和顯示許多H264視頻的最快方法C#

在打開問題的癥結之前,我將提供一些背景知識。

該功能需要烘焙成相當大的C#3.5(WinForms)應用程序。視頻將佔用應用程序中的矩形 - 託管代碼需要能夠指定每個視頻的繪製位置以及其大小。我們在C#中獲取H264數據包並將它們發送到本機H264解碼器中以獲取YUV12圖像數據。

一個早期的嘗試包括將YUV12圖像轉換爲RGB24並將它們BitBlt'ing到從C#傳入本機代碼的HWND。功能上,所有BitBlt'ing都必須在UI線程上發生,導致它在顯示多個視頻(2.6 GHZ核心2個二重奏)時出現故障。

當前嘗試在啓動時加速每個cpu-core的線程數,並在這些線程上解碼/顯示視頻。這種表現是令人興奮的(我發現觀看任務管理器比顯示的視頻更有趣)。用戶界面方面,它留下了很多想要的。

從非UI線程開始繪製到在UI線程(例如,面板停靠在WinForms控件中的面板)上創建的HWND的毫秒時間後,我們開始獲取各種各樣的時髦行爲, WinForms的安全性。這導致我們使用本地代碼創建HWND並將其繪製到這些代碼中,C#提供了應該在屏幕座標中繪製的矩形。

嘎! CanOfWorms.Open()。

問題:當C#應用程序收到焦點時,它跳轉到Z順序的前面並隱藏視頻窗口。 解決方案:將視頻窗口始終置於頂部。

問題:當用戶切換到另一個應用程序時,視頻窗口仍然在最上面。 解決方案:檢測C#應用程序的激活和禁用,並相應地顯示/隱藏視頻窗口。

問題:用戶說:「我希望我的視頻在一臺顯示器上播放,而我在另一臺顯示器上編輯Word文檔!」 解決方案:告訴用戶閉嘴,反正Word會吮吸。

問題:我被解僱了。

等等,等等

我想這個問題的關鍵是我們有HWND在非UI線程創建的,我們希望「模擬」那些被嵌入在C#應用程序。

有什麼想法/建議嗎?我完全在這裏吃午飯嗎?

如果存在的話,我更願意採取完全不同的方法(這個項目需要大量的學習 - 贏得彩票的可能性比我在沿着道路的每一步選擇最佳方法的可能性更大) 。

+0

FYI:開始開發這樣的組件,我建議在我的答案中,會讓你知道它是否工作得像它應該... – 2011-05-18 22:13:54

+0

非常感謝!我還沒有機會開始你的解決方案 - 取消了這個項目,以消除一些火災 - 在晚上堵塞它,但它的進展緩慢。 – Shea 2011-05-24 02:30:36

回答

2

毫秒我們開始繪製到UI線程上創建的HWND(例如,面板停靠在WinForms控件中)從非UI線程,我們開始得到各種各樣的時髦行爲, WinForms的線程安全性。這導致我們使用本地代碼創建HWND並將其繪製到這些代碼中,C#提供了應該在屏幕座標中繪製的矩形。

什麼樣的時髦行爲? 如果你的意思是閃爍或繪圖延遲,你是否嘗試鎖定()面板或任何其他類的線程/繪圖同步? 再次說明:將數據發送到解碼器,接收圖像,轉換並使用OnPaint處理程序繪製圖像時,確切的問題是什麼? (設置不同的線程循環在25fps的,叫panel1.Invalidate()則)

我想這個問題的關鍵是,我們有HWND對非UI線程創建的,我們希望「模擬」那些嵌入在C#應用程序中的。

不這樣做。嘗試在您的C#應用​​程序中繪製接收到的數據。一般來說,我不會推薦混合本地代碼和c#。在本地代碼中使用h264解碼器是唯一的例外。

使用你的線程來解碼視頻數據包(就像你已經做的那樣),然後有一個線程循環並調用Invalidate(如上所述)。然後爲每個顯示視頻的面板設置一個OnPaint處理程序。在此處理程序中獲取最新的視頻圖片並繪製它(e.Graphics)。

我希望這可以幫助,但還需要有關問題的詳細信息...

+0

感謝您的回覆。 時髦的行爲是在P/Invoke調用的站點上的AccessViolationException來解碼和顯示H264數據包。當這些調用在UI線程上時,AccessViolationException不會發生。 你有信心在UI線程上8x25 = 200 bitblts/sec是一個合理的要求嗎?如果是的話,我願意嘗試,因爲它可以解決所有問題... – Shea 2011-05-14 01:04:28

+0

你是對的。 200 Graphics.DrawImage()調用太多。嘗試使用一個大的面板。然後將圖片繪製到內部位圖。在每個OnDraw調用中,只有DrawImage將創建/更新的位圖繪製到面板上。在視頻之間添加邊框應該很簡單。 也嘗試使用1-4線程進行解碼。一個額外的線程用於計時fps(無效)。然後讓調用OnPaint的UI Thread完成圖像組合並將結果繪製到大面板上的工作! – riki 2011-05-14 01:20:04

+0

幸運/不幸的是,我們開發了一個佈局系統,允許用戶隨時隨地放置視頻,還有其他組件,例如可以散佈的圖表,因此不能保證視頻所需的所有空間的聯合將是一個大組。 你的第一個想法應該只需要4-5小時的代碼,但我認爲這值得探索。我將在一些由非託管代碼和託管代碼共享的內存中進行每種視頻解碼(雙緩衝),並且將託管代碼BitBlt作爲OnPaint上的最後解碼圖像 – Shea 2011-05-14 01:39:49

3

忘掉的BitBlt-ING和做到這一點:

  • 爲要播放視頻的每個窗口,創建一個DirectShow圖並將該圖的渲染器附加到該窗口中的渲染器之前的該窗口
  • 放置samplegrabber過濾器。它將允許您進行回調,在該回調中,您將能夠填充緩衝區而不是blitting,並解碼到samplegrabber中提供的緩衝區。

此外,我猜你可以將原始YUV12放入緩衝區,因爲VMRenderer可以直接顯示它們。使用DirectShowNet庫。

編輯:

是的,順便說一句,如果影片在同一個「畫布」,你可以使用同樣的技術與渲染器,並創建只有一個大窗口,然後「手」轉移解碼的視頻矩形和把它們放入幀緩衝區。

又一編輯:

BitBlts總是被序列,即,它們不能並行運行。

+0

有趣的想法! DirectShow能夠比手動BitBlt更快地渲染圖像數據的原因是什麼? – Shea 2011-05-14 22:50:46

+0

我不會在這裏進行推測,因爲在今天的時間裏,一切都是'加速'的,但DirectShow作爲DirectX的一部分,提供了直接訪問設備的最低級別,當GDI +以方便的高級別時尚。 – 2011-05-15 06:46:26

+0

太好了,謝謝。如果VMRenderer可以在非UI平臺上繪製一個「窗口」,我可以看到這會產生很大的變化。我是Felheart想法的1/2,所以我會先完成,然後嘗試這一個併發布結果。 – Shea 2011-05-15 20:07:21

0

我喜歡早些時候公佈的DirectShow的答案,但我想有一個附加選項,可能會更容易爲你實現的基礎上,從你的問題的摘錄:

雖然功能齊全,所有BitBlt'ing有這導致它顯示超過一對夫婦的視頻

時陷入癱瘓UI線程上發生

我的想法是從代碼開始,並使用異步CTP的Visual Studio 2010是currently available和包括上線許可證。從那裏,它應該是一個相對簡單的修改這個現有的代碼更具響應性:只需在幾個地方添加await和異步關鍵字,其餘的代碼應該在很大程度上保持不變。

+0

基礎架構(設備上下文)不支持任何類型的東西。 – 2011-05-14 21:01:37