0%

关于GStreamer未关闭Pipeline流输出导致的内存泄露

GStreamer引用计数查看方法

GStreamer提供了GST_OBJECT_REFCOUNT_VALUE宏用于查询引用计数,其要求输入一个GstElement*类型的变量,并返回gint类型的该变量引用计数值。

注意,当输入变量未被分配或已释放(输入变量的引用计数降为0)时,该宏的行为未定义。

Pipeline释放前未设置状态为NULL时可能导致的内存泄露

当Pipeline释放前未设置状态为NULL时,其具有许多外部的引用计数,此时即使将其unref,也不会使得管道被释放,这将可能导致内存泄露。

使用如下代码进行测试:

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
30
31
32
33
34
35
#include <gst/gst.h>

gboolean stop(gpointer data);

int main(int argc, char* argv[]) {
gst_init(&argc, &argv);

GstElement* pipeline = gst_parse_launch("playbin uri=https://gstreamer.freedesktop.org/data/media/sintel_trailer-480p.webm", NULL);
GMainLoop* main_loop = g_main_loop_new(NULL, FALSE);

g_timeout_add(5000, stop, main_loop);

g_print("pipeline ref on a: %d\n", GST_OBJECT_REFCOUNT_VALUE(pipeline));

gst_element_set_state(pipeline, GST_STATE_PLAYING);
g_print("pipeline ref on b: %d\n", GST_OBJECT_REFCOUNT_VALUE(pipeline));
g_main_loop_run(main_loop);
g_print("pipeline ref on c: %d\n", GST_OBJECT_REFCOUNT_VALUE(pipeline));

//gst_element_set_state(pipeline, GST_STATE_NULL);
g_print("pipeline ref on d: %d\n", GST_OBJECT_REFCOUNT_VALUE(pipeline));

gst_object_unref(pipeline);
g_print("pipeline ref on e: %d\n", GST_OBJECT_REFCOUNT_VALUE(pipeline));
g_main_loop_unref(main_loop);
return 0;
}

gboolean stop(gpointer data) {
GMainLoop* loop = (GMainLoop*)data;
g_print("STOP\n");
g_main_loop_quit(loop);

return FALSE;
}

运行后,控制台打印结果为:

1
2
3
4
5
6
pipeline ref on a: 1
pipeline ref on b: 3
STOP
pipeline ref on c: 7
pipeline ref on d: 7
pipeline ref on e: 6

当正确设置状态为NULL时可避免该问题:

1
2
3
4
5
pipeline ref on a: 1
pipeline ref on b: 3
STOP
pipeline ref on c: 7
pipeline ref on d: 1

运行后,控制台打印结果为:

1
2
3
4
5
pipeline ref on a: 1
pipeline ref on b: 3
STOP
pipeline ref on c: 7
pipeline ref on d: 1