예제 #1
0
static gboolean
gst_stream_splitter_sink_setcaps (GstPad * pad, GstCaps * caps)
{
  GstStreamSplitter *stream_splitter =
      (GstStreamSplitter *) GST_PAD_PARENT (pad);
  guint32 cookie;
  GList *tmp;
  gboolean res;

  GST_DEBUG_OBJECT (stream_splitter, "caps %" GST_PTR_FORMAT, caps);

  /* Try on all pads, choose the one that succeeds as the current stream */
  STREAMS_LOCK (stream_splitter);

resync:
  if (G_UNLIKELY (stream_splitter->srcpads == NULL)) {
    res = FALSE;
    goto beach;
  }

  res = FALSE;
  tmp = stream_splitter->srcpads;
  cookie = stream_splitter->cookie;

  while (tmp) {
    GstPad *srcpad = (GstPad *) tmp->data;
    GstCaps *peercaps;

    STREAMS_UNLOCK (stream_splitter);
    peercaps = gst_pad_peer_query_caps (srcpad, NULL);
    if (peercaps) {
      res = gst_caps_can_intersect (caps, peercaps);
      gst_caps_unref (peercaps);
    }
    STREAMS_LOCK (stream_splitter);

    if (G_UNLIKELY (cookie != stream_splitter->cookie))
      goto resync;

    if (res) {
      /* FIXME : we need to switch properly */
      GST_DEBUG_OBJECT (srcpad, "Setting caps on this pad was successful");
      stream_splitter->current = srcpad;
      goto beach;
    }
    tmp = tmp->next;
  }

beach:
  STREAMS_UNLOCK (stream_splitter);
  return res;
}
static GstCaps *
gst_stream_splitter_sink_getcaps (GstPad * pad, GstCaps * filter)
{
  GstStreamSplitter *stream_splitter =
      (GstStreamSplitter *) GST_PAD_PARENT (pad);
  guint32 cookie;
  GList *tmp;
  GstCaps *res = NULL;

  /* Return the combination of all downstream caps */

  STREAMS_LOCK (stream_splitter);

resync:
  if (G_UNLIKELY (stream_splitter->srcpads == NULL)) {
    res = (filter ? gst_caps_ref (filter) : gst_caps_new_any ());
    goto beach;
  }

  res = NULL;
  cookie = stream_splitter->cookie;
  tmp = stream_splitter->srcpads;

  while (tmp) {
    GstPad *srcpad = (GstPad *) tmp->data;

    /* Ensure srcpad doesn't get destroyed while we query peer */
    gst_object_ref (srcpad);
    STREAMS_UNLOCK (stream_splitter);
    if (res) {
      GstCaps *peercaps = gst_pad_peer_query_caps (srcpad, filter);
      if (peercaps)
        res = gst_caps_merge (res, peercaps);
    } else {
      res = gst_pad_peer_query_caps (srcpad, filter);
    }
    STREAMS_LOCK (stream_splitter);
    gst_object_unref (srcpad);

    if (G_UNLIKELY (cookie != stream_splitter->cookie)) {
      if (res)
        gst_caps_unref (res);
      goto resync;
    }
    tmp = tmp->next;
  }

beach:
  STREAMS_UNLOCK (stream_splitter);
  return res;
}
예제 #3
0
static void
gst_stream_splitter_release_pad (GstElement * element, GstPad * pad)
{
  GstStreamSplitter *stream_splitter = (GstStreamSplitter *) element;
  GList *tmp;

  STREAMS_LOCK (stream_splitter);
  tmp = g_list_find (stream_splitter->srcpads, pad);
  if (tmp) {
    GstPad *pad = (GstPad *) tmp->data;

    stream_splitter->srcpads =
        g_list_delete_link (stream_splitter->srcpads, tmp);
    stream_splitter->cookie++;

    if (pad == stream_splitter->current) {
      /* Deactivate current flow */
      GST_DEBUG_OBJECT (element, "Removed pad was the current one");
      stream_splitter->current = NULL;
    }

    gst_element_remove_pad (element, pad);
  }
  STREAMS_UNLOCK (stream_splitter);

  return;
}
예제 #4
0
static GstFlowReturn
gst_stream_splitter_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
{
  GstStreamSplitter *stream_splitter = (GstStreamSplitter *) parent;
  GstFlowReturn res;
  GstPad *srcpad = NULL;

  STREAMS_LOCK (stream_splitter);
  if (stream_splitter->current)
    srcpad = gst_object_ref (stream_splitter->current);
  STREAMS_UNLOCK (stream_splitter);

  if (G_UNLIKELY (srcpad == NULL))
    goto nopad;

  if (G_UNLIKELY (stream_splitter->pending_events))
    gst_stream_splitter_push_pending_events (stream_splitter, srcpad);

  /* Forward to currently activated stream */
  res = gst_pad_push (srcpad, buf);
  gst_object_unref (srcpad);

  return res;

nopad:
  GST_WARNING_OBJECT (stream_splitter, "No output pad was configured");
  return GST_FLOW_ERROR;
}
static gboolean
gst_stream_combiner_src_query (GstPad * pad, GstObject * parent,
    GstQuery * query)
{
  GstStreamCombiner *stream_combiner = (GstStreamCombiner *) parent;
  GstPad *sinkpad = NULL;
  gboolean ret = FALSE;

  switch (GST_QUERY_TYPE (query)) {
    case GST_QUERY_CAPS:
      ret = gst_pad_query_default (pad, parent, query);
      break;
    default:
      STREAMS_LOCK (stream_combiner);
      if (stream_combiner->current)
        sinkpad = stream_combiner->current;
      else if (stream_combiner->sinkpads)
        sinkpad = (GstPad *) stream_combiner->sinkpads->data;
      STREAMS_UNLOCK (stream_combiner);

      if (sinkpad)
        /* Forward upstream as is */
        ret = gst_pad_peer_query (sinkpad, query);
      break;
  }
  return ret;
}
static gboolean
gst_stream_combiner_sink_event (GstPad * pad, GstObject * parent,
    GstEvent * event)
{
  GstStreamCombiner *stream_combiner = (GstStreamCombiner *) parent;
  GstStreamCombinerPad *combiner_pad = GST_STREAM_COMBINER_PAD (pad);
  /* FIXME : IMPLEMENT */

  GST_DEBUG_OBJECT (pad, "Got event %s", GST_EVENT_TYPE_NAME (event));

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_EOS:
      STREAMS_LOCK (stream_combiner);
      combiner_pad->is_eos = TRUE;
      if (!_all_sink_pads_eos (stream_combiner)) {
        gst_event_unref (event);
        event = NULL;
      } else {
        GST_DEBUG_OBJECT (stream_combiner, "All sink pads eos, pushing eos");
      }
      STREAMS_UNLOCK (stream_combiner);
      break;
    default:
      break;
  }

  /* SEGMENT : lock, wait for other stream to EOS, select stream, unlock, push */
  /* FLUSH_START : lock, mark as flushing, unlock. if wasn't flushing forward */
  /* FLUSH_STOP : lock, unmark as flushing, unlock, if was flushing forward */
  /* OTHER : if selected pad forward */
  if (event)
    return gst_pad_push_event (stream_combiner->srcpad, event);
  return FALSE;
}
static gboolean
gst_stream_splitter_sink_acceptcaps (GstPad * pad, GstCaps * caps)
{
  GstStreamSplitter *stream_splitter =
      (GstStreamSplitter *) GST_PAD_PARENT (pad);
  guint32 cookie;
  GList *tmp;
  gboolean res = FALSE;

  /* check if one of the downstream elements accepts the caps */
  STREAMS_LOCK (stream_splitter);

resync:
  res = FALSE;

  if (G_UNLIKELY (stream_splitter->srcpads == NULL))
    goto beach;

  cookie = stream_splitter->cookie;
  tmp = stream_splitter->srcpads;

  while (tmp) {
    GstPad *srcpad = (GstPad *) tmp->data;

    /* Ensure srcpad doesn't get destroyed while we query peer */
    gst_object_ref (srcpad);
    STREAMS_UNLOCK (stream_splitter);

    res = gst_pad_peer_query_accept_caps (srcpad, caps);

    STREAMS_LOCK (stream_splitter);
    gst_object_unref (srcpad);

    if (G_UNLIKELY (cookie != stream_splitter->cookie))
      goto resync;

    if (res)
      break;

    tmp = tmp->next;
  }

beach:
  STREAMS_UNLOCK (stream_splitter);
  return res;
}
static GstPad *
gst_stream_splitter_request_new_pad (GstElement * element,
    GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
{
  GstStreamSplitter *stream_splitter = (GstStreamSplitter *) element;
  GstPad *srcpad;

  srcpad = gst_pad_new_from_static_template (&src_template, name);

  STREAMS_LOCK (stream_splitter);
  stream_splitter->srcpads = g_list_append (stream_splitter->srcpads, srcpad);
  gst_pad_set_active (srcpad, TRUE);
  gst_element_add_pad (element, srcpad);
  stream_splitter->cookie++;
  STREAMS_UNLOCK (stream_splitter);

  return srcpad;
}
static gboolean
gst_stream_combiner_src_event (GstPad * pad, GstObject * parent,
    GstEvent * event)
{
  GstStreamCombiner *stream_combiner = (GstStreamCombiner *) parent;
  GstPad *sinkpad = NULL;

  STREAMS_LOCK (stream_combiner);
  if (stream_combiner->current)
    sinkpad = stream_combiner->current;
  else if (stream_combiner->sinkpads)
    sinkpad = (GstPad *) stream_combiner->sinkpads->data;
  STREAMS_UNLOCK (stream_combiner);

  if (sinkpad)
    /* Forward upstream as is */
    return gst_pad_push_event (sinkpad, event);

  return FALSE;
}
예제 #10
0
static GstFlowReturn
gst_stream_splitter_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
{
  GstStreamSplitter *stream_splitter = (GstStreamSplitter *) parent;
  GstFlowReturn res;
  GstPad *srcpad = NULL;

  STREAMS_LOCK (stream_splitter);
  if (stream_splitter->current)
    srcpad = gst_object_ref (stream_splitter->current);
  STREAMS_UNLOCK (stream_splitter);

  if (G_UNLIKELY (srcpad == NULL))
    goto nopad;

  if (G_UNLIKELY (stream_splitter->pending_events)) {
    GList *tmp;
    GST_DEBUG_OBJECT (srcpad, "Pushing out pending events");

    for (tmp = stream_splitter->pending_events; tmp; tmp = tmp->next) {
      GstEvent *event = (GstEvent *) tmp->data;
      gst_pad_push_event (srcpad, event);
    }
    g_list_free (stream_splitter->pending_events);
    stream_splitter->pending_events = NULL;
  }

  /* Forward to currently activated stream */
  res = gst_pad_push (srcpad, buf);
  gst_object_unref (srcpad);

  return res;

nopad:
  GST_WARNING_OBJECT (stream_splitter, "No output pad was configured");
  return GST_FLOW_ERROR;
}
예제 #11
0
static gboolean
gst_stream_splitter_sink_event (GstPad * pad, GstObject * parent,
    GstEvent * event)
{
  GstStreamSplitter *stream_splitter = (GstStreamSplitter *) parent;
  gboolean res = TRUE;
  gboolean toall = FALSE;
  gboolean store = FALSE;
  gboolean eos = FALSE;
  gboolean flushpending = FALSE;

  /* FLUSH_START/STOP : forward to all
   * EOS : transform to CUSTOM_REAL_EOS and forward to all
   * INBAND events : store to send in chain function to selected chain
   * OUT_OF_BAND events : send to all
   */

  GST_DEBUG_OBJECT (stream_splitter, "Got event %s",
      GST_EVENT_TYPE_NAME (event));

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_CAPS:
    {
      GstCaps *caps;

      gst_event_parse_caps (event, &caps);
      res = gst_stream_splitter_sink_setcaps (pad, caps);

      store = TRUE;
      break;
    }
    case GST_EVENT_FLUSH_STOP:
      flushpending = TRUE;
      toall = TRUE;
      break;
    case GST_EVENT_FLUSH_START:
      toall = TRUE;
      break;
    case GST_EVENT_EOS:
      /* Replace with our custom eos event */
      gst_event_unref (event);
      event =
          gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM,
          gst_structure_new_empty ("stream-switching-eos"));
      toall = TRUE;
      eos = TRUE;
      break;
    default:
      if (GST_EVENT_TYPE (event) & GST_EVENT_TYPE_SERIALIZED)
        store = TRUE;
  }

  if (flushpending) {
    g_list_foreach (stream_splitter->pending_events, (GFunc) gst_event_unref,
        NULL);
    g_list_free (stream_splitter->pending_events);
    stream_splitter->pending_events = NULL;
  }

  if (store) {
    stream_splitter->pending_events =
        g_list_append (stream_splitter->pending_events, event);
  } else if (toall || eos) {
    GList *tmp;
    guint32 cookie;

    /* Send to all pads */
    STREAMS_LOCK (stream_splitter);
  resync:
    if (G_UNLIKELY (stream_splitter->srcpads == NULL)) {
      STREAMS_UNLOCK (stream_splitter);
      /* No source pads */
      gst_event_unref (event);
      res = FALSE;
      goto beach;
    }
    tmp = stream_splitter->srcpads;
    cookie = stream_splitter->cookie;
    while (tmp) {
      GstPad *srcpad = (GstPad *) tmp->data;
      STREAMS_UNLOCK (stream_splitter);
      /* In case of EOS, we first push out the real one to flush out
       * each streams (but which will be discarded in the streamcombiner)
       * before our custom one (which will be converted back to and EOS
       * in the streamcombiner) */
      if (eos)
        gst_pad_push_event (srcpad, gst_event_new_eos ());
      gst_event_ref (event);
      res = gst_pad_push_event (srcpad, event);
      STREAMS_LOCK (stream_splitter);
      if (G_UNLIKELY (cookie != stream_splitter->cookie))
        goto resync;
      tmp = tmp->next;
    }
    STREAMS_UNLOCK (stream_splitter);
    gst_event_unref (event);
  } else {
    GstPad *pad;

    /* Only send to current pad */

    STREAMS_LOCK (stream_splitter);
    pad = stream_splitter->current;
    STREAMS_UNLOCK (stream_splitter);
    if (pad)
      res = gst_pad_push_event (pad, event);
    else {
      gst_event_unref (event);
      res = FALSE;
    }
  }

beach:
  return res;
}
static gboolean
gst_stream_splitter_sink_event (GstPad * pad, GstObject * parent,
    GstEvent * event)
{
  GstStreamSplitter *stream_splitter = (GstStreamSplitter *) parent;
  gboolean res = TRUE;
  gboolean toall = FALSE;
  gboolean store = FALSE;
  gboolean flushpending = FALSE;

  /* FLUSH_START/STOP : forward to all
   * INBAND events : store to send in chain function to selected chain
   * OUT_OF_BAND events : send to all
   */

  GST_DEBUG_OBJECT (stream_splitter, "Got event %s",
      GST_EVENT_TYPE_NAME (event));

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_CAPS:
    {
      GstCaps *caps;

      gst_event_parse_caps (event, &caps);
      res = gst_stream_splitter_sink_setcaps (pad, caps);

      store = TRUE;
      break;
    }
    case GST_EVENT_FLUSH_STOP:
      flushpending = TRUE;
      toall = TRUE;
      break;
    case GST_EVENT_FLUSH_START:
      toall = TRUE;
      break;
    case GST_EVENT_EOS:
      toall = TRUE;
      break;
    default:
      if (GST_EVENT_TYPE (event) & GST_EVENT_TYPE_SERIALIZED)
        store = TRUE;
  }

  if (flushpending) {
    g_list_foreach (stream_splitter->pending_events, (GFunc) gst_event_unref,
        NULL);
    g_list_free (stream_splitter->pending_events);
    stream_splitter->pending_events = NULL;
  }

  if (store) {
    stream_splitter->pending_events =
        g_list_append (stream_splitter->pending_events, event);
  } else if (toall) {
    GList *tmp;
    guint32 cookie;

    /* Send to all pads */
    STREAMS_LOCK (stream_splitter);
  resync:
    if (G_UNLIKELY (stream_splitter->srcpads == NULL)) {
      STREAMS_UNLOCK (stream_splitter);
      /* No source pads */
      gst_event_unref (event);
      res = FALSE;
      goto beach;
    }
    tmp = stream_splitter->srcpads;
    cookie = stream_splitter->cookie;
    while (tmp) {
      GstPad *srcpad = (GstPad *) tmp->data;
      STREAMS_UNLOCK (stream_splitter);
      gst_event_ref (event);
      res = gst_pad_push_event (srcpad, event);
      STREAMS_LOCK (stream_splitter);
      if (G_UNLIKELY (cookie != stream_splitter->cookie))
        goto resync;
      tmp = tmp->next;
    }
    STREAMS_UNLOCK (stream_splitter);
    gst_event_unref (event);
  } else {
    GstPad *pad;

    /* Only send to current pad */

    STREAMS_LOCK (stream_splitter);
    pad = stream_splitter->current;
    STREAMS_UNLOCK (stream_splitter);
    if (pad)
      res = gst_pad_push_event (pad, event);
    else {
      gst_event_unref (event);
      res = FALSE;
    }
  }

beach:
  return res;
}