嵌入式 vlc從接收到數據流到播放視頻的過程分析

Vlc流播放流程

 vlc源碼目錄樹:

目錄名稱

說明

bindings

Java, CIL 和Python綁定

doc

幫助文檔 (不是更新的)

extras

另敘。

include

VLC 頭文件

libs

SRTP庫和裝載庫

lxdialog

製作 menuconfig的文件

m4

Automake和autoconf的宏文件

modules

除了src目錄外最重要的目錄。參考“功能模塊目錄樹”一節

po

i18n (語言翻譯)文件

projects

建立在 libvlc的項目,如Mozilla插件,ActiveX 插件和MacOS X Framework

share

圖標,腳本等等

src

除了功能模塊以外最重要的目錄。

test

一些腳本或測試代碼

extras 的內容

extras/analyser

一些代碼風格編輯器 (vim,emacs)的宏和一些valgrindsuppressions

extras/buildsystem

可選的編譯系統

extras/contrib

需要的庫文件 (包括Makefiles自動下載和編譯(或交叉編譯),補丁)。

extras/deprecated

deprecated 文件

extras/misc

未分類文件

extras/package

用於軟件發佈的文件如ipkg,不同的 rpm 規範文件,win32和Mac OS X安裝文件。

 

 

 

功能模塊目錄樹


目錄名稱

子目錄

說明

access


通過網絡獲取視頻流的協議(http,ftp,fake,tcp,udp等),獲取物理媒體介質的媒體內容如cd,dvd。


cdda

讀取CD音頻的輸入模塊


dshow

DirectShow獲取插件,用於WINDOWS平臺下的編碼卡。


dvb

使用V4L2API的輸入模塊,用於DVB-S/C/T媒體流。


mms

基於TCP,UDP的MMS和HTTP獲取模塊


rtsp



screen

獲取屏幕圖像的輸入模塊。


vcd

獲取VCD數據的輸入模塊。


vcdx

獲取VCD輸入模塊,可以導航,靜止




access-filter


包含下面的濾波器:timeshift, record, dump




access-output






audio-filter


各種音頻濾波器如解碼,均衡,轉換。


channel-mixer

各種混合器,解碼器如 Dolby解碼器


converter

定點或浮點音頻格式轉換如 AC/3,MPEGI-II 音頻層1,2, 3 解碼


resampler

各種音頻重採樣模塊




audio-mixer


混合器插件




audio-output


音頻輸出插件如ALSA,OSS和 DirectX音頻




codec


各種編解碼,特別是ffmpeg


cmml

持續媒體標記語言,腳本/超鏈接解釋器


dmo

一個DirectMediaObject解碼器,利用DirectMedia對WMV3視頻解碼


ffmpeg

ffmpeg 庫的視頻解碼器


spudec

RLE DVD 小標題解碼


xvmc

XVMC視頻輸出和解碼




control


控制播放器的各種接口:手勢, 熱鍵,lirc,遠程控制和telnet


http

HTTP遠程控制




demux


不同的解複用程序


asf

ASF 解復器


avi

AVI文件流解復器


mp4

MP4文件輸入模塊


mpeg



playlist

播放清單導入模塊




gui


不同平臺的用戶界面和 ncurses接口


beos

用於BeOS的音頻輸出,視頻輸出和用戶界面輸出。


macosx

Mac OS X 視頻輸出和用戶界面模塊


pda

iPaq用戶接口,使用Gtk2+widget集.


qnx

QNX RTOS 插件


qt4

使用Qt4庫交叉編譯的用戶界面模塊。該模塊是默認的界面庫


skins2

換夫模塊。


wince

Pocket PC 接口


wxwidgets

使用wxWindows庫跨平臺的接口。作爲默認的接口的VLC版本是0.86a.




meta-engine






misc




dummy

啞 (沒有GUI)音頻輸出,視頻輸出,用戶接口和輸入模塊。


memcpy

內存快拷貝模塊


notify

通知,使用libnotify


playlist



probe



testsuite



xml

LibXML 和 xtagxml 解析




mux

Various Muxers



mpeg



rtp


packetizer


打包模塊,用於H264/AVC和MPEG 4音視頻流。




services-discovery






stream-out




transrate





video-chroma


圖像格式轉換,如 YUV到 RGB




video-filter


各種視頻濾波模塊如Deinterlace,Transform, Wall, Crop,Panoramix 等等。




video-output




directx

WINDOWS視頻輸出模塊,使用Direct3D和Direct X API,OpenGL


qte

QT嵌入式視頻輸出模塊


x11

X11 API視頻輸出模塊




visualization


多種可視化模塊,包括goom


galaktos

輸出到 OpenGL的可視化模塊


visual

可視化系統

vlc核心的是libvlc,它提供界面,應用處理功能,所有的libvlc的源代碼都放在src目錄及其子目錄

 ./config/:  從命令行和配置文件中加載配置

  ./control/:提供動作控制功能,如播放等操作

 ./extras/:   大多是平臺的特殊代碼

 ./modules/: 模塊管理

./network/:  提供網絡接口(socket管理,網絡接口)

 ./osd/:        顯示屏幕上的操作

 ./test/:        libvlc測試模塊

 ./text/:        字符集

 ./interface/: 提供代碼中可以調用的接口,如按鍵後的硬件作出反應

 ./playlist/:   管理播放功能

 ./input/:     建立並讀取一個輸入流,並且分離其中的音頻和視頻,然後把分離好的音頻和視頻流發給解碼器

 ./audio_output/:初始化音頻混合器,即設置正確的同步頻率,並對從解碼器傳來的音頻流重新取樣

 ./video_output/:初始化視頻播放器,把從解碼器得到視頻畫面轉化格式從yuv到rgb,然後播放

 ./stream_output/ 輸出音頻流和視頻流到網絡

 ./misc/:            libvlc使用的其他部分功能,如線程系統,消息隊列等.

 

一、首先介紹一下vlc啓動動態加載模塊的過程

 

1. 最先程序段入口是文件Vlc.c(./bin/)中的main()函數完成的Functions(parsecommand line, start interface and spawnthreads),在main中程序會調用libvlc_new函數(./lib/Core.c)接口,實現創建一個VLC運行實例libvlc_instance_t,該實例在程序運行過程中唯一。

2. 在libvlc_new函數接口中,調用了libvlc_InternalInit()函數實現具體的初始化工作。

3. libvlc_InternalInit(./src/Libvlc.c)函數中,首先通過system_Init()函數完成傳入參數對系統的相關初始化,接着通過module_InitBank()(./src/modules/Bank.c)函數初始化module_bank結構體,並創建了main模塊,然後(不支持動態載入的時候則通過module_LoadBuiltins載入靜態模塊)通過module_LoadPlugins(./src/modules/Bank.c)函數載入動態模塊,通過module_need(./src/modules/Modules.c)函數載入並激活memcpy模塊,通過playlist_Create(./src/playlist/playlist.c)函數,創建了一個playlist播放管理的線程,其線程處理函數爲RunThread(./src/stream_out/sap.c),通過intf_Create(./src/interface/Interface.c)函數添加並激活hotkeys模塊,最後根據系統設置定義了宏HAVE_X11_XLIB_H,因此還需要添加screensaver模塊。

4. 此時加載的模塊有main,hotkeys,screensaver,memcpy;多創建了一個線程,用於管理playlist,該線程無限循環,直到p_playlist->b_die狀態爲止。

5. 其次程序中創建VLM對象,該接口調用的是vlm_New(./src/input/Vlm.c)函數,實現VLM對象的創建,函數返回值是指向vlm_t的指針。

6. vlm_New函數中,創建了一個vlm管理線程,線程處理函數爲Manage(./modueles/video_output/msw/Glwin32.c)。該函數循環處理當前各種媒體(vod、broadcast、schedule)的播放實例,控制其每個播放細節(如:從一個input切換到下一個input;schedule週期循環調度等)。與playlist線程不同的是,Manage主要針對播放實例的操作,而RunThread主要針對播放列表的管理,也就是說VLC管理是分級的,播放列表級和播放列表中媒體播放實例級。

7. 其次程序載入播放節目單,該接口調用的是ExecuteLoad(./src/input/Vlmshell.c)函數,在該函數中,依次調用如下函數:stream_UrlNew、stream_Seek、stream_Read、Load。

8. 接着程序調用libvlc_vlm_play_media(./lib/Vlm.c)將節目流發佈出去,實質是調用ExecuteCommand(./src/input/Vlmshell.c),完成對命令的執行,根據命令類型,由ExecuteControl(./src/input/Vlmshell.c)函數處理。

9. 然後由vlm_ControlMediaInstanceStart(./src/input/Vlm.c)函數完成播放實例的初始化,並調用input_CreateAndStart(./src/input/input.c)函數,input_CreateAndStart實際調用的是input_Create和input_Start(./src/input/input.c),在input_Start函數中實際調用vlc_clone最終完成播放線程的,線程的處理函數爲Run(./src/input/input.c)。

10. Run線程是整個VLC作爲流媒體服務器的核心。其主要分爲如下幾個步驟:Init、MainLoop和End。其中MainLoop是一個無限循環,是完成流媒體的整個發佈過程。

二、分別介紹獲取、轉化、播放

 

Rtsp協議獲取rtp數據包:

1.     調用用函數rtsp_connect(./modules/access/rtsp/Rtsp.c)向服務器發出rtsp請求,然後函數rtsp_get_answers將會處理rtsp服務器反饋回來的信息,如果建立成功,則進入下一步。

2.     然後進行建立rtsp交互,依次調用的函數是:rtsp_request_optionsàrtsp_request_describeàrtsp_request_setupàrtsp_request_setparameteràrtsp_request_playàrtsp_request_tearoff,完成建立交互和關閉交互。

3.     詳細的是在成功建立之後然後調用的是rtsp_read_data(./modules/access/rtsp/Rtsp.c)函數進行獲取不透明的rtp數據實際填充的rtsp_client_t結構體最終實現完成數據的獲取。

Rtp數據包的轉換:

1.     獲取rtp數據之後進行的轉換就是yuv格式到rgb格式,使用的文件是   i420_rgb.c(./modules/video_chroma/i420_rgb.c)來是完成視頻格式的轉換。

2.     首先要對rtp數據流進行解碼,調用的函數是Rtp.c(./modules/access/rtp/Rtp.c)對rtp數據流進行demux,實際首先調用rtp_autodetect(./modules/access/rtp/Rtp.c)去探測rtp數據包,然後調用函數codec_decode(./modules/access/rtp/Rtp.c)把rtp數據包發送到decoder線程進行解碼。

3.     在codec_decode函數中實際調用的接口是es_out_Control(./include/Vlc_es_out.h)和es_out_Send(./include/Vlc_es_out.h)來完成傳送數據包到解碼器,然後進入Decode.c(./src/input/Decodec.c)DecodeCreate等函數接口進行流解碼。

rgb數據的播放:

1.     在進行圖像格式的轉換成rgb格式之後由vout_new_buffer(./src/input/Decodec.c)接口實現由解碼器送到顯示器模塊,在顯示器通過vout_Request(./src/video_output/video_output.c)接口去獲取解碼之後的rgb格式的圖片或者子圖片。

2.     在vout_Request(./src/video_output/video_output.c)接口中如果vout原來存在的話就會進行嘗試重使用,通過spu_Attach(./src/video_output/vout_subpictures.c)函數接口進行流單元的附屬操作,完成再使用vout。

3.     如果vout不存在的,則轉向VoutCreate(./src/video_output/video_output.c)函數接口進行創建vout,在該函數接口調用spu_Create(./include/Vlc_spu.h)進行流單元的創建,最終完成vout的創建,並創建處理線程Thread。

4.     處理線程Thread(./src/video_output/video_output.c)來實際調用ThreadDisplaySubpicture以及結合其他控制函數接口來完成流的控制和播放。

 

 

參考資料:vlc官網:http://wiki.videolan.org/Developers_Corner

從接收到數據流到播放視頻的過程分析

從網絡接收到流->對數據流進行視頻和音頻分離->對視頻用解碼器解碼->顯示解碼後的視頻流

視頻顯示部分走勢線:分離->解碼->新的VOUT緩衝區->VOUT線程

Demux(modules\demux\mpeg\ps.c)->DemuxPs(modules\demux\mpeg\system.c)->ParsePS->input_SelectES(src\input\input_programs.c)->input_RunDecoder(src\input\input_dec.c)->CreateDecoder->

vout_new_buffer->vout_Request(src\video_output\video_output.c)->vout_Create->RunThread->vout_RenderPicture(src\video_output\vout_pictures.c)->pf_display

注意:p_dec->pf_vout_buffer_new =vout_new_buffer的pf_vout_buffer_new在ffmpeg_NewPictBuf(modules\codec\ffmpeg\video.c)函數中激活

解碼部分走勢線:

Demux(modules\demux\mpeg\ps.c)->DemuxPs(modules\demux\mpeg\system.c)->ParsePS->input_SelectES(src\input\input_programs.c)->input_RunDecoder(src\input\input_dec.c)->CreateDecoder->DecoderThread

注意:在解碼線程中對數據流(AUDIO 或者VIDEO)進行解碼

詳細資料 http://developers.videolan.org/vlc/   VLC API documentation  或者VLC developerdocumentation

Chapter 5.  The video outputlayer Data structures and main loop

Important data structures are defined in include/video.h and include/video_output.h.The main data structure is picture_t, which describes everything avideo decoder thread needs. Please refer to this file for moreinformation. Typically, p_data willbe a pointer to YUV planar picture.

Note also the subpicture_t structure. In fact the VLC SPU decoderonly parses the SPU header, and converts the SPU graphical data toan internal format which can be rendered much faster. So a part ofthe "real" SPU decoder lies in src/video_output/video_spu.c.

The vout_thread_t structure is much more complex, but you needn'tunderstand everything. Basically the video output thread manages aheap of pictures and subpictures (5 by default). Every picture hasa status (displayed, destroyed, empty...) and eventually apresentation time. The main job of the video output is an infiniteloop to : [this is subject to change in the near future]

  • Find the next picture to display in the heap.

  • Find the current subpicture to display.

  • Render the picture (if the video output plug-in doesn't support YUVoverlay). Rendering will call an optimized YUV plug-in, which willalso do the scaling, add subtitles and an optional pictureinformation field.

  • Sleep until the specified date.

  • Display the picture (plug-in function). For outputs which displayRGB data, it is often accomplished with a bufferswitching. p_vout->p_buffer isan array of two buffers where the YUV transform takes place, andp_vout->i_buffer_index indicates the currentlydisplayed buffer.

  • Manage events.

Methods used by video decoders

The video output exports a bunch of functions so that decoders cansend their decoded data. The most important functionis vout_CreatePicture whichallocates the picture buffer to the size indicated by the videodecoder. It then just needs to feed (void*) p_picture->p_data withthe decoded data, and call vout_DisplayPicture and vout_DatePicture uponnecessary.

  • picture_t * vout_CreatePicture (vout_thread_t *p_vout, int i_type, int i_width, int i_height) : Returns anallocated picture buffer. i_type willbe for instance YUV_420_PICTURE,and i_width and i_height are in pixels.

    Warning

    If no picture is available in the heap, vout_CreatePicture willreturn NULL.

  • vout_LinkPicture (vout_thread_t *p_vout, picture_t *p_pic ) : Increasesthe refcount of the picture, so that it doesn't get accidentlyfreed while the decoder still needs it. For instance, an I or Ppicture can still be needed after displaying to decode interleavedB pictures.

  • vout_UnlinkPicture (vout_thread_t *p_vout, picture_t *p_pic ) : Decreasesthe refcount of the picture. An unlink must be done for every linkpreviously made.

  • vout_DatePicture (vout_thread_t *p_vout, picture_t *p_pic ) : Gives thepicture a presentation date. You can start working on a picturebefore knowing precisely at what time it will be displayed. Forinstance to date an I or P picture, you must wait until you havedecoded all previous B pictures (which are indeed placed after -decoding order != presentation order).

  • vout_DisplayPicture (vout_thread_t *p_vout, picture_t *p_pic ) : Tells thevideo output that a picture has been completely decoded and isready to be rendered. It can be called before orafter vout_DatePicture.

  • vout_DestroyPicture (vout_thread_t *p_vout, picture_t *p_pic ) : Marks thepicture as empty (useful in case of a stream parsing error).

  • subpicture_t * vout_CreateSubPicture (vout_thread_t *p_vout, int i_channel, int i_type ) : Returns anallocated subpicture buffer. i_channel isthe ID of the subpicture channel, i_type is DVD_SUBPICTURE or TEXT_SUBPICTURE, i_size isthe length in bytes of the packet.

  • vout_DisplaySubPicture (vout_thread_t *p_vout, subpicture_t *p_subpic ) : Tells thevideo output that a subpicture has been completely decoded. Itobsoletes the previous subpicture.

  • vout_DestroySubPicture (vout_thread_t *p_vout, subpicture_t *p_subpic ) : Marks thesubpicture as empty.





  • 來源:http://blog.sina.com.cn/s/blog_8795b0970101ew4n.html


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