基于Windows的GStreamer从源码下载、编译到开发

本文介绍了在GStreamer下载方法, 使用过程中的部分依赖,以及在Windows上编译配置GStreamer 过程,为学习GStreamer 创建条件。

GStreamer 代码下载

  1. 到Sign up · GitLabfreedesktop.org GitLab loginhttps://gitlab.freedesktop.org/users/sign_up上注册一个用户。
  2. 在PC机上用ssh-keygen -t rsa -C "yourname@yourhost.com"生成id_rsa.pub值,把这个值贴到下面Key框里,如果这一步不会,请搜索参考 ssh-keygen的用法。
  3. git clone git@gitlab.freedesktop.org:gstreamer/gstreamer.git  或 git clone https://gitlab.freedesktop.org/gstreamer/gstreamer.git 下载源码。下载下来的代码是整个工程,目录结构如下:​

相关基础知识

一、glib路径:https://www.linuxfromscratch.org/blfs/view/svn/general/glib2.htmlhttps://www.linuxfromscratch.org/blfs/view/svn/general/glib2.html

二、准备GObject相关知识,代码在glib中

GObject又称为GLib对象系统,和glibc,libc没有关系,glibc是linux下的GNU C函数库,libc是linux下的ANSI C函数库。面向对像的方法常常用私有来隐藏信息,而用C语言实现的系统中,私有却没有那么简单。一种方法是将私有成员分离到独立的结构体中;另外一种方法是将私有结构体存放到源码文件,对外结构体中仅仅保存一个指针,指向这个结构。

GObject相关URL:GObject – 2.0https://docs.gtk.org/gobject/

三、下载gst-template:git clone git://anongit.freedesktop.org/gstreamer/gst-template.git 可以利用其中的工具来产生plugin,方法是:../tools/make_element plugin_name

四、第三方依赖库下载
        Gstreamer的功能有时候依赖第三方库,这些库在Gstreamer的subprojects下面没有对应的工程。如果自己下载编译,修改meson.build其实是个挺费时的工程,这个时候,可以到https://mesonbuild.com/Wrapdb-projects.html#meson-wrapdb-packages 这个网站上下载Meson WrapDB packages,然后将对应的.warp文件放到subprojects/目录下即可。如编译openssl就可以下载openssl.wrap。

五、编译三方库过程中,只生成*.dll文件,未生成*.lib的故障解决:故障原因由未导出任何API导致,可以由以下方式解决,如在.c文件中增加一个API,并且export。

#if defined(_WIN32)
__declspec(dllexport) int OPENSSL_generate_lib_func()
{return 1;
}
#endif

但这种方式治标不治本,编译产生的函数声明等等都没有导出来,导致链接的时候符号查找不到,可以在链接时,加入/DEF:openssl.def选项,

openssl_cflags = ['/DEF:openssl.def',]
libssl_dep = declare_dependency(include_directories: include_directories,dependencies: dependencies + [libcrypto_dep],link_with: libssl_lib,link_args:openssl_cflags,
)

官方指导链接:Built-in optionshttps://mesonbuild.com/Builtin-options.htmlopenssl.def是描述需要导出符号的文件:
LIBRARY   crypto
EXPORTS
    a2i_IPADDRESS
    ASN1_ANY_it
    ASN1_item_d2i
    ASN1_item_free
    ASN1_item_i2d
    ASN1_item_new

详情参见官方指导文档:/DEF (Specify Module-Definition File) | Microsoft Docs

可以在Gstreamer的顶层meson_options.txt中加入option('openssl', type : 'feature', value : 'auto'),在meson.build的subprojects中加入  ['openssl', { 'option': get_option('openssl'), 'match_gst_version': false}],就可以编译openssl了。

事实上.def文件要配置全是很难的,这里给出一种方式:

1. 首先,您可以创建静态库。修改meson.build,加入
libcrypto_lib = static_library('crypto',dependencies: dependencies,sources: libcrypto_sources,include_directories: include_directories,c_args: c_args,install: true,link_args:openssl_cflags,
)libssl_lib = static_library('ssl',dependencies: dependencies + [libcrypto_dep],sources: libssl_sources,include_directories: include_directories,c_args: c_args,link_args:openssl_cflags,install: true,
)
2. 然后使用“dumpbin/linkermember”从静态库中导出所有符号。dumpbin /LINKERMEMBER libcrypto.a > libcrypto.txtdumpbin /LINKERMEMBER libssl.a > libssl.txt
3. 将所有符号放入.def文件。
4. 使用.def文件创建dll。Gstreamer libogg中使用.def的方式:
sources = ['bitwise.c', 'framing.c']libogg = library('ogg',sources,include_directories : incdir,vs_module_defs: '../win32/ogg.def',install: true,
)bw_test = executable('bitwise', 'bitwise.c',include_directories : incdir,c_args : '-D_V_SELFTEST'
)
framing_test = executable('framing', 'framing.c',include_directories : incdir,c_args : '-D_V_SELFTEST'
)test('bitwise', bw_test)
test('framing', framing_test)libogg_dep = declare_dependency(link_with : libogg,include_directories : incdir)

不过,使用.def创建的dll,在使用时,涉及到具体的函数时,仍然需要import,用__declspec(dllimport),详见:EXPORTS | Microsoft DocsLearn more about: EXPORTShttps://docs.microsoft.com/en-us/cpp/build/reference/exports?view=msvc-160,换一种思维,不用编译成动态库,编译成静态库或许也可以。 有时候很多函数的声明或者定义在宏当中实现,不易查找位置,可以在编译的时候,重新对此函数进行另外一种定义,编译器报错并报告之前定义或者声明的位置,就可以找到函数原型了。

GStreamer源码Windows编译:

本人的PC机常年用于开发,具备一些基础工具。如果您在按步骤操作过程中遇到工具不足,需要install的情况,请根据自己的情况安装相应工具包。

1.   安装Visual Studio 2019,python,本人安装的python版本是Python 3.8.0,更新pip,安装 ninja和menson等等。

pip install --upgrade pip
pip install meson
pip install ninja

2. 以管理员身分运行x64 Native Tools Command Prompt for VS 2019,cd到GStreamer大包代码的顶层目录,然后输入meson build,meson是可以执行程序的名称,build是将产生ninja编译脚本所在的目录。

创建编译目录

The Meson build system
Version: 0.60.3
Source dir: F:\Source\OpenSource\gstreamer
Build dir: F:\Source\OpenSource\gstreamer\build
Build type: native build
Project name: gstreamer-full
Project version: 1.19.3.1
C compiler for the host machine: cl (msvc 19.29.30139 "???? x64 ?? Microsoft (R) C/C++ ????????? 19.29.30139 ??")
C linker for the host machine: link link 14.29.30139.0
Host machine cpu family: x86_64
Host machine cpu: x86_64
Program python3 found: YES (c:\program files\python.exe)
WARNING: Broken python installation detected. Python files installed by Meson might not be found by python interpreter.This warning can be avoided by setting "python.platlibdir" option.
WARNING: Broken python installation detected. Python files installed by Meson might not be found by python interpreter.This warning can be avoided by setting "python.purelibdir" option.
Program uname found: YES (C:\Program Files (x86)\Montage-tech\Brolga\msys\1.0\bin\uname.EXE)
Compiler for C supports arguments /utf-8: YES 

这个过程很慢,耐心等待吧,编译完成之后,发现文件夹目录有些变化。

首先是生成了build目录,其次在subprojects下面,多了许多依赖的插件。我们以FFMPEG为例,去看一下这些插件的目录 :

它包括了整包FFMPEG的源码,看一下它的修改日志:

当前使用的ffmpeg版本是FFmpeg 4.4.1 release。

3. 到build目录ninja编译,或者ninja -C build编译

ninja -C build

编译过程中可能会有些小错误出现,您可以会遇到不同的,需要我们自己手动解决一下:

  • FAILED: subprojects/glib/glib/libglib-2.0-0.dll.p/gstdio.c.obj
    ../subprojects/glib/glib/gstdio.c:66:16: error: redefinition of 'struct _REPARSE_DATA_BUFFER'c:\mingw\include\winnt.h:3586:16: note: originally defined heretypedef struct _REPARSE_DATA_BUFFER

    _REPARSE_DATA_BUFFER在winnt.h中也有定义,此处重新定义就冲突了,我们将此处的定义类型名重新修改一下或者直接删除就好,笔者看了winnt.h中关于此类型的定义和此处定义内容一致,因此也没必要保留两份。

  • FAILED: subprojects/glib/glib/libglib-2.0-0.dll.p/gstdio.c.obj
    ../subprojects/glib/glib/gstdio.c:225:24: error: implicit declaration of function '_alloca' [-Werror=implicit-function-declaration]char *drive_letter = _alloca (drive_letter_size);

    _alloca函数未定义,_alloca是内存分配函数,但是_alloca是在栈(stack)上申请空间,用完马上就释放。它包含在malloc.h头文件中,有的机器上很难实现,移植性较差。此处我们将malloc.h头文件包含到.c文件即可。报toupper函数未定义时,需要#include <ctype.h>这个头文件。

  • [3/8930] Compiling C object subprojects/glib/glib/libglib-2.0-0.dll.p/giowin32.c.obj
    ../subprojects/glib/glib/giowin32.c:1791:118: error: 'ERROR_BROKEN_PIPE' undeclared (first use in this function)

    ERROR_BROKEN_PIPE未定义,这是win32 api的错误码,定义在winerror.h中。FSCTL_GET_REPARSE_POINT未定义,这包含在winioctl.h中。
       比较容易搜索到的错误我就不再列举了,有些编译不过的是test文档,我们并不需要,注释掉就好了,还有一些功能,可能我们永远也用不到,所以也可以注释掉。笔者使用的VS版本是VS 2019社区版。笔者试过2010,2017的环境编译都有比较多的困难,用bash,MSYS2编译出错也会让你修改得怀疑人生。只有x64 Native Tools Command Prompt for VS 2019这个工具是最适合的,错误也相对较少。工具的选择我的建议是到GStreamer下载的官方网站,选用官方发布文件所用的编译工具Download GStreamerhttps://gstreamer.freedesktop.org/download/#windows比如如下Release版本对应的开发工具就是vs 2019:

官方给出的编译教程如下:

Building from source using Meson

编译成功 了咱们看一下:

F:\Source\OpenSource\gstreamer\build>ninja
ninja: no work to do.

再次输入ninja没有需要重新编译的文件。如果有文件重新修改后需要编译,只需要ninja即可,无需再次进行meson。接下来修改一下build.ninja文件,把编译好的文件放到指定位置以便我们引用,找到build meson-install: CUSTOM_COMMAND PHONY | all这句,增加一个--destdir选项:

build meson-install: CUSTOM_COMMAND PHONY | allDESC = Installing$ files.COMMAND = "C:\Python38\Scripts\meson" "install" "--no-rebuild" --destdir "C:\gstreamer"pool = console

可以使用ninja -C build devenv在编译的时候就修改环境变量,以便您也可以直接使用刚刚编译出来的工具。

4. ninja install

ninja install

安装完后的目录像这个样子:

展开GStreamer中的宏

GStreamer中的宏非常多,理论上讲,Windows编译时,在build.ninja文件的$ARGS参数里面加上/P /C参数就可以将文件里面的宏展开,生成临时文件。但由于GStreamer的依赖非常多,这些依赖的编码字符集也不一样,在宏展开时就常常会出现问题,导致加上/P /C参数的后代码编译不过。这里提供一种技巧示例,如我们想看gst_object_get_type ()这个函数的定义,这个函数就是用宏定义的,定义如下:

G_DEFINE_TYPE_WITH_CODE (GstPad, gst_pad, GST_TYPE_OBJECT,    G_ADD_PRIVATE (GstPad) _do_init);

我们将这个定义复制到.c文件,命名为test.c,然后文件内容如下:

#include <stdio.h>
#include <gst/gst.h>
G_DEFINE_TYPE_WITH_CODE (GstPad, gst_pad, GST_TYPE_OBJECT,    G_ADD_PRIVATE (GstPad) _do_init);

x64 Native Tools Command Prompt for VS 2019环境使用如下命令编译

"cl" "-IC:\gstreamer\include" "-IC:\gstreamer\include\gstreamer-1.0" "-IC:\gstreamer\include\glib-2.0" "-IC:\gstreamer\lib\glib-2.0\include" /P /C test.c

这样,就会生成test.i中间文件,展开的结果如下所示:

static void gst_pad_init(GstPad *self);
static void gst_pad_class_init(GstPadClass *klass);
static GType gst_pad_get_type_once(void);
static gpointer gst_pad_parent_class = ((void *)0);
static gint GstPad_private_offset;static void gst_pad_class_intern_init(gpointer klass)
{gst_pad_parent_class = g_type_class_peek_parent(klass);if (GstPad_private_offset != 0) {g_type_class_adjust_private_offset(klass, &GstPad_private_offset);}gst_pad_class_init((GstPadClass *) klass);
}static inline gpointer gst_pad_get_instance_private(GstPad *self)
{return (((gpointer)((guint8 *)(self) + (glong)(GstPad_private_offset))));
}GType gst_pad_get_type(void)
{static gsize static_g_define_type_id = 0;if ((g_once_init_enter((&static_g_define_type_id)))) {GType g_define_type_id = gst_pad_get_type_once();(g_once_init_leave((&static_g_define_type_id), (gsize)(g_define_type_id)));}return static_g_define_type_id;
}static GType gst_pad_get_type_once(void)
{GType g_define_type_id = g_type_register_static_simple((gst_object_get_type()), g_intern_static_string("GstPad"), sizeof(GstPadClass),(GClassInitFunc)(void (*)(void)) gst_pad_class_intern_init, sizeof(GstPad),(GInstanceInitFunc)(void (*)(void)) gst_pad_init, (GTypeFlags) 0);{{{GstPad_private_offset = g_type_add_instance_private(g_define_type_id, sizeof(GstPadPrivate));}_do_init;}}return g_define_type_id;
};

这样我们就能够明白gst_pad_get_type是怎么回事了,它是一外部函数,在gst_init时被调用。您也可以使用如下方式来展开文件的宏:

"cl" "-IC:\gstreamer\include" "-IC:\gstreamer\include\gstreamer-1.0" "-IC:\gstreamer\include\glib-2.0" "-IC:\gstreamer\lib\glib-2.0\include" "-IC:\gstreamer\include\gstreamer-1.0\gst" "-IC:\gstreamer\include\gstreamer-1.0\gst"  /P /C f:\source\opensource\gstreamer\gstreamer\subprojects\gstreamer\gst\Gstelement.c

在VS的调试UI,您也可以将宏复制到.c文件中,用鼠标指针指向它,VS会自动将其展开

也可以只针对单个文件展开宏,比如展开x509_vfy.c中的宏,可以这样修改build.ninja这个文件:

GStreamer之HelloWord

使用GStreamer之前,需要将C的头文件.h和需要的库文件.lib包含到我们的环境中:

1. 包含头文件路径

2. 包含库文件路径

3. 增加依赖库

4.设置运行环境,将GStreamer运行时需要的.dll文件库路径配置到环境中。

5.代码编写,使用的代码可参考:Basic tutorial 1: Hello world! 笔者的代码如下:

#include <gst/gst.h>int main(int argc, char* argv[])
{/* Initialize GStreamer */gst_init(&argc, &argv);g_printf("GStreamer Say Hello Word!");return 0;
}

6.运行结果

至此,GStreamer下载,编译链接成功,成功产生出第一个测试用例,后续部分陆续完成中,待整理好后一并奉上。本文实操过程中,也是屡屡踩坑,希望广大从来朋友以此为鉴,少走弯路。

日志管理

gst_debug_set_default_threshold(level)函数设计日志的默认调试级别
gst_debug_remove_log_function(func)去掉默认的日志打印函数
gst_debug_add_log_function(func,data,notify)添加新的日志打印函数
gst_debug_set_threshold_for_name(name,level)设置单个模块的调试级别

日志相关函数定义在subprojects\gstreamer\gst\gstinfo.h中,GST_DISABLE_GST_DEBUG作为调试开关,定义中subprojects/gstreamer/gst/gstconfig.h.in中,有的时候,调试日志如GST_MEMDUMP等等会点用大量CPU时间,所以Gstreamer相关软件版本发布的时候,最好关掉这类日志,来看一个例子:

gst_debug_set_active是总开关,设置以后,调试信息才会发送到调试信息处理函数,否则不会发送任何调试信息,在嵌入式平台建议不要打开这个调试信息。

如果调试过程中遇到inline函数或者宏不能断住,可以在gstinfo.c中可以找出void gst_debug_print_stack_trace (void)和gchar *gst_debug_get_stack_trace (GstStackTraceFlags flags)函数,用来打印调用栈信息。

Linux上编译

用同一包代码,Linux编译相对简单,同样的meson build,可能会出现几个小错误:

meson.build:1:0: ERROR: wrap-redirect /home/xxx/gstreamer/subprojects/harfbuzz\subprojects\libpng.wrap filename does not exist
meson.build:1:0: ERROR: wrap-redirect /home/xxx/gstreamer/subprojects/fontconfig\subprojects\gperf.wrap filename does not exist
meson.build:1:0: ERROR: wrap-redirect /home/xxx/gstreamer/subprojects/openh264\subprojects\gtest.wrap filename does not exist
meson.build:1:0: ERROR: wrap-redirect /home/xxx/gstreamer/subprojects/pango\subprojects\gi-docgen.wrap filename does not exist

打开gstreamer/subprojects/libpng.wrap,gstreamer/subprojects/gperf.wrap,gstreamer/subprojects/gtest.wrap,gstreamer/subprojects/gi-docgen.wrap文件,将路径的"\"符号修改成"/"就好。

然后ninja -C build,一路顺序编译结束,未遇到编译错误。

从零开始成为GStreamer专家——基于Windows的GStreamer从源码下载、编译到开发相关推荐

  1. 适合新手:从零开发一个IM服务端(基于Netty,有完整源码)

    本文由"yuanrw"分享,博客:juejin.im/user/5cefab8451882510eb758606,收录时内容有改动和修订. 0.引言 站长提示:本文适合IM新手阅读 ...

  2. android源码下载方法 批量下载 基于windows os

    安装win版的Gitbash, 在这里 http://msysgit.googlecode.com/files/Git-1.6.0.2-preview20080923.exe. 选择默认安装路径(否则 ...

  3. 基于JAVA网上专家门诊预约系统计算机毕业设计源码+数据库+lw文档+系统+部署

    基于JAVA网上专家门诊预约系统计算机毕业设计源码+数据库+lw文档+系统+部署 基于JAVA网上专家门诊预约系统计算机毕业设计源码+数据库+lw文档+系统+部署 本源码技术栈: 项目架构:B/S架构 ...

  4. 基于Java毕业设计宠物店管理系统源码+系统+mysql+lw文档+部署软件

    基于Java毕业设计宠物店管理系统源码+系统+mysql+lw文档+部署软件 基于Java毕业设计宠物店管理系统源码+系统+mysql+lw文档+部署软件 本源码技术栈: 项目架构:B/S架构 开发语 ...

  5. SSM框架基于web的房屋租售管理系统源码+论文第二稿+软件环境+包安装调试

    项目名称 SSM框架基于web的房屋租售管理系统源码 系统说明 用户: 1.首页:系统前台首页使用分块的结构设计进行展示,分别对系统的logo.轮播图.登录注册.新闻公告.最新房源.菜单功能.房屋类型 ...

  6. 基于html5制作3D拳击游戏源码下载

    今天给大家分享一款基于HTML5实现的3d拳王游戏源码.这款实例适用浏览器:360.FireFox.Chrome.Safari.Opera.傲游.搜狗.世界之窗. 不支持IE8及以下浏览器. 在线预览 ...

  7. Windows下调试PostGreSQL源码第一步 - 下载和编译源码、构造VS工程

    PostGreSQL是开源的DBMS系统:源码可用于研究学习:下面来看一下: 先下载源码:ftp站点下载,https://ftp.postgresql.org/pub/source/ 先下载安装Per ...

  8. php广告任务网源码_THINKPHP仿我爱广告任务网|任务网站源码下载基于PHP+MYSQL的在线广告打码任务网站源码...

    THINKPHP仿我爱广告任务网|任务网站源码下载基于PHP+MYSQL的在线广告打码任务网站源码 THINKPHP仿我爱广告任务网|任务网站源码下载是一款基于PHP+MYSQL开发制作的在线广告打码 ...

  9. Windows平台下Android源码的下载(Z)

    我最近在自学Android,当遇到问题时也只能看看开发文档,或者上网查资料解决,远没有直接看源码来得直接.国内倒是有个Android镜像网站,但不提供下载源码的链接;苦于没有下源码的地方,一气之下,上 ...

最新文章

  1. Power Network [POJ - 1459]
  2. 【iOS开发】静态库 a文件合成脚本解释
  3. JAVA JVM原理详解
  4. ios 防止按钮快速点击造成多次响应的避免方法。
  5. PHP截取IE浏览器并缩小原图的方法
  6. Firefox 18周岁
  7. android textview 白色,android – AutoCompleteTextview默认情况下,颜色设置为白色
  8. 自定义控件SettingItemView
  9. r语言descstats_一条命令轻松绘制CNS顶级配图-ggpubr
  10. Nginx 简单命令
  11. BlendMask 论文学习
  12. 转载:性格与健康(刘善人)之二
  13. 如何解决局域网广播风暴
  14. 19. OP-TEE中TA与CA执行流程详解-------软件架构篇
  15. 基于STM32F103单片机智能安全门禁人体感应报警方案设计
  16. 杭州建筑工程师职称评审条件
  17. java游戏蜀山回合制,蓝港3D萌系回合制仙侠手游《大话蜀山》上线
  18. 使用Spring Security OAuth2使用JWT生成token及自定义token携带的信息(十)
  19. php fundamentals,HZNUOJ--Programming Fundamentals
  20. Microbiome | 植物促生菌诱导的DNA甲基化修饰在植物-微生物互作中的长期影响

热门文章

  1. 响应式设计-Bootstrap栅格布局
  2. C++生成 桔灯 Aether仪器的 *.atts 格式 时间域文件
  3. 输入时间的前一秒和后一秒(c语言)
  4. 一个阿里P8的工程师,一年能赚多少钱?
  5. APEX日里面每个表的查询次数统计
  6. 408操作系统自用概念笔记
  7. python实现手写数字识别(小白入门)
  8. starccm实例教程_STARCCM实例操作教程(凤洞仿真)
  9. Redis 过期 key 删除,那些不得不说的事情!
  10. el-form标题做一个问号提示