gstreamer分析-rtp流的接收

 關於數據流的接收過程,[1]有很好的分析。這個問題,令人困惑,依然有些東西沒有搞明白。

gst_base_src_set_playing
{
    if (start)
      gst_pad_start_task (basesrc->srcpad, (GstTaskFunction) gst_base_src_loop,
          basesrc->srcpad, NULL);   
}
static void
gst_base_src_loop (GstPad * pad)
{
  ret = gst_base_src_get_range (src, position, blocksize, &buf);
}
static GstFlowReturn
gst_base_src_get_range (GstBaseSrc * src, guint64 offset, guint length,
    GstBuffer ** buf)
{
  ret = bclass->create (src, offset, length, &res_buf);
//GstBaseClass中的函數指針klass->create = GST_DEBUG_FUNCPTR (gst_base_src_default_create);
  if (src->priv->pending_bufferlist != NULL) {
    ret = gst_pad_push_list (pad, src->priv->pending_bufferlist);
    src->priv->pending_bufferlist = NULL;
  } else {
    ret = gst_pad_push (pad, buf);//數據在pipeline中流動,調用下一個element的chainfun,推送數據。
  }
}
static GstFlowReturn
gst_base_src_default_create (GstBaseSrc * src, guint64 offset,
    guint size, GstBuffer ** buffer)
{
    ret = bclass->fill (src, offset, size, res_buf);
//這個函數在子類中被覆蓋gstbasesrc_class->fill = GST_DEBUG_FUNCPTR (gst_push_src_fill);
}
static GstFlowReturn
gst_push_src_fill (GstBaseSrc * bsrc, guint64 offset, guint length,
    GstBuffer * ret)
{
  pclass = GST_PUSH_SRC_GET_CLASS (src);
  if (pclass->fill)//GstPushSrcClass有同名的方法,與bclass->fill不同
    fret = pclass->fill (src, ret);//這個方法再次被子類覆蓋
}
//其中GstUDPSrcClass繼承了GstPushSrc
//gstpushsrc_class->fill = gst_udpsrc_fill;
static GstFlowReturn
gst_udpsrc_fill (GstPushSrc * psrc, GstBuffer * outbuf)
{
//問題出現,向socket讀取數據,數據流就一定到來了嗎?
//g_socket_condition_timed_wait說明這個socket並不是一個阻塞的socket。那麼要是沒有數據該怎麼處理?
  res =
      g_socket_receive_message (udpsrc->used_socket, p_saddr, ivec, 2,
      p_msgs, &n_msgs, &flags, udpsrc->cancellable, &err);
}

 udosrc怎麼同rtpbin關聯起來呢?gst-lpugins-good/tests/examples/client-rtpaux.c下有個例子,有個圖:
example
 udosrc和rtpbin都繼承了element。gst_element_link_pads將兩者連起來。

rtpSrc = gst_element_factory_make ("udpsrc", NULL);
gst_element_link_pads (rtpSrc, "src", rtpBin, padName);

 rtpbin中的pad是如何接收數據呢?

static GstPad *
gst_rtp_bin_request_new_pad (GstElement * element,
    GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
{
  if (templ == gst_element_class_get_pad_template (klass, "recv_rtp_sink_%u")) {
    result = create_recv_rtp (rtpbin, templ, pad_name);
  }
}
static GstPad *
create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
{
  recv_rtp_sink = complete_session_sink (rtpbin, session, TRUE);
}
static GstPad *
complete_session_sink (GstRtpBin * rtpbin, GstRtpBinSession * session,
    gboolean bundle_demuxer_needed)
{
  session->recv_rtp_sink =
      gst_element_get_request_pad (session->session, "recv_rtp_sink");
}
static GstPad *
gst_rtp_session_request_new_pad (GstElement * element,
    GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
{
  /* figure out the template */
  if (templ == gst_element_class_get_pad_template (klass, "recv_rtp_sink")) {
    if (rtpsession->recv_rtp_sink != NULL)
      goto exists;

    result = create_recv_rtp_sink (rtpsession);
  }
}
static GstPad *
create_recv_rtp_sink (GstRtpSession * rtpsession)
{
  gst_pad_set_chain_function (rtpsession->recv_rtp_sink,
      gst_rtp_session_chain_recv_rtp);
  return rtpsession->recv_rtp_sink;
}

gst_pad_push中調用的chainfun就是這個gst_rtp_session_chain_recv_rtp。
 接下來分析rtp數據流的處理,以on-feedback-rtcp這個類型的消息爲例。

static GstFlowReturn
gst_rtp_session_chain_recv_rtp (GstPad * pad, GstObject * parent,
    GstBuffer * buffer)
{
  ret = rtp_session_process_rtp (priv->session, buffer, current_time,
      running_time, ntpnstime);
}
GstFlowReturn
rtp_session_process_rtp (RTPSession * sess, GstBuffer * buffer,
    GstClockTime current_time, GstClockTime running_time, guint64 ntpnstime)
{
  /* update pinfo stats */
  if (!update_packet_info (sess, &pinfo, FALSE, TRUE, FALSE, buffer,
          current_time, running_time, ntpnstime)) {
    GST_DEBUG ("invalid RTP packet received");
    RTP_SESSION_UNLOCK (sess);
    return rtp_session_process_rtcp (sess, buffer, current_time, ntpnstime);
  }
}
GstFlowReturn
rtp_session_process_rtcp (RTPSession * sess, GstBuffer * buffer,
    GstClockTime current_time, guint64 ntpnstime)
{
    switch (type) {
      case GST_RTCP_TYPE_PSFB:
        rtp_session_process_feedback (sess, &packet, &pinfo, current_time);
        break;
}
}
static void
rtp_session_process_feedback (RTPSession * sess, GstRTCPPacket * packet,
    RTPPacketInfo * pinfo, GstClockTime current_time)
{
  if (g_signal_has_handler_pending (sess,
          rtp_session_signals[SIGNAL_ON_FEEDBACK_RTCP], 0, TRUE)) {
    g_signal_emit (sess, rtp_session_signals[SIGNAL_ON_FEEDBACK_RTCP], 0,
        type, fbtype, sender_ssrc, media_ssrc, fci_buffer);
}
}
//需要查找下程序哪裏註冊了"on-feedback-rtcp"這個信號。
//以此爲例,信號的註冊是這個形式g_signal_connect (rtpsession, "on-feedback-rtcp", G_CALLBACK (callback_fun), self);
//信號發射g_signal_emit,就會調用callback_fun進行處理。
//這樣的註冊函數在kurento裏有。
static void
kms_remb_remote_on_feedback_rtcp (GObject *rtpsession,
    guint type, guint fbtype, guint sender_ssrc, guint media_ssrc,
    GstBuffer *fci)
{
  GST_LOG_OBJECT (rtpsession, "Signal 'on-feedback-rtcp'");
  if (type == GST_RTCP_TYPE_PSFB
      && fbtype == GST_RTCP_PSFB_TYPE_AFB) {
    process_psfb_afb (rtpsession, sender_ssrc, fci);
  }
}

 前前後後一共浪費了六天時間,好奇心害死貓。以後應該研究一些數學密集型的程序,而不是邏輯密集型的程序。
 劇終。
[1]GStreamer插件架構簡析

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章