gstreamer是个媒体引擎,可用用来开发流媒体,类似ffmpeg的filter,sink接收数据,filter处理数据(如:采集,缩放,编码等),src突出数据给链接的sink。
在Windows下,可用使用directshow来操作摄像头,gstreamer可用用利用 dshow来打开采集摄像头数据,然后推送给后面的处理filter。
gstreamer开始play会,会执行gst_element_set_state (bin, GST_STATE_PLAYING);这个函数经过一系列步骤,最终执行,
gst_element_pads_activate,应该是是遍历激活所有 pad,如下堆栈图:
static gboolean
gst_base_src_activate_push (GstPad * pad, gboolean active)
{
GstBaseSrc *basesrc;
GstEvent *event;
basesrc = GST_BASE_SRC (GST_OBJECT_PARENT (pad));
/* prepare subclass first */
if (active) { //激活
GST_DEBUG_OBJECT (basesrc, "Activating in push mode");
if (G_UNLIKELY (!basesrc->can_activate_push))
goto no_push_activation;
if (G_UNLIKELY (!gst_base_src_start (basesrc)))
goto error_start;
basesrc->priv->last_sent_eos = FALSE;
basesrc->priv->discont = TRUE;
gst_base_src_set_flushing (basesrc, FALSE, FALSE, FALSE, NULL);
/* do initial seek, which will start the task */
GST_OBJECT_LOCK (basesrc);
event = basesrc->data.ABI.pending_seek;
basesrc->data.ABI.pending_seek = NULL;
GST_OBJECT_UNLOCK (basesrc);
/* no need to unlock anything, the task is certainly
* not running here. The perform seek code will start the task when
* finished. */
if (G_UNLIKELY (!gst_base_src_perform_seek (basesrc, event, FALSE)))
goto seek_failed;
if (event)
gst_event_unref (event);
} else { //关闭
GST_DEBUG_OBJECT (basesrc, "Deactivating in push mode");
/* flush all */
gst_base_src_set_flushing (basesrc, TRUE, FALSE, TRUE, NULL);
/* stop the task */
gst_pad_stop_task (pad);
/* now we can stop the source */
if (G_UNLIKELY (!gst_base_src_stop (basesrc)))
goto error_stop;
}
return TRUE;
/* ERRORS */
no_push_activation:
{
GST_WARNING_OBJECT (basesrc, "Subclass disabled push-mode activation");
return FALSE;
}
error_start:
{
GST_WARNING_OBJECT (basesrc, "Failed to start in push mode");
return FALSE;
}
seek_failed:
{
GST_ERROR_OBJECT (basesrc, "Failed to perform initial seek");
/* flush all */
gst_base_src_set_flushing (basesrc, TRUE, FALSE, TRUE, NULL);
/* stop the task */
gst_pad_stop_task (pad);
/* Stop the basesrc */
gst_base_src_stop (basesrc);
if (event)
gst_event_unref (event);
return FALSE;
}
error_stop:
{
GST_DEBUG_OBJECT (basesrc, "Failed to stop in push mode");
return FALSE;
}
}
如上函数的逻辑,会判断active参数,如果是1 ,调用gst_base_src_start,里面又会调用协商函数gst_base_src_negotiate,
/* default negotiation code.
*
* Take intersection between src and sink pads, take first
* caps and fixate.
*/
static gboolean
gst_base_src_default_negotiate (GstBaseSrc * basesrc)
{
GstCaps *thiscaps;
GstCaps *caps = NULL;
GstCaps *peercaps = NULL;
gboolean result = FALSE;
/* first see what is possible on our source pad */
//获取本element的src的caps,可能有很多个structrue。
thiscaps = gst_pad_get_caps_reffed (GST_BASE_SRC_PAD (basesrc));
GST_DEBUG_OBJECT (basesrc, "caps of src: %" GST_PTR_FORMAT, thiscaps);
/* nothing or anything is allowed, we're done */
if (thiscaps == NULL || gst_caps_is_any (thiscaps))
goto no_nego_needed;
if (G_UNLIKELY (gst_caps_is_empty (thiscaps)))
goto no_caps;
/* get the peer caps */
//获取对端element的src的caps,下一个一般是个capsfilter,对camsrc的输出进行限定。
peercaps = gst_pad_peer_get_caps_reffed (GST_BASE_SRC_PAD (basesrc));
GST_DEBUG_OBJECT (basesrc, "caps of peer: %" GST_PTR_FORMAT, peercaps);
if (peercaps && !gst_caps_is_any (peercaps)) {
/* get intersection */
caps =
gst_caps_intersect_full (peercaps, thiscaps, GST_CAPS_INTERSECT_FIRST);
GST_DEBUG_OBJECT (basesrc, "intersect: %" GST_PTR_FORMAT, caps);
} else {
/* no peer, work with our own caps then */
caps = gst_caps_copy (thiscaps);
}
if (peercaps)
gst_caps_unref (peercaps);
gst_caps_unref (thiscaps);
//caps是个相交的结果。
if (caps) {
/* take first (and best, since they are sorted) possibility */
gst_caps_truncate (caps);
/* now fixate */
if (!gst_caps_is_empty (caps)) {
gst_pad_fixate_caps (GST_BASE_SRC_PAD (basesrc), caps);
GST_DEBUG_OBJECT (basesrc, "fixated to: %" GST_PTR_FORMAT, caps);
if (gst_caps_is_any (caps)) {
/* hmm, still anything, so element can do anything and
* nego is not needed */
result = TRUE;
} else if (gst_caps_is_fixed (caps)) {
/* yay, fixed caps, use those then, it's possible that the subclass does
* not accept this caps after all and we have to fail. */
//如果是个固定值,就设置给basesrc的src.
result = gst_pad_set_caps (GST_BASE_SRC_PAD (basesrc), caps);
}
}
gst_caps_unref (caps);
} else {
GST_DEBUG_OBJECT (basesrc, "no common caps");
}
return result;
no_nego_needed:
{
GST_DEBUG_OBJECT (basesrc, "no negotiation needed");
if (thiscaps)
gst_caps_unref (thiscaps);
return TRUE;
}
no_caps:
{
GST_ELEMENT_ERROR (basesrc, STREAM, FORMAT,
("No supported formats found"),
("This element did not produce valid caps"));
if (thiscaps)
gst_caps_unref (thiscaps);
return TRUE;
}
}
在gst_pad_set_caps里一般会启动dshow,如果dshow启动失败,会导致协商失败,最终会导致播放失败。