1
话说 gst-launch-1.0 这条命令老牛掰了,看是很复杂的媒体流,用这条命令,一行代码就搞定了。看看下面这行代码,区区几十个字符,就建立了测试视频流:
gst-launch-1.0 videotestsrc ! autovideosink
运行后可以在屏幕上显示视频测试图案,大概就是下面这个样子:
那些包含视频、音频,甚至用户定制信号的复杂媒体流,也能用 gst-launch-1.0 这样子玩吗?当然没问题。我们接下来聊聊如何构建复杂媒体流管道。
2
在刚才的例子中,我们的管道描述串是 videotestsrc ! autovideosink
,它包括了三个部分:
- 管道起始点:
videotestsrc
- 管道的终点:
autovideosink
- 起点和终点的连接:
!
这个管道描述串的意思是,把元素 videotestsrc
连接到元素 autovideosink
上。
说到这里,很多人很纳闷,不是说元素之间只能通过 Pad 链接吗?这里怎么直接连接元素呢?实际上这是一个简化用法,因为 videotestsrc
只有一个输出 Pad,autovideosink
也只有一个输入 Pad,这种情况下,就不需要再说明怎么样用 Pad 连接了。不过,上面这个例子完整的说明应该如下:
gst-launch-1.0 videotestsrc name=a a.src ! b.sink autovideosink name=b
看晕了吧?其实不复杂,听我继续道来…
3
gst-launch-1.0 的基本语法是
gst-launch-1.0 元素名称 属性=... 元素名称 属性=... ... 元素.SrcPad名称 ! 元素.SinkPad名称
所以,根据我们上面的例子,可以写出下面的命令行:
gst-launch-1.0 videotestsrc autovideosink
没看错吧?元素之间竟然没有 !
符号。没错,命令行运行后并没出现语法错误,只是这个管道并不会工作,因为没有链接。此时,管道描述符包含两个部分:
- 第一个元素:
videotestsrc
- 第二个元素:
autovideosink
要建立连接,就需要给元素命名:
gst-launch-1.0 videotestsrc name=a autovideosink name=b
当然,因为还没加入链接,当然还是不工作。此时,管道描述符仍然只包含两个部分:
- 第一个元素:
videotestsrc name=a
- 第二个元素:
autovideosink name=b
下面加入链接:
gst-launch-1.0 videotestsrc name=a autovideosink name=b a.src ! b.sink
运行一下,OK,很完美。
4
注意到没有,这次连接的位置竟然与刚才的例子不一样。其实,gst-launch-1.0 不在乎排列顺序。这个例子中,管道描述串包括三个部分:
- 第一个元素:
videotestsrc name=a
- 第二个元素:
autovideosink name=b
- 连接:
a.src ! b.sink
这三个部分可以任意排列。这三个部分之间并没有标点符号,会不会弄混?仔细分析一下就能发现,不会。因为元素名称前后都是空格,没有其他符号。元素的属性赋值(比如 name=a)有等号连接,连接描述有感叹号连接。所以,尽管描述串很复杂,而且无序,但不会弄错。
所以,前面看到的那个例子,管道描述串中也是由上面三个部分构成,只是顺序调整了一下,让人觉得很神的样子。你看一下能分出来三个部分吗?
gst-launch-1.0 videotestsrc name=a a.src ! b.sink autovideosink name=b
5
我们怎么能知道 videotestsrc
的 Pad 名称是 src
?这个不难,用命令 gst-inspect-1.0 videotestsrc
查看即可。gst-inspect-1.0 是研究插件库的好工具,一定要用好!
使用 gst-inspect-1.0 我们发现, videotestsrc
有一个叫做 pattern 的属性,默认值是 0,最大值可以取到 24。接下来我们改成 1 看看:
gst-launch-1.0 videotestsrc pattern=1 ! autovideosink
正如 gst-inspect-1.0 说的那样,这个是雪花 snow 模式!
6
刚才的例子,分辨率太低了,能不能转换成高清视频?当然没问题,我们利用 CAPS 转换,强迫 Pad 之间的连接通过我们指定的 CAPS 进行。看下面的例子:
gst-launch-1.0 videotestsrc ! video/x-raw, width=1920, height=1080 ! autovideosink
也可以:
gst-launch-1.0 videotestsrc name=a autovideosink name=b a.src ! video/x-raw, width=1920, height=1080 ! b.sink
需要注意两点:
a.src ! video/x-raw, width=1920, height=1080 ! b.sink
是一个链接,不可乱序video/x-raw, width=1920, height=1080
是 CAPS 说明,其中的属性之间用逗号隔开。这个表示方法与元素是不一样的,元素的属性是用空格隔开的。
7
因为 CAPS 的属性可能很复杂,比如 video/x-raw(memory:NVMM), width=(int)1920, height=(int)1080, format=(string)NV12
这种里面带括号的,无法直接放到 gst-launch-1.0。另外,CAPS标识如果太简单也可能与元素无法区别。于是,这类 CAPS 必须用单引号或双引号括起来,明确告诉 gst-launch-1.0 这是一个 CAPS 说明。所以下面的例子也是合法的:
gst-launch-1.0 videotestsrc ! 'video/x-raw, width=1920, height=1080' ! autovideosink
gst-launch-1.0 videotestsrc ! "video/x-raw, width=1920, height=1080" ! autovideosink
到此为止,我觉得建立管道描述串的知识应该够用了,我不能再讲了,否则你知道的就太多了,哈哈哈哈!
谢谢阅读,如果有用,请点赞收藏,如有问题,欢迎留言!
================
补充知识:GStreamer 插件体系简介
GStreamer 系统一个很重要的想法就是把媒体流拆解成了插件,插件通过连接组合,构造出复杂的媒体流管道。
GStreamer 的插件是以动态库,也就是 .so 形式发布,原则上我们不需要其源代码。这些插件在 GStreamer 系统中注册以后,我们就可以通过其注册名称找到它们,也可以通过其名称加载 .so 库代码,并调用相关功能。
建立一个这样的注册体系是一个很复杂的事情,但是我们用起来却省了很多事。我们可以在没有这些插件源代码的情况下,灵活运用这些插件。用一个简单的字符串,构造出通常需要成千上万行代码才能写出的系统。前面的那一条例子,如果用 C 语言写代码实现的话,即使同样利用这些插件,也需要几十行甚至数百行代码才能实现。
所以, gst-launch-1.0 这条命令,实际上扮演了一个解释程序的角色,可以把管道描述字符串翻译成复杂的代码,最终按照要求为我们构建的媒体流管道。
在我开发用的 Jetson Nano 上,GStreamer 的插件安装在目录 /usr/lib/aarch64-linux-gnu/gstreamer-1.0
下,文件名是:libgstvideotestsrc.so
。参见下面的截图:
可以用 gst-inspect-1.0 命令查看 GStreamer 系统注册的插件。当然,我们也可以自己编写插件,最基本的入门参见:
- 《编写 GStreamer 插件1:概述》
- 《编写 GStreamer 插件2:编写插件的基础知识(一)》
- 《编写 GStreamer 插件2:编写插件的基础知识(二)》
- 《在 Jetson Nano 上编写 GStreamer 插件 ——实现自己的第一个作品》
参考资料
- https://gstreamer.freedesktop.org/documentation/tools/gst-launch.html?gi-language=c