vlc 代码学习.docx
《vlc 代码学习.docx》由会员分享,可在线阅读,更多相关《vlc 代码学习.docx(11页珍藏版)》请在冰豆网上搜索。
vlc代码学习
【转】vlc代码学习
第一部分变量及宏定义
1.消息映射宏
vlc_module_begin();
…………………..
vlc_module_end();
2.结构中包含函数
structinput_thread_t
{
VLC_COMMON_MEMBERS
/*Threadproperties*/
vlc_bool_tb_eof;
vlc_bool_tb_out_pace_control;
/*Accessmodule*/
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.宏与换行符妙用
#defineVLC_COMMON_MEMBERS/**\nameVLC_COMMON_MEMBERS*thesemembersarecommonforallvlcobjects*//**@{*/inti_object_id;int
i_object_type;char*psz_object_type;char*psz_object_name;/**Justaremindersothatpeopledon'tcastgarbage*/int
be_sure_to_add_VLC_COMMON_MEMBERS_to_struct;/**@}*/
#defineVLC_OBJECT(x)\
((vlc_object_t*)(x))+
0*(x)-be_sure_to_add_VLC_COMMON_MEMBERS_to_struct
structvlc_object_t
{
VLC_COMMON_MEMBERS
};//定义一个结构来使用宏定义的公共成员
4.定义导出函数
#ifndef__PLUGIN__
#defineVLC_EXPORT(type,name,args)typenameargs
#else
#defineVLC_EXPORT(type,name,args)struct_u_n_u_s_e_d_
externmodule_symbols_t*p_symbols;
#endif
5.定义回调函数
typedefint(*vlc_callback_t)(vlc_object_t*,/*variable'sobject*/
charconst*,/*variablename*/
vlc_value_t,/*oldvalue*/
vlc_value_t,/*newvalue*/
void*);/*callbackdata*/
6.函数作为参数的定义方式
IntFun(intn,int(*pf)(int,int),char*pstr)
{intj=10;
pf(n,j);
}
7.回调函数的声明
必须声明为global,或者static
Intvlc_callback_t(int,int)
{。
。
。
。
。
。
。
。
。
。
。
}
8.回调函数的使用
Fun(0,vlc_callback_t,”test”);
9.函数表达式
#defineinput_BuffersInit(a)__input_BuffersInit(VLC_OBJECT(a))
void*__input_BuffersInit(vlc_object_t*);
#definemodule_Need(a,b,c,d)__module_Need(VLC_OBJECT(a),b,c,d)
VLC_EXPORT(module_t*,__module_Need,(vlc_object_t*,constchar*,constchar*,vlc_bool_t));
10.定义函数
/*Dynamicarrayhandling:
reallocarray,movedata,incrementposition*/
#defineINSERT_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;
}
returns;//注解:
s-p_sys改变了
}
第二部分程序框架实现
1.播放列表文件src/playlist/playlist.c的线程
playlist_t*__playlist_Create(vlc_object_t*p_parent)函数中创建的线程,线程函数为
staticvoidRunThread(playlist_t*p_playlist)
线程思路分析:
在RunThread里面执行循环,如果没有任务执行,则适当的延迟,如果接到p_playlist-i_status!
=PLAYLIST_STOPPED的条件,则调用PlayItem(
p_playlist)函数,在PlayItem(p_playlist)函数中从新创建输入线程。
通过voidplaylist_Command(playlist_t*p_playlist,playlist_command_ti_command,inti_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)函数中创建的线程,线程函数为
staticintRunThread(input_thread_t*p_input)
线程思路分析:
由input_thread_t结构的成员分析是接收文件流还是网络流,如果是文件流,则调用filemodule的读函数(pf_read)和打开函数(--).如果是network则打
开networkmodule的打开函数和读函数(pf_read)。
在RunThread线程函数中接收数据和调用demux或者decodeetc处理。
一旦产生新的输入,则在播放列表线程中会首先结束该输入线程,然后从新创建新的输入线程。
3.视频输出文件src/video_output/video_output.c的线程
vout_thread_t*__vout_Create(vlc_object_t*p_parent,
unsignedinti_width,unsignedinti_height,
vlc_fourcc_ti_chroma,unsignedinti_aspect)函数中创建的线程,线程函数为
staticvoidRunThread(vout_thread_t*p_vout)
线程思路分析:
在RunThread里面执行循环,任务是显示视频。
4.在modules\gui\wxwindows\wxwindows.cpp中的GUI线程
staticvoidRun(intf_thread_t*p_intf)函数中创建的线程,线程函数为
staticvoidInit(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,constchar*psz_capability,
constchar*psz_name,vlc_bool_tb_strict)
函数中用到了pf_activate激活GUI对话框;
在video_output.c的staticvoidRunThread(vout_thread_t*p_vout)线程中,也用到了pf_activate激活GUI对话框;
5.开始所有module的精髓
消息映射宏
vlc_module_begin();
set_callbacks(NetOpen,NULL);
vlc_module_end();
然后设置模块结构的成员函数为:
#defineset_callbacks(activate,deactivate)p_submodule-pf_activate=activate;p_submodule-pf_deactivate=deactivate
在__module_Need函数中启动pf_activate激活相应的module。
网络数据流接收处理分析
1、在input.c(src\input)文件中的主线程循环
Threadinchargeofprocessingthenetworkpacketsanddemultiplexing
RunThread(input_thread_t*p_input)
{
InitThread(p_input);
…………………………………………………….
input_SelectES(p_input,p_input->stream.p_newly_selected_es);
…………………………………………………….
/*Readanddemultiplexsomedata.*/
i_count=p_input->pf_demux(p_input);
}
2、在下列函数中:
分离出access,demux,name字符串;
根据分离出的access字符串通过module_Need函数找到acess指针模块;
根据分离出的demux字符串通过module_Need函数找到demux指针模块;
staticintInitThread(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);
/*Findandopenappropriateaccessmodule*/
p_input->p_access=module_Need(p_input,"access",
p_input->psz_access,VLC_TRUE);
…………………………………………………….
while(!
input_FillBuffer(p_input))
…………………………………………………….
/*Findandopenappropriatedemuxmodule*/
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函数中激活;
staticintActivate(vlc_object_t*p_this)
{
/*Setthedemuxfunction*/
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的成员函数;
staticintActivate(vlc_object_t*p_this)
{
staticmpeg_demux_tmpeg_demux=
{NULL,ReadPS,ParsePS,DemuxPS,ReadTS,DemuxTS};
mpeg_demux.cur_scr_time=-1;
memcpy(p_this->p_private,&mpeg_demux,sizeof(mpeg_demux));
returnVLC_SUCCESS;
}
并且申明函数staticssize_tReadPS(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流解码
intinput_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/ VLCAPIdocumentation 或者VLCdeveloperdocumentation
Chapter5. Thevideooutputlayer
Datastructuresandmainloop
Importantdatastructuresaredefinedininclude/video.handinclude/video_output.h.Themaindatastructureispicture_t,whichdescribes
everythingavideodecoderthreadneeds.Pleaserefertothisfileformoreinformation.Typically,p_datawillbeapointertoYUVplanar
picture.
Notealsothesubpicture_tstructure.InfacttheVLCSPUdecoderonlyparsestheSPUheader,andconvertstheSPUgraphicaldatatoan
internalformatwhichcanberenderedmuchfaster.Soapartofthe"real"SPUdecoderliesinsrc/video_output/video_spu.c.
Thevout_thread_tstructureismuchmorecomplex,butyouneedn'tunderstandeverything.Basicallythevideooutputthreadmanagesaheapof
picturesandsubpictures(5bydefault).Everypicturehasastatus(displayed,destroyed,empty...)andeventuallyapresentationtime.The
mainjobofthevideooutputisan