H264解碼多線程項目總結

從3月份開始到4月底,開始了多線程解碼的項目。這個項目主要爲了利用當今的CPU多核技術,將H.264解碼單線程變成多線程,以提高解碼速度。剛開始的時候不知道如何下手,不過老大(項目經理)給了我一些提示,讓我先看看ffmpeg中的解碼多線程是如何實現的,然後再根據ffmpeg中的多線程思路來完善我們公司自己的解碼器多線程功能。因此,基於這個項目基本上是按照以下的步驟實現的:

1)由於按照老大的提示需要參照ffmpeg的多線程解碼思路,所以第一步首先就需要實現ffmpeg的單步調試,以理解ffmpeg多線程解碼的運行方式。這裏可選擇兩種方法,第一種適合只安裝了VS2010的windows用戶,第二種則適合於在linux上進行代碼調試的人。第一種方法稍微複雜,主要是利用編譯出的pdb信息進行調試,詳細步驟可參考之前的文章《VS2010中進行ffmpeg編譯與單步調試》。第二種方法則相對比較簡單,由於ffmpeg源碼本身是在linux平臺上進行開發的,因此只要在linux平臺上先編譯源碼,然後安裝相應的IDE進行調試即可,IDE可採用QT creator或者code blocks。不過這裏值得注意的是,利用第一種方法進行ffmpeg的調試相對比較粗糙,因爲現在最新的ffmpeg版本代碼都需要C99的支持,而VS2010則不支持C99標準,所以需要在編譯時下載C99 warper進行包裝後才能編譯通過形成pdb文件,但這樣一來,在調試的時候問題也就來了,由於在編譯的時候採用了C99轉換,故而實際生成的調試信息和源代碼不能精確匹配,可能會給調試人員帶來理解上的困擾。因而,筆者建議,在條件允許的情況下,可以採用VS2012以後的版本進行調試,或者最好採用linux平臺進行代碼調試。但如果你沒有安裝linux平臺怎麼辦呢?筆者按照自己的經驗,建議你可以安裝一臺虛擬機,然後在虛擬機上裝一個linux系統,這樣你就能夠充分享用windows和linux兩者帶來的便利了。

2)ffmpeg的調試工作做好以後,接下來就是理解ffmpeg的多線程解碼思路了。通過調試我們可以發現,在ffmpeg中,可以分別採用幀內多線程解碼和幀間多線程解碼,幀內多線程解碼的的依據主要是幀內各宏塊的參考宏塊可能相同,需要相同參考宏塊進行解碼的宏塊可以同時進行解碼。同理,幀間多線程解碼的依據也是由於各幀圖像需要的參考幀可能相同,需要相同參考幀的幀可以同時進行解碼,最容易理解的就是部分B幀的並行解碼了。由於幀內多線程解碼的效率並不是很高,因此我主要針對的是幀間多線程解碼方法,關於幀間多線程解碼的內容可以參考網站http://blog.csdn.net/bsplover/article/details/7542980和碩士論文《視頻編解碼算法的並行研究》,以及以下三張圖片內容:



相信通過這三個資料的學習,再結合相應的代碼跟蹤調試,應該對於理解ffmpeg幀間多線程解碼思路不會太難。

3)理解了ffmpeg多線程解碼,接下里就是對應公司的H.264解碼器進行修改了。在進行這一步驟之前,需要先熟悉多線程編碼的相關問題。關於多線程編碼,在操作系統進入多任務作業時就已經成爲了大家研究的熱點。隨後,在硬件CPU多核的推動之下,越來越多的系統和應用程序採用了多線程實現的方式,這樣可以充分利用CPU多核技術,使任務得以並行處理,加快了任務處理的時間,提高了程序運行的效率。在不同的平臺下,也出現了不同的多線程編碼方式,如在windows下,以win32多線程編碼爲主,在linux平臺上,則採用基於POSIX標準的pthread進行多線程編碼,兩種平臺上的編碼底層接口不同,也導致了跨平臺移植的困難。所幸,之後出現了win32 pthread版本的接口,可以方便在windows平臺下開發出符合POSIX標準的linux上可運行的多線程代碼。關於win32 pthread的源碼,大家可以上http://www.sourceware.org/pthreads-win32/上下載,這樣你就可以在vs平臺上使用win32 源碼或者DLL嵌入進行調試編碼。

接下來要講一下多線程編碼常用的一些函數了,這裏分爲win32 和POSIX進行對比說明:

1.關於線程創建和消亡的操作。

1.1 創建和撤銷一個POSIX線程

pthread_create(&tid, NULL, start_fn, arg);

pthread_exit(status);

1.2 創建和撤銷一個Win32線程

CreateThread(NULL, NULL, start_fn, arg, NULL, NULL);

ExitThread(status);

2.關於線程的等待(join or wait for)的操作。

在多線程模型下,一個線程有可能必須等待其他的線程結束了才能繼續運行。比如說司機和售票員,司機只有當售票員確定所有的人都上車了,即售票員的行動結束以後才能開車,在這之前司機必須等待。

2.1等待一個POSIX線程

pthread_join(T1);

2.2等待一個Win32線程

WaitForSingleObject(T1);

Win32還提供一個調用WaitForMulitpleObject(T[]),可以用來等待多個線程。

3.關於線程的強制撤銷(cancellation or killing)的操作。

3.1 撤銷一個POSIX線程

pthread_cancel(T1);

3.2 撤銷一個Win32線程

TerminateThread(T1);

4.線程的同步機制(synchronization)

4.1互斥量mutex是最簡單的同步變量,它實現的操作實際上就是一把互斥鎖,如果一個線程擁有了這個mutex,其他線程在申請擁有這個mutex的時候,就會被阻塞,直到等到先那個線程釋放這個mutex。在任何時候,mutex至多隻有一個擁有者,它的操作是完全排他性的。

4.1.1 POSIX的mutex操作

pthread_mutex_init(MUTEX, NULL);

pthread_mutex_lock(MUTEX);

pthread_mutex_trylock(MUTEX);

pthread_mutex_timedlock(MUTEX, ABSTIME);

pthread_mutex_unlock(MUTEX);

pthread_mutex_destroy(MUTEX);

4.1.2 Win32的mutex操作

CreateMutex(NULL, FALSE, NULL);

WaitForSingleObject(MUTEX);

ReleaseMutex(MUTEX);

CloseHandle(MUTEX);

4.1.3 Win32的CriticalSection操作

InitializeCriticalSection(&cs);

EnterCriticalSection(&cs);

TryEnterCriticalSection(&cs);

LeaveCriticalSection(&cs);

DeleteCriticalSection(&cs);


4.2信號量semaphore最初是由E.W.Dijkstra於20世紀60年代引入的。通常,信號量是一個計數器和對於這個計數器的兩個操作(分別稱之爲P,V操作),以及一個等待隊列的總和。一個P操作使得計數器減少一次,如果計數器大於零,則執行P操作的線程繼續執行,如果小於零,那麼該線程就會被放入到等待隊列中;一個V操作使得計數器增加一次,如果等待隊列中由等待的線程,便釋放一個線程。

4.2.1 POSIX的信號量操作

sem_init(SEM, 0, VALUE);

sem_wait(SEM);

sem_trywait(SEM);

sem_destroy(SEM);

4.2.2 Win32的信號量操作

CreateSemaphore(NULL, 0, MaxVal, NULL);

WaitForSingleObject(SEM);

ReleaseSemaphore(SEM);

CloseHandle(SEM);

4.3條件量condition variables是一種非常類似於信號量的同步變量,不同的是,信號量關注的是counter的計數是多少,而條件量關注的僅僅是條件是否滿足,換一句話說,條件量可以簡單看作是計數器最大取值不超過1的信號量,但在它絕對不是信號量的簡單實現,某些情況下,它比信號量更直觀。

4.3.1 POSIX的條件量的操作

phtread_cond_init(COND, NULL);

phtread_cond_wait(COND, MUTEX);

phtread_cond_timedwait(COND, MUTEX, TIME);

phtread_cond_signal(COND);

phtread_cond_broadcast(COND);

phtread_cond_destroy(COND);

其中broadcast是用來喚醒所有等在該條件量上的線程。

Win32中並沒有條件量這個概念,但是它實現了一種叫做Event的同步變量,實質上和條件量是差不多的。


學習完上面的這些常用的多線程接口函數之後,我想大家現在就可以自己編寫一個多線程的程序了,當然爲了支持跨平臺,你可以選用上面提到的win32 pthread。同樣,我也是根據以上的多線程編碼知識實現了多線程解碼項目,最後歡迎大家提出批評和討論意見~~
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章