VLC框架分析

来源:互联网 发布:传奇盛世翅膀8升9数据 编辑:程序博客网 时间:2024/04/28 02:54

功能部份:

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可以将模块直接插入到应用程序中,例如不支持动态加载代码的操作系统.模块静态插入到应用程序叫内建.



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.include/main.h 文件: access to all program variables,主要定义了2个结构体:libvlc_t,vlc_t。
         a. struct libvlc_t 根据程序注释:该结构体只有一个实例,在main函数中被分配,而且只能在main中访问。它用来存储一些只能初始化一次的数据,比如说cpu容量或者global lock.
          b. struct vlc_t   注释称:This structure is a LibVLC instance
         libvlc_t,vlc_t在VLC_COMMON_MEMBERS宏中出现,分别定义了 libvlc_t *   p_libvlc; vlc_t *   p_vlc; 对象,注释称为 root of the evil,可见其结构体的重要性.所有的参数传递都在这里面(具体尚不清楚)。
2.include/Vlc_common.h 文件:common definitions,Collection of useful common types and macros definitions,通用类型和宏定义的集合
         主要作用是为了将不同的操作系统中的变量定义统一起来,比如说根据将unit_8来统一代表unsiged char类型.
        该文件中还定义了VLC_COMMON_MEMBERS宏,该宏中包括了所有VLC基本对象的通用成员变量:these members are common for all vlc objects。
        定义导出函数
#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
定义回调函数
      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 */          
3.include/vlc_objects.h 文件:vlc_object_t definition and manipulation methods,vlc_object_t的定义和处理函数
       struct vlc_object_t
{
VLC_COMMON_MEMBERS
}; //定义一个结构来使用宏定义的公共成员


VLC中vlm介绍

代码从两大部分入手,一个telnet 的deamon。还有就是rtsp的实现部分 。结果发现,他们通过了一个桥梁vlm的media进行沟通。

  • 当受到new MEDIANAME vod enabled 就建立一个media。
  • 如果受到setup MEDIANAME input filename.mpg 就读入流准备分析,建立input流
  • 当受到rtsp的请求后,就建立这个output流

这样,vod就和别的模块一致了。rtsp只是一种output流的module。

代码分析

1. /modules/control/telnet.c
/*****************************************************************************
* Run: main loop
*****************************************************************************/
static void Run( intf_thread_t *p_intf ){
vlm_ExecuteCommand( p_sys->mediatheque, cl->buffer_read,
&message );
}
2. /src/Misc/vlm.c
/*****************************************************************************
* vlm_ExecuteCommand:
*****************************************************************************/
int vlm_ExecuteCommand( vlm_t *p_vlm, const char *psz_command,
vlm_message_t **pp_message)
{
}
vlm_MediaNew( vlm_t *vlm, const char *psz_name, int i_type ){
vlm_media_t *media = malloc( sizeof( vlm_media_t ) );
}
*****************************************************
struct vlm_t
{
VLC_COMMON_MEMBERS
    vlc_mutex_t lock;
    int            i_media;
vlm_media_t    **media;
    int            i_vod;
vod_t          *vod;
    int            i_schedule;
vlm_schedule_t **schedule;
};
*****************************************************
int vlm_MediaSetup( vlm_t *vlm, vlm_media_t *media, const char *psz_cmd,
const char *psz_value ){

if( (p_input = input_CreateThread2( vlm, &media->item, psz_header
) ) )
{
while( !p_input->b_eof && !p_input->b_error ) msleep( 100000 );

input_StopThread( p_input );
input_DestroyThread( p_input );
vlc_object_detach( p_input );
vlc_object_destroy( p_input );
}
}
3. /src/Input/input.c
input_thread_t *__input_CreateThread2( vlc_object_t *p_parent,
input_item_t *p_item,
char *psz_header )
{
input_thread_t *p_input = NULL;      /* thread descriptor */
p_input = Create( p_parent, p_item, psz_header, VLC_FALSE );
/* Now we can attach our new input */
vlc_object_attach( p_input, p_parent );

/* Create thread and wait for its readiness. */
if( vlc_thread_create( p_input, "input", Run,
VLC_THREAD_PRIORITY_INPUT, VLC_TRUE ) )
{
msg_Err( p_input, "cannot create input thread" );
vlc_object_detach( p_input );
vlc_object_destroy( p_input );
return NULL;
}
}
static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
char *psz_header, vlc_bool_t b_quick )
{
}

/*****************************************************************************
* Run: main thread loop
* This is the "normal" thread that spawns the input processing chain,
* reads the stream, cleans up and waits
*****************************************************************************/
static int Run( input_thread_t *p_input )
{
}

=====================================================================================
4. \modules\misc\rtsp.c
static vod_media_t *MediaNew( vod_t *p_vod, const char *psz_name,
input_item_t *p_item )
{
vod_sys_t *p_sys = p_vod->p_sys;
vod_media_t *p_media = malloc( sizeof(vod_media_t) );
int i;
    if( !p_media )
{
msg_Err( p_vod, "not enough memory" );
return NULL;
}
    memset( p_media, 0, sizeof(vod_media_t) );
p_media->es = 0;
p_media->psz_mux = 0;
p_media->rtsp = 0;
p_media->b_raw = VLC_FALSE;
    asprintf( &p_media->psz_rtsp_path, "%s%s", p_sys->psz_path, psz_name );
p_media->p_rtsp_url =
httpd_UrlNewUnique( p_sys->p_rtsp_host, p_media->psz_rtsp_path, NULL,
NULL, NULL );
    if( !p_media->p_rtsp_url )
{
msg_Err( p_vod, "cannot create RTSP url (%s)", p_media->psz_rtsp_path);
free( p_media->psz_rtsp_path );
free( p_media );
return NULL;
}
    msg_Dbg( p_vod, "created RTSP url: %s", p_media->psz_rtsp_path );
    asprintf( &p_media->psz_rtsp_control_v4,
"a=control:rtsp://%%s:%d%s/trackID=%%d\r\n",
p_sys->i_port, p_media->psz_rtsp_path );
asprintf( &p_media->psz_rtsp_control_v6,
"a=control:rtsp://[%%s]:%d%s/trackID=%%d\r\n",
p_sys->i_port, p_media->psz_rtsp_path );
    httpd_UrlCatch( p_media->p_rtsp_url, HTTPD_MSG_SETUP,
RtspCallback, (void*)p_media );
httpd_UrlCatch( p_media->p_rtsp_url, HTTPD_MSG_DESCRIBE,
RtspCallback, (void*)p_media );
httpd_UrlCatch( p_media->p_rtsp_url, HTTPD_MSG_PLAY,
RtspCallback, (void*)p_media );
httpd_UrlCatch( p_media->p_rtsp_url, HTTPD_MSG_PAUSE,
RtspCallback, (void*)p_media );
httpd_UrlCatch( p_media->p_rtsp_url, HTTPD_MSG_TEARDOWN,
RtspCallback, (void*)p_media );
}
static int RtspCallback( httpd_callback_sys_t *p_args, httpd_client_t *cl,
httpd_message_t *answer, httpd_message_t *query )
{
switch( query->i_type )
{
case HTTPD_MSG_SETUP:
{
}
case HTTPD_MSG_PLAY:
{
p_rtsp = RtspClientGet( p_media, psz_session );
vod_MediaControl( p_vod, p_media, psz_session, VOD_MEDIA_PLAY,
psz_output );

}
}

}
5. vlc_vod.h
static inline int vod_MediaControl( vod_t *p_vod, vod_media_t *p_media,
char *psz_id, int i_query, ... )
{
i_result = p_vod->pf_media_control( p_vod->p_data, p_media, psz_id,
i_query, args );
}