static GstPad *
gst_output_selector_request_new_pad (GstElement * element,
    GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
{
  gchar *padname;
  GstPad *srcpad;
  GstOutputSelector *osel;

  osel = GST_OUTPUT_SELECTOR (element);

  GST_DEBUG_OBJECT (osel, "requesting pad");

  GST_OBJECT_LOCK (osel);
  padname = g_strdup_printf ("src_%u", osel->nb_srcpads++);
  srcpad = gst_pad_new_from_template (templ, padname);
  GST_OBJECT_UNLOCK (osel);

  gst_pad_set_active (srcpad, TRUE);

  /* Forward sticky events to the new srcpad */
  gst_pad_sticky_events_foreach (osel->sinkpad, forward_sticky_events, srcpad);

  gst_element_add_pad (GST_ELEMENT (osel), srcpad);

  /* Set the first requested src pad as active by default */
  if (osel->active_srcpad == NULL) {
    osel->active_srcpad = srcpad;
  }
  g_free (padname);

  return srcpad;
}
Пример #2
0
static GstFlowReturn
gst_funnel_sink_chain_object (GstPad * pad, GstFunnel * funnel,
    gboolean is_list, GstMiniObject * obj)
{
  GstFlowReturn res;

  GST_DEBUG_OBJECT (pad, "received %" GST_PTR_FORMAT, obj);

  GST_PAD_STREAM_LOCK (funnel->srcpad);

  if ((funnel->last_sinkpad == NULL)
      || ((funnel->forward_sticky_events_mode !=
              GST_FUNNEL_FORWARD_STICKY_EVENTS_MODE_NEVER)
          && (funnel->last_sinkpad != pad))) {

    GST_DEBUG_OBJECT (pad, "Forwarding sticky events");
    gst_pad_sticky_events_foreach (pad, forward_events_on_stream_changed,
        funnel);

    gst_object_replace ((GstObject **) & funnel->last_sinkpad,
        GST_OBJECT (pad));
  }

  if (is_list)
    res = gst_pad_push_list (funnel->srcpad, GST_BUFFER_LIST_CAST (obj));
  else
    res = gst_pad_push (funnel->srcpad, GST_BUFFER_CAST (obj));

  GST_PAD_STREAM_UNLOCK (funnel->srcpad);

  GST_LOG_OBJECT (pad, "handled buffer%s %s", (is_list ? "list" : ""),
      gst_flow_get_name (res));

  return res;
}
static void
update_sdp_from_tags (GstRTSPStream * stream, GstSDPMedia * stream_media)
{
  GstPad *src_pad;

  src_pad = gst_rtsp_stream_get_srcpad (stream);

  gst_pad_sticky_events_foreach (src_pad, get_info_from_tags, stream_media);

  gst_object_unref (src_pad);
}
Пример #4
0
static gboolean
gst_funnel_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
{
  GstFunnel *funnel = GST_FUNNEL (parent);
  GstFunnelPad *fpad = GST_FUNNEL_PAD_CAST (pad);
  gboolean forward = TRUE;
  gboolean res = TRUE;
  gboolean unlock = FALSE;

  GST_DEBUG_OBJECT (pad, "received event %" GST_PTR_FORMAT, event);

  if (GST_EVENT_IS_STICKY (event)) {
    unlock = TRUE;
    GST_PAD_STREAM_LOCK (funnel->srcpad);

    if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
      GST_OBJECT_LOCK (funnel);
      fpad->got_eos = TRUE;
      if (!gst_funnel_all_sinkpads_eos_unlocked (funnel, pad)) {
        forward = FALSE;
      } else {
        forward = TRUE;
      }
      GST_OBJECT_UNLOCK (funnel);
    } else if (pad != funnel->last_sinkpad) {
      forward = FALSE;
    }
  } else if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) {
    unlock = TRUE;
    GST_PAD_STREAM_LOCK (funnel->srcpad);
    GST_OBJECT_LOCK (funnel);
    fpad->got_eos = FALSE;
    GST_OBJECT_UNLOCK (funnel);
  } else if (GST_EVENT_TYPE (event) == GST_EVENT_GAP) {
    /* If no data is coming and we receive GAP event, need to forward sticky events. */
    unlock = TRUE;
    GST_PAD_STREAM_LOCK (funnel->srcpad);
    GST_OBJECT_LOCK (funnel);
    gst_object_replace ((GstObject **) & funnel->last_sinkpad,
        GST_OBJECT (pad));
    GST_OBJECT_UNLOCK (funnel);
    gst_pad_sticky_events_foreach (pad, forward_events, funnel->srcpad);
  }

  if (forward)
    res = gst_pad_push_event (funnel->srcpad, event);
  else
    gst_event_unref (event);

  if (unlock)
    GST_PAD_STREAM_UNLOCK (funnel->srcpad);

  return res;
}
static void
restart_context (MqStreamCtx * ctx, GstSplitMuxSink * splitmux)
{
  GstPad *peer = gst_pad_get_peer (ctx->srcpad);

  gst_pad_sticky_events_foreach (ctx->srcpad,
      (GstPadStickyEventsForeachFunction) (resend_sticky), peer);

  /* Clear EOS flag */
  ctx->out_eos = FALSE;

  gst_object_unref (peer);
}
Пример #6
0
static void
gst_deinterleave_add_new_pads (GstDeinterleave * self, GstCaps * caps)
{
  GstPad *pad;
  guint i;

  for (i = 0; i < GST_AUDIO_INFO_CHANNELS (&self->audio_info); i++) {
    gchar *name = g_strdup_printf ("src_%u", i);
    GstCaps *srccaps;
    GstAudioInfo info;
    GstAudioFormat format = GST_AUDIO_INFO_FORMAT (&self->audio_info);
    gint rate = GST_AUDIO_INFO_RATE (&self->audio_info);
    GstAudioChannelPosition position = GST_AUDIO_CHANNEL_POSITION_MONO;
    CopyStickyEventsData data;

    /* Set channel position if we know it */
    if (self->keep_positions)
      position = GST_AUDIO_INFO_POSITION (&self->audio_info, i);

    gst_audio_info_init (&info);
    gst_audio_info_set_format (&info, format, rate, 1, &position);

    srccaps = gst_audio_info_to_caps (&info);

    pad = gst_pad_new_from_static_template (&src_template, name);
    g_free (name);

    gst_pad_use_fixed_caps (pad);
    gst_pad_set_query_function (pad,
        GST_DEBUG_FUNCPTR (gst_deinterleave_src_query));
    gst_pad_set_active (pad, TRUE);

    data.pad = pad;
    data.caps = srccaps;
    gst_pad_sticky_events_foreach (self->sink, copy_sticky_events, &data);
    if (data.caps)
      gst_pad_set_caps (pad, data.caps);
    gst_element_add_pad (GST_ELEMENT (self), pad);
    self->srcpads = g_list_prepend (self->srcpads, gst_object_ref (pad));

    gst_caps_unref (srccaps);
  }

  gst_element_no_more_pads (GST_ELEMENT (self));
  self->srcpads = g_list_reverse (self->srcpads);
}
Пример #7
0
static void
forward_initial_events (GstRtpSsrcDemux * demux, guint32 ssrc, GstPad * pad,
                        PadType padtype)
{
    struct ForwardStickyEventData fdata;
    GstPad *sinkpad = NULL;

    if (padtype == RTP_PAD)
        sinkpad = demux->rtp_sink;
    else if (padtype == RTCP_PAD)
        sinkpad = demux->rtcp_sink;
    else
        g_assert_not_reached ();

    fdata.ssrc = ssrc;
    fdata.pad = pad;

    gst_pad_sticky_events_foreach (sinkpad, forward_sticky_events, &fdata);
}
static GstPad *
gst_tee_request_new_pad (GstElement * element, GstPadTemplate * templ,
    const gchar * name_templ, const GstCaps * caps)
{
  gchar *name;
  GstPad *srcpad;
  GstTee *tee;
  GstPadMode mode;
  gboolean res;
  guint index = 0;

  tee = GST_TEE (element);

  GST_DEBUG_OBJECT (tee, "requesting pad");

  GST_OBJECT_LOCK (tee);

  if (name_templ) {
    sscanf (name_templ, "src_%u", &index);
    GST_LOG_OBJECT (element, "name: %s (index %d)", name_templ, index);
    if (g_hash_table_contains (tee->pad_indexes, GUINT_TO_POINTER (index))) {
      GST_ERROR_OBJECT (element, "pad name %s is not unique", name_templ);
      GST_OBJECT_UNLOCK (tee);
      return NULL;
    }
    if (index >= tee->next_pad_index)
      tee->next_pad_index = index + 1;
  } else {
    index = tee->next_pad_index;

    while (g_hash_table_contains (tee->pad_indexes, GUINT_TO_POINTER (index)))
      index++;

    tee->next_pad_index = index + 1;
  }

  g_hash_table_insert (tee->pad_indexes, GUINT_TO_POINTER (index), NULL);

  name = g_strdup_printf ("src_%u", index);

  srcpad = GST_PAD_CAST (g_object_new (GST_TYPE_TEE_PAD,
          "name", name, "direction", templ->direction, "template", templ,
          NULL));
  GST_TEE_PAD_CAST (srcpad)->index = index;
  g_free (name);

  mode = tee->sink_mode;

  GST_OBJECT_UNLOCK (tee);

  switch (mode) {
    case GST_PAD_MODE_PULL:
      /* we already have a src pad in pull mode, and our pull mode can only be
         SINGLE, so fall through to activate this new pad in push mode */
    case GST_PAD_MODE_PUSH:
      res = gst_pad_activate_mode (srcpad, GST_PAD_MODE_PUSH, TRUE);
      break;
    default:
      res = TRUE;
      break;
  }

  if (!res)
    goto activate_failed;

  gst_pad_set_activatemode_function (srcpad,
      GST_DEBUG_FUNCPTR (gst_tee_src_activate_mode));
  gst_pad_set_query_function (srcpad, GST_DEBUG_FUNCPTR (gst_tee_src_query));
  gst_pad_set_getrange_function (srcpad,
      GST_DEBUG_FUNCPTR (gst_tee_src_get_range));
  /* Forward sticky events to the new srcpad */
  gst_pad_sticky_events_foreach (tee->sinkpad, forward_sticky_events, srcpad);
  GST_OBJECT_FLAG_SET (srcpad, GST_PAD_FLAG_PROXY_CAPS);
  gst_element_add_pad (GST_ELEMENT_CAST (tee), srcpad);

  return srcpad;

  /* ERRORS */
activate_failed:
  {
    gboolean changed = FALSE;

    GST_OBJECT_LOCK (tee);
    GST_DEBUG_OBJECT (tee, "warning failed to activate request pad");
    if (tee->allocpad == srcpad) {
      tee->allocpad = NULL;
      changed = TRUE;
    }
    GST_OBJECT_UNLOCK (tee);
    gst_object_unref (srcpad);
    if (changed) {
      gst_tee_notify_alloc_pad (tee);
    }
    return NULL;
  }
}
Пример #9
0
static void
gst_valve_repush_sticky (GstValve * valve)
{
  valve->need_repush_sticky = FALSE;
  gst_pad_sticky_events_foreach (valve->sinkpad, forward_sticky_events, valve);
}
static gboolean
gst_output_selector_switch (GstOutputSelector * osel)
{
  gboolean res = FALSE;
  GstEvent *ev = NULL;
  GstSegment *seg = NULL;
  GstPad *active_srcpad;

  /* Switch */
  GST_OBJECT_LOCK (osel);
  GST_INFO_OBJECT (osel, "switching to pad %" GST_PTR_FORMAT,
      osel->pending_srcpad);
  if (!osel->pending_srcpad) {
    GST_OBJECT_UNLOCK (osel);
    return TRUE;
  }

  if (gst_pad_is_linked (osel->pending_srcpad)) {
    osel->active_srcpad = osel->pending_srcpad;
    res = TRUE;
  }
  gst_object_unref (osel->pending_srcpad);
  osel->pending_srcpad = NULL;
  active_srcpad = res ? gst_object_ref (osel->active_srcpad) : NULL;
  GST_OBJECT_UNLOCK (osel);

  /* Send SEGMENT event and latest buffer if switching succeeded
   * and we already have a valid segment configured */
  if (res) {
    GstBuffer *latest_buffer;

    g_object_notify (G_OBJECT (osel), "active-pad");

    GST_OBJECT_LOCK (osel);
    latest_buffer =
        osel->latest_buffer ? gst_buffer_ref (osel->latest_buffer) : NULL;
    GST_OBJECT_UNLOCK (osel);

    gst_pad_sticky_events_foreach (osel->sinkpad, forward_sticky_events,
        active_srcpad);

    /* update segment if required */
    if (osel->segment.format != GST_FORMAT_UNDEFINED) {
      /* Send SEGMENT to the pad we are going to switch to */
      seg = &osel->segment;
      /* If resending then mark segment start and position accordingly */
      if (osel->resend_latest && latest_buffer &&
          GST_BUFFER_TIMESTAMP_IS_VALID (latest_buffer)) {
        seg->position = GST_BUFFER_TIMESTAMP (latest_buffer);
      }

      ev = gst_event_new_segment (seg);

      if (!gst_pad_push_event (active_srcpad, ev)) {
        GST_WARNING_OBJECT (osel,
            "newsegment handling failed in %" GST_PTR_FORMAT, active_srcpad);
      }
    }

    /* Resend latest buffer to newly switched pad */
    if (osel->resend_latest && latest_buffer) {
      GST_INFO ("resending latest buffer");
      gst_pad_push (active_srcpad, latest_buffer);
    } else if (latest_buffer) {
      gst_buffer_unref (latest_buffer);
    }

    gst_object_unref (active_srcpad);
  } else {
    GST_WARNING_OBJECT (osel, "switch failed, pad not linked");
  }

  return res;
}
Пример #11
0
static GstFlowReturn
gst_rtp_pt_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
{
  GstFlowReturn ret = GST_FLOW_OK;
  GstRtpPtDemux *rtpdemux;
  guint8 pt;
  GstPad *srcpad;
  GstCaps *caps;
  GstRTPBuffer rtp = { NULL };

  rtpdemux = GST_RTP_PT_DEMUX (parent);

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

  pt = gst_rtp_buffer_get_payload_type (&rtp);
  gst_rtp_buffer_unmap (&rtp);

  GST_DEBUG_OBJECT (rtpdemux, "received buffer for pt %d", pt);

  srcpad = find_pad_for_pt (rtpdemux, pt);
  if (srcpad == NULL) {
    /* new PT, create a src pad */
    GstRtpPtDemuxPad *rtpdemuxpad;
    GstElementClass *klass;
    GstPadTemplate *templ;
    gchar *padname;

    caps = gst_rtp_pt_demux_get_caps (rtpdemux, pt);
    if (!caps)
      goto no_caps;

    klass = GST_ELEMENT_GET_CLASS (rtpdemux);
    templ = gst_element_class_get_pad_template (klass, "src_%u");
    padname = g_strdup_printf ("src_%u", pt);
    srcpad = gst_pad_new_from_template (templ, padname);
    gst_pad_use_fixed_caps (srcpad);
    g_free (padname);
    gst_pad_set_event_function (srcpad, gst_rtp_pt_demux_src_event);

    GST_DEBUG ("Adding pt=%d to the list.", pt);
    rtpdemuxpad = g_slice_new0 (GstRtpPtDemuxPad);
    rtpdemuxpad->pt = pt;
    rtpdemuxpad->newcaps = FALSE;
    rtpdemuxpad->pad = srcpad;
    gst_object_ref (srcpad);
    GST_OBJECT_LOCK (rtpdemux);
    rtpdemux->srcpads = g_slist_append (rtpdemux->srcpads, rtpdemuxpad);
    GST_OBJECT_UNLOCK (rtpdemux);

    gst_pad_set_active (srcpad, TRUE);


    /* First push the stream-start event, it must always come first */
    gst_pad_push_event (srcpad,
        gst_pad_get_sticky_event (rtpdemux->sink, GST_EVENT_STREAM_START, 0));

    /* Then caps event is sent */
    caps = gst_caps_make_writable (caps);
    gst_caps_set_simple (caps, "payload", G_TYPE_INT, pt, NULL);
    gst_pad_set_caps (srcpad, caps);
    gst_caps_unref (caps);

    /* First sticky events on sink pad are forwarded to the new src pad */
    gst_pad_sticky_events_foreach (rtpdemux->sink, forward_sticky_events,
        srcpad);

    gst_element_add_pad (GST_ELEMENT_CAST (rtpdemux), srcpad);

    GST_DEBUG ("emitting new-payload-type for pt %d", pt);
    g_signal_emit (G_OBJECT (rtpdemux),
        gst_rtp_pt_demux_signals[SIGNAL_NEW_PAYLOAD_TYPE], 0, pt, srcpad);
  }

  if (pt != rtpdemux->last_pt) {
    gint emit_pt = pt;

    /* our own signal with an extra flag that this is the only pad */
    rtpdemux->last_pt = pt;
    GST_DEBUG ("emitting payload-type-changed for pt %d", emit_pt);
    g_signal_emit (G_OBJECT (rtpdemux),
        gst_rtp_pt_demux_signals[SIGNAL_PAYLOAD_TYPE_CHANGE], 0, emit_pt);
  }

  while (need_caps_for_pt (rtpdemux, pt)) {
    GST_DEBUG ("need new caps for %d", pt);
    caps = gst_rtp_pt_demux_get_caps (rtpdemux, pt);
    if (!caps)
      goto no_caps;

    clear_newcaps_for_pt (rtpdemux, pt);

    caps = gst_caps_make_writable (caps);
    gst_caps_set_simple (caps, "payload", G_TYPE_INT, pt, NULL);
    gst_pad_set_caps (srcpad, caps);
    gst_caps_unref (caps);
  }

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

  gst_object_unref (srcpad);

  return ret;

  /* ERRORS */
invalid_buffer:
  {
    /* this is fatal and should be filtered earlier */
    GST_ELEMENT_ERROR (rtpdemux, STREAM, DECODE, (NULL),
        ("Dropping invalid RTP payload"));
    gst_buffer_unref (buf);
    return GST_FLOW_ERROR;
  }
no_caps:
  {
    GST_ELEMENT_ERROR (rtpdemux, STREAM, DECODE, (NULL),
        ("Could not get caps for payload"));
    gst_buffer_unref (buf);
    if (srcpad)
      gst_object_unref (srcpad);
    return GST_FLOW_ERROR;
  }
}
static gboolean
activate_session (GstRDTManager * rdtmanager, GstRDTManagerSession * session,
    guint32 ssrc, guint8 pt)
{
  GstPadTemplate *templ;
  GstElementClass *klass;
  gchar *name;
  GstCaps *caps;
  GValue ret = { 0 };
  GValue args[3] = { {0}
  , {0}
  , {0}
  };

  GST_DEBUG_OBJECT (rdtmanager, "creating stream");

  session->ssrc = ssrc;
  session->pt = pt;

  /* get pt map */
  g_value_init (&args[0], GST_TYPE_ELEMENT);
  g_value_set_object (&args[0], rdtmanager);
  g_value_init (&args[1], G_TYPE_UINT);
  g_value_set_uint (&args[1], session->id);
  g_value_init (&args[2], G_TYPE_UINT);
  g_value_set_uint (&args[2], pt);

  g_value_init (&ret, GST_TYPE_CAPS);
  g_value_set_boxed (&ret, NULL);

  g_signal_emitv (args, gst_rdt_manager_signals[SIGNAL_REQUEST_PT_MAP], 0,
      &ret);

  g_value_unset (&args[0]);
  g_value_unset (&args[1]);
  g_value_unset (&args[2]);
  caps = (GstCaps *) g_value_dup_boxed (&ret);
  g_value_unset (&ret);

  if (caps)
    gst_rdt_manager_parse_caps (rdtmanager, session, caps);

  name = g_strdup_printf ("recv_rtp_src_%u_%u_%u", session->id, ssrc, pt);
  klass = GST_ELEMENT_GET_CLASS (rdtmanager);
  templ = gst_element_class_get_pad_template (klass, "recv_rtp_src_%u_%u_%u");
  session->recv_rtp_src = gst_pad_new_from_template (templ, name);
  g_free (name);

  gst_pad_set_element_private (session->recv_rtp_src, session);
  gst_pad_set_query_function (session->recv_rtp_src, gst_rdt_manager_query_src);
  gst_pad_set_activatemode_function (session->recv_rtp_src,
      gst_rdt_manager_src_activate_mode);

  gst_pad_set_active (session->recv_rtp_src, TRUE);

  gst_pad_sticky_events_foreach (session->recv_rtp_sink, forward_sticky_events,
      session->recv_rtp_src);
  gst_pad_set_caps (session->recv_rtp_src, caps);
  gst_caps_unref (caps);

  gst_element_add_pad (GST_ELEMENT_CAST (rdtmanager), session->recv_rtp_src);

  return TRUE;
}
static gboolean
gst_streamid_demux_event (GstPad * pad, GstObject * parent, GstEvent * event)
{
  gboolean res = TRUE;
  GstStreamidDemux *demux;
  const gchar *stream_id = NULL;
  GstPad *active_srcpad = NULL;

  demux = GST_STREAMID_DEMUX (parent);

  GST_DEBUG_OBJECT (demux, "event = %s, sticky = %d",
      GST_EVENT_TYPE_NAME (event), GST_EVENT_IS_STICKY (event));

  if (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_START) {
    gst_event_parse_stream_start (event, &stream_id);
    if (!stream_id)
      goto no_stream_id;

    GST_OBJECT_LOCK (demux);
    active_srcpad =
        gst_streamid_demux_get_srcpad_by_stream_id (demux, stream_id);
    if (!active_srcpad) {
      /* try to generate a srcpad */
      if (gst_streamid_demux_srcpad_create (demux, pad, stream_id)) {
        GST_OBJECT_UNLOCK (demux);

        gst_pad_set_active (demux->active_srcpad, TRUE);
        /* Forward sticky events to the new srcpad */
        gst_pad_sticky_events_foreach (demux->sinkpad, forward_sticky_events,
            demux->active_srcpad);
        gst_element_add_pad (GST_ELEMENT_CAST (demux), demux->active_srcpad);
      } else {
        GST_OBJECT_UNLOCK (demux);
        goto fail_create_srcpad;
      }
    } else if (demux->active_srcpad != active_srcpad) {
      demux->active_srcpad = active_srcpad;
      GST_OBJECT_UNLOCK (demux);

      g_object_notify (G_OBJECT (demux), "active-pad");
    } else
      GST_OBJECT_UNLOCK (demux);
  }

  if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_START
      || GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP
      || GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
    res = gst_pad_event_default (pad, parent, event);
  } else if (demux->active_srcpad) {
    GstPad *srcpad = NULL;
    GST_OBJECT_LOCK (demux);
    srcpad = gst_object_ref (demux->active_srcpad);
    GST_OBJECT_UNLOCK (demux);
    res = gst_pad_push_event (srcpad, event);
    gst_object_unref (srcpad);
  } else {
    gst_event_unref (event);
  }
  return res;

  /* ERRORS */
no_stream_id:
  {
    GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
        ("Error occurred trying to get stream-id to create a srcpad"),
        ("no stream-id found at %s", GST_EVENT_TYPE_NAME (event)));

    gst_event_unref (event);
    return FALSE;
  }

fail_create_srcpad:
  {
    GST_ELEMENT_ERROR (demux, STREAM, FAILED,
        ("Error occurred trying to create a srcpad"),
        ("Failed to create a srcpad via stream-id:%s", stream_id));
    gst_event_unref (event);
    return FALSE;
  }
}
Пример #14
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;
  GstCaps *caps;
  struct ForwardEventData fdata;
  GstPad *retpad;
  gulong rtp_block, rtcp_block;

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

  GST_PAD_LOCK (demux);

  demuxpad = find_demux_pad_for_ssrc (demux, ssrc);
  if (demuxpad != NULL) {
    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_PAD_UNLOCK (demux);
    return retpad;
  }

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

  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;
}
static GstFlowReturn
gst_rtp_mux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
{
  GstRTPMux *rtp_mux;
  GstFlowReturn ret;
  GstRTPMuxPadPrivate *padpriv;
  gboolean drop;
  gboolean changed = FALSE;
  GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT;

  rtp_mux = GST_RTP_MUX (parent);

  if (gst_pad_check_reconfigure (rtp_mux->srcpad)) {
    GstCaps *current_caps = gst_pad_get_current_caps (pad);

    if (!gst_rtp_mux_setcaps (pad, rtp_mux, current_caps)) {
      ret = GST_FLOW_NOT_NEGOTIATED;
      gst_buffer_unref (buffer);
      goto out;
    }
    gst_caps_unref (current_caps);
  }

  GST_OBJECT_LOCK (rtp_mux);
  padpriv = gst_pad_get_element_private (pad);

  if (!padpriv) {
    GST_OBJECT_UNLOCK (rtp_mux);
    gst_buffer_unref (buffer);
    return GST_FLOW_NOT_LINKED;
  }

  buffer = gst_buffer_make_writable (buffer);

  if (!gst_rtp_buffer_map (buffer, GST_MAP_READWRITE, &rtpbuffer)) {
    GST_OBJECT_UNLOCK (rtp_mux);
    gst_buffer_unref (buffer);
    GST_ERROR_OBJECT (rtp_mux, "Invalid RTP buffer");
    return GST_FLOW_ERROR;
  }

  drop = !process_buffer_locked (rtp_mux, padpriv, &rtpbuffer);

  gst_rtp_buffer_unmap (&rtpbuffer);

  if (!drop) {
    if (pad != rtp_mux->last_pad) {
      changed = TRUE;
      g_clear_object (&rtp_mux->last_pad);
      rtp_mux->last_pad = g_object_ref (pad);
    }

    if (GST_BUFFER_DURATION_IS_VALID (buffer) &&
        GST_BUFFER_PTS_IS_VALID (buffer))
      rtp_mux->last_stop = GST_BUFFER_PTS (buffer) +
          GST_BUFFER_DURATION (buffer);
    else
      rtp_mux->last_stop = GST_CLOCK_TIME_NONE;
  }

  GST_OBJECT_UNLOCK (rtp_mux);

  if (changed)
    gst_pad_sticky_events_foreach (pad, resend_events, rtp_mux);

  if (drop) {
    gst_buffer_unref (buffer);
    ret = GST_FLOW_OK;
  } else {
    ret = gst_pad_push (rtp_mux->srcpad, buffer);
  }

out:
  return ret;
}
static GstFlowReturn
gst_rtp_mux_chain_list (GstPad * pad, GstObject * parent,
    GstBufferList * bufferlist)
{
  GstRTPMux *rtp_mux;
  GstFlowReturn ret;
  GstRTPMuxPadPrivate *padpriv;
  gboolean changed = FALSE;
  struct BufferListData bd;

  rtp_mux = GST_RTP_MUX (parent);

  if (gst_pad_check_reconfigure (rtp_mux->srcpad)) {
    GstCaps *current_caps = gst_pad_get_current_caps (pad);

    if (!gst_rtp_mux_setcaps (pad, rtp_mux, current_caps)) {
      ret = GST_FLOW_NOT_NEGOTIATED;
      gst_buffer_list_unref (bufferlist);
      goto out;
    }
    gst_caps_unref (current_caps);
  }

  GST_OBJECT_LOCK (rtp_mux);

  padpriv = gst_pad_get_element_private (pad);
  if (!padpriv) {
    GST_OBJECT_UNLOCK (rtp_mux);
    ret = GST_FLOW_NOT_LINKED;
    gst_buffer_list_unref (bufferlist);
    goto out;
  }

  bd.rtp_mux = rtp_mux;
  bd.padpriv = padpriv;
  bd.drop = FALSE;

  bufferlist = gst_buffer_list_make_writable (bufferlist);
  gst_buffer_list_foreach (bufferlist, process_list_item, &bd);

  if (!bd.drop && pad != rtp_mux->last_pad) {
    changed = TRUE;
    g_clear_object (&rtp_mux->last_pad);
    rtp_mux->last_pad = g_object_ref (pad);
  }

  GST_OBJECT_UNLOCK (rtp_mux);

  if (changed)
    gst_pad_sticky_events_foreach (pad, resend_events, rtp_mux);

  if (bd.drop) {
    gst_buffer_list_unref (bufferlist);
    ret = GST_FLOW_OK;
  } else {
    ret = gst_pad_push_list (rtp_mux->srcpad, bufferlist);
  }

out:

  return ret;
}
Пример #17
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;
}