VLC媒体框架的体系结构

说明:本篇文章是对上篇文章 The architecture of VLC media framework 的翻译。翻译内容来自GOOGLE,我只是搬运工~~~


VLC媒体框架的体系结构

VLC是一个免费的开源跨平台多媒体播放器和框架,可播放大多数多媒体文件以及 DVD,音频CD,VCD和各种流媒体协议。从技术上讲,它是一个软件包,可以处理计算机和网络上的媒体。它提供直观的 API和模块化架构,可轻松添加对新编解码器,容器格式和传输协议的支持。来自 VLC的大多数已知软件包是Windows,Linux和 OSX上常用的播放器

根据Videolan网站,这个项目很难理解:

VLC媒体播放器是一个庞大而复杂的软件。它还使用大量依赖项。
作为开源,VLC开发可以从全球范围内的大型开发人员社区中受益。
但是,对于新开发人员来说,进入VLC媒体播放器等项目可能会很复杂。

代码由专家C黑客编写,有时很难理解。可能需要一本书来解释VLC的工作原理。我会用几句话来总结我在采矿中发现的东西。让我们从高级架构开始:

VLC有一个核心和很多模块(200400之间取决于构建)。没有模块,VLC无法做很多事情,因为模块提供了您期望的大部分功能。有以下模块:

  • libVLCcore是框架的核心。它为C 提供了面向对象的层,模块加载/卸载以及一组关于多媒体的抽象功能:输入,多路复用,多路分解,音频输出,视频输出。
  • 模块提供框架的具体功能。模块根据其功能进行分类。有输入管理模块(文件,网络,cd),编解码器模块(mp3,divx,...),gui模块(文本,web,telnet,qt-based,macosx native)。
  • 外部库由于存在许多模块,因此存在许多外部依赖项。VLC Developer's Wiki 上有一个页面试图维护这些deps。
  • vlc(主要) - 是玩家的主力。它初始化libVLC并启动用户界面。

模块

如前所述,没有模块的VLC是无用的。模块可以根据其功能进行分类。一个能力应该被看作是类似于一个面向对象接口的东西。模块加载很容易解释:当VLC需要具有特定功能的模块时(例如,当需要“解码器”时),它会打开该功能的所有模块,直到匹配为止。它以降低的分数顺序打开它们(首先是较大的分数,最后是较小的分数),并运行Open()模块的功能。当一个模块返回OK时,VLC使用该模块。你可以在这里进一步阅读。下图显示了VLC中实现的主要模块功能

VLC可以具有不同风格的用户界面。每种接口都是一个模块(在这里你可以找到一个基本的声音设计原则:“将用户逻辑与用户界面分开”)。在实际分配有基于用户界面QT适用于Windows / Linux的,在可可/ Objective-C中的OSX上ncurses的控制台界面和一个用于Maemo操作设备。

只是为了了解模块的物理结构,如果你打开modules/audio_output目录,你会发现一些看起来像的东西

其中有几种音频输出技术的实现:ALSA,用于Linux的PulseOSS,用于Windows的DirectX

面向对象的层 - VLC对象

VLC定义了一个面向对象的层,用于管理模型。在此基础上有一个VLC对象,定义如下:

/ ******************* ****************************
 * vlc_object_t类型。是的,就这么简单:-)
 ************************************************** *************************** /
/ **主要的vlc_object_t结构* /
struct vlc_object_t
{
    VLC_COMMON_MEMBERS
};

VLC_COMMON_MEMBERS是C“#define”,编码如下:

/ * VLC_COMMON_MEMBERS:所有基本vlc对象共有的成员* /
#define VLC_COMMON_MEMBERS \
/ ** \ name VLC_COMMON_MEMBERS \
 *这些成员对于所有vlc对象都是通用的
 * / \
/ ** @ {* / \
  const char * psz_object_type; \
	                                                             \
  / *邮件标题* / \
  char * psz_header; \
  int i_flags; \
	                                                             \
  / *对象属性* / \
  挥发性bool b_die; / ** <由外部设置* / \
  bool b_force; / ** <由外部设置(例如.module_need())* / \
	                                                             \
  / *与libvlc结构相关的东西* / \
  libvlc_int_t * p_libvlc; / ** <(万恶之源) -  1 * / \
	                                                             \
  vlc_object_t * p_parent; / ** <我们的父母* / \
	                                                             \
/ ** @} * /

如果您习惯使用面向对象语言,那么您会发现这种结构非常天真。在SRC /其它/ objects.c有方法来创建,销毁和查找 VLC对象:vlc_custom_create(..)vlc_object_destroy(...)vlc_object_find(...)。例如,这段代码创建了一个新的vlc对象:

p_libvlc = vlc_custom_create((vlc_object_t *)NULL, 
			sizeof(* priv),VLC_OBJECT_GENERIC,“libvlc”);

LibVLC实例

库的根类是libvlc实例,定义如下:

struct libvlc_instance_t
{
  libvlc_int_t * p_libvlc_int;
  libvlc_vlm_t libvlc_vlm;
  unsigned ref_count;
  int verbosity;
  vlc_mutex_t instance_lock;
  struct libvlc_callback_entry_list_t * p_callback_list;
};

哪里 libvlc_int_t是vlc对象。在引导期间,它链接到libvlc_priv_t包含库的主要数据和结构的类型。例如playlist_tsrc / playlist /)是一个中心抽象,它代表一个音乐播放列表。vlm_t是服务器核心的根对象,允许同时流式传输多个媒体。VLC可以具有不同的用户界面(图形,文本,基于irc,......)。它们由p_intf变量建模,指向用户界面根对象。

/ **
 *私有LibVLC实例数据。
 * /
typedef struct libvlc_priv_t
{
    。。。。。。
    。。。。。。
    bool playlist_active;

    / *消息* /
    msg_bank_t * msg_bank; /// <消息库

    / *单身对象* /
    module_t * p_memcpy_module; /// <使用快速memcpy插件
    playlist_t * p_playlist; // <播放列表单身
    vlm_t * p_vlm; /// <VLM单例(或NULL)
    vlc_object_t * p_dialog_provider; /// <对话提供者
    httpd_t * p_httpd; /// <HTTP守护进程(src / network / httpd.c)
    。。。。。。
    。。。。。。

    / *接口* /
    struct intf_thread_t * p_intf; /// <Interfaces linked-list

} libvlc_priv_t;

模块抽象和沟通

如前所述,VLC由大量模块组成。在开发人员的网站上有一个开发自己模块的操作指南。我们可以说模块必须遵守两个合同:

  • 从初始化方面来看,它必须实现open()close()方法。这些方法用于初始化/取消初始化模块。
  • 从功能方面来说,它必须根据功能实现方法。

例如,音频输出类别的模块必须实现以下方法:

..................
int aout_VolumeDown(vlc_object_t * p_object,int i_nb_steps,audio_volume_t * pi_volume)
int aout_VolumeUp(vlc_object_t * p_object,int i_nb_steps,audio_volume_t * pi_volume)
int aout_VolumeGet(vlc_object_t * p_object,audio_volume_t * pi_volume)
int aout_ToggleMute(vlc_object_t * p_object,audio_volume_t * pi_volume)
..................

视频输出类别中的模块必须实现以下方法:

....................
picture_t * vout_CreatePicture(vout_thread_t * p_vout,bool b_progressive,bool b_top_field_first,
                               unsigned int i_nb_fields)
void vout_DisplayPicture(vout_thread_t * p_vout,picture_t * p_pic)
void DestroyPicture(vout_thread_t * p_vout,picture_t * p_picture)
void vout_DropPicture(vout_thread_t * p_vout,picture_t * p_pic)
....................

VLC中还有另一个基本概念,即基于“Observer-Observable”模式构建,它有助于解耦模块之间的通信。它是VLC变量的概念。甲VLC变量是可以被分配给任何一个值VLC对象。有趣的是,变量可以向感兴趣的观众发送__callbacks_。让我们看看VLC变量是如何工作的。

您首先要使用以下var_Create( p_libvlc, name, VLC_VAR_INTEGER );方法创建变量:p_libvlc是指向vlc对象的指针,name是变量的名称,而VLC_VAR_INTEGER是其类型。当你想为这个变量设置一个值时,你会写出类似的东西var_SetInteger( p_libvlc, name, temp_value);temp_value是我们要插入的值。有一个var_getInteger值可以读取价值。

用于触发回调有一个var_AddCallback( vlc_object_t *p_this, const char *psz_name,vlc_callback_t pf_callback, void *p_data )其中psz_name是变量名,pf_callback是函数指针和P_DATA是传递给函数指针作为参数的通用数据。当您更改变量的值时,将TriggerCallback(..)调用方法并通知变量的所有观察者。这是我在生活中看到的Observer / Observable模式中最复杂的实现。

如何具体应用这个概念?如果我们查看VLC的ncurses文本用户界面,有一段代码表明: 这意味着当“playlist-item-append”变量被更改时,会调用一个回调方法(这是用户界面的本地方法) 。var_AddCallback( p_playlist, "playlist-item-append", PlaylistChanged, p_intf ); 
PlaylistChanged()

VLC变量是用于解耦模块之间通信的机制。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值