예제 #1
0
static void pad_added (GstElement *elem, GstPad *pad, PipelineChangeListenerContext *ctx)
{
	GstPad *peer = gst_pad_get_peer (pad);

	GST_INFO ("found pad: %s (%s)", gst_pad_get_name (pad), G_OBJECT_TYPE_NAME (pad));

	/* if this pad isn't already linked, setup a signal handler.. otherwise
	 * simulate the signal:
	 */
	if (peer != NULL)
	{
		pad_linked (pad, peer, ctx);
		gst_object_unref (peer);
	}
	else
	{
		g_signal_connect (pad, "linked", pad_linked, ctx);
	}
}
예제 #2
0
// Used to seal up unconnected source nodes by connecting unconnected src pads to fake sinks
bool MediaNode::releaseFakeSinkIfConnected(GstElement *tee, GstElement *fakesink, GstElement *bin)
{
    if (GST_ELEMENT_PARENT(fakesink) == GST_ELEMENT(bin)) {
        GstPad *sinkPad = gst_element_get_pad(fakesink, "sink");

        // Release requested src pad from tee
        GstPad *requestedPad = gst_pad_get_peer(sinkPad);
        if (requestedPad) {
            gst_element_release_request_pad(tee, requestedPad);
            gst_object_unref(requestedPad);
        }
        gst_object_unref(sinkPad);

        gst_element_set_state(fakesink, GST_STATE_NULL);
        gst_bin_remove(GST_BIN(bin), fakesink);
        Q_ASSERT(!GST_ELEMENT_PARENT(fakesink));
    }
    return true;
}
예제 #3
0
static void
gst_ghost_pad_dispose (GObject * object)
{
  GstPad *pad;
  GstPad *internal;
  GstPad *peer;

  pad = GST_PAD (object);

  GST_DEBUG_OBJECT (pad, "dispose");

  gst_ghost_pad_set_target (GST_GHOST_PAD (pad), NULL);

  /* Unlink here so that gst_pad_dispose doesn't. That would lead to a call to
   * gst_ghost_pad_do_unlink when the ghost pad is in an inconsistent state */
  peer = gst_pad_get_peer (pad);
  if (peer) {
    if (GST_PAD_IS_SRC (pad))
      gst_pad_unlink (pad, peer);
    else
      gst_pad_unlink (peer, pad);

    gst_object_unref (peer);
  }

  GST_PROXY_LOCK (pad);
  internal = GST_PROXY_PAD_INTERNAL (pad);

  gst_pad_set_activatepull_function (internal, NULL);
  gst_pad_set_activatepush_function (internal, NULL);

  g_signal_handler_disconnect (internal,
      GST_GHOST_PAD_PRIVATE (pad)->notify_id);

  /* disposes of the internal pad, since the ghostpad is the only possible object
   * that has a refcount on the internal pad. */
  gst_object_unparent (GST_OBJECT_CAST (internal));
  GST_PROXY_PAD_INTERNAL (pad) = NULL;

  GST_PROXY_UNLOCK (pad);

  G_OBJECT_CLASS (gst_ghost_pad_parent_class)->dispose (object);
}
예제 #4
0
static GstCaps *
gst_play_sink_convert_bin_getcaps (GstPad * pad, GstCaps * filter)
{
  GstPlaySinkConvertBin *self =
      GST_PLAY_SINK_CONVERT_BIN (gst_pad_get_parent (pad));
  GstCaps *ret;
  GstPad *otherpad, *peer;

  GST_PLAY_SINK_CONVERT_BIN_LOCK (self);
  if (pad == self->srcpad) {
    otherpad = self->sinkpad;
  } else if (pad == self->sinkpad) {
    otherpad = self->srcpad;
  } else {
    GST_ERROR_OBJECT (pad, "Not one of our pads");
    otherpad = NULL;
  }

  if (otherpad) {
    peer = gst_pad_get_peer (otherpad);
    if (peer) {
      GstCaps *peer_caps = gst_pad_query_caps (peer, filter);
      gst_object_unref (peer);
      if (self->converter_caps && is_raw_caps (peer_caps, self->audio)) {
        ret = gst_caps_merge (peer_caps, gst_caps_ref (self->converter_caps));
      } else {
        ret = peer_caps;
      }
    } else {
      ret = gst_caps_ref (self->converter_caps);
    }
  } else {
    ret = gst_caps_new_any ();
  }
  GST_PLAY_SINK_CONVERT_BIN_UNLOCK (self);

  gst_object_unref (self);

  GST_DEBUG_OBJECT (pad, "Returning caps %" GST_PTR_FORMAT, ret);

  return ret;
}
예제 #5
0
static void
kms_element_release_pad (GstElement * element, GstPad * pad)
{
  GstElement *agnosticbin;
  GstPad *target;
  GstPad *peer;

  if (g_str_has_prefix (GST_OBJECT_NAME (pad), "audio_src")) {
    agnosticbin = KMS_ELEMENT (element)->priv->audio_agnosticbin;
  } else if (g_str_has_prefix (GST_OBJECT_NAME (pad), "video_src")) {
    agnosticbin = KMS_ELEMENT (element)->priv->video_agnosticbin;
  } else {
    return;
  }

  // TODO: Remove pad if is a sinkpad

  target = gst_ghost_pad_get_target (GST_GHOST_PAD (pad));

  if (target != NULL) {
    if (agnosticbin != NULL) {
      gst_element_release_request_pad (agnosticbin, target);
    }
    g_object_unref (target);
  }

  peer = gst_pad_get_peer (pad);

  gst_pad_push_event (pad, gst_event_new_flush_start ());

  if (GST_STATE (element) >= GST_STATE_PAUSED
      || GST_STATE_PENDING (element) >= GST_STATE_PAUSED) {
    gst_pad_set_active (pad, FALSE);
  }

  if (peer) {
    gst_pad_send_event (peer, gst_event_new_flush_stop (FALSE));
    g_object_unref (peer);
  }

  gst_element_remove_pad (element, pad);
}
예제 #6
0
static void
mex_telepathy_channel_update_video_parameters (MexTelepathyChannel *self,
                                               gboolean             restart)
{
  MexTelepathyChannelPrivate *priv = self->priv;
  GstCaps *caps;
  GstPad *src, *peer;

  src = gst_element_get_static_pad (priv->video_input, "src");
  peer = gst_pad_get_peer (src);

  if (restart)
    {
      /* Assuming the pipeline is in playing state */
      gst_element_set_locked_state (priv->video_input, TRUE);
      gst_element_set_state (priv->video_input, GST_STATE_NULL);
      gst_bin_remove (GST_BIN (priv->pipeline), priv->video_input);
    }

  g_object_get (priv->video_capsfilter, "caps", &caps, NULL);
  caps = gst_caps_make_writable (caps);

  gst_caps_set_simple (caps,
                       "framerate", GST_TYPE_FRACTION, priv->framerate, 1,
                       "width", G_TYPE_INT, priv->width,
                       "height", G_TYPE_INT, priv->height,
                       NULL);

  g_object_set (priv->video_capsfilter, "caps", caps, NULL);

  if (restart)
    {
      gst_bin_add (GST_BIN (priv->pipeline), priv->video_input);

      gst_pad_link (src, peer);
      gst_element_set_locked_state (priv->video_input, FALSE);
      gst_element_sync_state_with_parent (priv->video_input);
    }

  gst_object_unref (src);
  gst_object_unref (peer);
}
static void
add_smpte_to_bin (GstPad * sink, GstElement * smptealpha,
    GESTrackVideoTransitionPrivate * priv)
{
  GstPad *peer, *sinkpad;

  g_object_set (smptealpha,
      "type", (gint) priv->pending_type, "invert", (gboolean) TRUE, NULL);
  gst_bin_add (GST_BIN (priv->topbin), smptealpha);
  gst_element_sync_state_with_parent (smptealpha);

  sinkpad = gst_element_get_static_pad (smptealpha, "sink");
  peer = gst_pad_get_peer (sink);
  gst_pad_unlink (peer, sink);

  gst_pad_link_full (peer, sinkpad, GST_PAD_LINK_CHECK_NOTHING);

  gst_object_unref (sinkpad);
  gst_object_unref (peer);
}
static void
gst_uri_downloader_stop (GstUriDownloader * downloader)
{
  GstPad *pad;

  GST_DEBUG_OBJECT (downloader, "Stopping source element");

  /* remove the bus' sync handler */
  gst_bus_set_sync_handler (downloader->priv->bus, NULL, NULL);
  /* unlink the source element from the internal pad */
  pad = gst_pad_get_peer (downloader->priv->pad);
  if (pad) {
    gst_pad_unlink (pad, downloader->priv->pad);
    gst_object_unref (pad);
  }
  /* set the element state to NULL */
  gst_element_set_state (downloader->priv->urisrc, GST_STATE_NULL);
  gst_element_get_state (downloader->priv->urisrc, NULL, NULL,
      GST_CLOCK_TIME_NONE);
}
예제 #9
0
static void
gst_v4l2sink_navigation_send_event (GstNavigation * navigation,
    GstStructure * structure)
{
  GstV4l2Sink *v4l2sink = GST_V4L2SINK (navigation);
  GstV4l2Xv *xv = v4l2sink->v4l2object->xv;
  GstPad *peer;

  if (!xv)
    return;

  if ((peer = gst_pad_get_peer (GST_VIDEO_SINK_PAD (v4l2sink)))) {
    GstVideoRectangle rect;
    gdouble x, y, xscale = 1.0, yscale = 1.0;

    gst_v4l2_video_overlay_get_render_rect (v4l2sink->v4l2object, &rect);

    /* We calculate scaling using the original video frames geometry to
     * include pixel aspect ratio scaling.
     */
    xscale = (gdouble) v4l2sink->video_width / rect.w;
    yscale = (gdouble) v4l2sink->video_height / rect.h;

    /* Converting pointer coordinates to the non scaled geometry */
    if (gst_structure_get_double (structure, "pointer_x", &x)) {
      x = MIN (x, rect.x + rect.w);
      x = MAX (x - rect.x, 0);
      gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE,
          (gdouble) x * xscale, NULL);
    }
    if (gst_structure_get_double (structure, "pointer_y", &y)) {
      y = MIN (y, rect.y + rect.h);
      y = MAX (y - rect.y, 0);
      gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE,
          (gdouble) y * yscale, NULL);
    }

    gst_pad_send_event (peer, gst_event_new_navigation (structure));
    gst_object_unref (peer);
  }
}
예제 #10
0
static void
gst_glimage_sink_navigation_send_event (GstNavigation * navigation, GstStructure
    * structure)
{
  GstGLImageSink *sink = GST_GLIMAGE_SINK (navigation);
  GstEvent *event = NULL;
  GstPad *pad = NULL;
  GstGLWindow *window = gst_gl_context_get_window (sink->context);
  guint width, height;
  gdouble x, y, xscale, yscale;

  g_return_if_fail (GST_GL_IS_WINDOW (window));

  width = GST_VIDEO_SINK_WIDTH (sink);
  height = GST_VIDEO_SINK_HEIGHT (sink);
  gst_gl_window_get_surface_dimensions (window, &width, &height);

  event = gst_event_new_navigation (structure);

  pad = gst_pad_get_peer (GST_VIDEO_SINK_PAD (sink));
  /* Converting pointer coordinates to the non scaled geometry */
  if (width != GST_VIDEO_SINK_WIDTH (sink) &&
      width != 0 && gst_structure_get_double (structure, "pointer_x", &x)) {
    xscale = (gdouble) GST_VIDEO_SINK_WIDTH (sink) / width;
    gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE,
        (gdouble) x * xscale, NULL);
  }
  if (height != GST_VIDEO_SINK_HEIGHT (sink) &&
      height != 0 && gst_structure_get_double (structure, "pointer_y", &y)) {
    yscale = (gdouble) GST_VIDEO_SINK_HEIGHT (sink) / height;
    gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE,
        (gdouble) y * yscale, NULL);
  }


  if (GST_IS_PAD (pad) && GST_IS_EVENT (event))
    gst_pad_send_event (pad, event);

  gst_object_unref (pad);
  gst_object_unref (window);
}
예제 #11
0
파일: util.c 프로젝트: rodrimc/libmicromb
GstPadProbeReturn
stop_pad_cb (GstPad *pad, GstPadProbeInfo *info, gpointer data)
{
  MbMedia *media = NULL;
  GstPad *peer;

  GST_DEBUG_OBJECT(pad, "pad is blocked now");
  /* first remove the probe */
  gst_pad_remove_probe (pad, GST_PAD_PROBE_INFO_ID(info));

  media = (MbMedia *) data;
  g_assert (media);

  peer = gst_pad_get_peer (pad);
  g_assert(peer);

  gst_pad_send_event (peer, gst_event_new_eos ());
  gst_object_unref(peer);

  return GST_PAD_PROBE_OK;
}
static void
check_all_streams_for_eos (GstDecodebin3 * dbin)
{
  GList *tmp;

  if (!all_inputs_are_eos (dbin))
    return;

  /* We know all streams are EOS, properly clean up everything */
  for (tmp = dbin->input_streams; tmp; tmp = tmp->next) {
    DecodebinInputStream *input = (DecodebinInputStream *) tmp->data;
    GstPad *peer = gst_pad_get_peer (input->srcpad);

    /* Send EOS and then remove elements */
    if (peer) {
      gst_pad_send_event (peer, gst_event_new_eos ());
      gst_object_unref (peer);
    }
    GST_FIXME_OBJECT (input->srcpad, "Remove input stream");
  }
}
static gboolean
idle_unlink (gpointer data)
{
  GstPad *sink, *src;

  GstElement *decoder = (GstElement *) data;
  GstElement *agnostic = g_object_get_data (G_OBJECT (decoder), AGNOSTIC_KEY);

  sink = gst_element_get_static_pad (decoder, "sink");
  src = gst_pad_get_peer (sink);

  gst_pad_unlink (src, sink);

  gst_element_release_request_pad (agnostic, src);
  g_object_unref (src);
  g_object_unref (sink);

  g_timeout_add (200, link_again, decoder);

  return FALSE;
}
예제 #14
0
static gboolean
gst_shape_wipe_src_query (GstPad * pad, GstQuery * query)
{
  GstShapeWipe *self = GST_SHAPE_WIPE (gst_pad_get_parent (pad));
  gboolean ret;
  GstPad *peer = gst_pad_get_peer (self->video_sinkpad);

  GST_DEBUG_OBJECT (pad, "Handling query of type '%s'",
      gst_query_type_get_name (GST_QUERY_TYPE (query)));

  if (!peer) {
    GST_INFO_OBJECT (pad, "No peer yet");
    ret = FALSE;
  } else {
    ret = gst_pad_query (peer, query);
    gst_object_unref (peer);
  }

  gst_object_unref (self);
  return ret;
}
static void
gst_d3dvideosink_navigation_send_event (GstNavigation * navigation,
    GstStructure * structure)
{
  GstD3DVideoSink *sink = GST_D3DVIDEOSINK (navigation);
  GstEvent *e;

  if ((e = gst_event_new_navigation (structure))) {
    GstPad *pad;
    if ((pad = gst_pad_get_peer (GST_VIDEO_SINK_PAD (sink)))) {
      if (!gst_pad_send_event (pad, gst_event_ref (e))) {
        /* If upstream didn't handle the event we'll post a message with it
         * for the application in case it wants to do something with it */
        gst_element_post_message (GST_ELEMENT_CAST (sink),
            gst_navigation_message_new_event (GST_OBJECT_CAST (sink), e));
      }
      gst_event_unref (e);
      gst_object_unref (pad);
    }
  }
}
예제 #16
0
static GstPadProbeReturn
remove_on_unlinked_blocked (GstPad * pad, GstPadProbeInfo * info, gpointer elem)
{
  KmsAgnosticBin2 *self;
  GstPad *sink;

  if (elem == NULL) {
    return GST_PAD_PROBE_REMOVE;
  }

  GST_DEBUG_OBJECT (pad, "Unlinking pad");

  GST_OBJECT_LOCK (pad);
  if (g_object_get_qdata (G_OBJECT (pad), unlinking_data_quark ())) {
    GST_OBJECT_UNLOCK (pad);
    if (GST_PAD_PROBE_INFO_TYPE (info) & GST_PAD_PROBE_TYPE_QUERY_BOTH) {
      /* Queries must be answered */
      return GST_PAD_PROBE_PASS;
    } else {
      return GST_PAD_PROBE_DROP;
    }
  }

  g_object_set_qdata (G_OBJECT (pad), unlinking_data_quark (),
      GINT_TO_POINTER (TRUE));

  GST_OBJECT_UNLOCK (pad);

  sink = gst_pad_get_peer (pad);
  if (sink != NULL) {
    gst_pad_unlink (pad, sink);
    g_object_unref (sink);
  }

  self = KMS_AGNOSTIC_BIN2 (GST_OBJECT_PARENT (elem));

  g_thread_pool_push (self->priv->remove_pool, g_object_ref (elem), NULL);

  return GST_PAD_PROBE_PASS;
}
예제 #17
0
static void
gst_ghost_pad_dispose (GObject * object)
{
  GstPad *pad;
  GstPad *internal;
  GstPad *intpeer;

  pad = GST_PAD (object);

  GST_DEBUG_OBJECT (pad, "dispose");

  GST_PROXY_LOCK (pad);
  internal = GST_PROXY_PAD_INTERNAL (pad);

  gst_pad_set_activatepull_function (internal, NULL);
  gst_pad_set_activatepush_function (internal, NULL);

  g_signal_handler_disconnect (internal, GST_GHOST_PAD_CAST (pad)->notify_id);

  intpeer = gst_pad_get_peer (internal);
  if (intpeer) {
    if (GST_PAD_IS_SRC (internal))
      gst_pad_unlink (internal, intpeer);
    else
      gst_pad_unlink (intpeer, internal);

    gst_object_unref (intpeer);
  }

  GST_PROXY_PAD_INTERNAL (internal) = NULL;

  /* disposes of the internal pad, since the ghostpad is the only possible object
   * that has a refcount on the internal pad. */
  gst_object_unparent (GST_OBJECT_CAST (internal));

  GST_PROXY_UNLOCK (pad);

  G_OBJECT_CLASS (gst_ghost_pad_parent_class)->dispose (object);
}
예제 #18
0
/* Must be called with mutex locked. */
static void
gst_uri_downloader_stop (GstUriDownloader * downloader)
{
  GstPad *pad;
  GstElement *urisrc;

  if (!downloader->priv->urisrc)
    return;

  GST_DEBUG_OBJECT (downloader, "Stopping source element %s",
      GST_ELEMENT_NAME (downloader->priv->urisrc));

  /* remove the bus' sync handler */
  gst_bus_set_sync_handler (downloader->priv->bus, NULL, NULL, NULL);
  /* unlink the source element from the internal pad */
  pad = gst_pad_get_peer (downloader->priv->pad);
  if (pad) {
    gst_pad_unlink (pad, downloader->priv->pad);
    gst_object_unref (pad);
  }
  urisrc = downloader->priv->urisrc;
  downloader->priv->urisrc = NULL;

  /* unlock so it doesn't block on chain function while changing state */
  g_mutex_unlock (&downloader->priv->lock);

  GST_DEBUG_OBJECT (downloader, "Stopping source element %s",
      GST_ELEMENT_NAME (urisrc));

  /* set the element state to NULL */
  gst_element_set_state (urisrc, GST_STATE_NULL);
  gst_element_get_state (urisrc, NULL, NULL, GST_CLOCK_TIME_NONE);
  gst_element_set_bus (urisrc, NULL);
  gst_object_unref (urisrc);

  /* caller expects the mutex to be locked */
  g_mutex_lock (&downloader->priv->lock);
  gst_bus_set_flushing (downloader->priv->bus, TRUE);
}
static gboolean
pipeline_op (GObject *player,
	     GstElement *fixture,
	     GstElement *element,
	     gboolean use_pad_block,
	     GstPadBlockCallback callback)
{
	RBGstPipelineOp *op;
	GstPad *fixture_pad;
	GstPad *block_pad;

	op = new_pipeline_op (player, fixture, element);

	/* seems like we should be able to just block the src pad connected
	 * to the fixture's sink pad..
	 */
	fixture_pad = gst_element_get_static_pad (fixture, "sink");
	block_pad = gst_pad_get_peer (fixture_pad);
	gst_object_unref (fixture_pad);

	if (use_pad_block) {
		char *whatpad;
		whatpad = gst_object_get_path_string (GST_OBJECT (block_pad));
		rb_debug ("blocking pad %s to perform an operation", whatpad);
		g_free (whatpad);

		gst_pad_set_blocked_async (block_pad,
					   TRUE,
					   callback,
					   op);
	} else {
		rb_debug ("not using pad blocking, calling op directly");
		(*callback) (block_pad, FALSE, op);
	}

	gst_object_unref (block_pad);
	return TRUE;
}
예제 #20
0
static gboolean
gst_ghost_pad_internal_activate_pull_default (GstPad * pad, GstObject * parent,
    gboolean active)
{
  gboolean ret;
  GstPad *other;

  GST_LOG_OBJECT (pad, "%sactivate pull on %s:%s", (active ? "" : "de"),
      GST_DEBUG_PAD_NAME (pad));

  if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) {
    /* we are activated in pull mode by our peer element, which is a sinkpad
     * that wants to operate in pull mode. This activation has to propagate
     * upstream through the pipeline. We call the internal activation function,
     * which will trigger gst_ghost_pad_activate_pull_default, which propagates even
     * further upstream */
    GST_LOG_OBJECT (pad, "pad is src, activate internal");
    GST_PROXY_PAD_ACQUIRE_INTERNAL (pad, other, FALSE);
    ret = gst_pad_activate_mode (other, GST_PAD_MODE_PULL, active);
    GST_PROXY_PAD_RELEASE_INTERNAL (other);
  } else if (G_LIKELY ((other = gst_pad_get_peer (pad)))) {
    /* We are SINK, the ghostpad is SRC, we propagate the activation upstream
     * since we hold a pointer to the upstream peer. */
    GST_LOG_OBJECT (pad, "activating peer");
    ret = gst_pad_activate_mode (other, GST_PAD_MODE_PULL, active);
    gst_object_unref (other);
  } else if (active) {
    /* this is failure, we can't activate pull if there is no peer */
    GST_LOG_OBJECT (pad, "not src and no peer, failing");
    ret = FALSE;
  } else {
    GST_LOG_OBJECT (pad, "deactivating pull, with no peer - allowing");
    ret = TRUE;
  }

  return ret;
}
static void
remove_input_stream (GstDecodebin3 * dbin, DecodebinInputStream * stream)
{
  MultiQueueSlot *slot;

  GST_DEBUG_OBJECT (dbin, "Removing input stream %p (%s)", stream,
      stream->active_stream ? gst_stream_get_stream_id (stream->active_stream) :
      "<NONE>");

  /* Unlink from slot */
  if (stream->srcpad) {
    GstPad *peer;
    peer = gst_pad_get_peer (stream->srcpad);
    if (peer) {
      gst_pad_unlink (stream->srcpad, peer);
      gst_object_unref (peer);
    }
  }

  g_mutex_lock (&dbin->selection_lock);
  slot = get_slot_for_input (dbin, stream);
  g_mutex_unlock (&dbin->selection_lock);
  if (slot) {
    slot->pending_stream = NULL;
    slot->input = NULL;
    GST_DEBUG_OBJECT (dbin, "slot %p cleared", slot);
  }

  if (stream->active_stream)
    gst_object_unref (stream->active_stream);
  if (stream->pending_stream)
    gst_object_unref (stream->pending_stream);

  dbin->input_streams = g_list_remove (dbin->input_streams, stream);

  g_free (stream);
}
static gboolean
gst_splitmux_part_reader_send_event (GstElement * element, GstEvent * event)
{
  GstSplitMuxPartReader *reader = (GstSplitMuxPartReader *) element;
  gboolean ret = FALSE;
  GstPad *pad = NULL;

  /* Send event to the first source pad we found */
  SPLITMUX_PART_LOCK (reader);
  if (reader->pads) {
    GstPad *proxy_pad = GST_PAD_CAST (reader->pads->data);
    pad = gst_pad_get_peer (proxy_pad);
  }
  SPLITMUX_PART_UNLOCK (reader);

  if (pad) {
    ret = gst_pad_send_event (pad, event);
    gst_object_unref (pad);
  } else {
    gst_event_unref (event);
  }

  return ret;
}
예제 #23
0
static void
gst_hls_sink2_release_pad (GstElement * element, GstPad * pad)
{
  GstHlsSink2 *sink = GST_HLS_SINK2_CAST (element);
  GstPad *peer;

  g_return_if_fail (pad == sink->audio_sink || pad == sink->video_sink);

  peer = gst_pad_get_peer (pad);
  if (peer) {
    gst_element_release_request_pad (sink->splitmuxsink, pad);
    gst_object_unref (peer);
  }

  gst_object_ref (pad);
  gst_element_remove_pad (element, pad);
  gst_pad_set_active (pad, FALSE);
  if (pad == sink->audio_sink)
    sink->audio_sink = NULL;
  else
    sink->video_sink = NULL;

  gst_object_unref (pad);
}
예제 #24
0
/* Clean up output/input pad and respective selector request pad */
void
cleanup_pad (GstPad * pad, GstElement * element)
{
    GstPad *selpad = NULL;
    guint probe_id = 0;

    fail_if (pad == NULL, "pad doesn't exist");

    /* remove probe if necessary */
    probe_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (pad), "probe_id"));
    if (probe_id)
        gst_pad_remove_data_probe (pad, probe_id);

    /* unlink */
    selpad = gst_pad_get_peer (pad);
    if (GST_PAD_DIRECTION (selpad) == GST_PAD_SRC) {
        gst_pad_unlink (selpad, pad);
    } else {
        gst_pad_unlink (pad, selpad);
    }

    /* caps could have been set, make sure they get unset */
    gst_pad_set_caps (pad, NULL);

    GST_DEBUG_OBJECT (pad, "clean up %" GST_PTR_FORMAT " and  %" GST_PTR_FORMAT,
                      selpad, pad);

    /* cleanup the pad */
    gst_pad_set_active (pad, FALSE);
    ASSERT_OBJECT_REFCOUNT (pad, "pad", 1);
    gst_object_unref (pad);

    /* cleanup selector pad, reffed by this function (_get_peer) and creator */
    gst_element_release_request_pad (element, selpad);
    gst_object_unref (selpad);
}
static void
gst_gtk_base_sink_navigation_send_event (GstNavigation * navigation,
    GstStructure * structure)
{
  GstGtkBaseSink *sink = GST_GTK_BASE_SINK (navigation);
  GstEvent *event;
  GstPad *pad;

  event = gst_event_new_navigation (structure);
  pad = gst_pad_get_peer (GST_VIDEO_SINK_PAD (sink));

  GST_TRACE_OBJECT (sink, "navigation event %" GST_PTR_FORMAT, structure);

  if (GST_IS_PAD (pad) && GST_IS_EVENT (event)) {
    if (!gst_pad_send_event (pad, gst_event_ref (event))) {
      /* If upstream didn't handle the event we'll post a message with it
       * for the application in case it wants to do something with it */
      gst_element_post_message (GST_ELEMENT_CAST (sink),
          gst_navigation_message_new_event (GST_OBJECT_CAST (sink), event));
    }
    gst_event_unref (event);
    gst_object_unref (pad);
  }
}
static GstCaps *
gst_aspect_ratio_crop_get_caps (GstPad * pad, GstCaps * filter)
{
  GstPad *peer;
  GstAspectRatioCrop *aspect_ratio_crop;
  GstCaps *return_caps;

  aspect_ratio_crop = GST_ASPECT_RATIO_CROP (gst_pad_get_parent (pad));

  g_mutex_lock (&aspect_ratio_crop->crop_lock);

  peer = gst_pad_get_peer (aspect_ratio_crop->sink);
  if (peer == NULL) {
    return_caps = gst_static_pad_template_get_caps (&src_template);
  } else {
    GstCaps *peer_caps;

    peer_caps = gst_pad_query_caps (peer, filter);
    return_caps =
        gst_aspect_ratio_crop_transform_caps (aspect_ratio_crop, peer_caps);
    gst_caps_unref (peer_caps);
    gst_object_unref (peer);
  }

  g_mutex_unlock (&aspect_ratio_crop->crop_lock);
  gst_object_unref (aspect_ratio_crop);

  if (return_caps && filter) {
    GstCaps *tmp =
        gst_caps_intersect_full (filter, return_caps, GST_CAPS_INTERSECT_FIRST);
    gst_caps_replace (&return_caps, tmp);
    gst_caps_unref (tmp);
  }

  return return_caps;
}
static void
pad_blocked_cb (GstPad * pad, gboolean blocked, GstPlaySinkVideoConvert * self)
{
    GstPad *peer;
    GstCaps *caps;
    gboolean raw;

    GST_PLAY_SINK_VIDEO_CONVERT_LOCK (self);
    self->sink_proxypad_blocked = blocked;
    GST_DEBUG_OBJECT (self, "Pad blocked: %d", blocked);
    if (!blocked)
        goto done;

    /* There must be a peer at this point */
    peer = gst_pad_get_peer (self->sinkpad);
    caps = gst_pad_get_negotiated_caps (peer);
    if (!caps)
        caps = gst_pad_get_caps_reffed (peer);
    gst_object_unref (peer);

    raw = is_raw_caps (caps);
    GST_DEBUG_OBJECT (self, "Caps %" GST_PTR_FORMAT " are raw: %d", caps, raw);
    gst_caps_unref (caps);

    if (raw == self->raw)
        goto unblock;
    self->raw = raw;

    if (raw) {
        GstBin *bin = GST_BIN_CAST (self);
        GstElement *head = NULL, *prev = NULL;
        GstPad *pad;

        GST_DEBUG_OBJECT (self, "Creating raw conversion pipeline");

        gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), NULL);
        gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), NULL);

        self->conv = gst_element_factory_make ("ffmpegcolorspace", "conv");
        if (self->conv == NULL) {
            post_missing_element_message (self, "ffmpegcolorspace");
            GST_ELEMENT_WARNING (self, CORE, MISSING_PLUGIN,
                                 (_("Missing element '%s' - check your GStreamer installation."),
                                  "ffmpegcolorspace"), ("video rendering might fail"));
        } else {
            gst_bin_add (bin, self->conv);
            gst_element_sync_state_with_parent (self->conv);
            distribute_running_time (self->conv, &self->segment);
            prev = head = self->conv;
        }

        self->scale = gst_element_factory_make ("videoscale", "scale");
        if (self->scale == NULL) {
            post_missing_element_message (self, "videoscale");
            GST_ELEMENT_WARNING (self, CORE, MISSING_PLUGIN,
                                 (_("Missing element '%s' - check your GStreamer installation."),
                                  "videoscale"), ("possibly a liboil version mismatch?"));
        } else {
            /* Add black borders if necessary to keep the DAR */
            g_object_set (self->scale, "add-borders", TRUE, NULL);
            gst_bin_add (bin, self->scale);
            gst_element_sync_state_with_parent (self->scale);
            distribute_running_time (self->scale, &self->segment);
            if (prev) {
                if (!gst_element_link_pads_full (prev, "src", self->scale, "sink",
                                                 GST_PAD_LINK_CHECK_TEMPLATE_CAPS))
                    goto link_failed;
            } else {
                head = self->scale;
            }
            prev = self->scale;
        }

        if (head) {
            pad = gst_element_get_static_pad (head, "sink");
            gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), pad);
            gst_object_unref (pad);
        }

        if (prev) {
            pad = gst_element_get_static_pad (prev, "src");
            gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), pad);
            gst_object_unref (pad);
        }

        if (!head && !prev) {
            gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad),
                                      self->sink_proxypad);
        }

        GST_DEBUG_OBJECT (self, "Raw conversion pipeline created");
    } else {
        GstBin *bin = GST_BIN_CAST (self);

        GST_DEBUG_OBJECT (self, "Removing raw conversion pipeline");

        gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), NULL);
        gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), NULL);

        if (self->conv) {
            gst_element_set_state (self->conv, GST_STATE_NULL);
            gst_bin_remove (bin, self->conv);
            self->conv = NULL;
        }
        if (self->scale) {
            gst_element_set_state (self->scale, GST_STATE_NULL);
            gst_bin_remove (bin, self->scale);
            self->scale = NULL;
        }

        gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad),
                                  self->sink_proxypad);

        GST_DEBUG_OBJECT (self, "Raw conversion pipeline removed");
    }

unblock:
    gst_pad_set_blocked_async_full (self->sink_proxypad, FALSE,
                                    (GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self),
                                    (GDestroyNotify) gst_object_unref);

done:
    GST_PLAY_SINK_VIDEO_CONVERT_UNLOCK (self);
    return;

link_failed:
    {
        GST_ELEMENT_ERROR (self, CORE, PAD,
                           (NULL), ("Failed to configure the video converter."));
        gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad),
                                  self->sink_proxypad);
        gst_pad_set_blocked_async_full (self->sink_proxypad, FALSE,
                                        (GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self),
                                        (GDestroyNotify) gst_object_unref);
        return;
    }
}
예제 #28
0
/* Helper function to test delayed linking support in parse_launch by creating
 * a test element based on bin, which contains a fakesrc and a sometimes 
 * pad-template, and trying to link to a fakesink. When the bin transitions
 * to paused it adds a pad, which should get linked to the fakesink */
static void
run_delayed_test (const gchar * pipe_str, const gchar * peer,
    gboolean expect_link)
{
  GstElement *pipe, *src, *sink;
  GstPad *srcpad, *sinkpad, *peerpad = NULL;

  pipe = setup_pipeline (pipe_str);

  src = gst_bin_get_by_name (GST_BIN (pipe), "src");
  fail_if (src == NULL, "Test source element was not created");

  sink = gst_bin_get_by_name (GST_BIN (pipe), "sink");
  fail_if (sink == NULL, "Test sink element was not created");

  /* The src should not yet have a src pad */
  srcpad = gst_element_get_static_pad (src, "src");
  fail_unless (srcpad == NULL, "Source element already has a source pad");

  /* Set the state to PAUSED and wait until the src at least reaches that
   * state */
  fail_if (gst_element_set_state (pipe, GST_STATE_PAUSED) ==
      GST_STATE_CHANGE_FAILURE);

  fail_if (gst_element_get_state (src, NULL, NULL, GST_CLOCK_TIME_NONE) ==
      GST_STATE_CHANGE_FAILURE);

  /* Now, the source element should have a src pad, and if "peer" was passed, 
   * then the src pad should have gotten linked to the 'sink' pad of that 
   * peer */
  srcpad = gst_element_get_static_pad (src, "src");
  fail_if (srcpad == NULL, "Source element did not create source pad");

  peerpad = gst_pad_get_peer (srcpad);

  if (expect_link == TRUE) {
    fail_if (peerpad == NULL, "Source element pad did not get linked");
  } else {
    fail_if (peerpad != NULL,
        "Source element pad got linked but should not have");
  }
  if (peerpad != NULL)
    gst_object_unref (peerpad);

  if (peer != NULL) {
    GstElement *peer_elem = gst_bin_get_by_name (GST_BIN (pipe), peer);

    fail_if (peer_elem == NULL, "Could not retrieve peer %s", peer);

    sinkpad = gst_element_get_static_pad (peer_elem, "sink");
    fail_if (sinkpad == NULL, "Peer element did not have a 'sink' pad");

    fail_unless (peerpad == sinkpad,
        "Source src pad got connected to the wrong peer");
    gst_object_unref (sinkpad);
  }

  gst_object_unref (srcpad);

  gst_object_unref (src);
  gst_object_unref (sink);

  gst_element_set_state (pipe, GST_STATE_NULL);
  gst_object_unref (pipe);
}
예제 #29
0
static void
run_output_order_test (gint n_linked)
{
  /* This test creates a multiqueue with 2 linked output, and 3 outputs that 
   * return 'not-linked' when data is pushed, then verifies that all buffers 
   * are received on not-linked pads only after earlier buffers on the 
   * 'linked' pads are made */
  GstElement *pipe;
  GstElement *mq;
  GstPad *inputpads[5];
  GstPad *sinkpads[5];
  struct PadData pad_data[5];
  guint32 max_linked_id;
  guint32 eos_seen;
  GMutex *mutex;
  GCond *cond;
  gint i;
  const gint NPADS = 5;
  const gint NBUFFERS = 1000;

  mutex = g_mutex_new ();
  cond = g_cond_new ();

  pipe = gst_bin_new ("testbin");

  mq = gst_element_factory_make ("multiqueue", NULL);
  fail_unless (mq != NULL);
  gst_bin_add (GST_BIN (pipe), mq);

  /* No limits */
  g_object_set (mq,
      "max-size-bytes", (guint) 0,
      "max-size-buffers", (guint) 0,
      "max-size-time", (guint64) 0,
      "extra-size-bytes", (guint) 0,
      "extra-size-buffers", (guint) 0, "extra-size-time", (guint64) 0, NULL);

  /* Construct NPADS dummy output pads. The first 'n_linked' return FLOW_OK, the rest
   * return NOT_LINKED. The not-linked ones check the expected ordering of 
   * output buffers */
  for (i = 0; i < NPADS; i++) {
    GstPad *mq_srcpad, *mq_sinkpad;
    gchar *name;

    name = g_strdup_printf ("dummysrc%d", i);
    inputpads[i] = gst_pad_new (name, GST_PAD_SRC);
    g_free (name);
    gst_pad_set_getcaps_function (inputpads[i], mq_dummypad_getcaps);

    mq_sinkpad = gst_element_get_request_pad (mq, "sink%d");
    fail_unless (mq_sinkpad != NULL);
    gst_pad_link (inputpads[i], mq_sinkpad);

    gst_pad_set_active (inputpads[i], TRUE);

    mq_srcpad = mq_sinkpad_to_srcpad (mq, mq_sinkpad);

    name = g_strdup_printf ("dummysink%d", i);
    sinkpads[i] = gst_pad_new (name, GST_PAD_SINK);
    g_free (name);
    gst_pad_set_chain_function (sinkpads[i], mq_dummypad_chain);
    gst_pad_set_event_function (sinkpads[i], mq_dummypad_event);
    gst_pad_set_getcaps_function (sinkpads[i], mq_dummypad_getcaps);

    pad_data[i].pad_num = i;
    pad_data[i].max_linked_id_ptr = &max_linked_id;
    pad_data[i].eos_count_ptr = &eos_seen;
    pad_data[i].is_linked = (i < n_linked ? TRUE : FALSE);
    pad_data[i].n_linked = n_linked;
    pad_data[i].cond = cond;
    pad_data[i].mutex = mutex;
    pad_data[i].first_buf = TRUE;
    gst_pad_set_element_private (sinkpads[i], pad_data + i);

    gst_pad_link (mq_srcpad, sinkpads[i]);
    gst_pad_set_active (sinkpads[i], TRUE);

    gst_object_unref (mq_sinkpad);
    gst_object_unref (mq_srcpad);
  }

  /* Run the test. Push 1000 buffers through the multiqueue in a pattern */

  max_linked_id = 0;
  eos_seen = 0;
  gst_element_set_state (pipe, GST_STATE_PLAYING);

  for (i = 0; i < NBUFFERS; i++) {
    const guint8 pad_pattern[] =
        { 0, 0, 0, 0, 1, 1, 2, 1, 0, 2, 3, 2, 3, 1, 4 };
    const guint n = sizeof (pad_pattern) / sizeof (guint8);
    guint8 cur_pad;
    GstBuffer *buf;
    GstFlowReturn ret;

    cur_pad = pad_pattern[i % n];

    buf = gst_buffer_new_and_alloc (4);
    g_static_mutex_lock (&_check_lock);
    fail_if (buf == NULL);
    g_static_mutex_unlock (&_check_lock);
    GST_WRITE_UINT32_BE (GST_BUFFER_DATA (buf), i + 1);
    GST_BUFFER_TIMESTAMP (buf) = (i + 1) * GST_SECOND;

    ret = gst_pad_push (inputpads[cur_pad], buf);
    g_static_mutex_lock (&_check_lock);
    if (pad_data[cur_pad].is_linked) {
      fail_unless (ret == GST_FLOW_OK,
          "Push on pad %d returned %d when FLOW_OK was expected", cur_pad, ret);
    } else {
      /* Expect OK initially, then NOT_LINKED when the srcpad starts pushing */
      fail_unless (ret == GST_FLOW_OK || ret == GST_FLOW_NOT_LINKED,
          "Push on pad %d returned %d when FLOW_OK or NOT_LINKED  was expected",
          cur_pad, ret);
    }
    g_static_mutex_unlock (&_check_lock);
  }
  for (i = 0; i < NPADS; i++) {
    gst_pad_push_event (inputpads[i], gst_event_new_eos ());
  }

  /* Wait while the buffers are processed */
  g_mutex_lock (mutex);
  while (eos_seen < 5) {
    g_cond_wait (cond, mutex);
  }
  g_mutex_unlock (mutex);

  /* Clean up */
  for (i = 0; i < 5; i++) {
    GstPad *mq_input = gst_pad_get_peer (inputpads[i]);

    gst_pad_unlink (inputpads[i], mq_input);
    gst_element_release_request_pad (mq, mq_input);
    gst_object_unref (mq_input);
    gst_object_unref (inputpads[i]);

    gst_object_unref (sinkpads[i]);
  }

  gst_element_set_state (pipe, GST_STATE_NULL);
  gst_object_unref (pipe);

  g_cond_free (cond);
  g_mutex_free (mutex);
}
static void
gst_insert_bin_do_change (GstInsertBin * self, GstPad * pad)
{
  struct ChangeData *data;

  GST_OBJECT_LOCK (self);

  if (!is_right_direction_for_block (pad)) {
    GST_WARNING_OBJECT (self, "Block pad does not have the expected direction");
    goto next;
  }

  while ((data = g_queue_pop_head (&self->priv->change_queue)) != NULL) {
    GstPad *peer = NULL;
    GstPad *other_peer = NULL;

    GST_OBJECT_UNLOCK (self);


    if (data->action == GST_INSERT_BIN_ACTION_ADD &&
        !validate_element (self, data->element))
      goto error;

    peer = gst_pad_get_peer (pad);

    if (peer == NULL) {
      GST_WARNING_OBJECT (self, "Blocked pad has no peer");
      goto error;
    }

    if (data->action == GST_INSERT_BIN_ACTION_ADD) {
      GstPad *srcpad = NULL, *sinkpad = NULL;
      GstPad *peersrcpad, *peersinkpad;

      /* First let's make sure we have the right pad */
      if (data->sibling) {
        GstElement *parent = NULL;
        GstPad *siblingpad;

        if ((gst_pad_get_direction (pad) == GST_PAD_SRC &&
                data->direction == DIRECTION_BEFORE) ||
            (gst_pad_get_direction (pad) == GST_PAD_SINK &&
                data->direction == DIRECTION_AFTER))
          siblingpad = peer;
        else
          siblingpad = pad;

        parent = gst_pad_get_parent_element (siblingpad);
        if (parent != NULL)
          gst_object_unref (parent);

        if (parent != data->sibling)
          goto retry;
      } else {
        GstObject *parent;
        GstPad *ghost;
        GstPad *proxypad;

        if (data->direction == DIRECTION_BEFORE) {
          ghost = self->priv->srcpad;
          if (gst_pad_get_direction (pad) == GST_PAD_SINK)
            proxypad = pad;
          else
            proxypad = peer;
        } else {
          ghost = self->priv->sinkpad;
          if (gst_pad_get_direction (pad) == GST_PAD_SINK)
            proxypad = peer;
          else
            proxypad = pad;
        }

        if (!GST_IS_PROXY_PAD (proxypad))
          goto retry;
        parent = gst_pad_get_parent (proxypad);
        if (!parent)
          goto retry;
        gst_object_unref (parent);
        if (GST_PAD_CAST (parent) != ghost)
          goto retry;
      }

      if (gst_pad_get_direction (pad) == GST_PAD_SRC) {
        peersrcpad = pad;
        peersinkpad = peer;
      } else {
        peersrcpad = peer;
        peersinkpad = pad;
      }

      if (GST_IS_PROXY_PAD (peersrcpad)) {
        GstObject *parent = gst_pad_get_parent (peersrcpad);

        if (GST_PAD_CAST (parent) == self->priv->sinkpad)
          peersrcpad = NULL;

        if (parent)
          gst_object_unref (parent);
      }

      if (GST_IS_PROXY_PAD (peersinkpad)) {
        GstObject *parent = gst_pad_get_parent (peersinkpad);

        if (GST_PAD_CAST (parent) == self->priv->srcpad)
          peersinkpad = NULL;

        if (parent)
          gst_object_unref (parent);
      }

      if (peersinkpad && peersrcpad) {
        gst_pad_unlink (peersrcpad, peersinkpad);
      } else {
        if (!peersinkpad)
          gst_ghost_pad_set_target (GST_GHOST_PAD (self->priv->srcpad), NULL);
        if (!peersrcpad)
          gst_ghost_pad_set_target (GST_GHOST_PAD (self->priv->sinkpad), NULL);
      }

      srcpad = get_single_pad (data->element, GST_PAD_SRC);
      sinkpad = get_single_pad (data->element, GST_PAD_SINK);

      if (srcpad == NULL || sinkpad == NULL) {
        GST_WARNING_OBJECT (self, "Can not get element src or sink pad");
        goto error;
      }

      if (!gst_bin_add (GST_BIN (self), data->element)) {
        GST_WARNING_OBJECT (self, "Can not add element to bin");
        goto error;
      }

      if (peersrcpad) {
        if (GST_PAD_LINK_FAILED (gst_pad_link (peersrcpad, sinkpad))) {
          GST_WARNING_OBJECT (self, "Can not link sibling's %s:%s pad"
              " to element's %s:%s pad", GST_DEBUG_PAD_NAME (peersrcpad),
              GST_DEBUG_PAD_NAME (sinkpad));
          goto error;
        }
      } else {
        if (!gst_ghost_pad_set_target (GST_GHOST_PAD (self->priv->sinkpad),
                sinkpad)) {
          GST_WARNING_OBJECT (self, "Can not set %s:%s as target for %s:%s",
              GST_DEBUG_PAD_NAME (sinkpad),
              GST_DEBUG_PAD_NAME (self->priv->sinkpad));
          goto error;
        }
      }

      if (peersinkpad) {
        if (GST_PAD_LINK_FAILED (gst_pad_link (srcpad, peersinkpad))) {
          GST_WARNING_OBJECT (self, "Can not link element's %s:%s pad"
              " to sibling's %s:%s pad", GST_DEBUG_PAD_NAME (srcpad),
              GST_DEBUG_PAD_NAME (peersinkpad));
          goto error;
        }
      } else {
        if (!gst_ghost_pad_set_target (GST_GHOST_PAD (self->priv->srcpad),
                srcpad)) {
          GST_WARNING_OBJECT (self, "Can not set %s:%s as target for %s:%s",
              GST_DEBUG_PAD_NAME (srcpad),
              GST_DEBUG_PAD_NAME (self->priv->srcpad));
          goto error;
        }
      }

      gst_object_unref (srcpad);
      gst_object_unref (sinkpad);

      if (!gst_element_sync_state_with_parent (data->element)) {
        GST_WARNING_OBJECT (self, "Can not sync element's state with parent");
        goto error;
      }
    } else {
      GstElement *parent = NULL;
      GstPad *other_pad;
      GstCaps *caps = NULL, *peercaps = NULL;
      gboolean can_intersect;
      gboolean success;

      parent = gst_pad_get_parent_element (peer);
      if (parent != NULL)
        gst_object_unref (parent);

      if (parent != data->element)
        goto retry;

      if (gst_pad_get_direction (peer) == GST_PAD_SRC)
        other_pad = get_single_pad (data->element, GST_PAD_SINK);
      else
        other_pad = get_single_pad (data->element, GST_PAD_SRC);

      if (!other_pad) {
        GST_WARNING_OBJECT (self, "Can not get element's other pad");
        goto error;
      }

      other_peer = gst_pad_get_peer (other_pad);
      gst_object_unref (other_pad);

      if (!other_peer) {
        GST_WARNING_OBJECT (self, "Can not get element's other peer");
        goto error;
      }

      /* Get the negotiated caps for the source pad peer,
       * because renegotiation while the pipeline is playing doesn't work
       * that fast.
       */
      if (gst_pad_get_direction (pad) == GST_PAD_SRC)
        caps = gst_pad_get_current_caps (pad);
      else
        peercaps = gst_pad_get_current_caps (other_peer);
      if (!caps)
        caps = gst_pad_query_caps (pad, NULL);
      if (!peercaps)
        peercaps = gst_pad_query_caps (other_peer, NULL);
      can_intersect = gst_caps_can_intersect (caps, peercaps);
      gst_caps_unref (caps);
      gst_caps_unref (peercaps);

      if (!can_intersect) {
        GST_WARNING_OBJECT (self, "Pads are incompatible without the element");
        goto error;
      }

      if (gst_pad_get_direction (other_peer) == GST_PAD_SRC &&
          gst_pad_is_active (other_peer)) {
        gulong probe_id;

        probe_id = gst_pad_add_probe (other_peer,
            GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
            wait_and_drop_eos_cb, NULL, NULL);
        gst_pad_send_event (peer, gst_event_new_eos ());
        gst_pad_remove_probe (other_peer, probe_id);
      }

      gst_element_set_locked_state (data->element, TRUE);
      gst_element_set_state (data->element, GST_STATE_NULL);
      if (!gst_bin_remove (GST_BIN (self), data->element)) {
        GST_WARNING_OBJECT (self, "Element removal rejected");
        goto error;
      }
      gst_element_set_locked_state (data->element, FALSE);

      if (gst_pad_get_direction (pad) == GST_PAD_SRC)
        success = GST_PAD_LINK_SUCCESSFUL (gst_pad_link_full (pad, other_peer,
                GST_PAD_LINK_CHECK_HIERARCHY |
                GST_PAD_LINK_CHECK_TEMPLATE_CAPS));
      else
        success = GST_PAD_LINK_SUCCESSFUL (gst_pad_link_full (other_peer, pad,
                GST_PAD_LINK_CHECK_HIERARCHY |
                GST_PAD_LINK_CHECK_TEMPLATE_CAPS));
      gst_object_unref (other_peer);
      other_peer = NULL;

      if (!success) {
        GST_ERROR_OBJECT (self, "Could not re-link after the element's"
            " removal");
        goto error;
      }
    }


    gst_insert_bin_change_data_complete (self, data, TRUE);
    gst_object_unref (peer);

    GST_OBJECT_LOCK (self);
    continue;
  done:
    if (other_peer != NULL)
      gst_object_unref (other_peer);

    if (peer != NULL)
      gst_object_unref (peer);
    break;
  retry:
    GST_OBJECT_LOCK (self);
    g_queue_push_head (&self->priv->change_queue, data);
    goto done;
  error:
    /* Handle error */
    gst_insert_bin_change_data_complete (self, data, FALSE);
    GST_OBJECT_LOCK (self);
    goto done;
  }

next:
  gst_insert_bin_block_pad_unlock (self);
}