vlc應用編程

VLC應用編程:

一、如何調用一個模塊及插件。

我們知道VLC的整體框架是設計成一套module的管理機制,將功能分類並抽象成modules。所以我們在應用編程時主要調用相應的模塊即可。
如果要調用相應的模塊,我們必須知道如何調用一個模塊。

在《VLC介紹中》中,我們知道VLC加載模塊的原理是根據類別(the capability)和優先級(the score)來加載模塊的。我們知道VLC有許多模塊,每個模塊又可以有適用於不同功能的函數,那麼VLC具體是怎麼取到自己需要的模塊及模塊中的插件呢?

1.1 VLC如何加載模塊
打開vlc\src\modules,在這個文件夾下有一些用於管理模塊的文件。
bank.c : Modules list 模塊列表
cache.c: Plugins cache 插件緩存
entry.c : Callbacks for module entry point 指向每個模塊的回調函數
modules.c : Builtin and plugin modules management functions 內置和插件管理功能
modules.h : Module management functions. 模塊管理函數
textdomain.c : Modules text domain management 模塊文本域管理
通過各個文件的描述我們知道每個文件的功能。在文件vlc\src\modules\Modules.c中,封裝函數會加載相應的模塊,主要原理是打開相應的模塊庫,然後根據函數指針,實現模塊的動態加載。下面是函數的執行步驟:
static int module_load (vlc_object_t *obj, module_t *m, vlc_activate_t init, va_list args)
{
…….
if (module_Map(obj, m->plugin))
…….

}
int module_Map(vlc_object_t *obj, vlc_plugin_t *plugin)
{
if (module_Load(obj, plugin->abspath, &handle, false))

module_Lookup(handle, vlc_entry_name);

}
int module_Load (vlc_object_t *p_this, const char *path,
module_handle_t *p_handle, bool lazy)
{
module_handle_t handle = dlopen (path, flags);
}
void *module_Lookup( module_handle_t handle, const char *psz_function )
{
return dlsym( handle, psz_function );
}

1.2libVLCcore對外接口API

上面只是揭示了vlc\src\modules\如何打開模塊及調用加載模塊的方法,現在我們使用模塊時只需要知道API即可。現在列出管理模塊的主要API:
序號 函數 功能
1 module_provides Checks whether a module implements a capability.
2 module_get_object Get the internal name of a module
3 module_get_name Get the human-friendly name of a module.
4 module_get_help Get the help for a module
5 module_get_capability Gets the capability of a module
6 module_get_score Get the score for a module
7 module_gettext Translate a string using the module’s text domain
8 module_start 啓動模塊
9 module_stop 關閉模塊
10 module_match_name
11 module_need 主要用於動態加載模塊
12 vlc_module_load 主要是封裝函數,供libvlc調用。
13 vlc_module_unload 主要是封裝函數,供libvlc調用。
14 module_find Get a pointer to a module_t given it’s name
15 module_exists Tell if a module exists
16 module_config_get Get the configuration of a module
17 module_config_free Release the configuration

二、創建一個簡單的播放器

在vlc源碼中有一個簡單了vlc播放器的例子,源碼位置:vlc\bin\vlc.c。
在這個例子中主要調用了libVLC封裝的兩個API:vlc = libvlc_new (argc, argv)函數和libvlc_playlist_play (vlc, -1, 0, NULL)函數,其次初始化信號並配置好線程的通知信號,因爲線程會調用sigwait()等待自己的信號,根據信號進行相應的操作。
libvlc_new函數和libvlc_playlist_play函數的具體調用流程在下一篇文章跟蹤。
這個例子主要是根據命令行輸入的參數,用默認的界面播放視頻。主要調用了三個封裝好的libVLC函數,vlc = libvlc_new (argc, argv)函數用於創建一個播放器,ibvlc_playlist_play()用於開始播放視頻,libvlc_add_intf()函數用於增加一個控制接口。
源碼:
int main( int i_argc, const char *ppsz_argv[] )
{
/* The so-called POSIX-compliant MacOS X reportedly processes SIGPIPE even
* if it is blocked in all thread.
* Note: this is NOT an excuse for not protecting against SIGPIPE. If
* LibVLC runs outside of VLC, we cannot rely on this code snippet. */
signal (SIGPIPE, SIG_IGN);
/* Restore SIGCHLD in case our parent process ignores it. */
signal (SIGCHLD, SIG_DFL);

ifndef NDEBUG

/* Activate malloc checking routines to detect heap corruptions. */
setenv ("MALLOC_CHECK_", "2", 1);
/* Disable the ugly Gnome crash dialog so that we properly segfault */
setenv ("GNOME_DISABLE_CRASH_DIALOG", "1", 1);

endif

ifdef TOP_BUILDDIR

setenv ("VLC_PLUGIN_PATH", TOP_BUILDDIR"/modules", 1);
setenv ("VLC_DATA_PATH", TOP_SRCDIR"/share", 1);

endif

/* Clear the X.Org startup notification ID. Otherwise the UI might try to
 * change the environment while the process is multi-threaded. That could
 * crash. Screw you X.Org. Next time write a thread-safe specification. */
unsetenv ("DESKTOP_STARTUP_ID");

ifndef ALLOW_RUN_AS_ROOT

if (geteuid () == 0)
{
    fprintf (stderr, "VLC is not supposed to be run as root. Sorry.\n"
    "If you need to use real-time priorities and/or privileged TCP ports\n"
    "you can use %s-wrapper (make sure it is Set-UID root and\n"
    "cannot be run by non-trusted users first).\n", ppsz_argv[0]);
    return 1;
}

endif

setlocale (LC_ALL, "");
if (isatty (STDERR_FILENO))
    /* This message clutters error logs. It is printed only on a TTY.
     * Fortunately, LibVLC prints version info with -vv anyway. */
    fprintf (stderr, "VLC media player %s (revision %s)\n",
             libvlc_get_version(), libvlc_get_changeset());
sigset_t set;
sigemptyset (&set);
/* VLC uses sigwait() to dequeue interesting signals.
 * For this to work, those signals must be blocked in all threads,
 * including the thread calling sigwait() (see the man page for details).
 *
 * There are two advantages to sigwait() over traditional signal handlers:
 *  - delivery is synchronous: no need to worry about async-safety,
 *  - EINTR is not generated: other threads need not handle that error.
 * That being said, some LibVLC programs do not use sigwait(). Therefore
 * EINTR must still be handled cleanly, notably from poll() calls.
 *
 * Signals that request a clean shutdown, and force an unclean shutdown
 * if they are triggered again 2+ seconds later.
 * We have to handle SIGTERM cleanly because of daemon mode. */
sigaddset (&set, SIGINT);
sigaddset (&set, SIGHUP);
sigaddset (&set, SIGQUIT);
sigaddset (&set, SIGTERM);
/* SIGPIPE can happen and would crash the process. On modern systems,
 * the MSG_NOSIGNAL flag protects socket write operations against SIGPIPE.
 * But we still need to block SIGPIPE when:
 *  - writing to pipes,
 *  - using write() instead of send() for code not specific to sockets.
 * LibVLC code assumes that SIGPIPE is blocked. Other LibVLC applications
 * shall block it (or handle it somehow) too.
 */
sigaddset (&set, SIGPIPE);
/* SIGCHLD must be dequeued to clean up zombie child processes.
 * Furthermore the handler must not be set to SIG_IGN (see above).
 * We cannot pragmatically handle EINTR, short reads and short writes
 * in every code paths (including underlying libraries). So we just
 * block SIGCHLD in all threads, and dequeue it below. */
sigaddset (&set, SIGCHLD);
/* Block all these signals */
pthread_t self = pthread_self ();
pthread_sigmask (SIG_SETMASK, &set, NULL);
const char *argv[i_argc + 3];
int argc = 0;
argv[argc++] = "--no-ignore-config";
argv[argc++] = "--media-library";

ifdef HAVE_DBUS

argv[argc++] = "--dbus";

endif

ppsz_argv++; i_argc--; /* skip executable path */

ifdef OS2

for (int i = 0; i < i_argc; i++)
    if ((argv[argc++] = FromSystem (ppsz_argv[i])) == NULL)
    {
        fprintf (stderr, "Converting '%s' to UTF-8 failed.\n",
                 ppsz_argv[i]);
        return 1;
    }

else

memcpy (argv + argc, ppsz_argv, i_argc * sizeof (*argv));
argc += i_argc;

endif

argv[argc] = NULL;
vlc_enable_override ();
/* Initialize libvlc */
libvlc_instance_t *vlc = libvlc_new (argc, argv);
if (vlc == NULL)
    return 1;
int ret = 1;
libvlc_set_exit_handler (vlc, vlc_kill, &self);
libvlc_set_app_id (vlc, "org.VideoLAN.VLC", PACKAGE_VERSION, PACKAGE_NAME);
libvlc_set_user_agent (vlc, "VLC media player", "VLC/"PACKAGE_VERSION);
libvlc_add_intf (vlc, "hotkeys,none");

if !defined (OS2)

libvlc_add_intf (vlc, "globalhotkeys,none");

endif

if (libvlc_add_intf (vlc, NULL))
    goto out;
libvlc_playlist_play (vlc, -1, 0, NULL);
/* Qt insists on catching SIGCHLD via signal handler. To work around that,
 * unblock it after all our child threads are created. */
sigdelset (&set, SIGCHLD);
pthread_sigmask (SIG_SETMASK, &set, NULL);
/* Do not dequeue SIGHUP if it is ignored (nohup) */
if (signal_ignored (SIGHUP))
    sigdelset (&set, SIGHUP);
/* Ignore SIGPIPE */
sigdelset (&set, SIGPIPE);
int signum;
sigwait (&set, &signum);
/* Restore default signal behaviour after 3 seconds */
sigemptyset (&set);
sigaddset (&set, SIGINT);
sigaddset (&set, SIGALRM);
signal (SIGINT, SIG_IGN);
signal (SIGALRM, exit_timeout);
pthread_sigmask (SIG_UNBLOCK, &set, NULL);
alarm (3);
ret = 0;
/* Cleanup */

out:
libvlc_release (vlc);

ifdef OS2

for (int i = argc - i_argc; i < argc; i++)
    free (argv[i]);

endif

return ret;

}

三、libVLC常用API列表:

具體的API列表我們可以在include\vlc目錄下查看頭文件。每個文件封裝的API具體用途如下:
序號 文件描述
1 deprecated.h: libvlc deprecated API
2 libvlc.h: libvlc external API
3 libvlc_dialog.h: libvlc dialog API
4 libvlc_events.h: libvlc_events external API structure
5
libvlc_media.h: libvlc external API
6 libvlc_media_discoverer.h: libvlc external API
7 libvlc_media_library.h: libvlc external API
8 libvlc_media_list.h: libvlc_media_list API
9 libvlc_media_list_player.h: libvlc_media_list API
10 libvlc_media_player.h: libvlc_media_player external API
11 libvlc_renderer_discoverer.h: libvlc external API
12 libvlc_vlm.h: libvlc_* new external API
13 vlc.h: global header for libvlc
總結,我們使用vlc做爲內核編寫播放器時,我們可以不管其內部如何實現,直接調用上述API即可。如果我們需要修改內核時,也僅僅需要修改或增加相應的模塊即可。注意編譯過程中加需要的模塊添加的vlc內核中。

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