VLC模块编写指南

对于一般的VLC应用编程来说,我们使用官网提供的模块就足够了。不过我们也得掌握如何编写自己的模块的方法。下面是自己根据官网的指南编写的如何添加一个模块的步骤。
一、编写源码

找到自己myhello.c源码的位置。我将自己编写的源码位于modules\control\myhello.c
打开myhello.c按照编程指南编写一个符合要求的模块源码。
二、修改编译脚本
a、官网说修改modules\control\modules.am不过我没有找到此文件,我按照modules\control\Makefiel.am中的hotkeys模块编写。在Makefile.am中增加:
libmyhello_plugin_la_SOURCES = control/myhello.c
libmyhello_plugin_la_LIBADD = $(LIBM)
control_LTLIBRARIES = \
libdummy_plugin.la \
libgestures_plugin.la \
libhotkeys_plugin.la \
libnetsync_plugin.la \
liboldrc_plugin.la \
libmyhello_plugin.la

b、在vlc跟目录下的configure.ac中增加对自己模块编译的规则。在configure.ac在增加:注意VLC_ADD_PLUGIN()中的形参是自己定义的模块名字,和Makefile.am中的模块名字一致。模块命名规则lib模块名_plugin.la.
dnl
dnl myhellomodule
dnl
VLC_ADD_PLUGIN([myhello])

三、验证
运行./bootstrap
运行 ./configure
运行 make
最后输入命令:./vlc -vvv –color –list
在列出的模块。我们可以找到自己添加的模块myhello。

下面附上官网的编程指导手册。
Hacker Guide/How To Write a Module
编程指南/如何编写一个模块

LibVLC is based on many independent modules, like most competing multimedia frameworks.
Each module provides specific functionality.
This article focuses on adding a new module (a.k.a. plug-in) to VLC (or any other LibVLC application).
You will need to read VLC Core and Modules and How VLC loads modules first,
otherwise you will not be able to flesh out the content of your new module.
LibVLC是基于许多独立模块的,是最具竞争力的架构。
每个模块提供特殊的功能。
这篇文章聚焦于如何添加一个模块。
你需要先阅读《 VLC Core and Modules 》《How VLC loads modules》
否则你将无法刷新你模块的内容

Contents 目录
1 In-tree and out-of-tree modules
1.1 Pros
1.2 Cons
2 Example stub module
2.1 Module Descriptor
2.1.1 Capability and score
2.1.2 Configuration categories and sub-categories
2.1.3 Configuration parameters
2.1.4 Callback
2.2 Open(vlc_object_t *)
2.3 Close(vlc_object_t *)
3 In-tree module integration
3.1 Git
3.2 Compiling your module
3.2.1 Modules.am
3.2.2 configure.ac
3.3 Loading your module
4 Out-of-tree module
5 Sub-modules
6 Module types
7 Module load troubleshooting
7.1 Mild version
7.2 Medium version (try this first)
7.3 Extreme version

1、In-tree and out-of-tree modules 

Most existing VLC modules are provided as source code in the directory modules within the main VLC source code repository (and also the source tarballs). 
大多数的现有的VLC模块都是有源码提供的,它们在VLC源码仓库的modules目录下。

They are compiled at the same time as the VLC core, and usually provided distributed together with VLC binary packages and installers. 
他们与VLC核心一起编译,通常和VLC的二进制包一起绑定和安装。

These modules are called in-tree modules.
这样的模块叫做非独立(内嵌)模块

However, it is also possible to write and compile VLC modules outside of VLC. 
然而,在VLC外部一样可以编写和编译VLC模块

That has some pros and cons over developing modules in-tree:
非独立(内嵌)开发模式的模块有下面几个好处和坏处

    Pros好处:
    Compilation is a lot faster (VLC and other modules are not included in the process
    编译速度快很多。

    You can use your own version control system, or even none at all.
    你可以使用你自己版本的控制系统,甚至不用。

    The copyright license does not need to abide by the requirements of the VideoLAN association for inclusion in VLC.
    版权许可证不需要遵守的VideoLAN协会包括VLC的要求

    The source code does not need to be provided, reviewed and accepted by the VLC developers.
    源代码不需要提供,审查和VLC开发商接受。

    The release schedule is independent of VLC releases. New versions of the module can be published at any time regardless of VLC release planning.
    发布计划是独立的VLC版本。该模块的新版本可以发布在任何时间无论VLC发布计划。

    Different programming languages can be used at least in theory. (The main VLC code base only uses C, C++ and Lua, and on MacOS Objective C.)
    在理论上可以使用不同的编程语言。(主要的VLC代码库只使用C,C++和Lua,和MacOS的目的C.)

    The module can use software libraries that would be inadequate for VLC to depend on.
    该模块可以使用VLC信赖的软件库。

    Cons坏处:
    The VLC developers will not review the code, which would be a good opportunity to improve the code quality.
    VLC开发商不会审查代码,这将是一个提高代码质量的好机会。

    VLC translators will not take care of localization for the module(s) where applicable. VLC is translated in many tens of languages.
    VLC译者不会关注这些使用的模块。VLC是翻译成几十种语言。

    The module(s) cannot be distributed through the videolan.org website and use the VideoLAN infrastructure such as the bug tracker and the build bots.
    模块不能分布相关的网站

    The module(s) will only work with the particular VLC (major) version that it has been compiled for.
    模块只能与特定的版本绑定。

    For instance, a module compiled for VLC 1.1.x will not work with VLC 1.0.x or VLC 2.0.x.
    比如,在1.1.x版本的编译模块将不能使用在其他版本上

    The module(s) will only work on the particular operating systems and architecture that it has been compiled for. 
    模块只对已编译的特定操作系统和体系结构进行工作。

    For instance, a Windows 32-bit module will only work with Windows 32-bit versions of VLC. 
    VLC supports many different combinations of operating systems and architectures.

2、Example stub module 例如:stub模块

Let's start with a small example module in the C language:
让我们开始用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);
}
**********************************************代码***********************************************************
And now some explanations about the code...
现在,我们解读这段代码

2.1 Module Descriptor
    模块描述

    A VLC media player module must include a description of itself, and the parameters it accepts.
    一个VLC多媒体播放器模块必须包括一个自身的描述,和他接受什么参数

    The module descriptor begins with:vlc_module_begin()
    模块描述以vlc_module_begin()为标记开始:

    You should set some basic information about your module. This is for the dvdread module:
    你应该为你的模块设置基本的信息。下面这是为dvdread模块的:
        set_shortname(N_("DVD without menus"))
        set_description(N_("DVDRead Input"))
        set_category(CAT_INPUT)
        set_subcategory(SUBCAT_INPUT_ACCESS)

    Note the use of N_("") to create a string that needs to be translated by gettext.
    注意:使用 N_("")去创建一个字符串,这个需要gettext库区翻译。

    2.1.1 Capability and score 类别和等级

        Definition Example:定义示例:
           set_capability("interface", 0)
        This defines a module of "interface" capability and a score of 0.
        这个定义这个模块是interface类别,并且是等级0

        The capability determines the type of module we are dealing with. 
        该类别决定了我们正在处理的模块的类型。

        It could be an access, a demux, a decoder, an interface, etc. Now is the time to re-read how VLC loads modules.
        他可以是an access, a demux, a decoder, an interface等。现在是时候复习一下《how VLC loads modules》

        If VLC needs to load a specific name, it will load it by its name and VLC directly opens this module
        如果VLC需要加载一个特点的名字,它将根据名字加载它,并且VLC会直接打开这个模块。

        If VLC needs a type of module ("I need a decoder"), 
        如果VLC需要一个("I need a decoder")模块,
        VLC will load all modules matching this capability in a decreasing score order until one modules's Open() function (see later) returns VLC_SUCCESS.
        VLC会在加载所有匹配的类别模块,递减score的每个都比较,直到找到一个模块的Open()返回 VLC_SUCCESS。

        See the major types of capabilities of VLC.
        查看VLC主要的类别:详细见VLC如何加module.c的章节(2.Major Capabilities of Modules//模块的主要功能)

        Score should be an integer, and related to other scores in the same category. Score 0 is a special case.
        等级(Score)应该是一个整数,并且与同一个类别下的其它等级相关。等级0是一个特殊的等级。
        (If a module has a score of 0, it needs to be explicitly requested by the user or vlc 
        (like forcing --codec, --vout or module_need("foo")) to be loaded.)


    2.1.2 Configuration categories and sub-categories配置类别和子类别
        You should use one of the predefined categories for configuration.
        您应该使用下列预定义的类别之一进行配置。
        The configuration categories and sub-categories specify where the module will appear in the preferences UI dialog.
        配置类别和子类别将指定模块出现在首选项UI对话框中的位置。

        The configuration categories include:配置的类别有一下几种:
        CAT_INTERFACE
        CAT_AUDIO
        CAT_VIDEO
        CAT_INPUT
        CAT_SOUT
        CAT_ADVANCED
        CAT_PLAYLIST

        You should use one of predefined sub-categories as well. 
        你应该使用预定于的子类别
        See include/vlc_configuration.h for definition of all configuration categories and sub-categories.
        在头文件include/vlc_configuration.h中定义了所有的类别和子类别

    2.1.3 Configuration parameters 配置参数
        You may need options to configure the run-time behavior of your module. Defining new options is easy.
        您可能需要选项来配置模块的运行时行为。定义新选项很容易。

        All option definitions take the following argument list:
        所有选项定义都包含以下参数列表:
         add_integer(name, value, text, longtext, advanced) 

        name is the string that identifies this parameter in the configuration. This name is used at the command prompt to set the configuration value.
        参数name:name是一个在配置中定义这个参数字符串。这个name是用于在命令行设置配置的值。

        value is the default value for this parameter,
        参数value:value是参数的默认值

        text A short description of the parameter, use _("") to create a string that needs to be translated,
        参数text:是对参数的简短描述,使用_("")来创建字符串需要被翻译

        longtext A complete description of the parameter, use _("") to create a string that needs to be translated,
        参数longtext:是对参数的完整描述,使用_("")来创建字符串需要被翻译

        advanced Boolean, ADVanced Configuration. If TRUE, this parameter will only be displayed when using the --advanced flag.
        参数advanced:是一个布尔变量。高级配置。如果是真,这个参数将在使 --advanced flag.是显示。

        You may add the following options/parameter types to your module:
        你可能添加下列的参数类型到你的模型中:
        add_integer,
        add_string,
        add_float,
        add_bool,
        add_key,
        add_file,
        add_directory,

        For complete definitions, see include/vlc_plugin.h
        在头文件include/vlc_plugin.h中有完整的定义,可以查看。

    2.1.4 Callback
        The activation and deactivation functions, detailed afterwards, must be defined in the descriptor. 
        激活和失活函数,在详细之后,必须在描述符中定义。

        This is so that the VLC core knows how to instantiate and run the module.
        这样做方便VLC核心知道如何实例化和运行模块。

        The set_callbacks() macro allows you to define 2 parameters: 
        set_callbacks()宏允许你定义两个参数:

        the first parameter is the pf_activate callback, and the second one, pf_deactivate. 
        第一个参数是pf_activate回调,第二个,pf_deactivate。

        The functions are most often called "Open" and "Close" respectively, though. 
        这两个函数通常称为“Open”和“Close”

        VLC invokes the pf_activate callback if/when it needs a plugin instance providing the correct interface, as declared with the set_capability() macro.
        当VLC需要一个插件实例提供正确的接口时,VLC引用这个 pf_activate回调函数,在set_capability()宏中宣告。

        Conversely, VLC invokes the pf_deactivate callback when the plugin is no longer needed - but only if the pf_activate callback returned VLC_SUCCESS (0) earlier.
        相反,当VLC不需要插件的时候,VLC引用 pf_deactivate。只有在引用pf_activate回调函数返回VLC_SUCCESS的前提下。



2.2 Open(vlc_object_t *)
    The most important function of a module is the opening: the usually-named Open() function.
    一个模块最重要的函数就是这个opening:习惯命名函数为Open()
    static int  Open ( vlc_object_t * );

    The Open() function is called when the VLC core tries to open the module, and wants to load it.
    当VLC核心试图打开或者加载它是会调用Open()函数

    During Open(), setup of structures, devices or I/O, checks should be done. 
    在open()中,设置结构体,设备或者I/O, 检查
    A successful open should return VLC_SUCCESS.
    调用成功会返回VLC_SUCCESS

     If the module cannot complete its initialization, it can return any other value, usually VLC_EGENERIC or VLC_ENOMEM.
     如果模块不能完成初始化,他将返回其他任意值,通常返回VLC_EGENERIC or VLC_ENOMEM.

    The Open() function is expected to allocate private data (if any), and set up the private structure.
    在Open()函数中预期申请私有数据的内存,并实例化。

    If the Opening fails, you may need to free any already allocated resources before returning. Otherwise, leaks will occur.
    如果Open()打开失败,你必须释放所有已经申请的内存再返回,否则导致段错误。

2.3 Close(vlc_object_t *)
    The second most important function of a module is the closing: the usually-named Close() function.
    static int  Close ( vlc_object_t * );
    The Close() function is called when the VLC core tries to close or unload an already-loaded module.
    NB: If the Open() function failed, Close() will not get called.
    During Close(), closing devices or I/O, and cleaning of structures should be done. Do not leak memory here!
    The Close() function should deallocate private data.

3、 In-tree module integration
非独立(内嵌)模块的集成

3.1 Git
    If you plan to submit your work to VLC upstream, be sure to look at the git introduction and check the send patches part.
    如果你计划将你的作品添加到VLC的发展流中,请确保你阅读了《 the git introduction》和检查了《 send patches part》部分
3.2 Compiling your module 编译你的模块
    3.2.1 Modules.am
        First, find the right subdirectory under modules/ to add your new code.
        首先,在modules/的目录下找到正确的子目录来添加新代码

        If the module has only one source code file module, simply add it in the subdirectory (e.g. modules/control/hello.c).
        如果新的模块只有一个源代码文件模块,只需将其添加到子目录中(例如模块/控制/ hello)。

        Larger modules should get a sub-subdirectory of their own (e.g. modules/control/hello/*).      */
        比较庞大的模块应该为他们新建一个目录。

        Then you need to declare the module in the build system. 
        然后比必须在构建系统中声明此模块

        For example, the file modules/control/Modules.am tells the build system which source files are needed for each control module.
        比如,在modules/control/Modules.am文件中告诉编译系统对于每个控制模块哪一个源文件是必须的。

         For the example above, we could add these lines:
         比如上面的例子,我们可以添加下面这几行:

        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

        Note that indentation in Modules.am (if needed) uses tabulations (ASCII 0x09), not white spaces.
        注意:在Modules.am(如果需要)请使用tab键,不要使用空格键。

    3.2.2 configure.ac
        If the module depends on some new library, some architecture or some operating system characteristics, 
        you may need to extend configure.ac to detect when and how to build the module. Refer to the configure.ac file and 
        the GNU autoconf documentation for details.
        如果新的模块依赖一些新的库,某些体系结构或某些操作系统特性,
        你可能需要延长configure.ac检测时,如何建立模块。指的是configure.ac文件
        GNU autoconf文件详情。

        Once this is done, you should only need to rebuild VLC:
        一旦这些做完,你应该重新编译VLC

        make //输入指令make
        (This will probably trigger a re-run of autoconf and automake, so it might take a while.)
        (这可能会触发一个autoconf和automake重新运行,所以它可能需要一段时间。)

3.3 Loading your module 加载自己编写的模块
    VLC keeps a cache of available modules for performance reasons. 
    VLC为可用模块保持了一个缓冲区以便提高模块加载性能。

    It should be updated automatically. But you can use ./vlc --reset-plugins-cache to force a reset.
    他应该是自动更新的,但是,你可以使用./vlc --reset-plugins-cache进行设置。

    Then use
    然后使用:

    ./vlc -vvv --color --list

    to check that your plugin is seen by VLC media player.
    来检查你的插件被VLC媒体播放器检测到了。

    You should also see it in the plugins dialog of the Qt interface (Linux and Windows).
    你同样可以在QT窗口的插件栏找到他

4、 Out-of-tree module//独立(非嵌入式)模块

There is a dedicated article. Please read out of tree compilation.
这有一篇专门介绍Out-of-tree模块编译的文章,请阅读《tree compilation》链接地址:《OutOfTreeCompile自有模块的编译.c》

5、 Sub-modules
子模块

Sub-modules, declared in some module descriptors with
子模块,一些模块的描述如下:

add_submodule()

work exactly the same way as modules.
 They are useful when different modules (usually but not necessarily of different capability) share common code.
 All sub-modules will be included in the same run-time library as the main module.
 与模块的工作方式完全相同。
当不同的模块(通常但不一定是不同的功能)共享公共代码时,它们是有用的。
所有子模块将包含在与主模块相同的运行时库中。

6、 Module types
模块的类型

Depending on the module capability, you will need more information, about the necessary functions to implement.
根据模块的功能,您需要更多的信息,实现所需的功能。

We will detail those here:
我们详细列出:

Access
Demux
Access_Demux
Decoder
Interface
Video filter
Video output
Audio filter
Audio output

7、Module load troubleshooting
加载模块时出现的错误

Sometimes when building an in-tree module, stuff doesn't work due to build system problems and other inconsistencies.
You probably need to go to the root of your VLC source tree, and do something akin to the following. The examples here assume the bash shell.
7.1 Mild version
    In some cases, automake dependencies break (for instance after some filenames have changed). This might then work:
    find . -name .deps -exec rm -rf \{\} \;
    ./config.status
    make
    ...but not always, so it may save some headaches to always use the "medium version" below.
7.2 Medium version (try this first)
    This is a more radical but still safe rebuild procedure:
    find . -name .deps -exec rm -rf \{\} \;
    ./bootstrap
    ./configure
    make
7.3 Extreme version
    If the none of the above helped, you can clean the source tree as a measure of last resort. Before you proceed, it is highly recommended that you check which files are going to be erased:
    git clean -nxd
    And then check what source code changes you would lose (if any):
    git diff
    You can extremely easily lose entire days of hard work with the following commands. The first command will permanently remove any files not tracked in git, including files that you might have created yourself. The second command will remove any uncommitted modification to existing files. Consider yourself warned.
    !!!BEWARE: THIS MAY CAUSE UNRECOVERABLE DATA LOSS!!!
    git clean -fxd
    git reset --hard HEAD
    ./bootstrap
    ./configure
    make

对于一般的VLC应用编程来说,我们使用官网提供的模块就足够了。不过我们也得掌握如何编写自己的模块的方法。下面是自己根据官网的指南编写的如何添加一个模块的步骤。
一、编写源码

找到自己myhello.c源码的位置。我将自己编写的源码位于modules\control\myhello.c
打开myhello.c按照编程指南编写一个符合要求的模块源码。
二、修改编译脚本
a、官网说修改modules\control\modules.am不过我没有找到此文件,我按照modules\control\Makefiel.am中的hotkeys模块编写。在Makefile.am中增加:
libmyhello_plugin_la_SOURCES = control/myhello.c
libmyhello_plugin_la_LIBADD = $(LIBM)
control_LTLIBRARIES = \
libdummy_plugin.la \
libgestures_plugin.la \
libhotkeys_plugin.la \
libnetsync_plugin.la \
liboldrc_plugin.la \
libmyhello_plugin.la

b、在vlc跟目录下的configure.ac中增加对自己模块编译的规则。在configure.ac在增加:注意VLC_ADD_PLUGIN()中的形参是自己定义的模块名字,和Makefile.am中的模块名字一致。模块命名规则lib模块名_plugin.la.
dnl
dnl myhellomodule
dnl
VLC_ADD_PLUGIN([myhello])

三、验证
运行./bootstrap
运行 ./configure
运行 make
最后输入命令:./vlc -vvv –color –list
在列出的模块。我们可以找到自己添加的模块myhello。

下面附上官网的编程指导手册。
Hacker Guide/How To Write a Module
编程指南/如何编写一个模块

LibVLC is based on many independent modules, like most competing multimedia frameworks.
Each module provides specific functionality.
This article focuses on adding a new module (a.k.a. plug-in) to VLC (or any other LibVLC application).
You will need to read VLC Core and Modules and How VLC loads modules first,
otherwise you will not be able to flesh out the content of your new module.
LibVLC是基于许多独立模块的,是最具竞争力的架构。
每个模块提供特殊的功能。
这篇文章聚焦于如何添加一个模块。
你需要先阅读《 VLC Core and Modules 》《How VLC loads modules》
否则你将无法刷新你模块的内容

Contents 目录
1 In-tree and out-of-tree modules
1.1 Pros
1.2 Cons
2 Example stub module
2.1 Module Descriptor
2.1.1 Capability and score
2.1.2 Configuration categories and sub-categories
2.1.3 Configuration parameters
2.1.4 Callback
2.2 Open(vlc_object_t *)
2.3 Close(vlc_object_t *)
3 In-tree module integration
3.1 Git
3.2 Compiling your module
3.2.1 Modules.am
3.2.2 configure.ac
3.3 Loading your module
4 Out-of-tree module
5 Sub-modules
6 Module types
7 Module load troubleshooting
7.1 Mild version
7.2 Medium version (try this first)
7.3 Extreme version

1、In-tree and out-of-tree modules 

Most existing VLC modules are provided as source code in the directory modules within the main VLC source code repository (and also the source tarballs). 
大多数的现有的VLC模块都是有源码提供的,它们在VLC源码仓库的modules目录下。

They are compiled at the same time as the VLC core, and usually provided distributed together with VLC binary packages and installers. 
他们与VLC核心一起编译,通常和VLC的二进制包一起绑定和安装。

These modules are called in-tree modules.
这样的模块叫做非独立(内嵌)模块

However, it is also possible to write and compile VLC modules outside of VLC. 
然而,在VLC外部一样可以编写和编译VLC模块

That has some pros and cons over developing modules in-tree:
非独立(内嵌)开发模式的模块有下面几个好处和坏处

    Pros好处:
    Compilation is a lot faster (VLC and other modules are not included in the process
    编译速度快很多。

    You can use your own version control system, or even none at all.
    你可以使用你自己版本的控制系统,甚至不用。

    The copyright license does not need to abide by the requirements of the VideoLAN association for inclusion in VLC.
    版权许可证不需要遵守的VideoLAN协会包括VLC的要求

    The source code does not need to be provided, reviewed and accepted by the VLC developers.
    源代码不需要提供,审查和VLC开发商接受。

    The release schedule is independent of VLC releases. New versions of the module can be published at any time regardless of VLC release planning.
    发布计划是独立的VLC版本。该模块的新版本可以发布在任何时间无论VLC发布计划。

    Different programming languages can be used at least in theory. (The main VLC code base only uses C, C++ and Lua, and on MacOS Objective C.)
    在理论上可以使用不同的编程语言。(主要的VLC代码库只使用C,C++和Lua,和MacOS的目的C.)

    The module can use software libraries that would be inadequate for VLC to depend on.
    该模块可以使用VLC信赖的软件库。

    Cons坏处:
    The VLC developers will not review the code, which would be a good opportunity to improve the code quality.
    VLC开发商不会审查代码,这将是一个提高代码质量的好机会。

    VLC translators will not take care of localization for the module(s) where applicable. VLC is translated in many tens of languages.
    VLC译者不会关注这些使用的模块。VLC是翻译成几十种语言。

    The module(s) cannot be distributed through the videolan.org website and use the VideoLAN infrastructure such as the bug tracker and the build bots.
    模块不能分布相关的网站

    The module(s) will only work with the particular VLC (major) version that it has been compiled for.
    模块只能与特定的版本绑定。

    For instance, a module compiled for VLC 1.1.x will not work with VLC 1.0.x or VLC 2.0.x.
    比如,在1.1.x版本的编译模块将不能使用在其他版本上

    The module(s) will only work on the particular operating systems and architecture that it has been compiled for. 
    模块只对已编译的特定操作系统和体系结构进行工作。

    For instance, a Windows 32-bit module will only work with Windows 32-bit versions of VLC. 
    VLC supports many different combinations of operating systems and architectures.

2、Example stub module 例如:stub模块

Let's start with a small example module in the C language:
让我们开始用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);
}
**********************************************代码***********************************************************
And now some explanations about the code...
现在,我们解读这段代码

2.1 Module Descriptor
    模块描述

    A VLC media player module must include a description of itself, and the parameters it accepts.
    一个VLC多媒体播放器模块必须包括一个自身的描述,和他接受什么参数

    The module descriptor begins with:vlc_module_begin()
    模块描述以vlc_module_begin()为标记开始:

    You should set some basic information about your module. This is for the dvdread module:
    你应该为你的模块设置基本的信息。下面这是为dvdread模块的:
        set_shortname(N_("DVD without menus"))
        set_description(N_("DVDRead Input"))
        set_category(CAT_INPUT)
        set_subcategory(SUBCAT_INPUT_ACCESS)

    Note the use of N_("") to create a string that needs to be translated by gettext.
    注意:使用 N_("")去创建一个字符串,这个需要gettext库区翻译。

    2.1.1 Capability and score 类别和等级

        Definition Example:定义示例:
           set_capability("interface", 0)
        This defines a module of "interface" capability and a score of 0.
        这个定义这个模块是interface类别,并且是等级0

        The capability determines the type of module we are dealing with. 
        该类别决定了我们正在处理的模块的类型。

        It could be an access, a demux, a decoder, an interface, etc. Now is the time to re-read how VLC loads modules.
        他可以是an access, a demux, a decoder, an interface等。现在是时候复习一下《how VLC loads modules》

        If VLC needs to load a specific name, it will load it by its name and VLC directly opens this module
        如果VLC需要加载一个特点的名字,它将根据名字加载它,并且VLC会直接打开这个模块。

        If VLC needs a type of module ("I need a decoder"), 
        如果VLC需要一个("I need a decoder")模块,
        VLC will load all modules matching this capability in a decreasing score order until one modules's Open() function (see later) returns VLC_SUCCESS.
        VLC会在加载所有匹配的类别模块,递减score的每个都比较,直到找到一个模块的Open()返回 VLC_SUCCESS。

        See the major types of capabilities of VLC.
        查看VLC主要的类别:详细见VLC如何加module.c的章节(2.Major Capabilities of Modules//模块的主要功能)

        Score should be an integer, and related to other scores in the same category. Score 0 is a special case.
        等级(Score)应该是一个整数,并且与同一个类别下的其它等级相关。等级0是一个特殊的等级。
        (If a module has a score of 0, it needs to be explicitly requested by the user or vlc 
        (like forcing --codec, --vout or module_need("foo")) to be loaded.)


    2.1.2 Configuration categories and sub-categories配置类别和子类别
        You should use one of the predefined categories for configuration.
        您应该使用下列预定义的类别之一进行配置。
        The configuration categories and sub-categories specify where the module will appear in the preferences UI dialog.
        配置类别和子类别将指定模块出现在首选项UI对话框中的位置。

        The configuration categories include:配置的类别有一下几种:
        CAT_INTERFACE
        CAT_AUDIO
        CAT_VIDEO
        CAT_INPUT
        CAT_SOUT
        CAT_ADVANCED
        CAT_PLAYLIST

        You should use one of predefined sub-categories as well. 
        你应该使用预定于的子类别
        See include/vlc_configuration.h for definition of all configuration categories and sub-categories.
        在头文件include/vlc_configuration.h中定义了所有的类别和子类别

    2.1.3 Configuration parameters 配置参数
        You may need options to configure the run-time behavior of your module. Defining new options is easy.
        您可能需要选项来配置模块的运行时行为。定义新选项很容易。

        All option definitions take the following argument list:
        所有选项定义都包含以下参数列表:
         add_integer(name, value, text, longtext, advanced) 

        name is the string that identifies this parameter in the configuration. This name is used at the command prompt to set the configuration value.
        参数name:name是一个在配置中定义这个参数字符串。这个name是用于在命令行设置配置的值。

        value is the default value for this parameter,
        参数value:value是参数的默认值

        text A short description of the parameter, use _("") to create a string that needs to be translated,
        参数text:是对参数的简短描述,使用_("")来创建字符串需要被翻译

        longtext A complete description of the parameter, use _("") to create a string that needs to be translated,
        参数longtext:是对参数的完整描述,使用_("")来创建字符串需要被翻译

        advanced Boolean, ADVanced Configuration. If TRUE, this parameter will only be displayed when using the --advanced flag.
        参数advanced:是一个布尔变量。高级配置。如果是真,这个参数将在使 --advanced flag.是显示。

        You may add the following options/parameter types to your module:
        你可能添加下列的参数类型到你的模型中:
        add_integer,
        add_string,
        add_float,
        add_bool,
        add_key,
        add_file,
        add_directory,

        For complete definitions, see include/vlc_plugin.h
        在头文件include/vlc_plugin.h中有完整的定义,可以查看。

    2.1.4 Callback
        The activation and deactivation functions, detailed afterwards, must be defined in the descriptor. 
        激活和失活函数,在详细之后,必须在描述符中定义。

        This is so that the VLC core knows how to instantiate and run the module.
        这样做方便VLC核心知道如何实例化和运行模块。

        The set_callbacks() macro allows you to define 2 parameters: 
        set_callbacks()宏允许你定义两个参数:

        the first parameter is the pf_activate callback, and the second one, pf_deactivate. 
        第一个参数是pf_activate回调,第二个,pf_deactivate。

        The functions are most often called "Open" and "Close" respectively, though. 
        这两个函数通常称为“Open”和“Close”

        VLC invokes the pf_activate callback if/when it needs a plugin instance providing the correct interface, as declared with the set_capability() macro.
        当VLC需要一个插件实例提供正确的接口时,VLC引用这个 pf_activate回调函数,在set_capability()宏中宣告。

        Conversely, VLC invokes the pf_deactivate callback when the plugin is no longer needed - but only if the pf_activate callback returned VLC_SUCCESS (0) earlier.
        相反,当VLC不需要插件的时候,VLC引用 pf_deactivate。只有在引用pf_activate回调函数返回VLC_SUCCESS的前提下。



2.2 Open(vlc_object_t *)
    The most important function of a module is the opening: the usually-named Open() function.
    一个模块最重要的函数就是这个opening:习惯命名函数为Open()
    static int  Open ( vlc_object_t * );

    The Open() function is called when the VLC core tries to open the module, and wants to load it.
    当VLC核心试图打开或者加载它是会调用Open()函数

    During Open(), setup of structures, devices or I/O, checks should be done. 
    在open()中,设置结构体,设备或者I/O, 检查
    A successful open should return VLC_SUCCESS.
    调用成功会返回VLC_SUCCESS

     If the module cannot complete its initialization, it can return any other value, usually VLC_EGENERIC or VLC_ENOMEM.
     如果模块不能完成初始化,他将返回其他任意值,通常返回VLC_EGENERIC or VLC_ENOMEM.

    The Open() function is expected to allocate private data (if any), and set up the private structure.
    在Open()函数中预期申请私有数据的内存,并实例化。

    If the Opening fails, you may need to free any already allocated resources before returning. Otherwise, leaks will occur.
    如果Open()打开失败,你必须释放所有已经申请的内存再返回,否则导致段错误。

2.3 Close(vlc_object_t *)
    The second most important function of a module is the closing: the usually-named Close() function.
    static int  Close ( vlc_object_t * );
    The Close() function is called when the VLC core tries to close or unload an already-loaded module.
    NB: If the Open() function failed, Close() will not get called.
    During Close(), closing devices or I/O, and cleaning of structures should be done. Do not leak memory here!
    The Close() function should deallocate private data.

3、 In-tree module integration
非独立(内嵌)模块的集成

3.1 Git
    If you plan to submit your work to VLC upstream, be sure to look at the git introduction and check the send patches part.
    如果你计划将你的作品添加到VLC的发展流中,请确保你阅读了《 the git introduction》和检查了《 send patches part》部分
3.2 Compiling your module 编译你的模块
    3.2.1 Modules.am
        First, find the right subdirectory under modules/ to add your new code.
        首先,在modules/的目录下找到正确的子目录来添加新代码

        If the module has only one source code file module, simply add it in the subdirectory (e.g. modules/control/hello.c).
        如果新的模块只有一个源代码文件模块,只需将其添加到子目录中(例如模块/控制/ hello)。

        Larger modules should get a sub-subdirectory of their own (e.g. modules/control/hello/*).      */
        比较庞大的模块应该为他们新建一个目录。

        Then you need to declare the module in the build system. 
        然后比必须在构建系统中声明此模块

        For example, the file modules/control/Modules.am tells the build system which source files are needed for each control module.
        比如,在modules/control/Modules.am文件中告诉编译系统对于每个控制模块哪一个源文件是必须的。

         For the example above, we could add these lines:
         比如上面的例子,我们可以添加下面这几行:

        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

        Note that indentation in Modules.am (if needed) uses tabulations (ASCII 0x09), not white spaces.
        注意:在Modules.am(如果需要)请使用tab键,不要使用空格键。

    3.2.2 configure.ac
        If the module depends on some new library, some architecture or some operating system characteristics, 
        you may need to extend configure.ac to detect when and how to build the module. Refer to the configure.ac file and 
        the GNU autoconf documentation for details.
        如果新的模块依赖一些新的库,某些体系结构或某些操作系统特性,
        你可能需要延长configure.ac检测时,如何建立模块。指的是configure.ac文件
        GNU autoconf文件详情。

        Once this is done, you should only need to rebuild VLC:
        一旦这些做完,你应该重新编译VLC

        make //输入指令make
        (This will probably trigger a re-run of autoconf and automake, so it might take a while.)
        (这可能会触发一个autoconf和automake重新运行,所以它可能需要一段时间。)

3.3 Loading your module 加载自己编写的模块
    VLC keeps a cache of available modules for performance reasons. 
    VLC为可用模块保持了一个缓冲区以便提高模块加载性能。

    It should be updated automatically. But you can use ./vlc --reset-plugins-cache to force a reset.
    他应该是自动更新的,但是,你可以使用./vlc --reset-plugins-cache进行设置。

    Then use
    然后使用:

    ./vlc -vvv --color --list

    to check that your plugin is seen by VLC media player.
    来检查你的插件被VLC媒体播放器检测到了。

    You should also see it in the plugins dialog of the Qt interface (Linux and Windows).
    你同样可以在QT窗口的插件栏找到他

4、 Out-of-tree module//独立(非嵌入式)模块

There is a dedicated article. Please read out of tree compilation.
这有一篇专门介绍Out-of-tree模块编译的文章,请阅读《tree compilation》链接地址:《OutOfTreeCompile自有模块的编译.c》

5、 Sub-modules
子模块

Sub-modules, declared in some module descriptors with
子模块,一些模块的描述如下:

add_submodule()

work exactly the same way as modules.
 They are useful when different modules (usually but not necessarily of different capability) share common code.
 All sub-modules will be included in the same run-time library as the main module.
 与模块的工作方式完全相同。
当不同的模块(通常但不一定是不同的功能)共享公共代码时,它们是有用的。
所有子模块将包含在与主模块相同的运行时库中。

6、 Module types
模块的类型

Depending on the module capability, you will need more information, about the necessary functions to implement.
根据模块的功能,您需要更多的信息,实现所需的功能。

We will detail those here:
我们详细列出:

Access
Demux
Access_Demux
Decoder
Interface
Video filter
Video output
Audio filter
Audio output

7、Module load troubleshooting
加载模块时出现的错误

Sometimes when building an in-tree module, stuff doesn't work due to build system problems and other inconsistencies.
You probably need to go to the root of your VLC source tree, and do something akin to the following. The examples here assume the bash shell.
7.1 Mild version
    In some cases, automake dependencies break (for instance after some filenames have changed). This might then work:
    find . -name .deps -exec rm -rf \{\} \;
    ./config.status
    make
    ...but not always, so it may save some headaches to always use the "medium version" below.
7.2 Medium version (try this first)
    This is a more radical but still safe rebuild procedure:
    find . -name .deps -exec rm -rf \{\} \;
    ./bootstrap
    ./configure
    make
7.3 Extreme version
    If the none of the above helped, you can clean the source tree as a measure of last resort. Before you proceed, it is highly recommended that you check which files are going to be erased:
    git clean -nxd
    And then check what source code changes you would lose (if any):
    git diff
    You can extremely easily lose entire days of hard work with the following commands. The first command will permanently remove any files not tracked in git, including files that you might have created yourself. The second command will remove any uncommitted modification to existing files. Consider yourself warned.
    !!!BEWARE: THIS MAY CAUSE UNRECOVERABLE DATA LOSS!!!
    git clean -fxd
    git reset --hard HEAD
    ./bootstrap
    ./configure
    make
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章