【gstreamer之messages和events】

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_*()函数来创建eventsapplication使用gst_element_send_event函数来发送一个event,elements使用gst_pad_send_eventgst_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传递
}
  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值