gstreamer移植qnx:交叉编译qnx版本的gstreamer插件库
Posted 玄道公子
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了gstreamer移植qnx:交叉编译qnx版本的gstreamer插件库相关的知识,希望对你有一定的参考价值。
一、简介
要移植gstreamer到qnx系统,除了本身的libgstreamer之外,还需要编译相关的插件库,比如编解码库,比如各种音视频容器库。
二、 编译plugin base 库
这里笔者一开始使用的和libgstreamer库一样,使用configure的方式,写一个myconfig.sh来编译,但是发现编译出来的plugin library会带有rpath的硬依赖路径,因此这里尝试了另一种方式, 和编译glib一样,使用meson交叉编译,写一个qnx_arm.txt的 cross file文件,其内容如下:
[host_machine]
system = 'qnx'
cpu_family = 'arm'
cpu = 'armv7'
endian = 'little'
[binaries]
c = 'arm-unknown-nto-qnx6.6.0eabi-gcc'
cpp = 'arm-unknown-nto-qnx6.6.0eabi-g++'
ar = 'arm-unknown-nto-qnx6.6.0eabi-ar'
strip = 'arm-unknown-nto-qnx6.6.0eabi-strip'
pkgconfig = 'pkg-config'
[properties]
c_args = ['-D_QNX_SOURCE=1']
c_link_args = ['-lsocket', '-L/media/guwen/workspace/project/gstreamer/out/lib',
'-lgobject-2.0', '-lgio-2.0', '-lgmodule-2.0', '-lffi']
cpp_args = ['-D_QNX_SOURCE=1']
cpp_link_args = ['-lsocket', '-L/media/guwen/workspace/project/gstreamer/out/lib',
'-lgobject-2.0', '-lgio-2.0', '-lgmodule-2.0', '-lffi']
[paths]
prefix = '/media/guwen/workspace/project/gstreamer/out'
除了cross file文件之外,还需要修改 meson.build文件,其修改部分如下:
default_options : [ 'warning_level=1',
'buildtype=release', # 修改编译类型为release
'gtk_doc=disabled', # 禁用gtk_doc
'alsa=disabled', # 禁用alsa
'x11=disabled', # 禁用x11
'pango=disabled', # 禁用pango
'orc=disabled' # 禁用orc
])
另外,还需要设置pkg config 的路径:
export PKG_CONFIG_LIBDIR=/media/guwen/workspace/project/gstreamer/out/lib/pkgconfig
注: 若果设置成了
export PKG_CONFIG_PATH=/media/guwen/workspace/project/gstreamer/out/lib/pkgconfig
就必须要在再设置PKG_CONFIG_LIBDIR, 因为如果只设置了PKG_CONFIG_PATH路径, pkg-config在这个路径搜索之后,再到PKG_CONFIG_LIBDIR(这个就会是寄主系统默认路径,Ubuntu的/usr/lib/pkgconfig等等)这个路径搜索, 因此一定要设置PKG_CONFIG_LIBDIR变量,以防止pkg-config到系统默认路径去搜索。
接下来也就是配置,编译,安装:
mkdir build
cd build
meson .. --cross-file ../qnx_arm.txt
ninja
ninja install
三、编译plugin good 库
plugin good库也是使用meson进行编译的,首先是qnx_arm.txt这个cross file的编写,其内容如下:
[host_machine]
system = 'qnx'
cpu_family = 'arm'
cpu = 'armv7'
endian = 'little'
[binaries]
c = 'arm-unknown-nto-qnx6.6.0eabi-gcc'
cpp = 'arm-unknown-nto-qnx6.6.0eabi-g++'
ar = 'arm-unknown-nto-qnx6.6.0eabi-ar'
strip = 'arm-unknown-nto-qnx6.6.0eabi-strip'
pkgconfig = 'pkg-config'
[properties]
c_args = ['-D_QNX_SOURCE=1']
c_link_args = ['-lsocket', '-L/media/guwen/workspace/project/gstreamer/out/lib',
'-lgobject-2.0', '-lgio-2.0', '-lgmodule-2.0', '-lglib-2.0', '-lintl',
'-lffi']
cpp_args = ['-D_QNX_SOURCE=1']
cpp_link_args = ['-lsocket', '-L/media/guwen/workspace/project/gstreamer/out/lib',
'-lgobject-2.0', '-lgio-2.0', '-lgmodule-2.0', '-lglib-2.0', '-lintl',
'-lffi']
[paths]
prefix = '/media/guwen/workspace/project/gstreamer/out'
然后是meson.build修改:
default_options : [ 'warning_level=1',
'buildtype=release', #修改编译类型为release
'c_std=gnu99', #修改c语言标准为99标准
'mpg123=enabled' #使能mp3 audio decoder
])
3.1 编译mpg123
首下载mpg123库源码 http://www.mpg123.de/download/mpg123-1.25.13.tar.bz2 ,这里使用的是最新的1.25.13版本。
mpg123使用的也是configure,make的方式。 因此为了方便,先编写myconfig.sh脚本文件,其内容如下:
./configure --prefix=/media/guwen/workspace/project/gstreamer/out \\
--build=i686-linux --host=arm-unknown-nto-qnx6.6.0eabi
接下来就是编译和安装:
make
make install
3.2 修改编译错误
- 修改源文件gst/flx/gstflxdec.c
/** 原始版本 882行 */
if (!flx_decode_chunks (flxdec, n_chunks, &chunks, &writer))
GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
("%s", "Could not decode chunk"), NULL);
goto unmap_input_error;
/
/** 修改之后的版本 */
if (!flx_decode_chunks (flxdec, n_chunks, &chunks, &writer))
GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
("%s", "Could not decode chunk"), (NULL));
goto unmap_input_error;
/
/
/** 原始版本 894行 */
out = gst_buffer_new_and_alloc (flxdec->size * 4);
if (!gst_buffer_map (out, &map, GST_MAP_WRITE))
GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
("%s", "Could not map output buffer"), NULL);
gst_buffer_unref (out);
goto unmap_input_error;
/
/** 修改之后的版本 */
out = gst_buffer_new_and_alloc (flxdec->size * 4);
if (!gst_buffer_map (out, &map, GST_MAP_WRITE))
GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
("%s", "Could not map output buffer"), (NULL));
gst_buffer_unref (out);
goto unmap_input_error;
- 修改文件 gst/multifile/gstsplitmuxsink.c
/** 原始版本 1564行 */
GST_ELEMENT_ERROR (splitmux, RESOURCE, SETTINGS,
("Could not create the new muxer/sink"), NULL);
/
/** 修改之后的版本 */
GST_ELEMENT_ERROR (splitmux, RESOURCE, SETTINGS,
("Could not create the new muxer/sink"), (NULL));
/
/
/** 原始版本 1753行 */
GST_ELEMENT_ERROR (splitmux, RESOURCE, SETTINGS,
("Could not create the new muxer/sink"), NULL);
/
/** 修改之后的版本 */
GST_ELEMENT_ERROR (splitmux, RESOURCE, SETTINGS,
("Could not create the new muxer/sink"), (NULL));
- 修改文件gst/rtp/gstrtpj2kdepay.c
/** 原始版本 211行 */
GST_ELEMENT_WARNING (depayload, STREAM, DEMUX, NULL,
("Non-compliant stream: sampling field missing. Frames my appear incorrect"));
/
/** 修改之后的版本 */
GST_ELEMENT_WARNING (depayload, STREAM, DEMUX, (NULL),
("Non-compliant stream: sampling field missing. Frames my appear incorrect"));
3.3 编译
和前面一样,流程是一样的:
export PKG_CONFIG_LIBDIR=/media/guwen/workspace/project/gstreamer/out/lib/pkgconfig
mkdir build
cd build
meson .. --cross-file ../qnx_arm.txt
ninja
ninja install
四、编译plugin bad库
qnx_arm.txt这个cross file的内容如下:
[host_machine]
system = 'qnx'
cpu_family = 'arm'
cpu = 'armv7'
endian = 'little'
[binaries]
c = 'arm-unknown-nto-qnx6.6.0eabi-gcc'
cpp = 'arm-unknown-nto-qnx6.6.0eabi-g++'
ar = 'arm-unknown-nto-qnx6.6.0eabi-ar'
strip = 'arm-unknown-nto-qnx6.6.0eabi-strip'
pkgconfig = 'pkg-config'
[properties]
c_args = ['-D_QNX_SOURCE=1']
c_link_args = ['-lsocket', '-L/media/guwen/workspace/project/gstreamer/out/lib',
'-lgobject-2.0', '-lgio-2.0', '-lgmodule-2.0','-lgstrtp-1.0',
'-lffi']
cpp_args = ['-D_QNX_SOURCE=1']
cpp_link_args = ['-lsocket', '-L/media/guwen/workspace/project/gstreamer/out/lib',
'-lgobject-2.0', '-lgio-2.0', '-lgmodule-2.0','-lgstrtp-1.0',
'-lffi']
[paths]
prefix = '/media/guwen/workspace/project/gstreamer/out'
meson.build 文件修改:
default_options : [ 'warning_level=1',
'buildtype=release' ]) #修改编译类型为release
4.1 修改编译错误
和plugin good一样,配置完成之后,编译会有错误需要修正。
- 修改文件gst/timecode/gstavwait.c
/** 原始版本 1128行 */
GST_ELEMENT_ERROR (self, CORE, FAILED,
("Failed to clip audio: it should have ended before the current segment"),
NULL);
/
/** 修改之后的版本 */
GST_ELEMENT_ERROR (self, CORE, FAILED,
("Failed to clip audio: it should have ended before the current segment"),
(NULL));
- 修改文件 gst/videoparsers/gstjpeg2000parse.c
/** 原始版本 354行 */
if (j2c_box_id_offset == -1)
GST_ELEMENT_ERROR (jpeg2000parse, STREAM, DECODE, NULL,
("Missing contiguous code stream box for j2c stream"));
ret = GST_FLOW_ERROR;
goto beach;
/** 修改之后的版本 */
if (j2c_box_id_offset == -1)
GST_ELEMENT_ERROR (jpeg2000parse, STREAM, DECODE, (NULL),
("Missing contiguous code stream box for j2c stream"));
ret = GST_FLOW_ERROR;
goto beach;
/** 原始版本 383行 */
if (j2c_box_id_offset + GST_JPEG2000_JP2_SIZE_OF_BOX_ID != magic_offset)
GST_ELEMENT_ERROR (jpeg2000parse, STREAM, DECODE, NULL,
("Corrupt contiguous code stream box for j2c stream"));
ret = GST_FLOW_ERROR;
goto beach;
/** 修改之后的版本 */
if (j2c_box_id_offset + GST_JPEG2000_JP2_SIZE_OF_BOX_ID != magic_offset)
GST_ELEMENT_ERROR (jpeg2000parse, STREAM, DECODE, (NULL),
("Corrupt contiguous code stream box for j2c stream"));
ret = GST_FLOW_ERROR;
goto beach;
/** 原始版本 421行 */
if ((profile > GST_JPEG2000_PARSE_PROFILE_CINEMA_LTS)
&& !gst_jpeg2000_parse_is_broadcast (profile)
&& !gst_jpeg2000_parse_is_imf (profile))
GST_ELEMENT_ERROR (jpeg2000parse, STREAM, DECODE, NULL,
("Unrecognized JPEG 2000 profile %d", profile));
ret = GST_FLOW_ERROR;
goto beach;
/** 修改之后的版本 */
if ((profile > GST_JPEG2000_PARSE_PROFILE_CINEMA_LTS)
&& !gst_jpeg2000_parse_is_broadcast (profile)
&& !gst_jpeg2000_parse_is_imf (profile))
GST_ELEMENT_ERROR (jpeg2000parse, STREAM, DECODE, (NULL),
("Unrecognized JPEG 2000 profile %d", profile));
ret = GST_FLOW_ERROR;
goto beach;
/** 原始版本 434行 */
if (sub_level > 9)
GST_ELEMENT_ERROR (jpeg2000parse, STREAM, DECODE, NULL,
("Sub level %d is invalid", sub_level));
ret = GST_FLOW_ERROR;
goto beach;
/** 修改之后的版本 */
if (sub_level > 9)
GST_ELEMENT_ERROR (jpeg2000parse, STREAM, DECODE, (NULL),
("Sub level %d is invalid", sub_level));
ret = GST_FLOW_ERROR;
goto beach;
/** 原始版本 441行 */
if (validate_main_level && main_level > 11)
GST_ELEMENT_ERROR (jpeg2000parse, STREAM, DECODE, NULL,
("Main level %d is invalid", main_level));
ret = GST_FLOW_ERROR;
goto beach;
/** 修改之后的版本 */
if (validate_main_level && main_level > 11)
GST_ELEMENT_ERROR (jpeg2000parse, STREAM, DECODE, (NULL),
("Main level %d is invalid", main_level));
ret = GST_FLOW_ERROR;
goto beach;
/** 原始版本 464行 */
/* sanity check on image dimensions */
if (x1 < x0 || y1 < y0)
GST_ELEMENT_ERROR (jpeg2000parse, STREAM, DECODE, NULL,
("Nonsensical image dimensions %d,%d,%d,%d", x0, y0, x1, y1));
ret = GST_FLOW_ERROR;
goto beach;
/** 修改之后的版本 */
if (x1 < x0 || y1 < y0)
GST_ELEMENT_ERROR (jpeg2000parse, STREAM, DECODE, (NULL),
("Nonsensical image dimensions %d,%d,%d,%d", x0, y0, x1, y1));
ret = GST_FLOW_ERROR;
goto beach;
/** 原始版本 484行 */
if (numcomps == 0 || numcomps > GST_JPEG2000_PARSE_MAX_SUPPORTED_COMPONENTS)
GST_ELEMENT_ERROR (jpeg2000parse, STREAM, DECODE, NULL,
("Unsupported number of components %d", numcomps));
ret = GST_FLOW_NOT_NEGOTIATED;
goto beach;
/** 修改之后的版本 */
if (numcomps == 0 || numcomps > GST_JPEG2000_PARSE_MAX_SUPPORTED_COMPONENTS)
GST_ELEMENT_ERROR (jpeg2000parse, STREAM, DECODE, (NULL),
("Unsupported number of components %d", numcomps));
ret = GST_FLOW_NOT_NEGOTIATED;
goto beach;
4.2 编译 fdk-aac 库
不知道怎么回事,gstreamer的libav插件好多decoder都不能正常使用,这里我验证用的mkv文件里面音频是aac格式的,结果用libav就匹配不了, 因此只能使用开源的fdk-acc库,首先是配置的脚本文件:
./configure --prefix=/media/guwen/workspace/project/gstreamer/out \\
--host=arm-unknown-nto-qnx6.6.0eabi --disable-static
然后再进行编译安装
make -j4
make install
4.3 编译
和前面一样,其过程如下:
export PKG_CONFIG_LIBDIR=/media/guwen/workspace/project/gstreamer/out/lib/pkgconfig
mkdir build
cd build
meson .. --cross-file ../qnx_arm.txt
ninja
ninja install
五、编译gst-libav 库
5.1 编译FFmpeg
首先是交叉编译FFmpeg库,第一步,编写进行配置用的shell脚本文件myconfig.sh,其内容如下:
./configure --prefix=/media/guwen/workspace/project/gstreamer/out \\
--cross-prefix=arm-unknown-nto-qnx6.6.0eabi- \\
--enable-cross-compile \\
--pkg-config=pkg-config \\
--target-os=qnx \\
--cc=arm-unknown-nto-qnx6.6.0eabi-gcc \\
--arch=arm \\
--enable-shared \\
--disable-static \\
--enable-gpl \\
--enable-nonfree \\
--disable-armv5te \\
--disable-armv6 \\
--disable-armv6t2 \\
--disable-debug \\
--enable-neon \\
--extra-cflags="-std=gnu99 -fPIC" \\
--disable-programs \\
--disable-encoders \\
--disable-devices \\
--disable-muxers \\
--disable-decoders \\
--disable-demuxers \\
--disable-avdevice \\
--disable-bsfs \\
--disable-filters \\
--disable-doc \\
--enable-decoder=h264 \\
--enable-decoder=aac \\
--enable-decoder=ac3 \\
--enable-demuxer=mov \\
--enable-demuxer=mp3 \\
--enable-demuxer=matroska
这里只enable了 h264 aac ac3 , mov, mp3, matroska 等几个解码器和容器,这样既可以加快编译速度,也可以减少生成lib的大小。
- 修改编译错误,文件libavformat/sctp.c
这个文件的错误主要是因为CMSG_SPACE这个宏来计算recvmsg和sendmsg的buffer size, 其错误原因,将这个计算出来的size,作为一个数组的size,但CMSG_SPACE这个宏的实现里面有一个是获取align大小的函数__cmsg_alignbytes,因此就会报这样的错误:
libavformat/sctp.c: In function ‘ff_sctp_recvmsg’:
libavformat/sctp.c:80:17: error: variable length array ‘incmsg’ is used [-Werror=vla]
libavformat/sctp.c: In function ‘ff_sctp_send’:
libavformat/sctp.c:131:22: error: variable length array ‘outcmsg’ is used [-Werror=vla]
因此这里需要自己实现CMSG_SPACE这个宏,在qnx的toolchain中,其定义如下:
/*
* Alignment requirement for CMSG struct manipulation.
* This basically behaves the same as ALIGN() ARCH/include/param.h.
* We declare it separately for two reasons:
* (1) avoid dependency between machine/param.h, and (2) to sync with kernel's
* idea of ALIGNBYTES at runtime.
* without (2), we can't guarantee binary compatibility in case of future
* changes in ALIGNBYTES.
*/
#define __CMSG_ALIGN(n) (((n) + __cmsg_alignbytes()) & ~__cmsg_alignbytes())
#define CMSG_SPACE(l) (__CMSG_ALIGN(sizeof(struct cmsghdr)) + __CMSG_ALIGN(l))
出现错误的原因就是因为这里的__cmsg_alignbytes是一个函数,其作用是获取cmsg是按几个字节对齐的,经过测试,这个函数的返回值为7, 因此这里实现的的宏如下所示:
/**为了预防冲突,将CMSG_SPACE 修改为 MY_CMSG_SPACE */
#define __MY_CMSG_ALIGN(n) (((n) + 7) & ~7)
#define MY_CMSG_SPACE(l) \\
(__MY_CMSG_ALIGN(sizeof(struct cmsghdr)) + __MY_CMSG_ALIGN(l))
- 修改运行错误,文件libavutil/mem.c
变了了FFMpeg4.2.1之后,在运行的时候发现在libavutil/eval.c文件的av_expr_parse_and_eval这个函数里面调用av_expr_free这个函数时,会在最后av_freep(&e);这句的时候发生错误(并产生coredump), 一开始我以为是发生了内存越界,但是通过在这段内存的前后都加上16字节的空余空间,在av_freep(&e);这句之前打印是否存在内存越界,结果是,并没有发生内存越界,更奇妙的是,这样做之后也不会发生错误了。 在网上搜索了一下,发现qnx下的posix_memalign 和memalign这两个函数似乎有问题, 因此这里需要修改一下av_malloc函数的实现:
void *av_malloc(size_t size)
void *ptr = NULL;
/* let's disallow possibly ambiguous cases */
if (size > (max_alloc_size - 32))
return NULL;
#if 0 /** 注释掉原本的实现 */
#if HAVE_POSIX_MEMALIGN
if (size) //OS X on SDK 10.6 has a broken posix_memalign implementation
if (posix_memalign(&ptr, ALIGN, size))
ptr = NULL;
#elif HAVE_ALIGNED_MALLOC
ptr = _aligned_malloc(size, ALIGN);
#elif HAVE_MEMALIGN
#ifndef __DJGPP__
ptr = memalign(ALIGN, size);
#else
ptr = memalign(size, ALIGN);
#endif
/* Why 64?
* Indeed, we should align it:
* on 4 for 386
* on 16 for 486
* on 32 for 586, PPro - K6-III
* on 64 for K7 (maybe for P3 too).
* Because L1 and L2 caches are aligned on those values.
* But I don't want to code such logic here!
*/
/* Why 32?
* For AVX ASM. SSE / NEON needs only 16.
* Why not larger? Because I did not see a difference in benchmarks ...
*/
/* benchmarks with P3
* memalign(64) + 1 3071, 3051, 3032
* memalign(64) + 2 3051, 3032, 3041
* memalign(64) + 4 2911, 2896, 2915
* memalign(64) + 8 2545, 2554, 2550
* memalign(64) + 16 2543, 2572, 2563
* memalign(64) + 32 2546, 2545, 2571
* memalign(64) + 64 2570, 2533, 2558
*
* BTW, malloc seems to do 8-byte alignment by default here.
*/
#else
ptr = malloc(size);
#endif
#else /**使用普通的malloc来替代posix_memalign 或 memalign函数 */
ptr = malloc(size);
#endif /** */
if(!ptr && !size)
size = 1;
ptr= av_malloc(1);
#if CONFIG_MEMORY_POISONING
if (ptr)
memset(ptr, FF_MEMORY_POISON, size);
#endif
return ptr;
-
编译过程
make make install
5.2 准备gst-libav库编译脚本
- 编写meson的cross file 文件qnx_arm.txt
[host_machine]
system = 'qnx'
cpu_family = 'arm'
cpu = 'armv7'
endian = 'little'
[binaries]
c = 'arm-unknown-nto-qnx6.6.0eabi-gcc'
cpp = 'arm-unknown-nto-qnx6.6.0eabi-g++'
ar = 'arm-unknown-nto-qnx6.6.0eabi-ar'
strip = 'arm-unknown-nto-qnx6.6.0eabi-strip'
pkgconfig = 'pkg-config'
[properties]
c_args = ['-D_QNX_SOURCE=1']
c_link_args = ['-lsocket', '-L/media/guwen/workspace/project/gstreamer/out/lib',
'-lgobject-2.0', '-lgio-2.0', '-lgmodule-2.0', '-lffi']
cpp_args = ['-D_QNX_SOURCE=1']
cpp_link_args = ['-lsocket', '-L/media/guwen/workspace/project/gstreamer/out/lib',
'-lgobject-2.0', '-lgio-2.0', '-lgmodule-2.0', '-lffi']
[paths]
prefix = '/media/guwen/workspace/project/gstreamer/out'
- 修改meson.build文件
default_options : [ 'warning_level=1',
'buildtype=release' ]) #编译 release版本
- 新增mp3 demuxer支持
我完成了所有编译移植之后,原本想那个常见的音乐格式mp3文件进行测试,但发现,却没有找到支持mp3 格式的demuxer插件或元件。因此需要在gst-libav目录里面把对于mp3格式的支持放开。
- 新增mkv demuxer支持,
同样,在进行视频播放测试的时候,准备使用mkv格式的视
以上是关于gstreamer移植qnx:交叉编译qnx版本的gstreamer插件库的主要内容,如果未能解决你的问题,请参考以下文章
gstreamer移植qnx:交叉编译gstreamer之 libgstreamer