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

  demux = GST_RTP_SSRC_DEMUX (parent);

  if (!gst_rtp_buffer_validate (buf))
    goto invalid_payload;

  gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
  ssrc = gst_rtp_buffer_get_ssrc (&rtp);
  gst_rtp_buffer_unmap (&rtp);

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

  GST_PAD_LOCK (demux);
  dpad = find_or_create_demux_pad_for_ssrc (demux, ssrc);
  if (dpad == NULL) {
    GST_PAD_UNLOCK (demux);
    goto create_failed;
  }
  srcpad = gst_object_ref (dpad->rtp_pad);
  GST_PAD_UNLOCK (demux);

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

  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 GstIterator *
gst_rtp_ssrc_demux_iterate_internal_links_src (GstPad * pad, GstObject * parent)
{
    GstRtpSsrcDemux *demux;
    GstPad *otherpad = NULL;
    GstIterator *it = NULL;
    GSList *current;

    demux = GST_RTP_SSRC_DEMUX (parent);

    GST_PAD_LOCK (demux);
    for (current = demux->srcpads; current; current = g_slist_next (current)) {
        GstRtpSsrcDemuxPad *dpad = (GstRtpSsrcDemuxPad *) current->data;

        if (pad == dpad->rtp_pad) {
            otherpad = demux->rtp_sink;
            break;
        } else if (pad == dpad->rtcp_pad) {
            otherpad = demux->rtcp_sink;
            break;
        }
    }
    if (otherpad) {
        GValue val = { 0, };

        g_value_init (&val, GST_TYPE_PAD);
        g_value_set_object (&val, otherpad);
        it = gst_iterator_new_single (GST_TYPE_PAD, &val);
        g_value_unset (&val);

    }
    GST_PAD_UNLOCK (demux);

    return it;
}
Пример #4
0
static gboolean
forward_event (GstPad * pad, gpointer user_data)
{
    struct ForwardEventData *fdata = user_data;
    GSList *walk = NULL;
    GstEvent *newevent = NULL;

    GST_PAD_LOCK (fdata->demux);
    for (walk = fdata->demux->srcpads; walk; walk = walk->next) {
        GstRtpSsrcDemuxPad *dpad = (GstRtpSsrcDemuxPad *) walk->data;

        /* Only forward the event if the initial events have been through first,
         * the initial events should be forwarded before any other event
         * or buffer is pushed */
        if ((pad == dpad->rtp_pad && dpad->pushed_initial_rtp_events) ||
                (pad == dpad->rtcp_pad && dpad->pushed_initial_rtcp_events)) {
            newevent = add_ssrc_and_ref (fdata->event, dpad->ssrc);
            break;
        }
    }
    GST_PAD_UNLOCK (fdata->demux);

    if (newevent)
        fdata->res &= gst_pad_push_event (pad, newevent);

    return TRUE;
}
Пример #5
0
static GstIterator *
gst_rtp_ssrc_demux_iterate_internal_links (GstPad * pad)
{
  GstRtpSsrcDemux *demux;
  GstPad *otherpad = NULL;
  GstIterator *it;
  GSList *current;

  demux = GST_RTP_SSRC_DEMUX (gst_pad_get_parent (pad));

  GST_PAD_LOCK (demux);
  for (current = demux->srcpads; current; current = g_slist_next (current)) {
    GstRtpSsrcDemuxPad *dpad = (GstRtpSsrcDemuxPad *) current->data;

    if (pad == demux->rtp_sink) {
      otherpad = dpad->rtp_pad;
      break;
    } else if (pad == demux->rtcp_sink) {
      otherpad = dpad->rtcp_pad;
    } else if (pad == dpad->rtp_pad) {
      otherpad = demux->rtp_sink;
      break;
    } else if (pad == dpad->rtcp_pad) {
      otherpad = demux->rtcp_sink;
      break;
    }
  }
  it = gst_iterator_new_single (GST_TYPE_PAD, otherpad,
      (GstCopyFunction) gst_object_ref, (GFreeFunc) gst_object_unref);
  GST_PAD_UNLOCK (demux);

  gst_object_unref (demux);
  return it;
}
Пример #6
0
static gboolean
gst_rtp_ssrc_demux_sink_event (GstPad * pad, GstObject * parent,
    GstEvent * event)
{
  GstRtpSsrcDemux *demux;
  gboolean res = FALSE;

  demux = GST_RTP_SSRC_DEMUX (parent);

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_FLUSH_STOP:
      gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
      /* fallthrough */
    default:
    {
      GSList *walk;
      GSList *pads = NULL;

      res = TRUE;
      /* need local snapshot of pads;
       * should not push downstream while holding lock as that might deadlock
       * with stuff traveling upstream tyring to get this lock while holding
       * other (stream)lock */
      GST_PAD_LOCK (demux);
      for (walk = demux->srcpads; walk; walk = g_slist_next (walk)) {
        GstRtpSsrcDemuxPad *pad = (GstRtpSsrcDemuxPad *) walk->data;

        pad = g_slice_dup (GstRtpSsrcDemuxPad, pad);
        gst_object_ref (pad->rtp_pad);

        pads = g_slist_prepend (pads, pad);
      }
      GST_PAD_UNLOCK (demux);

      for (walk = pads; walk; walk = g_slist_next (walk)) {
        GstRtpSsrcDemuxPad *dpad = walk->data;
        GstEvent *newevent;

        newevent = add_ssrc_and_ref (event, dpad->ssrc);

        res &= gst_pad_push_event (dpad->rtp_pad, newevent);
        gst_object_unref (dpad->rtp_pad);
        g_slice_free (GstRtpSsrcDemuxPad, dpad);
      }
      g_slist_free (pads);
      gst_event_unref (event);
      break;
    }
  }

  return res;
}
Пример #7
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;
    }
}
Пример #8
0
static gboolean
gst_rtp_ssrc_demux_rtcp_sink_event (GstPad * pad, GstEvent * event)
{
  GstRtpSsrcDemux *demux;
  gboolean res = FALSE;

  demux = GST_RTP_SSRC_DEMUX (gst_pad_get_parent (pad));

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_NEWSEGMENT:
    default:
    {
      GSList *walk;
      GSList *pads = NULL;

      res = TRUE;
      GST_PAD_LOCK (demux);
      for (walk = demux->srcpads; walk; walk = g_slist_next (walk)) {
        GstRtpSsrcDemuxPad *pad = (GstRtpSsrcDemuxPad *) walk->data;

        pads = g_slist_prepend (pads, gst_object_ref (pad->rtcp_pad));
      }
      GST_PAD_UNLOCK (demux);
      for (walk = pads; walk; walk = g_slist_next (walk)) {
        GstPad *pad = (GstPad *) walk->data;

        gst_event_ref (event);
        res &= gst_pad_push_event (pad, event);
        gst_object_unref (pad);
      }
      g_slist_free (pads);
      gst_event_unref (event);
      break;
    }
  }
  gst_object_unref (demux);
  return res;
}
Пример #9
0
static gboolean
gst_rtp_ssrc_demux_rtcp_sink_event (GstPad * pad, GstObject * parent,
    GstEvent * event)
{
  GstRtpSsrcDemux *demux;
  gboolean res = TRUE;
  GSList *walk;
  GSList *pads = NULL;

  demux = GST_RTP_SSRC_DEMUX (parent);

  GST_PAD_LOCK (demux);
  for (walk = demux->srcpads; walk; walk = g_slist_next (walk)) {
    GstRtpSsrcDemuxPad *pad = (GstRtpSsrcDemuxPad *) walk->data;

    pad = g_slice_dup (GstRtpSsrcDemuxPad, pad);
    gst_object_ref (pad->rtcp_pad);

    pads = g_slist_prepend (pads, pad);
  }
  GST_PAD_UNLOCK (demux);

  for (walk = pads; walk; walk = g_slist_next (walk)) {
    GstRtpSsrcDemuxPad *dpad = walk->data;
    GstEvent *newevent;

    newevent = add_ssrc_and_ref (event, dpad->ssrc);

    res &= gst_pad_push_event (dpad->rtcp_pad, newevent);
    gst_object_unref (dpad->rtcp_pad);
    g_slice_free (GstRtpSsrcDemuxPad, dpad);
  }
  g_slist_free (pads);
  gst_event_unref (event);

  return res;
}
Пример #10
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;
    }
}
Пример #11
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;
}
Пример #12
0
static GstFlowReturn
gst_rtp_ssrc_demux_rtcp_chain (GstPad * pad, GstObject * parent,
    GstBuffer * buf)
{
  GstFlowReturn ret;
  GstRtpSsrcDemux *demux;
  guint32 ssrc;
  GstRtpSsrcDemuxPad *dpad;
  GstRTCPPacket packet;
  GstRTCPBuffer rtcp = { NULL, };
  GstPad *srcpad;

  demux = GST_RTP_SSRC_DEMUX (parent);

  if (!gst_rtcp_buffer_validate (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 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_rtcp_buffer_unmap (&rtcp);

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

  GST_PAD_LOCK (demux);
  dpad = find_or_create_demux_pad_for_ssrc (demux, ssrc);
  if (dpad == NULL) {
    GST_PAD_UNLOCK (demux);
    goto create_failed;
  }
  srcpad = gst_object_ref (dpad->rtcp_pad);
  GST_PAD_UNLOCK (demux);

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

  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;
  }
}