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

我的整理:html

Vlc流播放流程web

 vlc源碼目錄樹:shell

目錄名稱macos

說明vim

bindings服務器

Java, CIL 和Python綁定網絡

docsocket

幫助文檔 (不是更新的)tcp

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,MPEG I-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使用的其餘部分功能,如線程系統,消息隊列等.

 

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

 

1. 最早程序段入口是文件Vlc.c(./bin/)中的main()函數完成的Functions(parse command line, start interface and spawn threads),在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是一個無限循環,是完成流媒體的整個發佈過程。

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

 

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 developer documentation

Chapter 5.  The video output layer 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 a video decoder thread needs. Please refer to this file for more information. Typically, p_data will be a pointer to YUV planar picture.

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

The vout_thread_t structure is much more complex, but you needn't understand everything. Basically the video output thread manages a heap of pictures and subpictures (5 by default). Every picture has a status (displayed, destroyed, empty...) and eventually a presentation time. The main job of the video output is an infinite loop 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 YUV overlay). Rendering will call an optimized YUV plug-in, which will also do the scaling, add subtitles and an optional picture information field.

  • Sleep until the specified date.

  • Display the picture (plug-in function). For outputs which display RGB data, it is often accomplished with a buffer switching. p_vout->p_buffer is an array of two buffers where the YUV transform takes place, and p_vout->i_buffer_index indicates the currently displayed buffer.

  • Manage events.

Methods used by video decoders

The video output exports a bunch of functions so that decoders can send their decoded data. The most important function is vout_CreatePicture which allocates the picture buffer to the size indicated by the video decoder. It then just needs to feed (void *) p_picture->p_data with the decoded data, and call vout_DisplayPicture and vout_DatePicture upon necessary.

  • picture_t * vout_CreatePicture ( vout_thread_t *p_vout, int i_type, int i_width, int i_height ) : Returns an allocated picture buffer. i_type will be 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 will return NULL.

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

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

  • vout_DatePicture ( vout_thread_t *p_vout, picture_t *p_pic ) : Gives the picture a presentation date. You can start working on a picture before knowing precisely at what time it will be displayed. For instance to date an I or P picture, you must wait until you have decoded 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 the video output that a picture has been completely decoded and is ready to be rendered. It can be called before or after vout_DatePicture.

  • vout_DestroyPicture ( vout_thread_t *p_vout, picture_t *p_pic ) : Marks the picture 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 an allocated subpicture buffer. i_channel is the ID of the subpicture channel, i_type is DVD_SUBPICTURE or TEXT_SUBPICTURE, i_size is the length in bytes of the packet.

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

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

  • 來源:http://blog.sina.com.cn/s/blog_8795b0970101ew4n.html
相關文章
相關標籤/搜索