GStreamer 是一个用于构建媒体处理组件图(也可以称为 pipeline,或管道)的库。它支持的应用非常广泛,从简单的 Ogg/Vorbis 播放,音频/视频流到复杂的音频(混音)和视频(非线性编辑)处理。
应用程序可以透明地利用编解码和过滤器技术的进步。开发者可以通过编写简单的基于一个干净、通用的接口的插件,来添加新的编解码器和过滤器。
GStreamer 可以运行于所有主要的操作系统平台,如 Linux,Android,Windows,Max OS X,iOS,以及大部分 BSDs,商业 Unixes,Solaris,和 Symbian。它已经被移植到了广泛的操作系统,处理器,和编译器平台上。它可以运行于所有主要的硬件架构上,包括 x86,ARM,MIPS,SPARC 和 PowerPC,32 位以及 64 位上,以及小尾端或大尾端。
GStreamer 可以桥接到其它多媒体框架,以复用已有的组件(比如编解码器)及使用平台的输入/输出机制:
- Linux/Unix:OpenMAX-IL (via gst-omx)
- Windows::DirectShow
- Mac OS X:QuickTime
GStreamer 核心框架
- 基于图的结构允许构建任何形态的管线
- 基于 GLib 2.0 对象模型 的面向对象设计和继承
- 小于 500KB 的紧凑的核心库,大约有 65k 行代码
- 构建多线程的管线是容易的且透明的
- 对于插件和应用程序开发者,都有着干净,简单和稳定的 API
- 极端轻量的数据处理意味着非常的高性能/低延迟。
- 无论是对于核心架构,还是对于插件/应用程序的开发者,都有完整的调试系统
- 具有时钟来确保全局的流间同步(a/v 同步)
- 具有服务质量 (qos) 来确保在高 CPU 负载下最优的可能质量。
智能插件架构
- 动态加载 的插件提供元素和媒体类型,通过一个注册表缓存按需加载,与 ld.so.cache 类似。
- 元素接口 处理所有已知类型的 source,过滤器,和 sinks
- 权能系统 允许使用 MIME 类型和媒体特有的属性验证元素的兼容性
- 自动插拔使用权能系统自动完成复杂的路径
- 可以通过把管线转储为一个 .dot 文件来将它可视化,并基于此创建一副 PNG 图像。
- 资源友好型插件不会浪费内存
多媒体技术的广泛覆盖
GStreamers 的能力可以通过新插件来扩展。下面列出的功能只是使用 GStreamers 时可用的 GStreamer 自己的插件的粗糙的概览,不包括任何第三方提供的。
- 容器格式:asf,avi,3gp/mp4/mov,flv,mpeg-ps/ts,mkv/webm,mxf,ogg
- 流:http,mms,rtsp
- 编解码器:FFmpeg,各种编解码库,第三方的编解码包
- 元数据:它们之间有着公共映射的本地容器格式
- 视频:各种颜色空间,支持渐进式和交错视频
- 音频:具有各种位深度的整型和浮点型音频数据和多通道配置
大量的开发工具
- gst-launch 命令行工具可用于快速的原型和测试,与 ecasound 类似
- 大量 文档,包括部分完成的 手册 和 插件编写者指南
- 大量可选的测试程序和每个模块中的示例代码
- 可通过 各种各样的编程语言 访问 GStreamer API
GStreamer 是一个灵活,快速和多平台的多媒体框架。
GStreamer 是一个极端强大和功能丰富的用于创建流媒体应用的框架。GStreamer 框架的许多优点来自于它的模块化:GStreamer 可以与新插件模块无缝的协同工作。但由于模块化和强大常常是以更大的复杂性为代价的,因而编写新应用并不总是那么简单。
GStreamer 编译
GStreamer 是一个开源的多媒体框架,因而从源码编译也是非常方便的。GStreamer 提供了 Meson 和 Cerbero 等编译方式。这里用 Meson 在 Ubuntu Linux 上编译 GStreamer。
Meson 构建系统是一个快速的可移植的构建系统。它根据构建配置文件,生成可以被 ninja
执行的构建指令,GStreamer 项目使用它作为所有子项目的构建系统。可以使用如下命令安装 ninja:
sudo apt-get install ninja-build
要编译最新版本的 GStreamer,Ubuntu 的软件源里的 meson 版本可能有点老,如 Ubuntu 20.04 版本通过 apt 安装的 meson 0.53.2 版,在编译 GStreamer master branch 的代码时,报错说版本太老:
hanpfei@ubuntu:~/Data/opensource/gstreamer$ meson build
The Meson build system
Version: 0.53.2
Source dir: /home/hanpfei/Data/opensource/gstreamer
Build dir: /home/hanpfei/Data/opensource/gstreamer/build
Build type: native build
meson.build:1:0: ERROR: Meson version is 0.53.2 but project requires >= 0.54
A full log can be found at /home/hanpfei/Data/opensource/gstreamer/build/meson-logs/meson-log.txt
最好用 Python 的 pip 工具来安装 meson(如果已经通过 apt 安装了 meson,需要先把它移除掉):
hanpfei@ubuntu:~/Data/opensource/gstreamer$ sudo apt install python3-pip
hanpfei@ubuntu:~/Data/opensource/gstreamer$ python3 -m pip install meson
Python 的 pip 工具将 meson 安装在了用户根目录下的一个隐藏目录 ~/.local/bin
下,如 /home/hanpfei/.local/bin
,这个路径还需要被加进 PATH
环境变量里。
ninja 也可以用 Python 的 pip 工具来安装:
hanpfei@ubuntu:~/Data/opensource/gstreamer$ python3 -m pip install ninja
此外,在编译 GStreamer 之前,还需要安装一些依赖:
hanpfei@ubuntu:~/Data/opensource/gstreamer$ sudo apt-get install flex bison
在 2021 年 9 月,所有主要的 GStreamer 模块都被合入了一个单独的代码仓库,GStreamer 单独的仓库 位于主 GStreamer git 仓库,这是如今 GStreamer 版本 1.19/1.20 及之后版本的所有 GStreamer 开发将发生的地方。
在这个单独的仓库合并位于分开的 git 仓库中不同的 GStreamer 模块之前,有一个称为 gst-build
的分开的元构建工程用于下载并构建所有的子项目。如果你想要开发更老的稳定分支,比如 GStreamer 1.16 或 1.18,则你应该使用它。
如果你想要构建或开发即将到来的开发或稳定分支,你应该使用包含在单个代码仓库中的 GStreamer 模块的 main
分支。gst-build
与单个代码仓库的工作方式基本相同,仅有的不同是它将下载各种 GStreamer 子模块。
为了构建当前的 GStreamer 开发版本,它将在不远的未来变为 1.20 稳定分支,需要先 clone GStreamer 仓库:
git clone https://gitlab.freedesktop.org/gstreamer/gstreamer.git
cd gstreamer
或者如果你具有这个仓库的开发者权限的话:
git clone [email protected]:gstreamer/gstreamer.git
cd gstreamer
如果你想要构建稳定的 1.18 或 1.16 分支,则 clone gst-build
:
git clone https://gitlab.freedesktop.org/gstreamer/gst-build.git
cd gst-build
仓库中包含了一些值得注意的脚本和目录:
-
meson.build
是顶层的构建定义,它递归地配置所有依赖。它也定义了一些辅助命令,使你可以有一个未安装的开发环境或简单地更新 GStreamer 模块的 git 仓库。 -
subprojects/
是包含了 GStreamer 模块和一系列依赖的目录。
通过执行如下命令配置一个模块(或在 gst-build 下一次配置多个):
meson
其中 build_directory
是所有的构建指令和输出将放置的位置(这也被称为 “输出目录” 构建)。如果目录还没有创建,则它将在此时创建。注意调用 meson
不需要任何命令参数其实是隐式地调用了 meson setup
命令(比如执行一个工程的初始化配置)。
就 build_directory
的位置而言只有一个限制:它不能与源码目录(比如你下载你的模块的目录)相同。尽管它可以位于目录的外面或下面/里面。
一旦 meson 配置完成,你可以:
- 进入特定的构建目录并运行 ninja:
cd
ninja
- 或不要在每次想要执行
ninja
时都切换到构建目录,你可以只指定构建目录作为一个参数。这个选项的好处是你可以在任何地方执行(而不是切换到 ninja 目录)
ninja -C
这将构建那个模块(和子工程如果构建 gst-build 或单个仓库)的所有东西。
注意:当你修改源文件时你不需要重新运行 meson
,你只需要重新运行 ninja
。如果构建/配置文件发生了改变,ninja
将自己判断出来 meson
需要重新运行并将自动地运行它。
Hello,World
要获得对于一个库的第一印象,再也没有比跑起来一个基于这个库开发的,在屏幕上输出 “Hello World” 的应用更好的方式了。但这里要处理的是多媒体框架,这里将用播放一个媒体文件来替代。
上面的构建过程也将一并构建出 GStreamer 工程的测试和示例应用,其中包括 GStreamer 的 helloworld 示例应用。这个应用的代码位于 gstreamer/tests/examples/helloworld
,编译之后生成的二进制可执行文件位于
。
helloworld 示例应用的源码如下:
#include
static gboolean
bus_call (GstBus * bus, GstMessage * msg, gpointer data)
{
GMainLoop *loop = (GMainLoop *) data;
switch (GST_MESSAGE_TYPE (msg)) {
case GST_MESSAGE_EOS:{
g_print ("End-of-stream\n");
g_main_loop_quit (loop);
break;
}
case GST_MESSAGE_ERROR:{
gchar *debug;
GError *err;
gst_message_parse_error (msg, &err, &debug);
g_printerr ("Debugging info: %s\n", (debug) ? debug : "none");
g_free (debug);
g_print ("Error: %s\n", err->message);
g_error_free (err);
g_main_loop_quit (loop);
break;
}
default:
break;
}
return TRUE;
}
gint
main (gint argc, gchar * argv[])
{
GstElement *playbin;
GMainLoop *loop;
GstBus *bus;
guint bus_watch_id;
gchar *uri;
gst_init (&argc, &argv);
if (argc < 2) {
g_print ("usage: %s \n", argv[0]);
return 1;
}
playbin = gst_element_factory_make ("playbin", NULL);
if (!playbin) {
g_print ("'playbin' gstreamer plugin missing\n");
return 1;
}
/* take the commandline argument and ensure that it is a uri */
if (gst_uri_is_valid (argv[1]))
uri = g_strdup (argv[1]);
else
uri = gst_filename_to_uri (argv[1], NULL);
g_object_set (playbin, "uri", uri, NULL);
g_free (uri);
/* create an event loop and feed gstreamer bus messages to it */
loop = g_main_loop_new (NULL, FALSE);
bus = gst_element_get_bus (playbin);
bus_watch_id = gst_bus_add_watch (bus, bus_call, loop);
gst_object_unref (bus);
/* start play back and listed to events */
gst_element_set_state (playbin, GST_STATE_PLAYING);
g_main_loop_run (loop);
/* cleanup */
gst_element_set_state (playbin, GST_STATE_NULL);
gst_object_unref (playbin);
g_source_remove (bus_watch_id);
g_main_loop_unref (loop);
return 0;
}
这个应用接收一个媒体资源的 URI,并播放这个媒体资源。具体用法如下:
$ build/tests/examples/helloworld/helloworld [URI]
如播放一个 AAC 文件:
$ build/tests/examples/helloworld/helloworld file:///home/hanpfei/aac.aac
但用这个应用播放媒体文件时,报了插件找不到的错,如:
$ build/tests/examples/helloworld/helloworld file:///home/hanpfei/aac.aac
'playbin' gstreamer plugin missing
helloworld 应用通过插件 "playbin" 来播放媒体文件。一般来说,插件的物理形式是一个动态链接库,GStreamer 框架在初始化过程中会到特定的目录下寻找插件。用户可以通过环境变量 GST_PLUGIN_PATH
来为 GStreamer 指定插件的搜索路径,或者以编程的方式,来让 GStreamer 在特定的目录中搜索插件,如:
GstRegistry *registry;
registry = gst_registry_get();
gst_registry_scan_path(registry, "/usr/lib/x86_64-linux-gnu/gstreamer-1.0");
上面看到的 "playbin" 插件,是 GStreamer 项目本身提供的一个基础的插件,其代码位于 gst-plugins-base 项目中,这个项目的具体位置为 https://github.com/GStreamer/gst-plugins-base
。对于 Ubuntu Linux,也可以通过如下命令安装编译好的二进制:
$ apt-get install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libgstreamer-plugins-bad1.0-dev gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-doc gstreamer1.0-tools gstreamer1.0-x gstreamer1.0-alsa gstreamer1.0-gl gstreamer1.0-gtk3 gstreamer1.0-qt5 gstreamer1.0-pulseaudio
这个命令一次性安装 GStreamer 的各种开发库,其中 gstreamer1.0-plugins-base 里会包含 "playbin" 这个插件,这个插件一般会安装在 /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstplayback.so
。
有了这些之后,helloworld 即可以正常运行起来。
接下来就可以开始愉快地探索 GStreamer 的概念和操作了。
参考文档:
GStreamer Documentation
Installing GStreamer on Linux