原文:https://wiki.videolan.org/Hacker_Guide/How_To_Write_a_Module/
本文由GOOGLE翻译,我只是搬运工~~
←返回黑客指南
LibVLC基于许多独立模块,如大多数竞争多媒体框架。每个模块都提供特定功能。
本文重点介绍如何向VLC(或任何其他LibVLC应用程序)添加新模块(也称为插件)。您需要先阅读 VLC核心和模块以及VLC如何加载模块,否则您将无法充实新模块的内容。
内容[ 隐藏 ] |
树内和树外模块
大多数现有VLC模块作为源代码提供在主VLC源代码存储库(以及源代码压缩包)中的目录模块中。它们与VLC核心同时编译,通常与VLC二进制包和安装程序一起提供。这些模块称为树内模块。
但是,也可以在VLC之外编写和编译VLC模块。这对于在树中开发模块有一些优点和缺点:
优点
- 编译速度要快得多(VLC和其他模块不包含在流程中)。
- 您可以使用自己的版本控制系统,甚至根本不使用。
- 版权许可证不需要遵守VideoLAN协会的要求以包含在VLC中。
- VLC开发人员无需提供,审查和接受源代码。
- 发布计划独立于VLC版本。无论VLC发布计划如何,都可以随时发布新版本的模块。
- 至少在理论上可以使用不同的编程语言。(主VLC代码库仅使用C,C ++和Lua,以及MacOS Objective C.)
- 该模块可以使用不适合VLC依赖的软件库。
缺点
- VLC开发人员不会审查代码,这将是提高代码质量的好机会。
- VLC翻译人员不会在适用的情况下处理模块的本地化。VLC翻译成数十种语言。
- 模块无法通过videolan.org网站分发,并使用VideoLAN基础设施,如错误跟踪器和构建机器人。
- 模块仅适用于已编译的特定VLC(主要)版本。例如,为VLC 1.1.x编译的模块不适用于VLC 1.0.x或VLC 2.0.x.
- 模块仅适用于已编译的特定操作系统和体系结构。例如,Windows 32位模块仅适用于Windows 32位版本的VLC。VLC支持许多不同的操作系统和体系结构组合。
示例存根模块
让我们从C语言中的一个小示例模块开始:
/**
* @file hello.c
* @brief Hello world interface VLC module example
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
/* VLC core API headers */
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_interface.h>
/* Forward declarations */
static int Open(vlc_object_t *);
static void Close(vlc_object_t *);
/* Module descriptor */
vlc_module_begin()
set_shortname(N_("Hello"))
set_description(N_("Hello interface"))
set_capability("interface", 0)
set_callbacks(Open, Close)
set_category(CAT_INTERFACE)
add_string("hello-who", "world", "Target", "Whom to say hello to.", false)
vlc_module_end ()
/* Internal state for an instance of the module */
struct intf_sys_t
{
char *who;
};
/**
* Starts our example interface.
*/
static int Open(vlc_object_t *obj)
{
intf_thread_t *intf = (intf_thread_t *)obj;
/* Allocate internal state */
intf_sys_t *sys = malloc(sizeof (*sys));
if (unlikely(sys == NULL))
return VLC_ENOMEM;
intf->p_sys = sys;
/* Read settings */
char *who = var_InheritString(intf, "hello-who");
if (who == NULL)
{
msg_Err(intf, "Nobody to say hello to!");
goto error;
}
sys->who = who;
msg_Info(intf, "Hello %s!", who);
return VLC_SUCCESS;
error:
free(sys);
return VLC_EGENERIC;
}
/**
* Stops the interface.
*/
static void Close(vlc_object_t *obj)
{
intf_thread_t *intf = (intf_thread_t *)obj;
intf_sys_t *sys = intf->p_sys;
msg_Info(intf, "Good bye %s!", sys->who);
/* Free internal state */
free(sys->who);
free(sys);
}
现在有关代码的一些解释......
模块描述符
一个VLC媒体播放器模块必须包括描述的本身,参数,它接受。
模块描述符以:
vlc_module_begin()
您应该设置有关模块的一些基本信息。这是为dvdread模块:
set_shortname(N_("DVD without menus"))
set_description(N_("DVDRead Input"))
set_category(CAT_INPUT)
set_subcategory(SUBCAT_INPUT_ACCESS)_ACCESS)
注意使用N_(“”)来创建需要由gettext翻译的字符串。
能力和得分
定义示例:
set_capability("interface", 0)
这定义了一个“接口”功能模块,得分为0。
该功能决定了我们正在处理的模块类型。它可以是访问,解复用,解码器,接口等。现在是时候重新阅读VLC如何加载模块了。
- 如果VLC需要加载特定名称,它将按名称加载它,VLC直接打开该模块
- 如果VLC需要一种模块(“我需要一个解码器”),VLC将按降序分数顺序加载所有匹配此功能的模块,直到一个模块的Open()函数(见下文)返回VLC_SUCCESS。
分数应为整数,并与同一类别中的其他分数相关。得分0是一个特例。
配置类别和子类别
您应该使用一个的的预定义类别进行配置。配置类别和子类别指定其中的模块将出现在首 UI对话框。
配置类别包括:
- CAT_INTERFACE
- CAT_AUDIO
- CAT_VIDEO
- CAT_INPUT
- CAT_SOUT
- CAT_ADVANCED
- CAT_PLAYLIST
您还应该使用预定义的子类别之一。有关所有配置类别和子类别的定义,请参阅include / vlc_configuration.h。
配置参数
您可能需要选项来配置模块的运行时行为。定义新选项很容易。
所有选项定义都采用以下参数列表:
add_integer(name, value, text, longtext, advanced)
- name是在配置中标识此参数的字符串。在命令提示符下使用此名称来设置配置值。
- value是此参数的默认值,
- text参数的简短描述,使用_(“”)创建需要翻译的字符串,
- longtext参数的完整描述,使用_(“”)创建需要翻译的字符串,
- 高级布尔值,ADVanced配置。如果为TRUE,则仅在使用--advanced标志时显示此参数。
您可以将以下选项/参数类型添加到模块:
- add_integer,
- add_string,
- add_float,
- add_bool,
- add_key,
- 添加文件,
- add_directory,
有关完整定义,请参阅include / vlc_plugin.h
打回来
之后详述的激活和取消激活功能必须在描述符中定义。这样VLC核心就知道如何实例化和运行模块。
set_callbacks()宏允许您定义2个参数:第一个参数是pf_activate回调,第二个参数是pf_deactivate。但是,这些功能通常分别称为“打开”和“关闭”。如果/当需要一个提供正确接口的插件实例时,VLC会调用pf_activate回调,如set_capability()宏所声明的那样。
相反,当不再需要插件时,VLC会调用pf_deactivate回调 - 但前提是pf_activate回调先前返回了VLC_SUCCESS(0)。
打开(vlc_object_t *)
模块最重要的功能是开放:通常命名的Open()函数。
static int Open ( vlc_object_t * );
当VLC核心试图打开模块并想要加载它时,将调用Open()函数。
在Open(),结构,设备或I / O的设置期间,应该进行检查。成功打开应该返回VLC_SUCCESS。如果模块无法完成初始化,则可以返回任何其他值,通常为VLC_EGENERIC或VLC_ENOMEM。
在打开()函数预计分配私有数据(如果有的话),并设置了私结构。
如果Open失败,您可能需要在返回之前释放任何已分配的资源。否则,将发生泄漏。
关闭(vlc_object_t *)
模块的第二个最重要的功能是结束:通常命名的Close()函数。
static int Close ( vlc_object_t * );
当VLC核心尝试关闭或卸载已加载的模块时,将调用Close()函数。
注意:如果Open()函数失败,则不会调用Close()。
在Close()期间,应关闭设备或I / O,并清理结构。不要在这里泄漏内存!
在关闭()函数应该释放私有数据。
树内模块集成
混帐
如果您计划将工作提交到VLC上游,请务必查看git简介并查看发送补丁部分。
编译你的模块
Modules.am
首先,在modules /下找到正确的子目录以添加新代码。
- 如果模块只有一个源代码文件模块,只需将其添加到子目录中(例如modules / control / hello.c)。
- 较大的模块应该获得自己的子子目录(例如modules / control / hello / *)。
然后,您需要在构建系统中声明该模块。例如,文件modules / control / Modules.am告诉构建系统每个控制模块需要哪些源文件。对于上面的示例,我们可以添加以下行:
libhello_plugin_la_SOURCES = hello.c
libhello_plugin_la_CFLAGS = $(AM_CFLAGS)
libhello_plugin_la_LIBADD = $(AM_LIBADD)
libhello_plugin_la_DEPENDENCIES =
# Always compile the hello module:
libvlc_LTLIBRARIES += libhello_plugin.la
请注意,Modules.am中的缩进(如果需要)使用制表符(ASCII 0x09),而不是空格。
configure.ac
如果模块依赖于某些新库,某些体系结构或某些操作系统特性,则可能需要扩展configure.ac以检测何时以及如何构建模块。有关详细信息,请参阅configure.ac文件和GNU autoconf文档。
完成后,您只需要重建VLC:
make
(这可能会触发autoconf和automake的重新运行,因此可能需要一段时间。)
加载您的模块
出于性能原因,VLC会保留可用模块的缓存。它应该自动更新。但您可以使用./vlc --reset-plugins-cache强制重置。
然后用
./vlc -vv --color --list
检查你的插件是否被VLC媒体播放器看到。
您还应该在Qt界面(Linux和Windows)的插件对话框中看到它。
树外模块
有一篇专门的文章。请读出树编译。
子模块
子模块,在一些模块描述符中声明
add_submodule()
工作方式与模块完全相同。当不同的模块(通常但不一定具有不同的功能)共享公共代码时,它们很有用。所有子模块都将包含在与主模块相同的运行时库中。
模块类型
根据模块功能,您将需要有关要实现的必要功能的更多信息。
我们将在这里详述:
模块负载故障排除
有时,在构建树内模块时,由于构建系统问题和其他不一致性,内容不起作用。
您可能需要转到VLC源树的根目录,并执行类似于以下操作的操作。这里的例子假设bash shell。
温和的版本
在某些情况下,automake依赖关系会中断(例如在某些文件名发生更改后)。这可能会起作用:
find . -name .deps -exec rm -rf \{\} \;
./config.status
make
...但并非总是如此,因此可能会因为总是使用下面的“中等版本”而节省一些麻烦。
中型(先试试)
这是一个更激进但仍然安全的重建程序:
find . -name .deps -exec rm -rf \{\} \;
./bootstrap
./configure
make
至尊版
如果以上都没有帮助,您可以清理源树作为最后的手段。在继续之前,强烈建议您检查哪些文件将被删除:
git clean -nxd
然后检查您将丢失的源代码更改(如果有):
git diff
使用以下命令可以非常轻松地完成整天的艰苦工作。第一个命令将永久删除任何未在git中跟踪的文件,包括您自己可能创建的文件。第二个命令将删除对现有文件的任何未提交的修改。考虑自己警告。
!!!请注意:这可能导致不可避免的数据丢失!
git clean -fxd
git reset --hard HEAD
./bootstrap
./configure
make
此页面是官方VLC媒体播放器文档的一部分(用户指南 • 流式传输方式 • 黑客指南 • 模块)在编辑文档之前,
请阅读文档编辑指南
根据自由软件基金会发布的GNU通用公共许可证条款,允许复制,分发和/或修改本文档; 许可证的第2版,或(根据您的选择)任何更高版本。