Пример #1
0
static GstFlowReturn
gst_rtp_ssrc_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
{
    GstFlowReturn ret;
    GstRtpSsrcDemux *demux;
    guint32 ssrc;
    GstRTPBuffer rtp = { NULL };
    GstPad *srcpad;
    GstRtpSsrcDemuxPad *dpad;

    demux = GST_RTP_SSRC_DEMUX (parent);

    if (!gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp))
        goto invalid_payload;

    ssrc = gst_rtp_buffer_get_ssrc (&rtp);
    gst_rtp_buffer_unmap (&rtp);

    GST_DEBUG_OBJECT (demux, "received buffer of SSRC %08x", ssrc);

    srcpad = find_or_create_demux_pad_for_ssrc (demux, ssrc, RTP_PAD);
    if (srcpad == NULL)
        goto create_failed;

    /* push to srcpad */
    ret = gst_pad_push (srcpad, buf);

    if (ret != GST_FLOW_OK) {
        /* check if the ssrc still there, may have been removed */
        GST_PAD_LOCK (demux);
        dpad = find_demux_pad_for_ssrc (demux, ssrc);
        if (dpad == NULL || dpad->rtp_pad != srcpad) {
            /* SSRC was removed during the push ... ignore the error */
            ret = GST_FLOW_OK;
        }
        GST_PAD_UNLOCK (demux);
    }

    gst_object_unref (srcpad);

    return ret;

    /* ERRORS */
invalid_payload:
    {
        /* this is fatal and should be filtered earlier */
        GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL),
                           ("Dropping invalid RTP payload"));
        gst_buffer_unref (buf);
        return GST_FLOW_ERROR;
    }
create_failed:
    {
        GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL),
                           ("Could not create new pad"));
        gst_buffer_unref (buf);
        return GST_FLOW_ERROR;
    }
}
Пример #2
0
static GstFlowReturn
gst_rtp_ssrc_demux_chain (GstPad * pad, GstBuffer * buf)
{
  GstFlowReturn ret;
  GstRtpSsrcDemux *demux;
  guint32 ssrc;
  GstRtpSsrcDemuxPad *dpad;

  demux = GST_RTP_SSRC_DEMUX (GST_OBJECT_PARENT (pad));

  if (!gst_rtp_buffer_validate (buf))
    goto invalid_payload;

  ssrc = gst_rtp_buffer_get_ssrc (buf);

  GST_DEBUG_OBJECT (demux, "received buffer of SSRC %08x", ssrc);

  GST_PAD_LOCK (demux);
  dpad = find_demux_pad_for_ssrc (demux, ssrc);
  if (dpad == NULL) {
    if (!(dpad =
            create_demux_pad_for_ssrc (demux, ssrc,
                GST_BUFFER_TIMESTAMP (buf))))
      goto create_failed;
  }
  GST_PAD_UNLOCK (demux);

  /* push to srcpad */
  ret = gst_pad_push (dpad->rtp_pad, buf);

  return ret;

  /* ERRORS */
invalid_payload:
  {
    /* this is fatal and should be filtered earlier */
    GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL),
        ("Dropping invalid RTP payload"));
    gst_buffer_unref (buf);
    return GST_FLOW_ERROR;
  }
create_failed:
  {
    GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL),
        ("Could not create new pad"));
    GST_PAD_UNLOCK (demux);
    gst_buffer_unref (buf);
    return GST_FLOW_ERROR;
  }
}
Пример #3
0
static void
gst_rtp_ssrc_demux_clear_ssrc (GstRtpSsrcDemux * demux, guint32 ssrc)
{
    GstRtpSsrcDemuxPad *dpad;

    GST_PAD_LOCK (demux);
    dpad = find_demux_pad_for_ssrc (demux, ssrc);
    if (dpad == NULL) {
        GST_PAD_UNLOCK (demux);
        goto unknown_pad;
    }

    GST_DEBUG_OBJECT (demux, "clearing pad for SSRC %08x", ssrc);

    demux->srcpads = g_slist_remove (demux->srcpads, dpad);
    GST_PAD_UNLOCK (demux);

    gst_pad_set_active (dpad->rtp_pad, FALSE);
    gst_pad_set_active (dpad->rtcp_pad, FALSE);

    g_signal_emit (G_OBJECT (demux),
                   gst_rtp_ssrc_demux_signals[SIGNAL_REMOVED_SSRC_PAD], 0, ssrc,
                   dpad->rtp_pad);

    gst_element_remove_pad (GST_ELEMENT_CAST (demux), dpad->rtp_pad);
    gst_element_remove_pad (GST_ELEMENT_CAST (demux), dpad->rtcp_pad);

    g_free (dpad);

    return;

    /* ERRORS */
unknown_pad:
    {
        GST_WARNING_OBJECT (demux, "unknown SSRC %08x", ssrc);
        return;
    }
}
Пример #4
0
static GstFlowReturn
gst_rtp_ssrc_demux_rtcp_chain (GstPad * pad, GstObject * parent,
                               GstBuffer * buf)
{
    GstFlowReturn ret;
    GstRtpSsrcDemux *demux;
    guint32 ssrc;
    GstRTCPPacket packet;
    GstRTCPBuffer rtcp = { NULL, };
    GstPad *srcpad;
    GstRtpSsrcDemuxPad *dpad;

    demux = GST_RTP_SSRC_DEMUX (parent);

    if (!gst_rtcp_buffer_validate_reduced (buf))
        goto invalid_rtcp;

    gst_rtcp_buffer_map (buf, GST_MAP_READ, &rtcp);
    if (!gst_rtcp_buffer_get_first_packet (&rtcp, &packet)) {
        gst_rtcp_buffer_unmap (&rtcp);
        goto invalid_rtcp;
    }

    /* first packet must be SR or RR, or in case of a reduced size RTCP packet
     * it must be APP, RTPFB or PSFB feeadback, or else the validate would
     * have failed */
    switch (gst_rtcp_packet_get_type (&packet)) {
    case GST_RTCP_TYPE_SR:
        /* get the ssrc so that we can route it to the right source pad */
        gst_rtcp_packet_sr_get_sender_info (&packet, &ssrc, NULL, NULL, NULL,
                                            NULL);
        break;
    case GST_RTCP_TYPE_RR:
        ssrc = gst_rtcp_packet_rr_get_ssrc (&packet);
        break;
    case GST_RTCP_TYPE_APP:
    case GST_RTCP_TYPE_RTPFB:
    case GST_RTCP_TYPE_PSFB:
        ssrc = gst_rtcp_packet_fb_get_sender_ssrc (&packet);
        break;
    default:
        goto unexpected_rtcp;
    }
    gst_rtcp_buffer_unmap (&rtcp);

    GST_DEBUG_OBJECT (demux, "received RTCP of SSRC %08x", ssrc);

    srcpad = find_or_create_demux_pad_for_ssrc (demux, ssrc, RTCP_PAD);
    if (srcpad == NULL)
        goto create_failed;

    /* push to srcpad */
    ret = gst_pad_push (srcpad, buf);

    if (ret != GST_FLOW_OK) {
        /* check if the ssrc still there, may have been removed */
        GST_PAD_LOCK (demux);
        dpad = find_demux_pad_for_ssrc (demux, ssrc);
        if (dpad == NULL || dpad->rtcp_pad != srcpad) {
            /* SSRC was removed during the push ... ignore the error */
            ret = GST_FLOW_OK;
        }
        GST_PAD_UNLOCK (demux);
    }

    gst_object_unref (srcpad);

    return ret;

    /* ERRORS */
invalid_rtcp:
    {
        /* this is fatal and should be filtered earlier */
        GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL),
                           ("Dropping invalid RTCP packet"));
        gst_buffer_unref (buf);
        return GST_FLOW_ERROR;
    }
unexpected_rtcp:
    {
        GST_DEBUG_OBJECT (demux, "dropping unexpected RTCP packet");
        gst_buffer_unref (buf);
        return GST_FLOW_OK;
    }
create_failed:
    {
        GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL),
                           ("Could not create new pad"));
        gst_buffer_unref (buf);
        return GST_FLOW_ERROR;
    }
}
Пример #5
0
static GstPad *
find_or_create_demux_pad_for_ssrc (GstRtpSsrcDemux * demux, guint32 ssrc,
                                   PadType padtype)
{
    GstPad *rtp_pad, *rtcp_pad;
    GstElementClass *klass;
    GstPadTemplate *templ;
    gchar *padname;
    GstRtpSsrcDemuxPad *demuxpad;
    GstPad *retpad;
    gulong rtp_block, rtcp_block;

    GST_PAD_LOCK (demux);

    demuxpad = find_demux_pad_for_ssrc (demux, ssrc);
    if (demuxpad != NULL) {
        gboolean forward = FALSE;

        switch (padtype) {
        case RTP_PAD:
            retpad = gst_object_ref (demuxpad->rtp_pad);
            if (!demuxpad->pushed_initial_rtp_events) {
                forward = TRUE;
                demuxpad->pushed_initial_rtp_events = TRUE;
            }
            break;
        case RTCP_PAD:
            retpad = gst_object_ref (demuxpad->rtcp_pad);
            if (!demuxpad->pushed_initial_rtcp_events) {
                forward = TRUE;
                demuxpad->pushed_initial_rtcp_events = TRUE;
            }
            break;
        default:
            retpad = NULL;
            g_assert_not_reached ();
        }

        GST_PAD_UNLOCK (demux);

        if (forward)
            forward_initial_events (demux, ssrc, retpad, padtype);
        return retpad;
    }

    GST_DEBUG_OBJECT (demux, "creating new pad for SSRC %08x", ssrc);

    klass = GST_ELEMENT_GET_CLASS (demux);
    templ = gst_element_class_get_pad_template (klass, "src_%u");
    padname = g_strdup_printf ("src_%u", ssrc);
    rtp_pad = gst_pad_new_from_template (templ, padname);
    g_free (padname);

    templ = gst_element_class_get_pad_template (klass, "rtcp_src_%u");
    padname = g_strdup_printf ("rtcp_src_%u", ssrc);
    rtcp_pad = gst_pad_new_from_template (templ, padname);
    g_free (padname);

    /* wrap in structure and add to list */
    demuxpad = g_new0 (GstRtpSsrcDemuxPad, 1);
    demuxpad->ssrc = ssrc;
    demuxpad->rtp_pad = rtp_pad;
    demuxpad->rtcp_pad = rtcp_pad;

    gst_pad_set_element_private (rtp_pad, demuxpad);
    gst_pad_set_element_private (rtcp_pad, demuxpad);

    demux->srcpads = g_slist_prepend (demux->srcpads, demuxpad);

    gst_pad_set_query_function (rtp_pad, gst_rtp_ssrc_demux_src_query);
    gst_pad_set_iterate_internal_links_function (rtp_pad,
            gst_rtp_ssrc_demux_iterate_internal_links_src);
    gst_pad_set_event_function (rtp_pad, gst_rtp_ssrc_demux_src_event);
    gst_pad_use_fixed_caps (rtp_pad);
    gst_pad_set_active (rtp_pad, TRUE);

    gst_pad_set_event_function (rtcp_pad, gst_rtp_ssrc_demux_src_event);
    gst_pad_set_iterate_internal_links_function (rtcp_pad,
            gst_rtp_ssrc_demux_iterate_internal_links_src);
    gst_pad_use_fixed_caps (rtcp_pad);
    gst_pad_set_active (rtcp_pad, TRUE);

    if (padtype == RTP_PAD) {
        demuxpad->pushed_initial_rtp_events = TRUE;
        forward_initial_events (demux, ssrc, rtp_pad, padtype);
    } else if (padtype == RTCP_PAD) {
        demuxpad->pushed_initial_rtcp_events = TRUE;
        forward_initial_events (demux, ssrc, rtcp_pad, padtype);
    } else {
        g_assert_not_reached ();
    }

    gst_element_add_pad (GST_ELEMENT_CAST (demux), rtp_pad);
    gst_element_add_pad (GST_ELEMENT_CAST (demux), rtcp_pad);

    switch (padtype) {
    case RTP_PAD:
        retpad = gst_object_ref (demuxpad->rtp_pad);
        break;
    case RTCP_PAD:
        retpad = gst_object_ref (demuxpad->rtcp_pad);
        break;
    default:
        retpad = NULL;
        g_assert_not_reached ();
    }

    gst_object_ref (rtp_pad);
    gst_object_ref (rtcp_pad);

    rtp_block = gst_pad_add_probe (rtp_pad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
                                   NULL, NULL, NULL);
    rtcp_block = gst_pad_add_probe (rtcp_pad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
                                    NULL, NULL, NULL);

    GST_PAD_UNLOCK (demux);

    g_signal_emit (G_OBJECT (demux),
                   gst_rtp_ssrc_demux_signals[SIGNAL_NEW_SSRC_PAD], 0, ssrc, rtp_pad);

    gst_pad_remove_probe (rtp_pad, rtp_block);
    gst_pad_remove_probe (rtcp_pad, rtcp_block);

    gst_object_unref (rtp_pad);
    gst_object_unref (rtcp_pad);

    return retpad;
}
Пример #6
0
/* with PAD_LOCK */
static GstRtpSsrcDemuxPad *
find_or_create_demux_pad_for_ssrc (GstRtpSsrcDemux * demux, guint32 ssrc)
{
  GstPad *rtp_pad, *rtcp_pad;
  GstElementClass *klass;
  GstPadTemplate *templ;
  gchar *padname;
  GstRtpSsrcDemuxPad *demuxpad;
  GstCaps *caps;
  struct ForwardEventData fdata;

  GST_DEBUG_OBJECT (demux, "creating pad for SSRC %08x", ssrc);

  demuxpad = find_demux_pad_for_ssrc (demux, ssrc);
  if (demuxpad != NULL) {
    return demuxpad;
  }

  klass = GST_ELEMENT_GET_CLASS (demux);
  templ = gst_element_class_get_pad_template (klass, "src_%u");
  padname = g_strdup_printf ("src_%u", ssrc);
  rtp_pad = gst_pad_new_from_template (templ, padname);
  g_free (padname);

  templ = gst_element_class_get_pad_template (klass, "rtcp_src_%u");
  padname = g_strdup_printf ("rtcp_src_%u", ssrc);
  rtcp_pad = gst_pad_new_from_template (templ, padname);
  g_free (padname);

  /* wrap in structure and add to list */
  demuxpad = g_new0 (GstRtpSsrcDemuxPad, 1);
  demuxpad->ssrc = ssrc;
  demuxpad->rtp_pad = rtp_pad;
  demuxpad->rtcp_pad = rtcp_pad;

  fdata.ssrc = ssrc;

  gst_pad_set_element_private (rtp_pad, demuxpad);
  gst_pad_set_element_private (rtcp_pad, demuxpad);

  demux->srcpads = g_slist_prepend (demux->srcpads, demuxpad);

  gst_pad_set_query_function (rtp_pad, gst_rtp_ssrc_demux_src_query);
  gst_pad_set_iterate_internal_links_function (rtp_pad,
      gst_rtp_ssrc_demux_iterate_internal_links_src);
  gst_pad_set_event_function (rtp_pad, gst_rtp_ssrc_demux_src_event);
  gst_pad_use_fixed_caps (rtp_pad);
  gst_pad_set_active (rtp_pad, TRUE);
  fdata.pad = rtp_pad;
  gst_pad_sticky_events_foreach (demux->rtp_sink, forward_sticky_events,
      &fdata);

  gst_pad_set_event_function (rtcp_pad, gst_rtp_ssrc_demux_src_event);
  gst_pad_set_iterate_internal_links_function (rtcp_pad,
      gst_rtp_ssrc_demux_iterate_internal_links_src);
  gst_pad_use_fixed_caps (rtcp_pad);
  gst_pad_set_active (rtcp_pad, TRUE);
  fdata.pad = rtcp_pad;
  gst_pad_sticky_events_foreach (demux->rtcp_sink, forward_sticky_events,
      &fdata);

  /* copy caps from input */
  if ((caps = gst_pad_get_current_caps (demux->rtp_sink))) {
    gst_pad_set_caps (rtp_pad, caps);
    gst_caps_unref (caps);
  }
  if ((caps = gst_pad_get_current_caps (demux->rtcp_sink))) {
    gst_pad_set_caps (rtcp_pad, caps);
    gst_caps_unref (caps);
  }
  gst_element_add_pad (GST_ELEMENT_CAST (demux), rtp_pad);
  gst_element_add_pad (GST_ELEMENT_CAST (demux), rtcp_pad);

  g_signal_emit (G_OBJECT (demux),
      gst_rtp_ssrc_demux_signals[SIGNAL_NEW_SSRC_PAD], 0, ssrc, rtp_pad);

  return demuxpad;
}
Пример #7
0
static GstFlowReturn
gst_rtp_ssrc_demux_rtcp_chain (GstPad * pad, GstBuffer * buf)
{
  GstFlowReturn ret;
  GstRtpSsrcDemux *demux;
  guint32 ssrc;
  GstRtpSsrcDemuxPad *dpad;
  GstRTCPPacket packet;

  demux = GST_RTP_SSRC_DEMUX (GST_OBJECT_PARENT (pad));

  if (!gst_rtcp_buffer_validate (buf))
    goto invalid_rtcp;

  if (!gst_rtcp_buffer_get_first_packet (buf, &packet))
    goto invalid_rtcp;

  /* first packet must be SR or RR or else the validate would have failed */
  switch (gst_rtcp_packet_get_type (&packet)) {
    case GST_RTCP_TYPE_SR:
      /* get the ssrc so that we can route it to the right source pad */
      gst_rtcp_packet_sr_get_sender_info (&packet, &ssrc, NULL, NULL, NULL,
          NULL);
      break;
    default:
      goto unexpected_rtcp;
  }

  GST_DEBUG_OBJECT (demux, "received RTCP of SSRC %08x", ssrc);

  GST_PAD_LOCK (demux);
  dpad = find_demux_pad_for_ssrc (demux, ssrc);
  if (dpad == NULL) {
    GST_DEBUG_OBJECT (demux, "creating pad for SSRC %08x", ssrc);
    if (!(dpad = create_demux_pad_for_ssrc (demux, ssrc, -1)))
      goto create_failed;
  }
  GST_PAD_UNLOCK (demux);

  /* push to srcpad */
  ret = gst_pad_push (dpad->rtcp_pad, buf);

  return ret;

  /* ERRORS */
invalid_rtcp:
  {
    /* this is fatal and should be filtered earlier */
    GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL),
        ("Dropping invalid RTCP packet"));
    gst_buffer_unref (buf);
    return GST_FLOW_ERROR;
  }
unexpected_rtcp:
  {
    GST_DEBUG_OBJECT (demux, "dropping unexpected RTCP packet");
    gst_buffer_unref (buf);
    return GST_FLOW_OK;
  }
create_failed:
  {
    GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL),
        ("Could not create new pad"));
    GST_PAD_UNLOCK (demux);
    gst_buffer_unref (buf);
    return GST_FLOW_ERROR;
  }
}