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

gstreamer移植qnx:概览篇

gstreamer移植qnx:编写gstreamer插件audio sink和video sink

支持qnx中的cmake??从 Linux 移植到 QNX

基于arm5718的交叉编译gstreamer移植

基于arm5718的交叉编译gstreamer移植