0%

GStreamer学习笔记(1)

Demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#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=file:///root/video.mp4", 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;
}

效果如下图:

关键代码解析

1
gst_init(&argc, &argv);

gst_init用于初始化,必须在其他GStreamer接口之前被调用,不需要其处理命令行参数时可将参数赋值为NULL。

1
GstElement *pipeline = gst_parse_launch("playbin uri=file:///root/video.mp4", NULL);

创建了一个Pipeline,该Pipeline是Playbin类型的。

GStreamer是一个基于管道机制的多媒体库,一个典型的GStreamer程序包含了一个或多个Pipeline,每个Pipeline通过其拥有的一系列Element完成对多媒体数据的处理。同时,虽然是由C语言实现的,但GStreamer实现了自己的面向对象机制,因此其各类型间具有继承关系。

本句中涉及了两个类型,GstPipelineplaybin

其中,GstPipeline是一个在GStreamer当中十分重要的类型,其继承关系如下所示。

1
2
3
4
5
6
GObject
╰── GInitiallyUnowned
╰── GstObject
╰── GstElement
╰── GstBin
╰── GstPipeline

GstElement是一个抽象基类,定义了Element、Pipeline等的接口,在GStreamer中该接类被广泛的用作基类。

GstBin是一个能够容纳和管理其他GstElement的类型,其能够将用户的操作分发到其管理的多个GstElement中,降低了使用复杂性。同时,GstBin还提供了对GstMessage的拦截功能。

GstPipeline通常被用作顶层的容器,其进一步的拓展了GstBin的功能,对内提供了用于多媒体数据同步的全局时钟GstClock,对外提供了统一的消息接口GstBus

playbin则是扩展了GstPipeline的功能,其能够通过有效的Uri获取数据并将其渲染到屏幕上。因为其功能的完整性和高度的集成化,本文不对其进行展开叙述。

gst_parse_launch则通过解析传入字符串来创建指定的GstPipeline

1
gst_element_set_state(pipeline, GST_STATE_PLAYING);

gst_element_set_state用于设置GstElement的状态,该句将pipeline设为了播放状态,使得视频开始能够播放。

正如上文所说的,GstBin能对其管理的GstElement进行统一操作。实际上在该句之后pipeline中包含的所有GstElement都转变为了播放状态,这才使得多媒体数据顺利播放。

每一个GstElement都具有内部状态,通常使用的是以下几个:

1. GST_STATE_NULL:默认状态,该状态下[GstElement](https://gstreamer.freedesktop.org/documentation/gstreamer/gstelement.html?gi-language=c)不会具有任何资源。转入该状态后会释放持有的资源。

2. GST_STATE_READY:在该状态下[GstElement](https://gstreamer.freedesktop.org/documentation/gstreamer/gstelement.html?gi-language=c)将获得全部需要的资源,包括打开的设备、缓冲区等,但流还是会处于关闭状态并被置零。如果在流打开过的情况下转入该状态,将会重置流的配置和位置。

3. GST_STATE_PAUSED:在该状态下[GstElement](https://gstreamer.freedesktop.org/documentation/gstreamer/gstelement.html?gi-language=c)不仅具有GST_STATE_READY分配的全部资源,还会将流打开,使得能够对流进修改。但不会具有运行时钟,流不会随着时钟而发生变化。

4. GST_STATE_PLAYING:在该状态下[GstElement](https://gstreamer.freedesktop.org/documentation/gstreamer/gstelement.html?gi-language=c)的情况与GST_STATE_PAUSED基本相同。但是会具有运行时钟,流会自然地随时钟信号进行处理。
1
2
3
GstBus *bus = gst_element_get_bus(pipeline);
GstMessage *msg = gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE,
GST_MESSAGE_ERROR | GST_MESSAGE_EOS);

这两句分别用于获取消息总线和等待播放程序运行完毕。

gst_element_get_bus返回传入的GstElement对应的GstBus

GstBus是一个能够传递GstMessage的类型。GstBus主要用于解决多线程通信的问题。在播放时,GStreamer内部可能会创建多个线程进行处理,这使得GStreamer需要一个统一的消息传递机制来降低应用程序的复杂度。

gst_bus_timed_pop_filtered则用于监听传入的GstBus,等待目标消息的返回。根据该句的传入参数,程序将会无限等待,直到有发生错误或播放完毕的消息传回。

GstMessage是GStreamer封装的消息类型。一个常用的读取程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
if(msg != NULL) {
GError *err;
gchar *debug_info;

switch (GST_MESSAGE_TYPE (msg)) {
case GST_MESSAGE_ERROR:
gst_message_parse_error (msg, &err, &debug_info);
g_printerr ("Error received from element %s: %s\n",
GST_OBJECT_NAME (msg->src), err->message);
g_printerr ("Debugging information: %s\n",
debug_info ? debug_info : "none");
g_clear_error (&err);
g_free (debug_info);
break;
case GST_MESSAGE_EOS:
g_print ("End-Of-Stream reached.\n");
break;
default:
/* We should not reach here because we only asked for ERRORs and EOS */
g_printerr ("Unexpected message received.\n");
break;
}
gst_message_unref (msg);
}
1
2
3
4
5
if(msg != NULL)
gst_message_unref(msg);
gst_object_unref(bus);
gst_element_set_state(pipeline, GST_STATE_NULL);
gst_object_unref(pipeline);

本段进行了资源释放。由于C语言没有析构函数和垃圾回收等资源管理机制,因此仍然需要进行手动管理。

GStreamer使用引用计数的方式来管理资源。通过在每个类型中放置一个引用数,并在引用数归零是才进行资源释放的方式,能够避免资源的过早释放,因此在使用GStreamer提供的API时,需要着重关注其对引用计数的影响。

gst_object_unref能够将输入的变量的引用计数减一,归零时自动释放。

与之对应的gst_object_ref能够将输入的变量的引用计数加一。