Gstreamer-GstEvent

本文深入探讨GStreamer的事件机制,解析事件类的功能,包括事件的创建、解析、类型及内容,重点介绍标准事件类型如EOS、seek和stream-start等,并讲解如何在管道中使用事件进行信号发送。

相关连接:https://blog.youkuaiyun.com/knowledgebao/article/details/84621238


Includes

#include <gst/gst.h>

Description

event类提供构造和解析events的方法,而events事件是通信的载体。

events通常调用类似 gst_event_new_*() 这样的函数去创建。应用程序一般通过gst_element_send_event() 函数发送events,而element通常通过 gst_pad_send_event() or gst_pad_push_event()发送events。如果events构建后没有被发送,需要调用gst_event_unref()释放。如果发送了就由对方去释放。

events可以通过类似 gst_event_parse_*() 这样的函数去解析内容,当然events可以只有类型而没有内容,既内容可以为空。

events主要在一个bin里的element之间传递。一些events可以包含有数据流。一些events只能向下游传递,一些events只能向上游传递,一些events既可以向下游传递,也可以向上游传递。events一般用于在数据流中发出特殊的信号,比如EOS(流的结束)或新流段的开始。events也会被用于刷新任何挂起数据的pipeline。

大多数事件API是在插件中使用的。应用程序通常只构造和使用seek事件。使用gst_event_new_seek()创建一个seek事件。它使用所需的参数来指定查找时间和模式。如下边代码段:

GstEvent *event;
gboolean result;
...
// construct a seek event to play the media from second 2 to 5, flush
// the pipeline to decrease latency.
event = gst_event_new_seek (1.0,
   GST_FORMAT_TIME,
   GST_SEEK_FLAG_FLUSH,
   GST_SEEK_TYPE_SET, 2 * GST_SECOND,
   GST_SEEK_TYPE_SET, 5 * GST_SECOND);
...
result = gst_element_send_event (pipeline, event);
if (!result)
  g_warning ("seek failed");
...

举例:

1,pad关联一个event处理函数,上游pad可以发送event事件给下游

#define gst_pad_set_event_function(p,f)   gst_pad_set_event_function_full((p),(f),NULL,NULL)
void gst_pad_set_event_function_full(GstPad *pad,GstPadEventFunction event,gpointer user_data,GDestroyNotify notify);
//解析函数定义及调用:
//设置指定pad接收函数
gst_pad_set_event_function(priv->sinkpad, GST_DEBUG_FUNCPTR(gst_ff_audio_enc_sink_event));
//定义及实现接收函数
static gboolean gst_ff_audio_enc_sink_event(GstPad * pad, GstObject * parent, GstEvent * event)
{
    GST_LOG_OBJECT(filter, "audio Enc * Received %s event: %" GST_PTR_FORMAT,
        GST_EVENT_TYPE_NAME(event), event);

    switch (GST_EVENT_TYPE(event)) {
    case GST_EVENT_EOS:
    {
        GST_FF_AUDIO_ENC_LOCK(priv);
        ret = gst_pad_push_event(priv->srcpad, event);
        gst_event_unref(event);
        GST_FF_AUDIO_ENC_UNLOCK(priv);
        break;
    }
    case GST_EVENT_CAPS:
    {
        GST_FF_AUDIO_ENC_LOCK(priv);
        GstCaps * caps;
        gst_event_parse_caps(event, &caps);
        ret = gst_ff_audio_enc_create(filter, caps);
        if (ret)
            ret = gst_ff_audio_enc_setcaps(filter);
        gst_event_unref(event);
        GST_FF_AUDIO_ENC_UNLOCK(priv);
        break;
    }
    default:
        ret = gst_pad_event_default(pad, parent, event);
        break;
    }

    return ret;
}
//上游发送events
ret = gst_pad_push_event(priv->srcpad, gst_event_new_caps(fixcaps));

Types and Values

structGstEvent包含4个字段:父指针GstMiniObject mini_object;类型GstEventType type;序列号guint32 seqnum
enumGstEventTypeFlags构建GstEventType的枚举参数,详见GstEventType
#defineGST_EVENT_TYPE_BOTHGstEventTypeFlags中 GST_EVENT_TYPE_UPSTREAM | GST_EVENT_TYPE_DOWNSTREAM.
enumGstEventTypeGstEventType是一个枚举类型,这里的枚举类型是可以在管道中发送的标准事件类型。

自定义事件类型一般都携带一个GstStructure,通过GstStructure来传递内容。如何构造事件类型,详见GST_EVENT_MAKE_TYPE,一般用户自定义类型可能会重复,所以最好通过GstStructure内容来区分具体信息。用户自定义EventType仅作为第一道入口。

enumGstStreamFlags流类型,包括:稀疏型,必选型,非必选型等。通过函数

gst_event_set_stream_flags ()和gst_event_parse_stream_flags()设置和获取,对应stream-start event

enumGstQOSType函数gst_event_new_qos()的第一个参数,枚举GOS的类型。包括:数据太快,数据太慢,无所谓3中状态,具体参考gst_event_new_qos()
enumGstSeekTypeseek类型枚举,参考 gst_event_new_seek() or  gst_segment_do_seek().有3个值:不变,相对文件头,相对文件尾。
enumGstSeekFlagsseek标签枚举,可以通过或多个同时使用,参考 gst_event_new_seek()  or  gst_segment_do_seek().有10几个标识,此处不具体描述。比如快进、快退、是否查找关键帧等。


Functions

#defineGST_EVENT_MAKE_TYPE()用户定义事件类型。#define GST_EVENT_MAKE_TYPE(num,flags) \
    (((num) << GST_EVENT_NUM_SHIFT) | (flags)),用户定义num一般必须大于320;flag取值范围为GstEventTypeFlags。系统定义的类型详见GstEventType枚举。
#defineGST_EVENT_TYPE()返回事件类型,具体类型参见GstEventTypeFlags
#defineGST_EVENT_TYPE_NAME()和类型对应的描述信息
#defineGST_EVENT_TIMESTAMP()返回事件创建时间
#defineGST_EVENT_SEQNUM()返回seqnum
#defineGST_EVENT_IS_UPSTREAM()Check if an event can travel upstream.详见GstEventTypeFlags
#defineGST_EVENT_IS_DOWNSTREAM()Check if an event can travel downstream.详见GstEventTypeFlags
#defineGST_EVENT_IS_SERIALIZED()Check if an event is serialized with the data stream.详见GstEventTypeFlags
#defineGST_EVENT_IS_STICKY()Check if an event is sticky on the pads.详见GstEventTypeFlags
GstEventTypeFlagsgst_event_type_get_flags ()详见GstEventTypeFlags
const gchar *gst_event_type_get_name ()返回event名称,系统自定义的event对应都定义了名称,比如:GST_EVENT_SEEK, "seek"或GST_EVENT_CAPS, "caps"等
GQuarkgst_event_type_to_quark ()返回event的索引值,也就是GST_EVENT_SEEK,GST_EVENT_CAPS等这些大小。实际就是一个int值
GstEvent *gst_event_ref ()event索引+1
voidgst_event_unref ()event索引-1
gbooleangst_event_replace ()event指针交换,原子操作。the old event is unreffed, the new one is reffed
GstEvent *gst_event_copy ()copy
GstEvent *gst_event_steal ()event指针转移,类似gst_event_replace ()
gbooleangst_event_take ()gst_event_replace (),唯一区别是此函数获取new_event的ownership(所有权)
#definegst_event_is_writable()是否可写
#definegst_event_make_writable()使其可写,如果不可写会调用gst_event_copy ()得到一份新的event
GstStructure *gst_event_writable_structure ()获取可写的Structure,无需释放
GstEvent *gst_event_new_custom ()构造用户Event,包含type和一个GstStructure,建议不要完全依赖type来区分事件,因为用户自定义type可能会重复,所以结合GstStructure内容来唯一确定事件
const GstStructure *gst_event_get_structure ()获取GSTStructure指针,无需释放,如果event被释放,此指针可能成为野指针。
gbooleangst_event_has_name ()检测event名称
guint32gst_event_get_seqnum ()GST_EVENT_SEQNUM()
voidgst_event_set_seqnum ()设置序列号,一般递增,但是可以做一些关联,取决于用户
gint64gst_event_get_running_time_offset ()获取event的运行时长
voidgst_event_set_running_time_offset ()设置event的运行时长,暂时理解有点模糊,运行时长设置的作用?

Events passing through GstPads that have a running time offset set via gst_pad_set_offset() will get their offset adjusted according to the pad's offset.

If the event contains any information that related to the running time, this information will need to be updated before usage with this offset.

GstEvent *gst_event_new_flush_start ()等价于gst_event_new_custom (GST_EVENT_FLUSH_START, NULL);创建一个开始刷新event。一般在Seek之后,用于清空之前的缓存。Any event (except a GST_EVENT_FLUSH_STOP) received on a flushing pad will return FALSE immediately.
GstEvent *gst_event_new_flush_stop ()等价于  event = gst_event_new_custom (GST_EVENT_FLUSH_STOP,
      gst_structure_new_id (GST_QUARK (EVENT_FLUSH_STOP),
          GST_QUARK (RESET_TIME), G_TYPE_BOOLEAN, reset_time, NULL));创建一个停止刷新event,一般在FLUSH_START event之后,用于重新开始正常缓存流动
voidgst_event_parse_flush_stop ()解析gst_event_new_flush_stop ()创建的event
GstEvent *gst_event_new_eos ()创建一个流结束event,
GstEvent *gst_event_new_gap ()gap空白,产生一个空白消息,用于通知下游一小段时间内可能无数据,比如用于字幕流等。带一个时长的参数
voidgst_event_parse_gap ()解析gst_event_new_gap ()产生的event
GstEvent *gst_event_new_stream_start ()Create a new STREAM_START event.一般作为第一个消息时间发送。一遍demux需要发送,待一个stream_id参数, gst_pad_create_stream_id() or gst_pad_create_stream_id_printf() can be used to create a stream-id. 
voidgst_event_parse_stream_start ()解析gst_event_new_stream_start ()创建的event
voidgst_event_set_stream_flags ()给时间设置flag,参考GstStreamFlags
voidgst_event_parse_stream_flags ()解析gst_event_set_stream_flags ()
voidgst_event_set_group_id ()给event设置组ID,相关联的Streams应该有相同的组ID,不同的StreamID。组ID可以通过函数gst_util_group_id_next()获取 比如一个rtsp流,音频和视频流有相同的组ID不同的StreamID.
gbooleangst_event_parse_group_id ()解析gst_event_set_group_id ()
voidgst_event_set_stream ()将stream绑定到event上
voidgst_event_parse_stream ()解析gst_event_set_stream ()
GstEvent *gst_event_new_segment ()Create a new SEGMENT event for segment 。具体参考segment 
voidgst_event_parse_segment ()从event中解析出segment 
voidgst_event_copy_segment ()同上,解析出的segment 是本地的另一个,不依赖event
GstEvent *gst_event_new_tag ()Generates a metadata tag event from the given taglist .
voidgst_event_parse_tag ()解析gst_event_parse_tag ()
GstEvent *gst_event_new_buffer_size ()Create a new buffersize event. 
voidgst_event_parse_buffer_size ()解析gst_event_new_buffer_size ()
GstEvent *gst_event_new_qos ()Allocate a new qos event with the given values.查考GstQOSType,用于数据太快、太慢
voidgst_event_parse_qos ()解析gst_event_new_qos ()
GstEvent *gst_event_new_seek ()Allocate a new seek event with the given parameters.用于seek,快进、快退等
voidgst_event_parse_seek ()解析gst_event_parse_seek ()
GstEvent *gst_event_new_navigation ()Create a new navigation event from the given description.一般自定义使用。参数是GstStructure
GstEvent *gst_event_new_latency ()Create a new latency event. 创建一个延迟消息,参数是GstClockTime
voidgst_event_parse_latency ()解析gst_event_new_latency ()
GstEvent *gst_event_new_step ()Create a new step event. 主要用于rate等的改变
voidgst_event_parse_step ()解析gst_event_new_step ()
GstEvent *gst_event_new_sink_message ()Create a new sink-message event. 具体参考GstMessage
voidgst_event_parse_sink_message ()解析gst_event_new_sink_message ()
GstEvent *gst_event_new_reconfigure ()Create a new reconfigure event. 用于下游通知上游重新协商caps
GstEvent *gst_event_new_caps ()Create a new CAPS event for caps . 
voidgst_event_parse_caps ()解析gst_event_new_caps ()
GstEvent *gst_event_new_toc ()Generate a TOC event from the given toc ,具体参考SstToc,用于通知TOC发生变化
voidgst_event_parse_toc ()解析gst_event_new_toc ()
GstEvent *gst_event_new_toc_select ()Generate a TOC select event with the given uid . The purpose of the TOC select event is to start playback based on the TOC's entry with the given uid .
voidgst_event_parse_toc_select ()解析gst_event_new_toc_select ()
GstEvent *gst_event_new_segment_done ()Create a new segment-done event. This event is sent by elements that finish playback of a segment as a result of a segment seek.
voidgst_event_parse_segment_done ()解析gst_event_parse_segment_done ()
GstEvent *gst_event_new_protection ()Creates a new event containing information specific to a particular protection system
voidgst_event_parse_protection ()解析gst_event_parse_protection ()
GstEvent *gst_event_new_select_streams ()Allocate a new select-streams event.
voidgst_event_parse_select_streams ()解析gst_event_parse_select_streams ()
GstEvent *gst_event_new_stream_collection ()Create a new STREAM_COLLECTION event. 
voidgst_event_parse_stream_collection ()解析gst_event_new_stream_collection ()
GstEvent *gst_event_new_stream_group_done ()Create a new Stream Group Done event. Elements that receive the event on a pad should handle it mostly like EOS
voidgst_event_parse_stream_group_done ()解析gst_event_new_stream_group_done ()

Object Hierarchy

    GBoxed
    ╰── GstEvent

 

 

参考资料:

  1. https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstEvent.html

 


有任何问题,请联系knowledgebao@163.com

<think> 我们正在讨论GStreamer中的caps协商流程。根据提供的引用,我们可以总结出以下关键点: 1. Caps协商是GStreamer元素之间就媒体格式(GstCaps)达成一致的过程。 2. 协商的目标是找到一个双方都能处理的媒体格式。 3. 协商通常由下游元素发起,从sink元素开始向上游传播。 详细流程如下: - 当两个元素准备连接时,它们需要协商媒体格式(caps)。 - 下游元素(通常是sink)会向上游元素发送一个GST_EVENT_CAPS事件,其中包含它能够处理的caps(可能是多个选项)。 - 上游元素收到这个事件后,会尝试从这些caps中选择一个它也能处理的格式。 - 如果上游元素能够处理,它会设置自己的sink pad(输入垫)的caps,并可能重新配置自身以适应新的caps。 - 然后,上游元素会基于协商的输入caps和自身的能力,确定输出caps,并设置到它的src pad(输出垫)上。 - 如果上游元素需要更改输出caps,它会向下游发送一个新的GST_EVENT_CAPS事件,从而触发下游元素重新协商。 在引用[2]中提到,sink的event响应函数会接收到GST_EVENT_CAPS消息,然后调用`gst_base_transform_setcaps`将caps设置到sink pad上。`gst_base_transform_setcaps`会调用`gst_base_transform_configure_caps`,其中`incaps`是上游传来的caps,而`outcaps`是输出caps(在transform元素中,输出caps通常由元素根据输入caps和自身能力决定)。 在更复杂的场景中,比如有多个可能的caps选项时,GStreamer会尝试选择一个最优的(通常是最具体的)caps。 引用[4]提到,caps中的字段可以是固定的,也可以是非固定的(如范围)。在协商过程中,非固定的字段必须被固定为具体的值。此外,caps中可能包含可选字段,这些字段提供额外的信息但不作为强制约束。 对于自定义元素,开发者需要实现`set_caps`虚方法(或相应的信号处理函数)来处理协商细节(引用[3])。 因此,整个协商流程可以概括为: 1. 下游元素向上游发送caps事件(包含其可接受的caps列表)。 2. 上游元素选择并接受一个caps(如果可能),并设置自己的sink pad。 3. 上游元素根据协商的输入caps确定输出caps,并设置src pad。 4. 如果输出caps需要通知下游,则向下游发送caps事件。 5. 下游元素收到后设置自己的sink pad,并可能继续向上游传递(如果它也是中间元素)。 这个过程会一直进行,直到整个pipeline的每个连接都达成一致的caps。 §§相关问题§§ 1. 在GStreamer中,如果两个元素无法就caps达成一致,会发生什么? 2. 如何为自定义GStreamer元素实现caps协商? 3. GStreamer中的动态pad和有时pad(sometimes pad)是如何参与caps协商的? </think>### GStreamer Caps协商流程 GStreamer Caps协商是确定两个相连元素间可共同处理的媒体格式(`GstCaps`)的过程,核心流程如下: 1. **初始化查询(下游发起)** 下游元素(如sink)通过`GST_QUERY_CAPS`向上游查询支持的格式[^1][^4]。例如: ```c GstCaps *filter = gst_caps_new_empty_simple("video/x-raw"); GstCaps *caps = gst_pad_peer_query_caps(sinkpad, filter); // 获取上游支持的caps ``` 2. **事件传递(上游响应)** 上游元素通过`GST_EVENT_CAPS`事件将选定的媒体格式发送给下游[^2]: ```c GstEvent *event = gst_event_new_caps(negotiated_caps); // 创建CAPS事件 gst_pad_push_event(srcpad, event); // 向下游发送 ``` 3. **格式设置与确认** 下游元素在事件处理函数中接收并应用caps[^2][^3]: ```c static gboolean sink_event_handler(GstPad *pad, GstObject *parent, GstEvent *event) { if (GST_EVENT_TYPE(event) == GST_EVENT_CAPS) { GstCaps *caps; gst_event_parse_caps(event, &caps); gst_base_transform_set_caps(trans, caps, NULL); // 设置caps到sinkpad } return TRUE; } ``` 4. **约束固定化** 协商过程中,非固定字段(如分辨率范围)会被锁定为具体值[^4]: ```c // 协商前:video/x-raw, width=[1,1920], height=[1,1080] // 协商后:video/x-raw, width=1280, height=720 ``` 5. **动态重协商** 若运行中格式需变更(如分辨率切换),通过`gst_pad_push_event()`重新触发流程[^3]。 **关键特性**: - ⚖️ **双向协商**:下游发起查询,上游决策格式 - 🧩 **层次化处理**:每个元素独立实现`set_caps`虚方法[^3] - 🎯 **最优匹配**:通过`gst_caps_intersect()`计算交集选择最具体格式[^1] - 🔄 **状态同步**:caps确定后元素内部状态机进入`READY`或`PAUSED`状态 > 示例:视频解码管道 > ``` > filesrc → decodebin (输出动态caps) → videoconvert (协商) → autovideosink > ``` > `autovideosink`首先查询支持格式,`decodebin`根据硬件能力返回候选列表,最终选定`video/x-raw(format=NV12, width=1920)`等参数[^4]。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值