模块的简单分析
【GStreamer】GstAllocator的简单分析
【GStreamer】GstMemory的简单分析
【GStreamer】GstBuffer的简单分析
【GStreamer】GstPad的简单分析
【GStreamer】GstElement的简单分析
【GStreamer】GstBus和GstMessage的简单分析
【GStreamer】GstDevice和GstPlugin的简单分析
1.GstBus
GstBus用于在应用程序和管道pipeline之间传递消息,允许应用程序异步地接收来自管道或元素的通知、错误、警告和状态变化等消息。由元素运行时生成的消息,会被发布到与管道关联的bus中,应用程序可以通过轮询或信号机制从bus中获取消息,这些消息可以是同步的或异步的,之后根据消息类型执行相应的操作
1.1 类定义
(1)GstBusFlags
typedef enum {
// 当前bus正在丢弃所有message
GST_BUS_FLUSHING = (GST_OBJECT_FLAG_LAST << 0),
/* padding */
GST_BUS_FLAG_LAST = (GST_OBJECT_FLAG_LAST << 1)
} GstBusFlags;
(2)GstBusSyncReply
总线同步处理函数的返回值
typedef enum
{
GST_BUS_DROP = 0, // 丢弃msg
GST_BUS_PASS = 1, // 将msg给到异步队列
GST_BUS_ASYNC = 2 // 将msg给到异步队列,并继续处理当前消息
} GstBusSyncReply;
(3)_GstBus和_GstBusClass
struct _GstBus
{
GstObject object;
/*< private >*/
GstBusPrivate *priv;
gpointer _gst_reserved[GST_PADDING];
};
struct _GstBusClass
{
GstObjectClass parent_class;
/* signals */
/**
* GstBusClass::message:
* @bus: the #GstBus
* @message: the message that has been posted asynchronously
*
* A message has been posted on the bus.
*/
void (*message) (GstBus *bus, GstMessage *message);
/**
* GstBusClass::sync_message:
* @bus: the #GstBus
* @message: the message that has been posted synchronously
*
* A message has been posted on the bus.
*/
void (*sync_message) (GstBus *bus, GstMessage *message);
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
};
1.2 常用函数
(1)gst_bus_pop
从bus队列中取出信息
GstMessage *
gst_bus_pop (GstBus * bus)
{
g_return_val_if_fail (GST_IS_BUS (bus), NULL);
return gst_bus_timed_pop_filtered (bus, 0, GST_MESSAGE_ANY);
}
gst_bus_timed_pop_filtered
GstMessage *
gst_bus_timed_pop_filtered (GstBus * bus, GstClockTime timeout,
GstMessageType types)
{
GstMessage *message;
gint64 now, then;
gboolean first_round = TRUE;
GstClockTime elapsed = 0;
g_return_val_if_fail (GST_IS_BUS (bus), NULL);
g_return_val_if_fail (types != 0, NULL);
g_return_val_if_fail (timeout == 0 || bus->priv->poll != NULL, NULL);
g_mutex_lock (&bus->priv->queue_lock);
// 消息轮询
while (TRUE) {
gint ret;
GST_LOG_OBJECT (bus, "have %" G_GSIZE_FORMAT " messages",
gst_vec_deque_get_length (bus->priv->queue));
// 从bus队列中取出消息
while ((message = gst_vec_deque_pop_head (bus->priv->queue))) {
if (bus->priv->poll) {
while (!gst_poll_read_control (bus->priv->poll)) {
if (errno == EWOULDBLOCK) {
/* Retry, this can happen if pushing to the queue has finished,
* popping here succeeded but writing control did not finish
* before we got to this line. */
/* Give other threads the chance to do something */
g_thread_yield ();
continue;
} else {
/* This is a real error and means that either the bus is in an
* inconsistent state, or the GstPoll is invalid. GstPoll already
* prints a critical warning about this, no need to do that again
* ourselves */
break;
}
}
}
GST_DEBUG_OBJECT (bus, "got message %p, %s from %s, type mask is %u",
message, GST_MESSAGE_TYPE_NAME (message),
GST_MESSAGE_SRC_NAME (message), (guint) types);
// 检查消息的类型是否匹配types,如果匹配,则跳转到beach标签,返回该消息
if ((GST_MESSAGE_TYPE (message) & types) != 0) {
/* Extra check to ensure extended types don't get matched unless
* asked for */
if ((!GST_MESSAGE_TYPE_IS_EXTENDED (message))
|| (types & GST_MESSAGE_EXTENDED)) {
/* exit the loop, we have a message */
goto beach;
}
}
// 消息类型不匹配,释放消息,继续遍历
GST_DEBUG_OBJECT (bus, "discarding message, does not match mask");
gst_message_unref (message);
message = NULL;
}
/* no need to wait, exit loop */
if (timeout == 0)
break;
else if (timeout != GST_CLOCK_TIME_NONE) {
if (first_round) {
then = g_get_monotonic_time ();
first_round = FALSE;
} else {
now = g_get_monotonic_time ();
elapsed = (now - then) * GST_USECOND;
if (elapsed > timeout)
break;
}
}
/* only here in timeout case */
g_assert (bus->priv->poll);
g_mutex_unlock (&bus->priv->queue_lock);
ret = gst_poll_wait (bus->priv->poll, timeout - elapsed);
g_mutex_lock (&bus->priv->queue_lock);
if (ret == 0) {
GST_DEBUG_OBJECT (bus, "timed out, breaking loop");
break;
} else {
GST_DEBUG_OBJECT (bus, "we got woken up, recheck for message");
}
}
beach:
g_mutex_unlock (&bus->priv->queue_lock);
return message;
}
(2)gst_bus_peek
查看消息但不会移除,适合需要预览消息而不改变队列状态的场景
GstMessage *
gst_bus_peek (GstBus * bus)
{
GstMessage *message;
g_return_val_if_fail (GST_IS_BUS (bus), NULL);
g_mutex_lock (&bus->priv->queue_lock);
// 这里是peek而不是pop,所以指示从队列中获取消息而不会清除
message = gst_vec_deque_peek_head (bus->priv->queue);
if (message)
gst_message_ref (message);
g_mutex_unlock (&bus->priv->queue_lock);
GST_DEBUG_OBJECT (bus, "peek on bus, got message %p", message);
return message;
}
(3)gst_bus_post
将一个消息发布到总线上
gboolean
gst_bus_post (GstBus * bus, GstMessage * message)
{
GstBusSyncReply reply = GST_BUS_PASS;
gboolean emit_sync_message;
SyncHandler *sync_handler = NULL;
g_return_val_if_fail (GST_IS_BUS (bus), FALSE);
g_return_val_if_fail (GST_IS_MESSAGE (message), FALSE);
GST_DEBUG_OBJECT (bus, "[msg %p] posting on bus %" GST_PTR_FORMAT, message,
message);
/* check we didn't accidentally add a public flag that maps to same value */
g_assert (!GST_MINI_OBJECT_FLAG_IS_SET (message,
GST_MESSAGE_FLAG_ASYNC_DELIVERY));
GST_OBJECT_LOCK (bus);
/* check if the bus is flushing */
// 检查总线状态
if (GST_OBJECT_FLAG_IS_SET (bus, GST_BUS_FLUSHING))
goto is_flushing;
// 获取同步处理函数
if (bus->priv->sync_handler)
sync_handler = sync_handler_ref (bus->priv->sync_handler);
emit_sync_message = bus->priv->num_sync_message_emitters > 0;
GST_OBJECT_UNLOCK (bus);
/* first call the sync handler if it is installed */
// 调用同步处理函数
if (sync_handler)
reply = sync_handler->handler (bus, message, sync_handler->user_data);
/* emit sync-message if requested to do so via
gst_bus_enable_sync_message_emission. terrible but effective */
// 如果需要发出同步消息且同步处理函数没有丢弃消息,发送sync-message
if (emit_sync_message && reply != GST_BUS_DROP
&& (!sync_handler
|| sync_handler->handler != gst_bus_sync_signal_handler))
gst_bus_sync_signal_handler (bus, message, NULL);
g_clear_pointer (&sync_handler, sync_handler_unref);
/* If this is a bus without async message delivery always drop the message.
* If the sync handler returned GST_BUS_DROP it is responsible of unreffing
* the message, otherwise do it ourself. */
if (!bus->priv->poll && reply != GST_BUS_DROP) {
reply = GST_BUS_DROP;
gst_message_unref (message);
}
/* now see what we should do with the message */
// 处理消息
switch (reply) {
case GST_BUS_DROP: // 丢弃消息
/* drop the message */
GST_DEBUG_OBJECT (bus, "[msg %p] dropped", message);
break;
case GST_BUS_PASS:{ // 将消息放入异步队列
g_mutex_lock (&bus->priv->queue_lock);
gsize length = gst_vec_deque_get_length (bus->priv->queue);
if (G_UNLIKELY (length > 0 && length % WARN_QUEUE_SIZE == 0)) {
GST_WARNING_OBJECT (bus,
"queue overflows with %" G_GSIZE_FORMAT " messages. "
"Application is too slow or is not handling messages. "
"Please add a message handler, otherwise the queue will grow "
"infinitely.", length);
}
/* pass the message to the async queue, refcount passed in the queue */
GST_DEBUG_OBJECT (bus, "[msg %p] pushing on async queue", message);
gst_vec_deque_push_tail (bus->priv->queue, message);
gst_poll_write_control (bus->priv->poll);
GST_DEBUG_OBJECT (bus, "[msg %p] pushed on async queue", message);
g_mutex_unlock (&bus->priv->queue_lock);
break;
}
case GST_BUS_ASYNC: // 进行异步处理,等待消息被处理完成
{
/* async delivery, we need a mutex and a cond to block
* on */
GCond *cond = GST_MESSAGE_GET_COND (message);
GMutex *lock = GST_MESSAGE_GET_LOCK (message);
g_cond_init (cond);
g_mutex_init (lock);
GST_MINI_OBJECT_FLAG_SET (message, GST_MESSAGE_FLAG_ASYNC_DELIVERY);
GST_DEBUG_OBJECT (bus, "[msg %p] waiting for async delivery", message);
/* now we lock the message mutex, send the message to the async
* queue. When the message is handled by the app and destroyed,
* the cond will be signalled and we can continue */
g_mutex_lock (lock);
g_mutex_lock (&bus->priv->queue_lock);
gst_vec_deque_push_tail (bus->priv->queue, message);
gst_poll_write_control (bus->priv->poll);
g_mutex_unlock (&bus->priv->queue_lock);
/* now block till the message is freed */
g_cond_wait (cond, lock);
/* we acquired a new ref from gst_message_dispose() so we can clean up */
g_mutex_unlock (lock);
GST_DEBUG_OBJECT (bus, "[msg %p] delivered asynchronously", message);
GST_MINI_OBJECT_FLAG_UNSET (message, GST_MESSAGE_FLAG_ASYNC_DELIVERY);
g_mutex_clear (lock);
g_cond_clear (cond);
gst_message_unref (message);
break;
}
default: // 无效的返回值,直接释放消息
g_warning ("invalid return from bus sync handler");
gst_message_unref (message);
break;
}
return TRUE;
/* ERRORS */
is_flushing:
{
GST_DEBUG_OBJECT (bus, "bus is flushing");
GST_OBJECT_UNLOCK (bus);
gst_message_unref (message);
return FALSE;
}
}
(4)gst_bus_create_watch
创建bus的监视器
GSource *
gst_bus_create_watch (GstBus * bus)
{
GSource *source;
g_return_val_if_fail (GST_IS_BUS (bus), NULL);
g_return_val_if_fail (bus->priv->poll != NULL, NULL);
GST_OBJECT_LOCK (bus);
source = gst_bus_create_watch_unlocked (bus);
GST_OBJECT_UNLOCK (bus);
return source;
}
gst_bus_create_watch_unlocked
static GSource *
gst_bus_create_watch_unlocked (GstBus * bus)
{
GstBusSource *source;
if (bus->priv->gsource) {
GST_ERROR_OBJECT (bus,
"Tried to add new GSource while one was already there");
return NULL;
}
bus->priv->gsource = g_source_new (&gst_bus_source_funcs,
sizeof (GstBusSource));
source = (GstBusSource *) bus->priv->gsource;
g_source_set_name ((GSource *) source, "GStreamer message bus watch");
g_source_set_dispose_function ((GSource *) source, gst_bus_source_dispose);
source->bus = gst_object_ref (bus);
g_source_add_poll ((GSource *) source, &bus->priv->pollfd);
return (GSource *) source;
}
(5)gst_bus_poll
从总线中轮询消息,这个函数会阻塞,直到指定的消息类型出现在总线上,或者超时
GstMessage *
gst_bus_poll (GstBus * bus, GstMessageType events, GstClockTime timeout)
{
GstBusPollData *poll_data; // 存储轮询的数据
GstMessage *ret;
gulong id;
g_return_val_if_fail (GST_IS_BUS (bus), NULL);
poll_data = g_new (GstBusPollData, 1);
poll_data->source_running = TRUE; // 表示轮询正在进行
poll_data->loop = g_main_loop_new (NULL, FALSE); // 创建新的loop
poll_data->events = events; // 需要监听的消息类型
poll_data->message = NULL;
if (timeout != GST_CLOCK_TIME_NONE)
poll_data->timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE,
timeout / GST_MSECOND, (GSourceFunc) poll_timeout, poll_data,
(GDestroyNotify) poll_destroy_timeout);
else
poll_data->timeout_id = 0;
// 设置回调函数poll_func(),当总线有新消息时,会调用poll_func()
id = g_signal_connect_data (bus, "message", G_CALLBACK (poll_func), poll_data,
(GClosureNotify) poll_destroy, 0);
/* these can be nested, so it's ok */
gst_bus_add_signal_watch (bus);
GST_DEBUG ("running mainloop %p", poll_data->loop);
// 启动主循环,阻塞当前线程,直到接收到消息或超时
g_main_loop_run (poll_data->loop);
GST_DEBUG ("mainloop stopped %p", poll_data->loop);
// 移除信号监视器
gst_bus_remove_signal_watch (bus);
/* holds a ref */
ret = poll_data->message;
if (poll_data->timeout_id)
g_source_remove (poll_data->timeout_id);
/* poll_data will be freed now */
// 断开信号连接
g_signal_handler_disconnect (bus, id);
GST_DEBUG_OBJECT (bus, "finished poll with message %p", ret);
return ret;
}
2.GstMessage
GstMessage用于在管道pipeline和应用程序之间传递信息,它封装了各种类型的消息,例如错误、警告、状态变化、流结束(EOS)等,通过GstBus,这些消息可以从管道传递到应用程序,以便应用程序能够对pipeline的行为做出响应
2.1 类定义
(1)GstMessageType
GstMessageType描述了消息的类型
typedef enum
{
GST_MESSAGE_UNKNOWN = 0, // 未知消息类型
GST_MESSAGE_EOS = (1 << 0), // 流结束
GST_MESSAGE_ERROR = (1 << 1), // 错误消息
GST_MESSAGE_WARNING = (1 << 2), // 警告信息
GST_MESSAGE_INFO = (1 << 3), // 信息消息
GST_MESSAGE_TAG = (1 << 4), // 标签消息
GST_MESSAGE_BUFFERING = (1 << 5), // 缓冲消息
GST_MESSAGE_STATE_CHANGED = (1 << 6), // 状态改变消息
GST_MESSAGE_STATE_DIRTY = (1 << 7), // 状态脏消息
GST_MESSAGE_STEP_DONE = (1 << 8), // 步进完成消息
GST_MESSAGE_CLOCK_PROVIDE = (1 << 9), // 时钟提供消息
GST_MESSAGE_CLOCK_LOST = (1 << 10), // 时钟丢失消息
GST_MESSAGE_NEW_CLOCK = (1 << 11), // 新时钟消息
GST_MESSAGE_STRUCTURE_CHANGE = (1 << 12), // 结构变化消息
GST_MESSAGE_STREAM_STATUS = (1 << 13), // 流状态消息
GST_MESSAGE_APPLICATION = (1 << 14), // 应用程序消息
GST_MESSAGE_ELEMENT = (1 << 15), // 元素消息
GST_MESSAGE_SEGMENT_START = (1 << 16), // 段开始消息
GST_MESSAGE_SEGMENT_DONE = (1 << 17), // 段结束消息
GST_MESSAGE_DURATION_CHANGED = (1 << 18), // 持续事件变化消息
GST_MESSAGE_LATENCY = (1 << 19), // 延迟消息
GST_MESSAGE_ASYNC_START = (1 << 20), // 异步开始消息
GST_MESSAGE_ASYNC_DONE = (1 << 21), // 异步结束消息
GST_MESSAGE_REQUEST_STATE = (1 << 22), // 请求状态消息
GST_MESSAGE_STEP_START = (1 << 23), // 步进开始消息
GST_MESSAGE_QOS = (1 << 24), // 服务质量消息
GST_MESSAGE_PROGRESS = (1 << 25), // 进度消息
GST_MESSAGE_TOC = (1 << 26), // 目录消息
GST_MESSAGE_RESET_TIME = (1 << 27), // 重置时间消息
GST_MESSAGE_STREAM_START = (1 << 28), // 流开始消息
GST_MESSAGE_NEED_CONTEXT = (1 << 29), // 需要上下文消息
GST_MESSAGE_HAVE_CONTEXT = (1 << 30), // 拥有上下文消息
GST_MESSAGE_EXTENDED = (gint) (1u << 31), // 扩展消息类型
GST_MESSAGE_DEVICE_ADDED = GST_MESSAGE_EXTENDED + 1, // 设备添加
GST_MESSAGE_DEVICE_REMOVED = GST_MESSAGE_EXTENDED + 2, // 设备移除
GST_MESSAGE_PROPERTY_NOTIFY = GST_MESSAGE_EXTENDED + 3, // 属性通知
GST_MESSAGE_STREAM_COLLECTION = GST_MESSAGE_EXTENDED + 4, // 流集合
GST_MESSAGE_STREAMS_SELECTED = GST_MESSAGE_EXTENDED + 5, // 流选择
GST_MESSAGE_REDIRECT = GST_MESSAGE_EXTENDED + 6, // 重定向
GST_MESSAGE_DEVICE_CHANGED = GST_MESSAGE_EXTENDED + 7, // 设备更改
GST_MESSAGE_INSTANT_RATE_REQUEST = GST_MESSAGE_EXTENDED + 8, // 即时速率请求
GST_MESSAGE_ANY = (gint) (0xffffffff)
} GstMessageType;
(2)GstStreamStatusType
流状态类型
typedef enum {
GST_STREAM_STATUS_TYPE_CREATE = 0, // 创建流
GST_STREAM_STATUS_TYPE_ENTER = 1, // 流进入某个状态
GST_STREAM_STATUS_TYPE_LEAVE = 2, // 流离开某个状态
GST_STREAM_STATUS_TYPE_DESTROY = 3, // 流被销毁
GST_STREAM_STATUS_TYPE_START = 8, // 流开始处理数据
GST_STREAM_STATUS_TYPE_PAUSE = 9, // 流暂停处理数据
GST_STREAM_STATUS_TYPE_STOP = 10 // 流停止处理数据
} GstStreamStatusType;
(3)GstProgressType
进度消息的具体类型
typedef enum {
GST_PROGRESS_TYPE_START = 0, // 操作已开始
GST_PROGRESS_TYPE_CONTINUE = 1, // 操作正在进行中
GST_PROGRESS_TYPE_COMPLETE = 2, // 操作已完成
GST_PROGRESS_TYPE_CANCELED = 3, // 操作已被取消
GST_PROGRESS_TYPE_ERROR = 4 // 操作中发生错误
} GstProgressType;
(4)_GstMessage
message表示在总线上传递的消息,用于在pipeline和应用程序之间进行通信,例如通知应用程序某个事件的发生或请求应用程序采取某些操作
struct _GstMessage
{
GstMiniObject mini_object;
/*< public > *//* with COW */
GstMessageType type; // 消息类型
guint64 timestamp; // 消息时间戳
GstObject *src; // 消息的来源对象
guint32 seqnum; // 消息序列号
/*< private >*//* with MESSAGE_LOCK */
// 消息锁
GMutex lock; /* lock and cond for async delivery */
// 条件变量
GCond cond;
};
2.2 常用函数
(1)gst_message_new_custom
gst_message_new_custom()用于创建一个自定义的message对象,其核心是为消息分配内存并初始化,同时将传入的structure附加到消息中
GstMessage *
gst_message_new_custom (GstMessageType type, GstObject * src,
GstStructure * structure)
{
GstMessageImpl *message;
// 分配msg内存
message = g_new0 (GstMessageImpl, 1);
GST_CAT_LOG (GST_CAT_MESSAGE, "source %s: creating new message %p %s",
(src ? GST_OBJECT_NAME (src) : "NULL"), message,
gst_message_type_get_name (type));
// 传入的structure必须是独立对象,不能被其他父对象持有
if (structure) {
/* structure must not have a parent */
if (!gst_structure_set_parent_refcount (structure,
&message->message.mini_object.refcount))
goto had_parent;
}
// 初始化消息的基本字段,包括消息类型、源对象等
gst_message_init (message, type, src);
GST_MESSAGE_STRUCTURE (message) = structure;
return GST_MESSAGE_CAST (message);
/* ERRORS */
had_parent:
{
g_free (message);
g_warning ("structure is already owned by another object");
return NULL;
}
}
(2)gst_message_init
初始化一条消息
static void
gst_message_init (GstMessageImpl * message, GstMessageType type,
GstObject * src)
{
gst_mini_object_init (GST_MINI_OBJECT_CAST (message), 0, _gst_message_type,
(GstMiniObjectCopyFunction) _gst_message_copy,
(GstMiniObjectDisposeFunction) _gst_message_dispose,
(GstMiniObjectFreeFunction) _gst_message_free);
GST_MESSAGE_TYPE (message) = type;
if (src)
gst_object_ref (src);
GST_MESSAGE_SRC (message) = src;
GST_MESSAGE_TIMESTAMP (message) = GST_CLOCK_TIME_NONE;
GST_MESSAGE_SEQNUM (message) = gst_util_seqnum_next ();
}
(3)gst_message_new_eos
新建一条eos消息
GstMessage *
gst_message_new_eos (GstObject * src)
{
GstMessage *message;
message = gst_message_new_custom (GST_MESSAGE_EOS, src, NULL);
return message;
}
(4)gst_message_new_info
创建一个info消息,这种消息通常包括的是状态更新、警告或调试信息
GstMessage *
gst_message_new_info (GstObject * src, GError * error, const gchar * debug)
{
return gst_message_new_info_with_details (src, error, debug, NULL);
}
(5)gst_message_new_state_changed
新建一条状态变化的消息
GstMessage *
gst_message_new_state_changed (GstObject * src,
GstState oldstate, GstState newstate, GstState pending)
{
GstMessage *message;
GstStructure *structure;
structure = gst_structure_new_static_str ("GstMessageStateChanged",
"old-state", GST_TYPE_STATE, (gint) oldstate,
"new-state", GST_TYPE_STATE, (gint) newstate,
"pending-state", GST_TYPE_STATE, (gint) pending, NULL);
message = gst_message_new_custom (GST_MESSAGE_STATE_CHANGED, src, structure);
return message;
}
(6)gst_message_new_stream_start
新建一条流开始消息
GstMessage *
gst_message_new_stream_start (GstObject * src)
{
GstMessage *message;
GstStructure *s;
s = gst_structure_new_static_str_empty ("GstMessageStreamStart");
message = gst_message_new_custom (GST_MESSAGE_STREAM_START, src, s);
return message;
}
(7)gst_message_new_device_added
新建一条添加新设备的消息
GstMessage *
gst_message_new_device_added (GstObject * src, GstDevice * device)
{
GstMessage *message;
GstStructure *structure;
g_return_val_if_fail (device != NULL, NULL);
g_return_val_if_fail (GST_IS_DEVICE (device), NULL);
structure = gst_structure_new_static_str ("GstMessageDeviceAdded",
"device", GST_TYPE_DEVICE, device, NULL);
message = gst_message_new_custom (GST_MESSAGE_DEVICE_ADDED, src, structure);
return message;
}