1. Message
在gstreamer中,message可以称为Bus Message,通常用于pipeline和application之间交互使用。提到Message的同时,需要对总线(Bus)进行相应的了解,其作用是将pipeline中释放的Message传递给Application。默认情况下,每一个pipeline都会包含一个Bus,因此在编写Application程序时不需要创建Bus。Application唯一需要做的是在Bus上设置Message处理函数。
如何处理Bus中的Message?
- 可以使用gst_bus_post方法将Message发布到Bus上。并可以采用gst_bus_peek和gst_bus_pop方法来查看或检索以前发布的消息
- 应用程序可以使用 gst_bus_add_watch_full 或 gst_bus_add_watch 来异步监听Bus,并将Message处理函数附加到Pipeline的Bus上,每当Pipeline向Bus发出Message时,都将调用该函数。
每当Pipeline的状态从READY改变成NULL,其Bus会设置成flushing状态。Message的类型具体可以参考GstMessageType.
/* adds a watch for new message on our pipeline's message bus to
* the default GLib main context, which is the main context that our
* GLib main loop is attached to below
*/
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
bus_watch_id = gst_bus_add_watch (bus, bus_call, NULL); // bus_call为Message处理回调函数
gst_object_unref (bus);
1.1 message类型分析
message 类型的具体信息可以参考GstMessageType。下面主要介绍一下重要常用的message。
-
GST_MESSAGE_EOS:end-of-stream reached in a pipeline. application只有在pipeline的state为PLAYING下才能接收该message,以及每次在EOS状态下再次设置pipeline的state为PLAYING。当application在pipeline上执行一个flush seek,将会撤销EOS状态。
-
GST_MESSAGE_WARNING:a warning occurred.
-
GST_MESSAGE_ERROR:
-
GST_MESSAGE_STATE_CHANGED:a state change happened
-
GST_MESSAGE_ELEMENT:特定element发出的message。
-
GST_MESSAGE_STREAM_STATUS:status about a stream, emitted when it starts, stops, errors, etc..
-
GST_MESSAGE_STREAM_START:标识一个new stream开始的message
1.2 bus_call函数的实现
bus的回调函数语法格式如下:
static gboolean
bus_call (GstBus * bus, GstMessage * msg, gpointer data)
{
GMainLoop *loop = (GMainLoop *) data;
...
return TRUE;
}
gpointer data:指的是用户传入的数据。example中传入的loop信息。
1.2.1 捕获bus上所有的message
g_print ("Received message on bus: source %s, msg_type %s.\n",
GST_MESSAGE_SRC_NAME (msg), GST_MESSAGE_TYPE_NAME (msg));
g_print("the sequence number of the message: %d.\n", msg->seqnum);
g_print("source: %s.\n", GST_OBJECT_NAME (msg->src));
GST_MESSAGE_SRC_NAME:用于获取发出message的element是哪个
GST_MESSAGE_TYPE_NAME:获取发出message的type是哪个
1.2.1 捕获不同类型的message并分析
switch (GST_MESSAGE_TYPE (msg))
{
case GST_MESSAGE_EOS:
{
g_print ("End of stream\n");
g_main_loop_quit (loop);
break;
}
case GST_MESSAGE_WARNING:
{
gchar *debug;
GError *error;
gst_message_parse_warning (msg, &error, &debug);
g_printerr ("WARNING from element %s: %s\n",
GST_OBJECT_NAME (msg->src), error->message);
g_free (debug);
g_printerr ("Warning: %s\n", error->message);
g_error_free (error);
break;
}
case GST_MESSAGE_ERROR:
{
gchar *debug;
GError *error;
gst_message_parse_error (msg, &error, &debug);
g_printerr ("ERROR from element %s: %s\n",
GST_OBJECT_NAME (msg->src), error->message);
if (debug)
g_printerr ("Error details: %s\n", debug);
g_free (debug);
g_error_free (error);
g_main_loop_quit (loop);
}
}
上面代码介绍了常见的EOS,WARNING, ERROR message的处理程序。下面就其他可能用到的message添加一些处理程序。
stream相关message
case GST_MESSAGE_STREAM_START:
{
g_print("Signals the start of a new stream from source %s.\n", GST_OBJECT_NAME (msg->src));
break;
}
case GST_MESSAGE_STREAM_STATUS:
{
GstStreamStatusType type;
GstElement *owner;
const GValue *val;
gchar *path;
GstTask *task = NULL;
g_message ("received STREAM_STATUS");
gst_message_parse_stream_status (msg, &type, &owner);
val = gst_message_get_stream_status_object (msg);
g_message ("type: %d", type);
path = gst_object_get_path_string (GST_MESSAGE_SRC (msg));
g_message ("source: %s", path);
g_free (path);
path = gst_object_get_path_string (GST_OBJECT (owner));
g_message ("owner: %s", path);
g_free (path);
g_message ("object: type %s, value %p", G_VALUE_TYPE_NAME (val),
g_value_get_object (val));
break;
}
#ifndef PLATFORM_TEGRA
case GST_MESSAGE_ELEMENT:
{
if (gst_nvmessage_is_stream_eos (msg))
{
guint stream_id;
if (gst_nvmessage_parse_stream_eos (msg, &stream_id))
{
g_print ("Got EOS from stream %d\n", stream_id);
}
}
break;
}
#endif
2. Events
Events: Seeking, Navigation and More
Buffers and Events
2.1 events的作用
event与buffer一起在pipeline的up and downstream中传播,在elements之间进行交互传递events。
2.2 events的类型
Gstreamer的events类型如下,常用的event类型便是EOS。
typedef enum {
GST_EVENT_UNKNOWN = GST_EVENT_MAKE_TYPE (0, 0),
/* bidirectional events */
GST_EVENT_FLUSH_START = GST_EVENT_MAKE_TYPE (10, FLAG(BOTH)),
GST_EVENT_FLUSH_STOP = GST_EVENT_MAKE_TYPE (20, FLAG(BOTH) | FLAG(SERIALIZED)),
/* downstream serialized events */
GST_EVENT_STREAM_START = GST_EVENT_MAKE_TYPE (40, FLAG(DOWNSTREAM) | FLAG(SERIALIZED) | FLAG(STICKY)),
GST_EVENT_CAPS = GST_EVENT_MAKE_TYPE (50, FLAG(DOWNSTREAM) | FLAG(SERIALIZED) | FLAG(STICKY)),
GST_EVENT_SEGMENT = GST_EVENT_MAKE_TYPE (70, FLAG(DOWNSTREAM) | FLAG(SERIALIZED) | FLAG(STICKY)),
GST_EVENT_STREAM_COLLECTION = GST_EVENT_MAKE_TYPE (75, FLAG(DOWNSTREAM) | FLAG(SERIALIZED) | FLAG(STICKY) | FLAG(STICKY_MULTI)),
GST_EVENT_TAG = GST_EVENT_MAKE_TYPE (80, FLAG(DOWNSTREAM) | FLAG(SERIALIZED) | FLAG(STICKY) | FLAG(STICKY_MULTI)),
GST_EVENT_BUFFERSIZE = GST_EVENT_MAKE_TYPE (90, FLAG(DOWNSTREAM) | FLAG(SERIALIZED) | FLAG(STICKY)),
GST_EVENT_SINK_MESSAGE = GST_EVENT_MAKE_TYPE (100, FLAG(DOWNSTREAM) | FLAG(SERIALIZED) | FLAG(STICKY) | FLAG(STICKY_MULTI)),
GST_EVENT_STREAM_GROUP_DONE = GST_EVENT_MAKE_TYPE (105, FLAG(DOWNSTREAM) | FLAG(SERIALIZED) | FLAG(STICKY)),
GST_EVENT_EOS = GST_EVENT_MAKE_TYPE (110, FLAG(DOWNSTREAM) | FLAG(SERIALIZED) | FLAG(STICKY)),
GST_EVENT_TOC = GST_EVENT_MAKE_TYPE (120, FLAG(DOWNSTREAM) | FLAG(SERIALIZED) | FLAG(STICKY) | FLAG(STICKY_MULTI)),
GST_EVENT_PROTECTION = GST_EVENT_MAKE_TYPE (130, FLAG (DOWNSTREAM) | FLAG (SERIALIZED) | FLAG (STICKY) | FLAG (STICKY_MULTI)),
/* non-sticky downstream serialized */
GST_EVENT_SEGMENT_DONE = GST_EVENT_MAKE_TYPE (150, FLAG(DOWNSTREAM) | FLAG(SERIALIZED)),
GST_EVENT_GAP = GST_EVENT_MAKE_TYPE (160, FLAG(DOWNSTREAM) | FLAG(SERIALIZED)),
/* upstream events */
GST_EVENT_QOS = GST_EVENT_MAKE_TYPE (190, FLAG(UPSTREAM)),
GST_EVENT_SEEK = GST_EVENT_MAKE_TYPE (200, FLAG(UPSTREAM)),
GST_EVENT_NAVIGATION = GST_EVENT_MAKE_TYPE (210, FLAG(UPSTREAM)),
GST_EVENT_LATENCY = GST_EVENT_MAKE_TYPE (220, FLAG(UPSTREAM)),
GST_EVENT_STEP = GST_EVENT_MAKE_TYPE (230, FLAG(UPSTREAM)),
GST_EVENT_RECONFIGURE = GST_EVENT_MAKE_TYPE (240, FLAG(UPSTREAM)),
GST_EVENT_TOC_SELECT = GST_EVENT_MAKE_TYPE (250, FLAG(UPSTREAM)),
GST_EVENT_SELECT_STREAMS = GST_EVENT_MAKE_TYPE (260, FLAG(UPSTREAM)),
/* custom events start here */
GST_EVENT_CUSTOM_UPSTREAM = GST_EVENT_MAKE_TYPE (270, FLAG(UPSTREAM)),
GST_EVENT_CUSTOM_DOWNSTREAM = GST_EVENT_MAKE_TYPE (280, FLAG(DOWNSTREAM) | FLAG(SERIALIZED)),
GST_EVENT_CUSTOM_DOWNSTREAM_OOB = GST_EVENT_MAKE_TYPE (290, FLAG(DOWNSTREAM)),
GST_EVENT_CUSTOM_DOWNSTREAM_STICKY = GST_EVENT_MAKE_TYPE (300, FLAG(DOWNSTREAM) | FLAG(SERIALIZED) | FLAG(STICKY) | FLAG(STICKY_MULTI)),
GST_EVENT_CUSTOM_BOTH = GST_EVENT_MAKE_TYPE (310, FLAG(BOTH) | FLAG(SERIALIZED)),
GST_EVENT_CUSTOM_BOTH_OOB = GST_EVENT_MAKE_TYPE (320, FLAG(BOTH))
} GstEventType;
events在pipeline中传播只有两种方式:downstream或者upstream。downstream events通过sinkpad的event处理程序接收。主要的downstream events包括SEGMENT, CAPS, TAG, EOS。
upstream events通常由downstream的element生成(例如,video sink想生成一个navigation events来通知upstream elements现在鼠标指针的位置)。同样,当application在pipeline上执行seek request时,这个请求将传递到sink element,然后将生成一个upstream seek事件。
最常见的upstream events是 seek,Quality-of-Service(Qos)和reconfigure事件。
2.3 如何获取events
通过probe在element的pad上附加callback函数来接收events。
2.3.1 probe的概念
probe可以被看作为一个pad的监听器。从技术上讲,probe不过是使用gst_pad_add_probe()函数附加到一个pad上的一个callback回调函数。同样的,你可以使用gst_pad_remove_probe ()删除回调。连接后,probe会通知你pad上的任何活动。你可以定义添加probe后感兴趣的通知类型。
2.3.2 gst_pad_add_probe方法介绍
gulong gst_pad_add_probe (GstPad * pad, GstPadProbeType mask,
GstPadProbeCallback callback, gpointer user_data, GDestroyNotify destroy_data)
作用:用来通知pads的不同状态。每次state满足mask的要求都会调用callback函数。
Probes的调用顺序:首先调用GST_PAD_PROBE_TYPE_BLOCK类型,然后调用其他类型,最后调用GST_PAD_PROBE_TYPE_IDLE类型。顺序调用。唯一例外是,当gst_pad_add_probe方法被调用时pad已经空闲,则会立刻调用GST_PAD_PROBE_TYPE_IDLE类型。
2.3.3 常用的GstPadProbeType
- GST_PAD_PROBE_TYPE_IDLE
- GST_PAD_PROBE_TYPE_BLOCK
- GST_PAD_PROBE_TYPE_BUFFER
- GST_PAD_PROBE_TYPE_DATA_BOTH
- GST_PAD_PROBE_TYPE_EVENT_BOTH
2.3.4 callback函数
GstPadProbeReturn (*GstPadProbeCallback) (GstPad * pad, GstPadProbeInfo * info,
gpointer user_data)
callback允许修改info的数据指针。
- pad:blocked pad
- info:GstPadProbeInfo
- user_data:用户自定义数据
- GstPadProbeReturn:返回值
- GST_PAD_PROBE_DROP :丢弃数据在data probes上。在push mode下(src pad),指的是捕获到的item不会向下游element传递。在pull mode 下,指的是捕获到的item捕获向上游element传递。
- GST_PAD_PROBE_OK:正常返回值。即不对item做任何处理,在这个过程中可以决定将是否将丢弃或传递data到其他probes上。如果没有其他probes,则执行probe type的默认行为
- GST_PAD_PROBE_REMOVE :删除probe即回调函数,传递数据。对于blocked probes,将会使data flow转换为unblock,除非有其他的blocking probes安装
- GST_PAD_PROBE_PASS :在blocked probe上传递获取到的item并将下一个item blocked。
- GST_PAD_PROBE_HANDLED
2.3.5 example
1. 在pad上添加probe回调函数
/* Lets add probe to get informed of the meta data generated, we add probe to
* the sink pad of the osd element, since by that time, the buffer would have
* had got all the metadata. */
osd_sink_pad = gst_element_get_static_pad (nvvidconv, "src");
if (!osd_sink_pad)
g_print ("Unable to get src pad\n");
else
gst_pad_add_probe (osd_sink_pad, (GstPadProbeType)(GST_PAD_PROBE_TYPE_BUFFER |
GST_PAD_PROBE_TYPE_EVENT_BOTH) , osd_sink_pad_buffer_probe, NULL, NULL);
2. probe回调函数的实现
static GstPadProbeReturn
osd_sink_pad_buffer_probe (GstPad * pad, GstPadProbeInfo * info, gpointer u_data)
{
if ((info->type & GST_PAD_PROBE_TYPE_BUFFER)) // buffer push and pull
{
// g_print("buffer.\n");
GstBuffer *buf = (GstBuffer *) info->data;
if(gst_buffer_is_writable(buf))
process_buffer(buf);
}
if ((info->type & GST_PAD_PROBE_TYPE_EVENT_BOTH))
{
GstEvent *event = GST_EVENT (info->data);
switch (GST_EVENT_TYPE (event))
{
case GST_EVENT_STREAM_START:
{
// g_print("stream start.\n");
break;
}
default:
break;
}
}
return GST_PAD_PROBE_OK;
}
2.4 如何发送events
通常使用gst_event_new_*()函数来创建events。application使用gst_element_send_event函数来发送一个event,elements使用gst_pad_send_event和gst_pad_push_event函数。如果一个event没有被send,需要通过gst_event_unref函数来释放。
2.4.1 添加probe回调函数和发送eos event
下面的代码实现了如图的一个效果,在Filter类的element的sink pad上释放EOS event,在src pad上通过绑定回调函数捕获EOS event。
static GstPadProbeReturn
pad_probe_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
{
GstPad *srcpad, *sinkpad;
/* install new probe for EOS */
srcpad = gst_element_get_static_pad (filter_element, "src");
gst_pad_add_probe (srcpad, GST_PAD_PROBE_TYPE_BLOCK |
GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, event_probe_cb, user_data, NULL);
gst_object_unref (srcpad);
/* push EOS into the element, the probe will be fired when the
* EOS leaves the effect and it has thus drained all of its data */
sinkpad = gst_element_get_static_pad (filter_element, "sink");
gst_pad_send_event (sinkpad, gst_event_new_eos ());
gst_object_unref (sinkpad);
return GST_PAD_PROBE_OK;
}
static GstPadProbeReturn
event_probe_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
{
// probe中data flow处于blocked状态
if (GST_EVENT_TYPE (GST_PAD_PROBE_INFO_DATA (info)) != GST_EVENT_EOS)
return GST_PAD_PROBE_PASS; // 将获取到的其他类型的events向下传递
return GST_PAD_PROBE_DROP; // 将获取的EOS event抛弃,不再向downstream elements传递
}