本篇教程会学到:
- 如何使用gst_init()初始化GStreamer
- 如何使用gst_parse_launch()从文本描述来快速构建一个pipeline
- 如何使用playbin创建一个自动播放的pipeline
- 如何使用gst_element_set_state()通知GStreamer开始播放
- 如何使用gst_element_get_bus()和gst_bus_timed_pop_filtered()处理事件通知
学习一门编程语言,打印一个hello world是最好的实践。学习gstreamer也是,不过不是打印hello world,而是播放一个视频文件。
首先把如下代码拷贝到一个命名为basic-tutorial-1.c
的文件中。
#include <gst/gst.h>
int
main(int argc, char *argv[])
{
GstElement *pipeline;
GstBus *bus;
GstMessage *msg;
/* Initialize GStreamer */
gst_init(&argc, &argv);
/* Build the pipeline */
pipeline =
gst_parse_launch
("playbin uri=https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm",
NULL);
/* Start playing */
gst_element_set_state(pipeline, GST_STATE_PLAYING);
/* Wait until error or EOS */
bus = gst_element_get_bus(pipeline);
msg =
gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE,
GST_MESSAGE_ERROR | GST_MESSAGE_EOS);
/* Free resources */
if (msg != NULL)
gst_message_unref(msg);
gst_object_unref(bus);
gst_element_set_state(pipeline, GST_STATE_NULL);
gst_object_unref(pipeline);
return 0;
}
执行编译(linux)
gcc basic-tutorial-1.c -o basic-tutorial-1 `pkg-config --cflags --libs gstreamer-1.0`
运行
效果是会弹出一个视频播放窗口,播放的是从网络上拉取一段带有音频的视频。
代码走读
/* Initialize GStreamer */
gst_init(&argc, &argv);
使用gstreamer必须先调用此函数,它做的事情包括:
- 初始化所有内部数据结构
- 检查所有可用的插件(plug-ins)
- 执行所有的命令行选项
/* Build the pipeline */
pipeline =
gst_parse_launch
("playbin uri=https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm",
NULL);
这行代码是本篇教程的核心,它包含了两个重要的点:gst_parse_launch()和playbin。
gst_parse_launch
GStreamer是一个用来处理多媒体流的框架。多媒体经过“source”元件(生产者),流到“sink”元件(消费者),中间经过一系列的用于处理各种任务的元件。这样将多个元件连接起来的集合就称为一个pipeline。注意,这里说的元件是一个专有名词,英文是element,后面还会提到。
在GStreamer中,通常是手动的组合各个独立的元件来构成一个pipeline。但是当pipeline足够简单的时候,你不需要一些高级特性的时候,你就可以使用gst_parse_launch()。
此函数采用管道的文本表示形式并将其转换为实际的管道,非常方便。 实际上,这个功能的使用非常方便,它有一个完全围绕它构建的工具,在看过后面的教程后你就会非常熟悉了(请参阅基础教程10:GStreamer工具以了解gst-launch-1.0和gst-launch-1.0语法)。
playbin
在本例中,我们用gst_parse_launch()构建了一个由称为playbin的单个元件组成的管道。
playbin是一个特殊的元件,它既是一个source元件,也是一个sink元件,并且也是一个完整的pipeline。在内部,他创建并连接了播放多媒体必需的所有元件,所以我们不用过多操心。
它没有像手工pipeline那样的控制粒度,但是仍然有足够的自定义部分以满足各种应用程序的需要,包括本教程。
在本例中,我们只向playbin传了一个参数,那就是我们想要播放的视频的URI,当然也可以尝试更改为其他的以http://或file://为前缀的URI。playbin都会透明地实例化相应的GStreamer source。
如果你写入的URI是错误的,或者文件不存在,或者缺少插件,则GStreamer提供了几种通知机制,但是在此例中我们唯一要做的就是错误时退出,不再做过多介绍。
/* Start playing */
gst_element_set_state(pipeline, GST_STATE_PLAYING);
这行代码里有一个重要的概念:状态。每一个GStreamer的元件都有一个关联的状态,你可以或多或少地将其视为常规DVD播放器中的“播放/暂停”按钮。 在将管道设置为“PLAYING”状态之前,播放不会开始。
这行代码用gst_element_set_state将pipeline的状态设置为PLAYING,从而启动了播放。
/* Wait until error or EOS */
bus = gst_element_get_bus(pipeline);
msg =
gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE,
GST_MESSAGE_ERROR | GST_MESSAGE_EOS);
这段代码会一直等待,直到出现错误或到达流的结尾。gst_element_get_bus会获取pipeline的bus,gst_bus_timed_pop_filtered会阻塞到通过bus收到错误或者EOS(End-Of-Stream)。GStreamer的bus概念在第二篇教程还会解释。
这个示例就这些,GStreamer会做大部分的事情,直到遇到错误或者到达流的末尾,执行操作才会结束。当然,随时执行control+C都会立即中断程序。
清理
在退出程序之前,还有一些清理工作要做。
/* Free resources */
if (msg != NULL)
gst_message_unref(msg);
gst_object_unref(bus);
gst_element_set_state(pipeline, GST_STATE_NULL);
gst_object_unref(pipeline);
记住,一定要阅读对应函数的文档,这样才能知道是否应该释放掉他们返回的对象。
比如在本例中:
gst_bus_timed_pop_filtered()返回了一个必须要用gst_message_unref()释放的message对象。
gst_element_get_bus()的调用,会让bus增加一个引用,因此也必须用gst_object_unref()来释放。
将pipeline的状态设置为NULL,以确保它释放了所有之前申请的资源。
最后,释放pipeline以销毁它及其所有相关内容。