嵌入式 vlc源碼分析錦集

http://blog.sina.com.cn/s/blog_8795b0970101eeku.html

嵌入式 vlc源碼分析錦集

VLC源碼分析

目錄

1 VLC源碼結構

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

1.1 ./config/

從命令行和配置文件中加載配置

1.2 ./control/

提供動作控制功能,如播放等操作

1.3  ./extras/

大多是平臺的特殊代碼

1.4  ./modules/

模塊管理

1.5  ./network/

提供網絡接口(socket管理,網絡接口)

1.6  ./osd/

顯示屏幕上的操作

1.7  ./test/

libvlc測試模塊

1.8  ./text/

字符集

1.9  ./interface/

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

1.10  ./playlist/

管理播放功能

1.11  ./input/

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

1.12  ./audio_output/

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

 

1.13  ./video_output/

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

1.14  ./stream_output/ 

輸出音頻流和視頻流到網絡

1.15  ./misc/

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

2 configure詳解

 

概述

VLC 屬於Video LAN開源項目組織中的一款全開源的流媒體服務器和多媒體播放器。作爲流媒體服務器,VLC跨平臺,支持多操作系統和計算機體系結構;作 爲多媒體播放器,VLC可以播放多種格式的媒體文件。主要包括有:WMV、ASF、MPG、MP、AVI、H.264等多種常見媒體格式。

VLC 採用全模塊化結構,在系統內部,通過動態的載入所需的模塊,放入一個module_bank的結構體中統一管理,連VLC的Main模塊也是通過插件的方 式動態載入的(通過module_InitBank函數在初始化建立module_bank時)。對於不支持動態載入插件的系統環境中,VLC也可以採用 builtin的方式,在VLC啓動的時候靜態載入所需要的插件,並放入module_bank統一管理。

VLC 的模塊分成很多類別主要有:access、access_filter、access_output、audio_filter、 audio_mixer、audio_output、codec、control、demux、gui、misc、mux、packetizer、 stream_output、video_filter、video_output、interface、input、playlist等(其中黑體爲核 心模塊)。VLC無論是作爲流媒體服務器還是多媒體播放器,它的實質思路就是一個“播放器”,之所以這麼形象描述,是因爲(The core gives a framework to do the media processing, from input (files, network streams) to output (audio or video, on ascreen or a network), going through various muxers, demuxers, decoders and filters. Even the interfaces are plugins for LibVLC. It is up to the developer to choose which module will be loaded. 摘 於官網說明) 它實質處理的是ES、PES、PS、TS等流間的轉換、傳輸與顯示。對於流媒體服務器,如果從文件作爲輸入 即:PS->DEMUX->ES->MUX->TS;對於多媒體播放器如果採用UDP方式傳輸 即:TS->DEMUX->ES。

1. 插件管理框架

在VLC中每種類型的模塊中都有一個抽象層/結構體,在抽象層或結構體中定義了若干操作的函數指針,通過這些函數指針就能實現模塊的動態載入,賦值相關的函數指針的函數地址,最後通過調用函數指針能調用實際模塊的操作。

對 於VLC所有的模塊中,有且僅有一個導出函數:vlc_entry__(MODULE_NAME)。(其中MODULE_NAME爲宏定義,對於main 模塊,在\include\modules_inner.h中定義爲main)動態載入模塊的過程是:使用module_Need函數,在 module_bank中根據各個插件的capability等相關屬性,尋找第一個能滿足要求並激活的模塊。所謂激活是指,調用插件的初始化函數成功。 對於各個插件的初始化函數和析構函數均在vlc_entry__(MODULE_NAME)函數中指定了相關函數地址。因此載入各個插件(動態庫)的過 程,就成爲了解析動態庫文件,並找到其中vlc_entry__函數的地址,然後運行。這樣各個模塊的激活函數就會賦值各個操作的函數地址,以待後面函數 動態調用。

具體函數調用過程如下:

l Main模塊的載入過程:

int main( int i_argc, char *ppsz_argv[] )(src\vlc.c)->i_ret = VLC_Init( 0, i_argc, ppsz_argv )-> module_InitBank( p_vlc ) (src\libvlc.c void __module_InitBank( vlc_object_t *p_this ))-> module_LoadMain( p_this ) (src\misc \modules.c)->AllocateBuiltinModule( p_this, vlc_entry__main )->pf_entry( p_module ) (激活了main模塊,以上爲main模塊的載入過程,對於main模塊調用的實際函數爲導出函數vlc_entry__main,其它模塊導出的均爲 vlc_entry__0_8_6)

l Module_Need函數實現載入任意模塊的過程:

module_t * __module_Need( vlc_object_t *p_this, const char *psz_capability,

                          const char *psz_name, vlc_bool_t b_strict )(src\misc\modules.c)-> vlc_list_find(將所有已經載入的模塊查詢出來)->然後循環,根據 capability查找第一個最合適的module->AllocatePlugin(動態載入所需要的插件,該函數會在動態庫所在目錄,遍歷所 有動態庫文件,)->p_module->pf_activate(調用激活函數)

l VLC_Init函數流程:

module_InitBank->module_LoadBuiltins(載入靜態插件)->module_LoadPlugins(載入動態插件->VLC_AddIntf(添加interface插件,VLC會靜態載入hotkeys模塊)

在VLC中根據處理任務不同,會靜態載入不同的模塊,main、memcpy、hotkeys等;動態載入的模塊根據處理任務不同,差異很大。

2. VLC流媒體服務器體系結構

以下主要討論VLC作爲流媒體服務器時的體系結構。針對一個節目單文件,調試其運行過程,並最後給出總結。

該實例的播放節目單爲如下:

New br broadcast enabled

Setup br input /mnt/hgfs/movie/caiyan.mpg

Setup br output #standard{mux=ts,access=udp,url=234.0.1.4,sap,name=ch1}

在例子中,通過VLC提供API:libvlc_new,libvlc_vlm_new,libvlc_vlm_play_media,libvlc_vlm_load_file等(有些API是自己添加的)可以完成對廣播節目br的播放。

下面讓我們仔細看看通過這幾個接口,VLC內部到底是怎麼工作完成了流媒體發佈的。

1. 首先程序調用libvlc_new(\src\control\core.c)接口,實現創建一個VLC運行實例libvlc_instance_t,該實例在程序運行過程中唯一。

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

3. VLC_Init(\src \libvlc.c)函數中,首先通過system_Init函數完成傳入參數對系統的相關初始化,接着通過module_InitBank(\src \misc\modules.c)函數初始化module_bank結構體,並創建了main模塊,然後通過module_LoadBuiltins載入 靜態模塊,通過module_LoadPlugins(\src\misc\modules.c)函數載入動態模塊,通過 module_Need(\src\misc\modules.c)函數載入並激活memcpy模塊,通過playlist_Create(\src \playlist\playlist.c)函數,創建了一個playlist播放管理的線程,其線程處理函數爲RunThread(\src \playlist\playlist.c),通過VLC_AddIntf(\src\libvlc.c)函數添加並激活hotkeys模塊,最後根據系 統設置定義了宏HAVE_X11_XLIB_H,因此還需要添加screensaver模塊。

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

5. 其次程序中調用libvlc_vlm_new接口,創建VLM對象(該接口爲自己添加的)。

6. 該接口調用的是vlm_New(\src\misc\vlm.c)函數,實現VLM對象的創建,函數返回值是指向vlm_t的指針。

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

8. 其次程序調用libvlc_vlm_load_file接口,載入播放節目單(該接口也爲自己添加,播放節目單如上所述)。

9. 該接口調用的是vlm_Load(\src\misc\vlm.c)函數,在該函數中,依次調用如下函數:stream_UrlNew、stream_Seek、stream_Read、Load,以下詳細介紹各個函數作用。

a) 首 先是stream_UrlNew(\src\input\stream.c)函數。先調MRLSplit(\src\input\input.c)函數完 成對access、demux和path的解析。具體對於本例解析的結果爲:access= " ",demux=" ",path=" aa"。然後調 用access2_New(\src\input\access.c)函數創建一個access_t結構體並初始化。具體運行時載入模塊的相關參數 是:capability="access2",name="access_file",psz_filename=access/libaccess_file_plugin.so。 最後調用stream_AccessNew(\src\input\stream.c)函數,創建stream_t結構體對象,並初始化對象中所有函數指 針;

b) 再調用stream_Seek(\include\vlc_stream.h)內聯函數,設置起始位置;

c) 再調用stream_Size(\include\vlc_stream.h)獲得大小;

d) 再調用stream_Read(\include\vlc_stream.h),讀取到緩衝區;

e) 最 後調用Load(\src\misc\vlm.c),完成實際的載入節目單。對於節目單文件,是一行行解析,並調用 ExecuteCommand(\src\misc\vlm.c)完成解析的。Load函數的調用僅僅是設置了相關參數,如:設置input字符串值,設 置output字符串值,設置mux的值及與播放相關的enabled、loop等參數。Load工作僅僅是爲了下一步發佈流做準備的。

10. 程序中調用libvlc_vlm_play_media接口,將節目流發佈出去。(自己添加接口)

11. 在libvlc_vlm_play_media接口中,實質是創建了命令“control br play”再調用 vlm_ExecuteCommand(\src\misc\vlm.c),完成對命令的執行,根據命令類型,由vlm_MediaControl(\src\misc\vlm.c)函數處理。

12. 在vlm_MediaControl函數中,會調用vlc_input_item_Init(\include\vlc_input.h)函數完成播放實例 的初始化,並調用input_CreateThread2(\src\input\input.c)函數完成播放線程的創建。該線程的處理函數爲 Run(\src\input\input.c)。

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

a) 首先調用Init(\src\input\input.c)函數,初始化相關統計參數;

b) 其次再調用input_EsOutNew(\src\input\es_out.c)函數,初始化es_out_t結構體對象和es_out_sys_t結構體對象,並設置相關函數指針;

c) 再調用InputSourceInit(\src\input\input.c)函數,初始化input_thread_t對象中的input_source_t對象,主要有access_t、stream_t、demux_t三個結構體對象;

d) 總結此時各個模塊實際載入的情況:

1) (access_t)type="access",name="access_filter",capability="access2",psz_filename="access/libaccess_file_plugin.so";

2) (stream_t)type="stream",pf_read="AStreamReadStream",pf_seek="AStreamPeekStream",pf_control="AStreamControl",pf_destory="AStreamDestory";

3) (demux_t)type="demux",capability="demux2",shortcuts="ps";

4) (sout_instance_t)type="stream out",psz_capability="sout stream",shortcut="stream_out_standard",psz_filename="/stream_out/libstream_out_standard_plugin.so";

5) (es_out_t)pf_add="ESOutAdd",pf_send="ESOutSend",pf_del="ESOutDel",pf_control="ESOutControl";

e) 再調用MainLoop(\src\input\input.c)函數,完成讀取、解複用、解碼、複用和傳輸;

f) MainLoop函數爲無限循環,直到input_thread_t對象存在b_die、b_error、b_eof時爲止。在該函數中,存在如下行代碼:

i_ret=p_input->input.p_demux->pf_demux(p_input->input.p_demux);

它就是流媒體服務器運行的起點,所有的後續操作都會在該函數中繼續衍生。

g) Pf_demux調用的是(\modules\demux\ps.c)中的Demux函數,在該函數中主要完成如下操作:

1) 先調用ps_pkt_resynch(\modules\demux\ps.c)函數,完成PS流中數據包重新同步(這裏應該涉及到多媒體相關知識,需要補補);

2) 再調用ps_pkt_read(\modules\demux\ps.c)函數,最終調用stream_Block函數,這個函數內部會根據實際情況,調用stream_t模塊中的pf_read或pf_block函數,函數結果會返回一個讀取的buffer;

3) 根據數據包的i_code的值,做不同的處理,對於音視頻數據流,調用es_out_Send(\include\vlc_es_out.h)函數處理;

4) es_out_Send一個抽象層函數,其通過函數指針,實際調用的是EsOutSend(\src\input\es_out.c)函數;

5) EsOutSend函數最終會調用input_DecoderDecode(\src\input\decoder.c)函數;

6) input_DecoderDecode函數會調用DecoderDecode(\src\input\decoder.c)函數完成解碼;

7) DecoderDecode函數會調用pf_packetize(\modules\packetizer\mpegvideo.c)函數實現PES的打包;

8) DecoderDecode函數會調用sout_InputSendBuffer(\src\stream_output\stream_output.c)函數,實現發送;

9) sout_InputSendBuffer函數中的pf_send指針,指向的是(\modules\stream_out\standard.c)Send函數;

10) Send 函數調用的是流化輸出(stream_output)的抽象層(\src\stream_output\stream_output.c)中的 sout_MuxSendBuffer函數,首先將要發送的數據放入fifo隊列中,然後調用pf_mux函數指針,完成多路複用;

11) Pf_mux函數指針指向的是(\modules\mux\mpeg\ts.c)的Mux函數,完成多路複用後,最終調用(\modules\mux\mpeg\ts.c)TSSchedule函數,準備調度發送了;

12) TSSchedule函數中調用了TSDate(\modules\mux\mpeg\ts.c)函數;

13) TSDate函數中調用了流化輸出(stream_output)的抽象層(\src\stream_output\stream_output.c)中的sout_AccessOutWrite函數,最終調用pf_write函數完成數據輸出;

14) pf_write函數指向的是(\modules\access_output\udp.c)中的Write函數,完成數據UDP發送,這樣數據就轉換稱TS流輸出了;

15) 總結:pf_demux函數爲流媒體所有操作的起點,通過該處衍生了很多其他模塊的處理,從上面的分析可以看出,系統實質就是PS、ES、PES和TS幾種流間的轉換,針對應用場合(主要指做服務器或客戶端)的不同,轉換的方式不同

第一部分 變量及宏定義
1.消息映射宏
vlc_module_begin();
…………………..
vlc_module_end();
2.結構中包含函數
struct input_thread_t
{
VLC_COMMON_MEMBERS

vlc_bool_t b_eof;
vlc_bool_t b_out_pace_control;

module_t * p_access;
ssize_t (* pf_read ) ( input_thread_t *, byte_t *, size_t );
int (* pf_set_program )( input_thread_t *, pgrm_descriptor_t * );
int (* pf_set_area )( input_thread_t *, input_area_t * );
void (* pf_seek ) ( input_thread_t *, off_t );
}
3.宏與換行符妙用
#define VLC_COMMON_MEMBERS inti_object_id; int
i_object_type; char *psz_object_type; char *psz_object_name; int

be_sure_to_add_VLC_COMMON_MEMBERS_to_struct;
#define VLC_OBJECT( x ) \
((vlc_object_t *)(x))+
0*(x)- be_sure_to_add_VLC_COMMON_MEMBERS_to_struct
struct vlc_object_t
{
VLC_COMMON_MEMBERS
};//定義一個結構來使用宏定義的公共成員
4.定義導出函數
#ifndef __PLUGIN__
# define VLC_EXPORT( type, name, args ) type name args
#else
# define VLC_EXPORT( type, name, args ) struct _u_n_u_s_e_d_
extern module_symbols_t* p_symbols;
#endif
5.定義回調函數
typedef int ( * vlc_callback_t ) ( vlc_object_t *,
char const *,
vlc_value_t,
vlc_value_t,
void * );
6.函數作爲參數的定義方式
Int Fun(int n,int (*pf)(int ,int),char *pstr)
{ int j =10;
pf(n,j);
}
7.回調函數的聲明
必須聲明爲global,或者static
Int vlc_callback_t (int ,int)
{。。。。。。。。。。。}

8.回調函數的使用
Fun(0, vlc_callback_t,”test”);
9.函數表達式
#define input_BuffersInit(a) __input_BuffersInit(VLC_OBJECT(a))
void * __input_BuffersInit( vlc_object_t * );
#define module_Need(a,b,c,d) __module_Need(VLC_OBJECT(a),b,c,d)
VLC_EXPORT( module_t *, __module_Need, ( vlc_object_t *, const char *, constchar *, vlc_bool_t ) );
10.定義函數

#define INSERT_ELEM( p_ar, i_oldsize, i_pos, elem ) do { if( i_oldsize ) {(p_ar) = realloc( p_ar, ((i_oldsize) + 1) * sizeof( *(p_ar) )

); } else { (p_ar) = malloc(((i_oldsize) + 1) * sizeof( *(p_ar) ) ); } if( (i_oldsize) - (i_pos) ) {memmove( (p_ar) + (i_pos) + 1, (p_ar) +

(i_pos),((i_oldsize) - (i_pos)) * sizeof( *(p_ar) ) ); } (p_ar)[i_pos] = elem;(i_oldsize)++; } while( 0 )
應用爲:
INSERT_ELEM( p_new- p_libvlc- pp_objects,
p_new- p_libvlc- i_objects,
p_new- p_libvlc- i_objects,
p_new );
11.改變地址的方式傳遞其值
stream_t *input_StreamNew( input_thread_t *p_input )
{ stream_t *s = vlc_object_create( p_input, sizeof( stream_t ) );
input_stream_sys_t *p_sys;
if( s )
{
s- p_sys = malloc( sizeof( input_stream_sys_t ) );
p_sys = (input_stream_sys_t*)s- p_sys;
p_sys- p_input = p_input;
}
return s;//註解:s- p_sys改變了
}
第二部分 程序框架實現
1.播放列表文件src/playlist/playlist.c的線程
playlist_t * __playlist_Create ( vlc_object_t *p_parent )函數中創建的線程,線程函數爲
static void RunThread ( playlist_t *p_playlist )
線程思路分析:
在RunThread裏面執行循環,如果沒有任務執行,則適當的延遲,如果接到p_playlist-i_status != PLAYLIST_STOPPED的條件,則調用PlayItem(

p_playlist )函數,在PlayItem( p_playlist )函數中從新創建輸入線程。
通過void playlist_Command( playlist_t *p_playlist, playlist_command_t i_command,int i_arg )接收來自GUI界面的各種命令,然後設置p_playlist-

i_status的狀態,由該狀態改變該播放列表文件主循環線程的執行。
2.輸入文件SRC/INPUT/INPUT.C的輸入線程
input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
input_item_t *p_item )函數中創建的線程,線程函數爲
static int RunThread( input_thread_t *p_input )
線程思路分析:
由 input_thread_t結構的成員分析是接收文件流還是網絡流,如果是文件流,則調用file module 的讀函數(pf_read)和打開函數(--).如果是network 則打

開network module 的打開函數和讀函數(pf_read)。
在 RunThread線程函數中接收數據和調用demux 或者decode etc處理。
一旦產生新的輸入,則在播放列表線程中會首先結束該輸入線程,然後從新創建新的輸入線程。
3.視頻輸出文件src/video_output/video_output.c的線程
vout_thread_t * __vout_Create( vlc_object_t *p_parent,
unsigned int i_width, unsigned int i_height,
vlc_fourcc_t i_chroma, unsigned int i_aspect )函數中創建的線程,線程函數爲
static void RunThread( vout_thread_t *p_vout)
線程思路分析:
在RunThread裏面執行循環,任務是顯示視頻。
4.在modules\gui\wxwindows\wxwindows.cpp中的GUI線程
static void Run( intf_thread_t *p_intf ) 函數中創建的線程,線程函數爲
static void Init( intf_thread_t *p_intf )
線程思路分析:
在Init( intf_thread_t *p_intf )裏面執行循環,創建新的GUI實例。Instance-》OnInit()(CreateDialogsProvider)-》DialogsProvider爲運行的對話

框。
接收網絡文件的步驟
OnOpenNet( wxCommandEvent& event )打開網絡文件的步驟。打開OpenDialog對話框,點擊Ok後調用OpenDialog::OnOk(wxCommandEvent& WXUNUSED(event)

)函數,調用playlist_Command函數改變播放列表線程的狀態。
激活線程分析:
在wxwindow.cpp中的消息映射中set_callbacks( OpenDialogs, Close ); 則設置了module_t-pf_activate= OpenDialogs函數,
在module.c 的__module_Need(vlc_object_t *p_this, const char *psz_capability,
const char *psz_name, vlc_bool_t b_strict )
函數中用到了pf_activate激活GUI對話框;
在video_output.c 的static voidRunThread( vout_thread_t *p_vout)線程中,也用到了pf_activate激活GUI對話框;
5.開始所有module 的精髓
消息映射宏
vlc_module_begin();
set_callbacks( NetOpen, NULL );
vlc_module_end();
然後設置模塊結構的成員函數爲:
#define set_callbacks( activate, deactivate ) p_submodule- pf_activate =activate; p_submodule- pf_deactivate = deactivate
在__module_Need函數中啓動pf_activate 激活相應的module。


網絡數據流接收處理分析
1、在input.c(src\input)文件中的主線程循環
Thread in charge of processing the network packets and demultiplexing
RunThread( input_thread_t *p_input )
{
InitThread( p_input ) ;
…………………………………………………….
input_SelectES( p_input, p_input->stream.p_newly_selected_es );
…………………………………………………….

i_count = p_input->pf_demux( p_input );
}
2、在下列函數中:
分離出access , demux , name字符串 ;
根據分離出的access 字符串通過module_Need函數找到acess 指針模塊;
根據分離出的demux 字符串通過module_Need函數找到demux 指針模塊;
static int InitThread( input_thread_t * p_input )
{
msg_Dbg( p_input, "access `%s', demux `%s', name `%s'",
p_input->psz_access, p_input->psz_demux, p_input->psz_name );

p_input->p_access = module_Need( p_input, "access",
p_input->psz_access, VLC_TRUE );
…………………………………………………….
while( !input_FillBuffer( p_input ) )
…………………………………………………….

p_input->p_demux =
module_Need( p_input, "demux",
(p_input->psz_demux && *p_input->psz_demux) ?
p_input->psz_demux : "$demux",
(p_input->psz_demux && *p_input->psz_demux) ?
VLC_TRUE : VLC_FALSE );
…………………………………………………….
}
3、在ps.c (module\demux\mpeg)文件中
a.通過消息映射宏賦值啓動函數Activate;
b.通過函數Activate賦值p_input->pf_demux= Demux;
c. 通過函數module_Need( p_input,"mpeg-system", NULL, 0 ) 激活p_input->p_demux_data->mpeg.pf_read_ps(p_input, &p_data )函數(pf_read_ps)

;
d.在InitThread函數中激活;
static int Activate( vlc_object_t * p_this )
{

p_input->pf_demux = Demux;
p_input->p_private = (void*)&p_demux->mpeg;
p_demux->p_module = module_Need( p_input, "mpeg-system", NULL, 0);
}
4、在system.c (module\demux\mpeg)文件中
賦值解碼模塊mpeg_demux_t的成員函數;
static int Activate ( vlc_object_t *p_this )
{
static mpeg_demux_t mpeg_demux =
{ NULL, ReadPS, ParsePS, DemuxPS, ReadTS, DemuxTS };
mpeg_demux.cur_scr_time = -1;
memcpy( p_this->p_private, &mpeg_demux, sizeof( mpeg_demux ) );
return VLC_SUCCESS;
}
並且申明函數static ssize_t ReadPS( input_thread_t *p_input, data_packet_t ** pp_data );
5、在ps.c (module\demux\mpeg)文件中
Demux( input_thread_t * p_input )
{
i_result = p_input->p_demux_data->mpeg.pf_read_ps( p_input, &p_data);
p_input->p_demux_data->mpeg.pf_demux_ps( p_input, p_data );
}
進行讀取數據和分離工作;
6、在system.c (module\demux\mpeg)文件中
數據走向圖如下
ReadPS-> PEEK-> input_Peek(src\input\input_ext-plugins.c)->input_FillBuffert 通過 i_ret =p_input->pf_read( p_input,
(byte_t *)p_buf + sizeof(data_buffer_t)
+ i_remains,
p_input->i_bufsize );
input_thread_t結構的pf_read函數成員如果是爲udp.c(modules\access)的RTPChoose函數
則在開啓access(UDP 模塊)時通過module_need 激活;
激活網絡讀數據模塊 RTPChoose(modules\access\udp.c)->Read->net_Read(src\misc\net.c);
7、在input_programs.c(src\input)文件中
運行解碼器對ES流解碼
int input_SelectES( input_thread_t * p_input, es_descriptor_t * p_es )
{
p_es->p_dec = input_RunDecoder( p_input, p_es );

}
input_SelectES(src\input\input_programs.c)->input_RunDecoder(src \input\input_dec.c)->DecoderThread->DecoderDecode -

>vout_DisplayPicture

 


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

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

 

    視頻顯示部分走勢線:分離->解碼->新的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  或者VLCdeveloper documentation


Chapter 5.  The video outputlayer
Data structures and main loop

Important data structures are defined ininclude/video.h and include/video_output.h. The main data structure ispicture_t, which describes

everything a video decoder thread needs.Please refer to this file for more information. Typically, p_data will be apointer to YUV planar

picture.

Note also the subpicture_t structure. Infact the VLC SPU decoder only parses the SPU header, and converts the SPUgraphical data to an

internal format which can be renderedmuch faster. So a part of the "real" SPU decoder lies insrc/video_output/video_spu.c.

The vout_thread_t structure is much morecomplex, but you needn't understand everything. Basically the video outputthread manages a heap of

pictures and subpictures (5 by default).Every picture has a status (displayed, destroyed, empty...) and eventually apresentation time. The

main job of the video output is aninfinite loop to : [this is subject to change in the near future]

   1.

      Find the next picture to display inthe heap.
2.

      Find the current subpicture todisplay.
3.

      Render the picture (if the videooutput plug-in doesn't support YUV overlay). Rendering will call an optimizedYUV plug-in, which will

also do thescaling, add subtitles and an optional picture information field.
4.

      Sleep until the specified date.
5.

      Display the picture (plug-infunction). For outputs which display RGB data, it is often accomplished with abuffer switching. p_vout-

>p_bufferis an array of two buffers where the YUV transform takes place, andp_vout->i_buffer_index indicates the currently displayed buffer.
6.

      Manage events.

Methods used by video decoders

The video output exports a bunch offunctions so that decoders can send their decoded data. The most importantfunction is vout_CreatePicture

which allocates the picture buffer tothe size indicated by the video decoder. It then just needs to feed (void *)p_picture->p_data with the

decoded data, and callvout_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 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 theheap, 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'tget accidently

freed whilethe decoder still needs it. For instance, an I or P picture can still be neededafter displaying to decode interleaved B pictures.
*

      vout_UnlinkPicture ( vout_thread_t*p_vout, picture_t *p_pic ) : Decreases the refcount of the picture. An unlinkmust be done for every

linkpreviously made.
*

      vout_DatePicture ( vout_thread_t*p_vout, picture_t *p_pic ) : Gives the picture a presentation date. You canstart working on a picture

before knowing precisely at what time itwill be displayed. For instance to date an I or P picture, you must wait untilyou have decoded all

previous Bpictures (which are indeed placed after - decoding order != presentationorder).
*

      vout_DisplayPicture ( vout_thread_t*p_vout, picture_t *p_pic ) : Tells the video output that a picture has beencompletely decoded and

is ready tobe 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 astream parsing error).
*

      subpicture_t * vout_CreateSubPicture (vout_thread_t *p_vout, int i_channel, int i_type ) : Returns an allocatedsubpicture buffer.

i_channel isthe 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 subpicturehas been completely

decoded. Itobsoletes the previous subpicture.
*

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

 


VLC(五) 視頻播放的基本原理

    當初Roger看VLC代碼花了不少時間,其中很大的原因是不太瞭解視頻播放的基本原理。現在看來,幾乎所有的視頻播放器,如VLC、MPlayer、 Xine,包括

DirectShow,在播放視頻的原理和架構上都是非常相似的,理解這個對理解VLC的源碼會有事半功倍的效果。

    大致的來說,播放一個視頻分爲4個步驟:

    1.  acess 訪問,或者理解爲接收、獲取、得到

    2. demux 解複用,就是把通常合在一起的音頻和視頻分離(還有可能的字幕) 

    3. decode 解碼,包括音頻和視頻的解碼

    4. output 輸出,也分爲音頻和視頻的輸出(aout和vout)

    拿播放一個UDP組播的MPEG TS流來說吧,access部分負責從網絡接收組播流,放到VLC的內存緩衝區中,access模塊關注IP協議,如是否IPv6、組播地址、組

協議、端口等信息;如果檢測出來是RTP協議(RTP協議在UDP頭部簡單得加上了固定12個字節的信息),還要分析RTP頭部信息。這部分可以參看VLC源碼

/modules/access/udp.c 。在同目錄下還可以看到大量的access模塊,如file、http、dvd、ftp、smb、tcp、dshow、mms、v4l…等等

    而demux部分首先要解析TS流的信息。TS格式是MPEG2協議的一部分,概括地說,TS通常是固定188字節的一個packet,一個TS流可以包含多個program(節目)

,一個program又可以包含多個視頻、音頻、和文字信息的ES流;每個ES流會有不同的PID標示。而又爲了可以分析這些ES流,TS有一些固定的PID用來間隔發送

program和es流信息的表格:PAT和PMT表。關於TS格式的詳細信息可以去google一下。

    VLC專門做了一個獨立的庫libdvbpsi來解析和編碼TS流,而調用它的代碼可以參見VLC源碼 /modules/demux/ts.c。

    其實之所以需要demux,是因爲音視頻在製作的時候實際上都是獨立編碼的,得到的是分開的數據,爲了傳輸方便必須要用某種方式合起來,這就有了各種封

裝格式也就有了demux。

    demux分解出來的音頻和視頻流分別送往音頻解碼器和視頻解碼器。因爲原始的音視頻都是佔用大量空間,而且冗餘度較高的數據,通常在製作的時候就會進

行某種壓縮。這就是我們熟知的音視頻編碼格式,包括MPEG1(VCD)、MPEG2(DVD)、MPEG4、H.264、rmvb等等。音視頻解碼器的作用就是把這些壓縮了的數據還

原成原始的音視頻數據。VLC解碼MPEG2使用了一個獨立的庫libmpeg2,調用它的源文件是 /modules/codec/libmpeg2.c。VLC關於編解碼的模塊都放

在/modules/codec目錄下,其中包括著名的龐大的 ffmpeg。

    解碼器,例如視頻解碼器輸出的是一張一張的類似位圖格式的圖像,但是要讓人從屏幕看得到,還需要一個視頻輸出的模塊。當然可以像一個Win32窗口程序

那樣直接把圖像畫到窗口DC上——VLC的一個輸出模塊WinGDI就是這麼幹的,但是通常這太慢了,而且消耗大量的CPU。在Windows下比較好的辦法是用DirectX的接

口,會自動調用顯卡的加速功能。

    這樣的功能分解使得模塊化更容易一點,每個模塊住需要專注於自己的事;從整體來說功能強大而且靈活。

    但是事情總是不會那麼簡單。就拿access來說,媒體的訪問是分層的,如RTSP就涉及到IPv4、TCP、UDP、RTCP、RTSP等多個層次的協議。有些視頻格式包括了

傳輸、封裝格式和編輯碼格式如MPEG系列,有些封裝格式是獨立的容器,但是很多人會誤解它是編解碼格式,如mkv、avi這些。

    音頻和視頻在demux之後就是獨立的,但是需要有一套機制把它們同步起來。同時我們需要有一套機制來控制速度、暫停、停止、跳進,獲取各種媒體信息,

這些都是很複雜而又很重要的事情。

    另外也許需要在某個地方插入一些修改,來實現某種效果。如音頻的EQ,視頻的亮度調整之類的,VLC專門設計了access_filter、audio_filter和

video_filter類型的模塊來做這一類事情。

    VLC比較獨特的地方是集成了原來的VLS的功能,這依賴於VLC中stream_output類型的模塊,它們可以把正在播放的視頻以某種方式重新轉碼和發送出去,如

http、UDP、文件等等。

    MPlayer的結構與此是類似的,如/stream目錄對應的是access的功能,/mpdemux對應的demux功能,/libmpcodecs是解碼器,/libvo和/libao2分別是視頻和音

頻的輸出。

    DirectShow也是類似的,不過分類更多一些更復雜一點。DirectShow裏面的模塊叫做“filter”,filter之間通過”pin”來連接。access的模塊對應於

DirectShow中的SourceFIlter,這一類Filter只有輸出pin沒有輸入pin。demux模塊對應於splitterfilter,這種filter有一個輸入pin,多個輸出pin。解碼模

塊是一類transformfilter,有一個輸入pin、一個輸出pin,輸出模塊對應於readeringfilter,有一個輸入pin,沒有輸出pin。當然transformfilter不一定是

解碼器,也可能是某種其他的處理。

    回到VLC的話題。每一類的模塊數量都很多,那麼在打開某一個視頻時,VLC如何決定採用哪一個呢?哈哈,這個以後再說 ^_^

    另外給出一個VLC的API Document,有點老了不過挺值得一看的,在VLC wiki上找不到了,就貼出來:http://rogerfd.cn/doc/vlcapi.htm

嵌入式 IP數據報的TS、ES、PS流

IP數據報有首部和數據兩部分組成的,首部的前一部分是固定長度20字節,是所有IP數據報必須具有的。首部包括:總長度、標識、MF、DF、片偏移。
 
數字信號實際傳送的是數據流,一般數據流包括以下三種:

ES流:也叫基本碼流,包含視頻、音頻或數據的連續碼流。
PES流:也叫打包的基本碼流,是將基本的碼流ES流根據需要分成長度不等的數據包,並加上包頭就形成了打包的基本碼流PES流。

TS流:也叫傳輸流,是由固定長度爲188字節的包組成,含有獨立時基的一個或多個節目,適用於誤碼較多的環境。 
 
TS流(TransportStream)即在MPEG-2系統中,由視頻,音頻的ES流和輔助數據復接生成的用於實際傳輸的標準信息流稱爲MPEG-2傳送流。信息複合/分離的過程稱爲系統復接/分接,據傳輸媒體的質量不同,MPEG-2中定義了兩種複合信息流:傳送流(TS)和節目流(PS:ProgramStream)

MPEG2-PS主要應用於存儲的具有固定時長的節目,如DVD電影,而MPEG-TS則主要應用於實時傳送的節目,比如實時廣播的電視節目


TS流與PS流的區別在於TS流的包結構是固定長度的,而PS流的包結構是可變長度。 PS包與TS包在結構上的這種差異,導致了它們對傳輸誤碼具有不同的抵抗能力,因而應用的環境也有所不同。TS碼流由於採用了固定長度的包結構,當傳輸誤碼破壞了某一TS包的同步信息時,接收機可在固定的位置檢測它後面包中的同步信息,從而恢復同步,避免了信息丟失。而PS包由於長度是變化的,一旦某一PS包的同步信息丟失,接收機無法確定下一包的同步位置,就會造成失步,導致嚴重的信息丟失。因此,在信道環境較爲惡劣,傳輸誤碼較高時,一般採用TS碼流;而在信道環境較好,傳輸誤碼較低時,一般採用PS碼流由於TS碼流具有較強的抵抗傳輸誤碼的能力,因此目前在傳輸媒體中進行傳輸的MPEG-2碼流基本上都採用了TS碼流的包格。

 

嵌入式 rtp、rtsp、trcp的區別

RTP(Real-time TransportProtocol)是用於Internet上針對多媒體數據流的一種傳輸協議。RTP被定義爲在一對一或一對多的傳輸情況下工作。其目的是提供時間信息和實現流同步。但RTP通常使用UDP來傳送數據。但RTP也可以在TCPATM等其他協議之上工作。當應用程序開始一個RTP會話時將使用兩個端口:一個給RTP一個給 RTCPRTP本身並不能爲接順序傳送數據包提供可靠的傳送機制。也不提供流量控制或擁塞控制。它依靠RTCP提供這些服務。通常RTP算法並不作爲一個獨立的網絡層來實現。而是作爲應用程序代碼的一部分。實時傳送控制協議RTCP.RTCP(Real-time Transport Control Protocol)RTP提供流量控制和擁塞控制。在RTP會話期間,各參與者週期性地傳送RTCP.RTCP包中含有已發送的數據包的數量、丟失的數據包的數量等統計資料.因此,服務器可以利用這些信息動態地改變傳輸速率,甚至改變有效載荷類型。RTPRTCP配合使用,它們能以有效的反饋和最小的開銷使傳輸效率最佳化。因而特別適合傳送網上的實時數據。 

實時流協議 RTSP 
實時流協議RTSP(Real-time StreamingProtocol)是由Real NetworksNetscape共同中提出的。該協議定義了一對多應用程序如何有效地通過lP網絡傳送多媒體數據。RTSP在體系結構上位於RTPRTCP之上。它使用TCPRTP完成數據傳輸。HTTPRTSP相比。HTTP傳送HTML。而RTP傳送是多媒體數據。HTTP請求由客戶機發出,服務器作出響應;使用RTSP時,客戶機和服務器都可以發出請求,即RTSP可以是雙向的。

RTP/RTSP/RTCP的區別用一句簡單的話總結:RTSP發起/終結流媒體、RTP傳輸流媒體數據RTCPRTP進行控制,同步。
之所以以前對這幾個有點分不清,是因爲CTC標準裏沒有對RTCP進行要求,因此在標準RTSP的代碼中沒有看到相關的部分。而在私有RTSP的代碼中,有關控制、同步等,是在RTP Header中做擴展定義實現的
另外,RFC3550可以看作是RFC1889的升級文檔,只看RFC3550即可。

·                RTP:實時傳輸協議(Real-time Transport Protocol

·                        RTP/RTCP是實際傳輸數據的協議 

·                        RTP傳輸音頻/視頻數據,如果是PLAYServer發送到Client端,如果是RECORD,可以由Client發送到Server 

·                        整個RTP協議由兩個密切相關的部分組成:RTP數據協議和RTP控制協議(即RTCP

·                RTSP:實時流協議(Real Time Streaming ProtocolRTSP

·                        RTSP的請求主要有DESCRIBE,SETUP,PLAY,PAUSE,TEARDOWN,OPTIONS等,顧名思義可以知道起對話和控制作用 

·                        RTSP的對話過程中SETUP可以確定RTP/RTCP使用的端口,PLAY/PAUSE/TEARDOWN可以開始或者停止RTP的發送,等等

·                RTCP

·                        RTP/RTCP是實際傳輸數據的協議 

·                        RTCP包括Sender ReportReceiver Report,用來進行音頻/視頻的同步以及其他用途,是一種控制協議 

以下是每個協議的概要介紹:
一、RTP數據協議 
RTP
數據協議負責對流媒體數據進行封包並實現媒體流的實時傳輸,每一個RTP數據報都由頭部(Header)和負載(Payload)兩個部分組成,其中頭部前12個字節的含義是固定的,而負載則可以是音頻或者視頻數據。RTP數據報的頭部格式如圖1所示:


其中比較重要的幾個域及其意義如下: 

·                CSRC記數(CC):表示CSRC標識的數目。CSRC標識緊跟在RTP固定頭部之後,用來表示RTP數據報的來源,RTP協議允許在同一個會話中存在多個數據源,它們可以通過RTP混合器合併爲一個數據源。例如,可以產生一個 CSRC列表來表示一個電話會議,該會議通過一個RTP混合器將所有講話者的語音數據組合爲一個RTP數據源。

·                負載類型(PT):標明RTP負載的格式,包括所採用的編碼算法、採樣頻率、承載通道等。例如,類型2表明該RTP數據包中承載的是用ITU G.721算法編碼的語音數據,採樣頻率爲8000Hz,並且採用單聲道。

·                序列號:用來爲接收方提供探測數據丟失的方法,但如何處理丟失的數據則是應用程序自己的事情,RTP協議本身並不負責數據的重傳。

·                時間戳:記錄了負載中第一個字節的採樣時間,接收方能夠時間戳能夠確定數據的到達是否受到了延遲抖動的影響,但具體如何來補償延遲抖動則是應用程序自己的事情。

RTP數據報的格式不難看出,它包含了傳輸媒體的類型、格式、序列號、時間戳以及是否有附加數據等信息,這些都爲實時的流媒體傳輸提供了相應的基礎。RTP協議的目的是提供實時數據(如交互式的音頻和視頻)的端到端傳輸服務,因此RTP中沒有連接的概念,它可以建立在底層的面向連接或面向非連接的傳輸協議之上;RTP也不依賴於特別的網絡地址格式,而僅僅只需要底層傳輸協議支持組幀(Framing)和分段(Segmentation)就足夠了;另外RTP本身還不提供任何可靠性機制,這些都要由傳輸協議或者應用程序自己來保證。在典型的應用場合下,RTP一般是在傳輸協議之上作爲應用程序的一部分加以實現的,如圖2所示:



二、RTCP控制協議 
RTCP控制協議需要與RTP數據協議一起配合使用,當應用程序啓動一個RTP會話時將同時佔用兩個端口,分別供RTPRTCP使用。RTP本身並不能爲按序傳輸數據包提供可靠的保證,也不提供流量控制和擁塞控制,這些都由RTCP來負責完成。通常RTCP會採用與RTP相同的分發機制,向會話中的所有成員週期性地發送控制信息,應用程序通過接收這些數據,從中獲取會話參與者的相關資料,以及網絡狀況、分組丟失概率等反饋信息,從而能夠對服務質量進行控制或者對網絡狀況進行診斷。 

RTCP
協議的功能是通過不同的RTCP數據報來實現的,主要有如下幾種類型: 


·                SR:發送端報告,所謂發送端是指發出RTP數據報的應用程序或者終端,發送端同時也可以是接收端。

·                RR:接收端報告,所謂接收端是指僅接收但不發送RTP數據報的應用程序或者終端。

·                SDES:源描述,主要功能是作爲會話成員有關標識信息的載體,如用戶名、郵件地址、電話號碼等,此外還具有向會話成員傳達會話控制信息的功能。

·                BYE:通知離開,主要功能是指示某一個或者幾個源不再有效,即通知會話中的其他成員自己將退出會話。

·                APP:由應用程序自己定義,解決了RTCP的擴展性問題,並且爲協議的實現者提供了很大的靈活性。

RTCP數據報攜帶有服務質量監控的必要信息,能夠對服務質量進行動態的調整,並能夠對網絡擁塞進行有效的控制。由於RTCP數據報採用的是多播方式,因此會話中的所有成員都可以通過RTCP數據報返回的控制信息,來了解其他參與者的當前情況。
在一個典型的應用場合下,發送媒體流的應用程序將週期性地產生髮送端報告SR,該RTCP數據報含有不同媒體流間的同步信息,以及已經發送的數據報和字節的計數,接收端根據這些信息可以估計出實際的數據傳輸速率。另一方面,接收端會向所有已知的發送端發送接收端報告RR,該RTCP數據報含有已接收數據報的最大序列號、丟失的數據報數目、延時抖動和時間戳等重要信息,發送端應用根據這些信息可以估計出往返時延,並且可以根據數據報丟失概率和時延抖動情況動態調整發送速率,以改善網絡擁塞狀況,或者根據網絡狀況平滑地調整應用程序的服務質量。


三、RTSP實時流協議 
作爲一個應用層協議,RTSP提供了一個可供擴展的框架,它的意義在於使得實時流媒體數據的受控和點播變得可能。總的說來,RTSP是一個流媒體表示協議,主要用來控制具有實時特性的數據發送,但它本身並不傳輸數據,而是必須依賴於下層傳輸協議所提供的某些服務。RTSP可以對流媒體提供諸如播放、暫停、快進等操作,它負責定義具體的控制消息、操作方法、狀態碼等,此外還描述了與RTP間的交互操作(RFC2326

RTSP
在制定時較多地參考了HTTP/1.1協議,甚至許多描述與HTTP/1.1完全相同RTSP之所以特意使用與HTTP/1.1類似的語法和操作,在很大程度上是爲了兼容現有的Web基礎結構,正因如此,HTTP/1.1的擴展機制大都可以直接引入到RTSP中。
RTSP控制的媒體流集合可以用表示描述(Presentation Description)來定義,所謂表示是指流媒體服務器提供給客戶機的一個或者多個媒體流的集合,而表示描述則包含了一個表示中各個媒體流的相關信息,如數據編碼/解碼算法、網絡地址、媒體流的內容等。
雖然RTSP服務器同樣也使用標識符來區別每一流連接會話(Session),但RTSP連接並沒有被綁定到傳輸層連接(如TCP等),也就是說在整個 RTSP連接期間,RTSP用戶可打開或者關閉多個對RTSP服務器的可靠傳輸連接以發出RTSP 請求。此外,RTSP連接也可以基於面向無連接的傳輸協議(如UDP等)。

RTSP
協議目前支持以下操作: 

·                檢索媒體:允許用戶通過HTTP或者其它方法向媒體服務器提交一個表示描述。如表示是組播的,則表示描述就包含用於該媒體流的組播地址和端口號;如果表示是單播的,爲了安全在表示描述中應該只提供目的地址。

·                邀請加入:媒體服務器可以被邀請參加正在進行的會議,或者在表示中回放媒體,或者在表示中錄製全部媒體或其子集,非常適合於分佈式教學。

·                添加媒體:通知用戶新加入的可利用媒體流,這對現場講座來講顯得尤其有用。與HTTP/1.1類似,RTSP請求也可以交由代理、通道或者緩存來進行處理。

 

嵌入式 交換機與路由器的廣播包

廣播分二層廣播和三層廣播,二層廣播是FFFF.FFFF.FFFF,二層交換機遇到這種包就會泛洪到所有同VLAN的端口,不會過濾掉,因爲如果二層交換機過濾這種包,arp廣播怎麼正常工作呢?沒有arp,同網段的PC如何通信呢?路由器可以過濾二層廣播是因爲路由器是三層設備,如果路由器不過濾這種包,任何人發起的二層廣播包就會到達Internet的整個範圍,這樣還要路由器做什麼呢?路由器就是爲了劃分廣播域用的阿。

對於三層廣播還有本地廣播255.255.255.255和特定子網廣播比如192.168.1.255/24之分,255.255.255.255這種本地廣播是肯定沒發跨越路由器的,因爲一旦這種廣播能跨越路由器的話,同樣任何人發起的這種廣播就會跑到Internet的任何角落。然而對於特定子網的廣播是可以配置爲允許跨路由器或者不允許跨路由器的,如果允許的話,我就可以跨越路由器對特定的子網發起三層廣播。通常不要允許這類廣播,因爲你一旦允許了很容易造成icmp sumrf攻擊的。

再說一下這種三層廣播對二層交換機來說是沒有意義的,普通二層交換機只能看到二層頭。也只會根據二層頭中的目標地址進行處理。

 

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