GStreamer 基础教程学习 3 - 动态管道 (Basic tutorial 3: Dynamic pipelines)

https://gstreamer.freedesktop.org/documentation/tutorials/basic/dynamic-pipelines.html?gi-language=c

本节进一步扩展了上一节的管道, 在运行过程中(on the fly)创建管道,而不是在运行前创建一个指定的管道。

可以想象,将一个没有完全创建的管道设置为播放状态,那么在什么都不做的情况下,数据将到达管道的最后然后报错。为了避免这种情况,就需要做点什么。

本节的例子使用一个复用的文件,例如某种格式的多媒体文件,既包含视频也包含音频。

The ports through which GStreamer elements communicate with each other are called pads (GstPad). There exists sink pads, through which data enters an element, and source pads, through which data exits an element. It follows naturally that source elements only contain source pads, sink elements only contain sink pads, and filter elements contain both.

GStreamer的元素用来和其他元素进行通信的端口, 称之为pads(GstPad)。有sink pads, 通过这种端口, 数据流入元素。也有source pads, 通过这种端口,数据流出元素。 

和之前两节类似,例子创建了4个元素:

/* Create the elements */
  data.source = gst_element_factory_make ("uridecodebin", "source");
  data.convert = gst_element_factory_make ("audioconvert", "convert");
  data.resample = gst_element_factory_make ("audioresample", "resample");
  data.sink = gst_element_factory_make ("autoaudiosink", "sink");

创建管道: 

/* Create the empty pipeline */
  data.pipeline = gst_pipeline_new ("test-pipeline");

之后把这些元素全部扔到管道中,并且把后面3个连接在一起,而作为源的元素并没有连接。

/* Build the pipeline. Note that we are NOT linking the source at this
   * point. We will do it later. */
  gst_bin_add_many (GST_BIN (data.pipeline), data.source, data.convert, data.resample, data.sink, NULL);
  if (!gst_element_link_many (data.convert, data.resample, data.sink, NULL)) {
    g_printerr ("Elements could not be linked.\n");
    gst_object_unref (data.pipeline);
    return -1;
  }

之后就是重点了,

 /* Connect to the pad-added signal */
  g_signal_connect (data.source, "pad-added", G_CALLBACK (pad_added_handler), &data);

这里涉及到信号,通过g_signal_connect(), 将元素data.source所具有的,标识为”pad-added"的信号与回调函数pad_added_handler相绑定,那么一旦元素data.source创建了一个新的pad后,该信号就自动发出,并由回调函数执行相对的响应。 

GSignals are a crucial point in GStreamer. They allow you to be notified (by means of a callback) when something interesting has happened. Signals are identified by a name, and each GObject has its own signals.

In this line, we are attaching to the “pad-added” signal of our source (an uridecodebin element). To do so, we use g_signal_connect() and provide the callback function to be used (pad_added_handler) and a data pointer. GStreamer does nothing with this data pointer, it just forwards it to the callback so we can share information with it. In this case, we pass a pointer to the CustomData structure we built specially for this purpose.

The signals that a GstElement generates can be found in its documentation or using the gst-inspect-1.0 tool as described in Basic tutorial 10: GStreamer tools.

由于源元素,在没有获得URI数据之前,不知道需要创建什么类型的pad,所以只能在运行时进行创建。 在对管道进行设置为播放状态后(此时管道没有全部连接),此时源元素收到URI数据然后对输入数据进行判断并决定创建什么样类型的pad,确定pad类型后创建pad,在pad创建好的同时,发出“pad-added"信号,由于之前使用g_signal_connect把这个信号与回调函数进行了绑定,那么回调函数就开始响应这个信号。

static void pad_added_handler (GstElement *src, GstPad *new_pad, CustomData *data) {

src is the GstElement which triggered the signal. In this example, it can only be the uridecodebin, since it is the only signal to which we have attached. The first parameter of a signal handler is always the object that has triggered it.

new_pad is the GstPad that has just been added to the src element. This is usually the pad to which we want to link.

data is the pointer we provided when attaching to the signal. In this example, we use it to pass the CustomData pointer.

之后检查pad的cap(capabilities ), 判断新创建的pad是否是”audio/x-raw"类型。

/* Check the new pad's type */
new_pad_caps = gst_pad_get_current_caps (new_pad, NULL);
new_pad_struct = gst_caps_get_structure (new_pad_caps, 0);
new_pad_type = gst_structure_get_name (new_pad_struct);
if (!g_str_has_prefix (new_pad_type, "audio/x-raw")) {
  g_print ("It has type '%s' which is not raw audio. Ignoring.\n", new_pad_type);
  goto exit;
}

如果是的话,把pad相连接

/* Attempt the link */
ret = gst_pad_link (new_pad, sink_pad);
if (GST_PAD_LINK_FAILED (ret)) {
  g_print ("Type is '%s' but link failed.\n", new_pad_type);
} else {
  g_print ("Link succeeded (type '%s').\n", new_pad_type);
}

gst_pad_link() tries to link two pads. As it was the case with gst_element_link(), the link must be specified from source to sink, and both pads must be owned by elements residing in the same bin (or pipeline).

GStreamer状态

StateDescription
NULLthe NULL state or initial state of an element.
READYthe element is ready to go to PAUSED.
PAUSEDthe element is PAUSED, it is ready to accept and process data. Sink elements however only accept one buffer and then block.
PLAYINGthe element is PLAYING, the clock is running and the data is flowing.

You can only move between adjacent ones, this is, you can't go from NULL to PLAYING, you have to go through the intermediate READY and PAUSED states. If you set the pipeline to PLAYING, though, GStreamer will make the intermediate transitions for you.

状态只能在相邻的状态之间切换,不可以从NULL直接跳转到PLAYING,必须通过中间的READY和PAUSED两个状态。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值