VLC框架分析

 

VLC內部運行機制以及架構分析個人總結

放大字體  縮小字體 發佈日期:2011-05-10   瀏覽次數:441
VLC架構剖析1. VideoLan簡介1.1 videolan組成Videolan有以下兩部分組成:VLC:一個最主要的部分,它可以播放各種類型的媒體文件和流

vlc架構剖析

1. VideoLan簡介

1.1 videolan組成

Videolan有以下兩部分組成:

VLC:一個最主要的部分,它可以播放各種類型的媒體文件和流媒體文件,並且可以創造媒體
流並保存成各種格式的媒體文件,這些文件的質量要比沒保存前的件好。videolan作爲客戶
端可以播放本地文件,httP://,rtsp://。

VLS:是一種流服務器,專門用來解決流的各種問題,它也具有一些VLC的特徵。videolan作
爲服務器可以輸出httP,rtP,rtsp的流。

1.2 VLC優點

VLC是一種跨平臺的媒體播放器和流媒體服務器,最初爲videolan的客戶端,它是一種
非常簡便的多媒體播放器,它可以用來播放各種各樣的音視頻的格式文件(MPEG-1、MPEG-
2、MPEG- 4、DivX、WMV、mp3、OGG、Vorbis、AC3、AAC等等)流媒體協議,最具特色的
功能是可以邊下載邊觀看Divx媒體文件,並可以播放不完全的AVI文件。並且支持界面的
更改。VLC支持多種的操作系統,linux(rh9,Debian,Mandrake,Gentoo),BSD,windows,
Mac OS X,Be OS,Solaris等等。支持帶菜單的VCD,SVCD,和DVD,數字衛星頻道、數字
地球電視頻道(digital terrestrial television channels),在這些操作系統下通過寬帶IPv4、IPv6
網絡播放線上影片。此軟件開發項目是由法國學生所發起的,參與者來自於世界各地,設計
了多平臺的支持,可以用於播放網絡流媒體及本機多媒體文件,特別是它能直接播放未下載
完整的多媒體文件。

下圖表示出了VideoLan的解決方案:

 


VideoLan Client是VideoLan項目(一個完整的MPEG-2客戶/服務器解決方案)的一個組成
部分。不過VideoLan Client也可以作爲一個獨立的程序來播放來自硬盤或者DVDROM的
MPEG數據流。它目前支持GTK+、GNOME、KDE和QT,並且可以使用X11、Xvideo、SDL
或者DirectX作爲視頻輸出。對於聲音,VideoLan Client支持OSS、ALSA和ESD。要訪問DVD,
VideoLan Client使用的是Libdvdcss庫。它是一個簡單的專爲DVD訪問設計的庫。它可以像
訪問塊設備一樣訪問DVD,而不用考慮解密問題。

2. VLC整體架構分析

2.1 LibVLC

LibVLC是VLC的核心部分。它是一個提供接口的庫,比如給VLC提供些功能接口:流的
接入,音頻和視頻輸出,插件管理,線程系統。所有的LibVLC源碼位於src\及其子目錄:

Interface/:包含與用戶交互的代碼如按鍵和設備彈出。

Playlist/:管理播放列表的交互,如停止,播放,下一個,或者隨機播放。

Input/:打開一個輸入組件,讀包,解析它們並且將被還原的基本流傳遞給解碼器。

Video_output/:初始化video顯示器,從解碼器得到所有的圖片和子圖片(如subtitles)。隨意
將它們轉換爲其它格式(如:YUV到RGB)並且播放。

Audio_output/:初始化音頻mixer(混合器)。如:發現正確的播放頻率,然後重新制作從解碼器
接收過來的音頻幀。

Stream_output/:類似Audio_output。

Misc/:被libvlc其它部分使用的雜項,如線程系統,消息隊列,CPU探測,對象查詢系統,
或者特定平臺代碼。

 


2.2 VLC

VLC是一個純粹圍繞着LibVLC寫成的程序。它是非常小的,但是功能很齊全的媒體播放
器,歸功於LibVLC的動態組件支持

2.3 組件

 組件位於modules\子目錄,在運行時被加載。每一個組件提供不同的特徵適應特定的
文件的環境。另外,大量的不斷編寫的可移植功能位於audio_output\,vidco_output\和
interface\組件,以支持新的平臺(如:BeoS Mae OS X)。

組件中的插件被位於src\misc\modules.c和include\modules*.h中的函數動態加載和卸
載。寫組件的API描述如下,共3種:

(l)組件描述宏:聲明組件具有哪種優先級的能力(接口,demux2等等),還有GUI組件的
實現參數,特定組件的配置變量,快捷方式,子組件等等;

(2)Open(vlc_objeet_t*p_object):被VLC調用初始化這個組件,它被組件描述宏賦值給了
結構體module_t中的pf_activate函數指針,被Module_Need調用;

(3)Close(vlc_objeet_t*p_object):被VLC調用負初始化這個組件,保證消耗Open分配的所
有資源。它被組件描述宏賦值給了結構體module_t中的pf_deactivate函數指針,被
Module_Unneed調用。

用LibVLC寫的組件能夠直接被編譯進VLC,因爲有的OS不支持動態加載代碼。被靜態
編譯進VLC的組件叫做內置組件。

2.4 線程分析

(l)線程管理:

VLC是一個密集的多線程應用。由於解碼器必須預先清空和播放工序必須預先做好流程
(比如說解碼器和輸出必須被分開使用,否則無法保證在要求的時間裏播放文件),因此VLC
不採用單線程方法。目前不支持單線程的客戶端,多線程的解碼器通常就意味着更多的開銷
(各線程共享內存的問題等),進程間的通信也會比較複雜。

VLC的線程結構基於pthreads線程模型。爲了可移植的目的,沒有直接使用pthreads
函數,而是做了一系列類似的包裹函數:vlc_thread_create,vlc_thread_exit,vlc_thread_join,
vlc_mutex_init,vlc_mutex_lock,vlc_mutex_unlock,vlc_mutex_destroy,vlc_cond_init,
vlc_cond_signal,vlc_cond_broadcast,vlc_cond_wait,vlc_cond_destroy和類似結
構:vlc_thread_t,vlc_mutex_t,and vlc_cond_t。

(2)線程同步:

VLC的另一個關鍵特徵就是解碼和播放是異步的:解碼由一個解碼器線程工作,播放由音
頻輸出線程或者視頻輸出線程工作。這個設計的主要目的是不會阻塞任何解碼器線程,能夠
及時播放正確的音頻幀或者視頻幀。這樣實現也導致產生了在接口,輸入,解碼器和輸出之
間的一個複雜的通訊結構。

雖然當前接口並不允許,但是讓若干個輸入和視頻輸出線程在同一時刻讀取多個文件是
可行的(這是VLC未來改進的主要方向)。現在的客戶端就是用這種思想實現的,這就意味着
如果沒有用到全局鎖的話那麼一個不能重入的庫是不能被使用的(尤其是liba52庫)。

VLC輸出的流裏包含時間戳,被傳遞給解碼器,所有有時間戳標記的流也均被記錄,這


樣輸出層可以正確及時的播放這些流。時間mtime_t是一個有符號的64-bit整形變量,單位
是百萬分之一秒,是從1970年7月1日以來的絕對時間。

當前時間能夠被mdate()函數恢復。一個線程可以被阻塞到mwait(mtime_t date)等到一
個確定的時間才被執行。也可以用msleep(mtime_t delay)休眠一段時間。如果有重要的事情
要處理的話,那麼應該在正常時間到來之前被喚醒(如色度變換)。例如在
modules\codec\mpeg_vldeo\synchro.c中,通常的解碼時間被記錄,保證圖像被即時解碼。

3. VLC接口技術分析

3.1 VLC運行過程

通過對相關資料和自己的分析,VLC的運行過程如下:

ELF(Linux下可執行文件的格式)先被動態加載,然後主線程就變成了接口線程並且在
src/interface/interface.c中開始。它執行下列步驟:

1.cpu探測:什麼型號?所有能力(MMX,MMXEXT,3DNow,AltiVec等等)

2.消息接口初始化;

3.命令行選項解析組件

4.創建播放列表

5.倉庫初始化

6.加載所有內置和動態組件

7.打開接口

8.安裝信號處理器:SIGHUP,SIGINT和SIGQUIT(捕獲一個,忽略後來的並退出)。

9.派生音頻輸出線程;

10.派生視頻輸出線程;

11.主循環:事件管理;

下圖表示了這些步驟的執行過程:


 

VLC的運行過程圖


3.2 消息接口

由於printf()函數不是線程安全的,因此在調用printf()函數時一個線程的執行將會受到
干擾,當這個線程被另一個函數所調用時就會其狀態被破壞而退出程序。所以VLC構造了自
己的線程安全的消息接口。

VLC的線程安全的消息接口有兩種實現方式:如果在config.h裏定義了INTF_MSG_QUEUE
的話,每一個類似printf()的函數將會把排隊的消息放到鏈表裏,這個鏈表將會在事件循環
中被線程接口用紅色標記的方式打印出來。如果INTF_MSG_QUEUE沒被定義的話,調用線
程將會獲得一個print lock(用來防止在同一時刻有兩個printf操作被執行)同時直接打印出消
息(默認操作)。

以下爲VLC線程安全消息的API:

QueueMsg:添加一條消息到消息隊列,如果消息隊列滿了,先打印所有的消息;

FlushMsg:打印所有在消息隊列裏的消息,特別的,消息隊列必須被提前加鎖,因爲該
函數不檢查鎖。

PrintMsg:打印一條消息到stderr,可以打印彩色消息。

3.3 命令行選項

 VLC用GNU的getopt解析命令行選項。Getopt結構定義在src\extras\getopt.h裏。所有
的配置也可以用環境變量改變:調用函數main_Put*Variable和main_Get*Variable。所
以,.\vlc--height=240和 .\vic_height=240./vlc(這種方式用於所有地方,包括插件)是一樣的。
但是爲了線程安全的考慮,當第二個線程派生了,main_Put*Variable便不能被使用了

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