天天看點

嵌入式 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.