前面大致的了解了 vlc 解码器开发的过程以及 vlc-h265 插件开发的实例,于是开始尝试开发一个支持 avs2 标准的 vlc 播放器
- 拓展阅读:播放器插件实现系列 —— vlc
- 拓展阅读:Hacker Guide/How To Write a Module
- 扩展阅读:VLC Developers site
- 需要资源:vlc Github仓库地址
1 内部模块注册
1.1 注册声明
vlc 的模块注册是一套标准的流程,我们的类型应当选择解码器 “Decoder”,在我们的核心 .c 文件中添加:
vlc_module_begin ()
set_category( CAT_VIDEO )
set_description( N_("avs2 Decoder library") )
set_capability( "decoder", 100 )
set_callbacks( Open, Close )
vlc_module_end ()
ps :这里的 N_() 是用于创建一个可以被 gettext 轻松转换的字符串(语种之类的)的形式
- set_category::标明这个模块起作用的地方(video)
- set_description:模块的描述,添加成功后可以在 ./vlc --list 中显示
- set_capability:功能与评分,这里下面会细讲
- set_callbacks:调用模块时的入口与出口(开关函数)
1.2 功能与评分
set_capability 函数是一开始困惑了我挺久的一个函数,因为我一直不知道后面这个 score 到底要怎么算...
第一个参数很好理解,我们作为一个解码器功能自然是 "decoder" ,而第二个参数需要的是一个 score,不同的模块可以选择不同的 socre(对没错,是自己选的),主要功能就是当 vlc 需要一个功能的时候(比如解码),他会大喊一声:“解码器!”,然后所有解码器们就开始排队,排队的依据就是他们的 score ,高个在前,然后由 vlc 给出对应的格式询问。
这个过程中排队主要的意义就是优先选择更愿意接受某种格式的模块,比如同样支持 .bin 格式的两个模块,一个 score=100 ,一个 score=50 ,最后的结果就是选择前一个。
当然这里面就有了一个特例—— score=0,在这种情况下这个模块只有被用户或 vlc 明确指定的情况下才会被加载,否则不参与前面的排队。
2 定义自己的模块主体
注册之后主要实现解码器的逻辑与功能,这部分 emmm..... 没法记,主要就是定义一个自己的数据结构体(上下文之类的),然后实现 Open、Close函数以及我们的 DecoderBlock,完成内部的调用或者其他逻辑。具体实现参照可以参考最开始的第一个拓展阅读。
3 模块正式注册
模块的正式注册就是在 vlc 的模块列表里正式添加我们的模块,必须修改的文件一个是 vlc/configure.ac 一个是 vlc/modules/codec/Makefile.am (我们的核心代码与这个 Makefile.am 应该在同一目录下)。
3.1 configure.ac
这个文件主要是在 autoconf 中设置 vlc ,我们在里面加入一段我们自己的配置:
dnl
dnl AVS2 decoder module
dnl
AC_ARG_ENABLE(avs2,
[ --enable-avs2 AVS2 support (default disabled)])
AS_IF([test "${enable_avs2}" != "no"], [
AC_CHECK_HEADERS(cavs2dec.h, [
VLC_ADD_PLUGIN([avs2])
])
])
这里面 dnl 就是注释的意思,AC_ARG_ENABLE 是在编译过程中是否编译该模块的选择,如果进行编译,则检查头文件:cavs2dec.h,头文件存在则执行 VLC_ADD_PLUGIN([avs2]) ,不存在则--(没写,需要的话可以写在第三个参数上)。
3.2 Makefile.am
这个文件是在 make 过程中的模块加载,我们也添加一下:
### AVS2 Decoder Module ###
libavs2dec_plugin_la_SOURCES = codec/cavs2dec.c
libavs2dec_plugin_la_CPPFLAGS = $(AM_CPPFLAGS)
libavs2dec_plugin_la_CFLAGS = $(AM_CFLAGS)
libavs2dec_plugin_la_LDFLAGS = $(AM_LDFLAGS)
libavs2dec_plugin_la_LIBADD = $(LIBM) -lpthread -lcavs2dec
codec_LTLIBRARIES += libavs2dec_plugin.la
我们编译最终生成的的插件文件名字叫做 libavs2dec_plugin.la ,一定要注意上面的配置语句要和我们最终的名称匹配。SOURCE 是我们刚刚编写的核心代码,CFLAGS、CPPFLAGS、LDFLAGS 使我们在编译过程中需要的头文件和优化项(没啥特殊需求就和其他模块一样),LIBADD 使我们额外需要添加的编译依赖,这里我们需要 m、pthread 以及暂时在本地 install 过的 cavs2dec 。
4 编译与查询
编译进新模块和查询的指令:
./bootstrap
./configure --enable-avs2
make
./vlc -vvv --color --list | grep avs
一定要运行一下 ./bootstrap ,因为我们更改了 configure.ac ,这里面主要是执行了一些 autoconf 命令。
顺利运行后我们找到了我们刚刚加入的模块:
...
avs2dec avs2 Decoder library
...
5 加入我们的解码器(TS)
5.1 ts.c
/* check only MPEG2, H.264, AVS2 and VC-1 */
if( p_es->fmt.i_codec != VLC_CODEC_MPGV &&
p_es->fmt.i_codec != VLC_CODEC_H264 &&
p_es->fmt.i_codec != VLC_CODEC_AVS2 &&
p_es->fmt.i_codec != VLC_CODEC_VC1 )
continue;
5.1 ts_psi.c
p_regs[] = {
{ "AC-3", AUDIO_ES, VLC_CODEC_A52 },
{ "EAC3", AUDIO_ES, VLC_CODEC_EAC3 },
// ……
{ "avs2", VIDEO_ES, VLC_CODEC_AVS2 },
{ "", UNKNOWN_ES, 0 }
switch( i_stream_type )
{
case 0x01: /* MPEG-1 video */
es_format_Change( fmt, VIDEO_ES, VLC_CODEC_MPGV );
fmt->i_original_fourcc = VLC_CODEC_MP1V;
break;
case 0x02: /* MPEG-2 video */
// ……
case 0x42: /* CAVS (Chinese AVS) */
es_format_Change( fmt, VIDEO_ES, VLC_CODEC_CAVS );
break;
case 0x43: /* AVS2 (Chinese AVS2) */
case 0xd2:
es_format_Change( fmt, VIDEO_ES, VLC_CODEC_AVS2 );
break;
5.3 fourcc
#define VLC_CODEC_AVS2 VLC_FOURCC('A','V','S','2')
B(VLC_CODEC_CAVS, "Chinese AVS"),
A("CAVS"),
6 小插曲—— vlc 界面问题
git clone 了 vlc 的 master (v4.0.0)之后编译运行 ./vlc 不显示界面,只能在命令行界面下运行。
仔细看了一下编译结束后的输出信息发现有特别多需要的包并没有被安装(开始时是跟着编译缺包的信息装的),后来在师兄提醒下用了 apt-get build-dep vlc 命令轻松地安上了很多需要的依赖,当然有时候会提醒未指定 deb-src 的问题,需要把 /etc/apt/sources.list 里面必要的语句解除注释。
再次编译后输出:
libvlc configuration
--------------------
version : 4.0.0-dev
system : linux
architecture : x86_64 mmx sse sse2
optimizations : yes
vlc aliases : cvlc rvlc
在 vlc 的 Makefile.am 里可以找到
cvlc: make-alias Makefile
$(AM_V_GEN)$(MKALIAS) dummy
rvlc: make-alias Makefile
$(AM_V_GEN)$(MKALIAS) rc
svlc: make-alias Makefile
$(AM_V_GEN)$(MKALIAS) skins2
qvlc: make-alias Makefile
$(AM_V_GEN)$(MKALIAS) qt
nvlc: make-alias Makefile
$(AM_V_GEN)$(MKALIAS) ncurses
也就是说我们用于显示界面的很重要的 qvlc 没有被编译进来。
于是在安装完 QT5 后进行编译时候使用命令
./configure --enable-qt
出现了一个错误
# include QPNI_HEADER 不存在这个文件或目录
这个错误大概是 wayland 与 xwindow 的原因导致头文件生成出现了问题,于是最终编译命令就变成了
./configure --enable-debug --enable-qt --disable-wayland --enable-avs2
最后终于成功啦~
附成果截图: