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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章