? ? http://blog.csdn.net/eplaylity/archive/2008/12/05/3454431.aspx http://www.cnblogs.com/konyel/tag/SDL+Guide+%E4%B8%AD%E6%96%87%E8%AF%91%E7%89%88/ ffmpeg文檔http://blog.sina.com.cn/s/blog_46dc65a90100a91b.html http://dranger.com/ffmpeg/ffmpeg.html |
VLC核心
功能部份:
VLC媒體播放器的核心是libvlc ,它提供了界面,應用處理功能,如播放列表管理,音頻和視頻解碼和輸出,線程系統。所有libvlc源文件設在的/src目錄及其子目錄:
# config/ :從命令行和配置文件加載配置,提供功能模塊的讀取和寫入配置
# control/: 提供動作控制功能,如播放/暫停,音量管理,全屏,日志等。
# extras/: 大多是平臺的特殊代碼
# modules/: 模塊管理
# network/: 提供網絡接口(socket管理,網絡錯誤等)
# osd/: 顯示屏幕上的操作
# test/: libvlc測試模塊
# text/: 字符集
# interface/ : 提供代碼中可以調用的接口中,如按鍵后硬件作出反應。
# playlist/: 管理播放功能,如停止,播放,下一首,隨機播放等
# input/: 建立并讀取一個輸入流,并且分離其中的音頻和視頻,然后把分離好的音頻流和視頻流發送給解碼器.
# video_output/ : 初始化視頻播放器,把從解碼器得到的視頻畫面轉化格式(從YUV 轉為 RGB)然后播放它們
# audio_output/ : 初始化音頻混合器,即設置正確的同步頻率,并對從解碼器傳來的音頻流重新取樣
# stream_output/: 輸出音頻流和視頻流到網絡
# misc/: libvlc使用的其他部分功能 ,如線程系統,消息隊列, CPU的檢測,對象查找系統,或平臺的特定代碼。
模塊部份:
VLC媒體播放器的模塊部份,在/modules的子目錄下(詳細說明可以參考其下的List文件),這些模塊只在程序載入它們時有效.每一個模塊,可提供不同的功能,它們會適合的特定文件或某一特定的環境.此外,audio_output/video_output/interface 模塊都寫成了可跨平臺的代碼,方便支持新的平臺(如beos或服務Mac OS X ) 。
插件模塊可以在 src/modules.c 和 include/vlc_modules*.h 提供函數中,動態加載和卸載
LibVLC可以將模塊直接插入到應用程序中,例如不支持動態加載代碼的操作系統.模塊靜態插入到應用程序叫內建.
VLC框架分析
1.vlc.c 只是入口程序
2.Libvlc.c 是各個模塊的結合點,這要是對接口編程
- Vlc_Create(): 兩個重要的數據結構:libvlc_t & vlc_t , 所有的參數傳遞都在這里面
- Vlc_Init(): 初始化參數, module_bank
- Vlc_AddInf(): 添加module
3./src/misc/configure.c 命令行參數和參數文件分析
參數文件是~/.vnc/vlcrc。其中可以設置log文件的位置
4./include/ 所有頭文件的集合
5./src/interface/Interface.h 所有module的集合
6./src/misc/Modules.c
其中module_t * __module_Need( vlc_object_t *p_this, const char *psz_capability,
const char *psz_name, vlc_bool_t b_strict ) 方法是尋找合適的interface
如果找到合適的,就調用AllocatePlugin()動態的分配一個。
7.how to link to different modules without OOP
?
?
vlc網絡數據流接收處理過程分析
?
網絡數據流接收處理分析
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 );
???????????? …………………………………………………….
??? ??/* Read and demultiplex some data. */
??? 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 );
?
??? /* Find and open appropriate access module */
??? p_input->p_access = module_Need( p_input, "access",
???????????????????????????????????? p_input->psz_access, VLC_TRUE );
…………………………………………………….
while( !input_FillBuffer( p_input ) )
…………………………………………………….
??? /* Find and open appropriate demux module */
??? 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 )
{
????? /* Set the demux function */
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
VLC程序宏及線程分析
第一部分 變量及宏定義
1.消息映射宏
vlc_module_begin();
…………………..
vlc_module_end();
2.結構中包含函數
struct input_thread_t
{
VLC_COMMON_MEMBERS
/* Thread properties */
vlc_bool_t b_eof;
vlc_bool_t b_out_pace_control;
/* Access module */
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 /
/** /name VLC_COMMON_MEMBERS /
* these members are common for all vlc objects /
*/ /
/**@{*/ /
int i_object_id; /
int i_object_type; /
char *psz_object_type; /
char *psz_object_name; /
/
/** Just a reminder so that people don't cast garbage */ /
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 *, /* variable's object */
char const *, /* variable name */
vlc_value_t, /* old value */
vlc_value_t, /* new value */
void * ); /* callback data */
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 *, const char *, vlc_bool_t ) );
10.定義函數
/* Dynamic array handling: realloc array, move data, increment position */
#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 void RunThread( 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。
?
?
#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
定義回調函數
char const *,??????????? /* variable name */
vlc_value_t,???????????? /* old value */
vlc_value_t,??????????? /* new value */
{
VLC_COMMON_MEMBERS
}; //定義一個結構來使用宏定義的公共成員