static void
really_remove_filter (GstPad *pad,
		      gboolean blocked,
		      RBGstPipelineOp *op)
{
	GstPad *mypad;
	GstPad *prevpad, *nextpad;
	GstElement *bin;

	/* get the containing bin and remove it */
	bin = GST_ELEMENT (gst_element_get_parent (op->element));
	if (bin == NULL) {
		return;
	}

	rb_debug ("removing filter %p", op->element);
	_rb_player_gst_filter_emit_filter_pre_remove (RB_PLAYER_GST_FILTER (op->player), op->element);

	/* probably check return? */
	gst_element_set_state (bin, GST_STATE_NULL);

	/* unlink our sink */
	mypad = gst_element_get_static_pad (bin, "sink");
	prevpad = gst_pad_get_peer (mypad);
	gst_pad_unlink (prevpad, mypad);
	gst_object_unref (mypad);

	/* unlink our src */
	mypad = gst_element_get_static_pad (bin, "src");
	nextpad = gst_pad_get_peer (mypad);
	gst_pad_unlink (mypad, nextpad);
	gst_object_unref (mypad);

	/* link previous and next pads */
	gst_pad_link (prevpad, nextpad);

	gst_object_unref (prevpad);
	gst_object_unref (nextpad);

	gst_bin_remove (GST_BIN (op->fixture), bin);
	gst_object_unref (bin);

	/* if we're supposed to be playing, unblock the sink */
	if (blocked) {
		rb_debug ("unblocking pad after removing filter");
		gst_pad_set_blocked_async (pad, FALSE, (GstPadBlockCallback)pipeline_op_done, NULL);
	}

	free_pipeline_op (op);
}
Example #2
0
static gboolean
construct_pipeline (RBPlayerGst *mp, GError **error)
{
	GstElement *sink;

	mp->priv->playbin = gst_element_factory_make ("playbin2", NULL);
	if (mp->priv->playbin == NULL) {
		g_set_error (error,
			     RB_PLAYER_ERROR,
			     RB_PLAYER_ERROR_GENERAL,
			     _("Failed to create playbin2 element; check your GStreamer installation"));
		return FALSE;
	}
	g_signal_connect_object (G_OBJECT (mp->priv->playbin),
				 "about-to-finish",
				 G_CALLBACK (about_to_finish_cb),
				 mp, 0);
	g_signal_connect_object (G_OBJECT (mp->priv->playbin),
				 "deep-notify::volume",
				 G_CALLBACK (volume_notify_cb),
				 mp, 0);
	g_signal_connect_object (G_OBJECT (mp->priv->playbin),
				 "notify::source",
				 G_CALLBACK (source_notify_cb),
				 mp, 0);

	gst_bus_add_watch (gst_element_get_bus (mp->priv->playbin),
			   (GstBusFunc) bus_cb,
			   mp);

	/* let plugins add bits to playbin */
	g_object_notify (G_OBJECT (mp), "playbin");
	g_object_notify (G_OBJECT (mp), "bus");

	/* Use gsettingsaudiosink for audio if there's no audio sink yet */
	g_object_get (mp->priv->playbin, "audio-sink", &mp->priv->audio_sink, NULL);
	if (mp->priv->audio_sink == NULL) {
		const char *try_sinks[] = { "gsettingsaudiosink", "gconfaudiosink", "autoaudiosink" };
		int i;

		for (i = 0; i < G_N_ELEMENTS (try_sinks); i++) {
			mp->priv->audio_sink = rb_player_gst_try_audio_sink (try_sinks[i], NULL);
			if (mp->priv->audio_sink != NULL) {
				g_object_set (mp->priv->playbin, "audio-sink", mp->priv->audio_sink, NULL);
				break;
			}
		}
	} else {
		rb_debug ("existing audio sink found");
		g_object_unref (mp->priv->audio_sink);
	}

	{
		GstPad *pad;
		GList *l;
		GstElement *queue;
		GstPad *ghostpad;

		/* setup filterbin */
		mp->priv->filterbin = rb_gst_create_filter_bin ();

		/* set up the sinkbin with its tee element */
		mp->priv->sinkbin = gst_bin_new (NULL);
		mp->priv->tee = gst_element_factory_make ("tee", NULL);
		queue = gst_element_factory_make ("queue", NULL);

		/* link it all together and insert */
		gst_bin_add_many (GST_BIN (mp->priv->sinkbin), mp->priv->filterbin, mp->priv->tee, queue, mp->priv->audio_sink, NULL);
		gst_element_link_many (mp->priv->filterbin, mp->priv->tee, queue, mp->priv->audio_sink, NULL);

		pad = gst_element_get_pad (mp->priv->filterbin, "sink");
		ghostpad = gst_ghost_pad_new ("sink", pad);
		gst_element_add_pad (mp->priv->sinkbin, ghostpad);
		gst_object_unref (pad);

		g_object_set (G_OBJECT (mp->priv->playbin), "audio-sink", mp->priv->sinkbin, NULL);

		/* add any tees and filters that were waiting for us */
		for (l = mp->priv->waiting_tees; l != NULL; l = g_list_next (l)) {
			rb_player_gst_tee_add_tee (RB_PLAYER_GST_TEE (mp), GST_ELEMENT (l->data));
		}
		g_list_free (mp->priv->waiting_tees);
		mp->priv->waiting_tees = NULL;

		for (l = mp->priv->waiting_filters; l != NULL; l = g_list_next (l)) {
			rb_player_gst_filter_add_filter (RB_PLAYER_GST_FILTER(mp), GST_ELEMENT (l->data));
		}
		g_list_free (mp->priv->waiting_filters);
		mp->priv->waiting_filters = NULL;
	}

	/* Use fakesink for video if there's no video sink yet */
	g_object_get (mp->priv->playbin, "video-sink", &sink, NULL);
	if (sink == NULL) {
		sink = gst_element_factory_make ("fakesink", NULL);
		g_object_set (mp->priv->playbin, "video-sink", sink, NULL);
	} else {
		g_object_unref (sink);
	}

	if (mp->priv->cur_volume > 1.0)
		mp->priv->cur_volume = 1.0;
	if (mp->priv->cur_volume < 0.0)
		mp->priv->cur_volume = 0;

	rb_debug ("pipeline construction complete");
	return TRUE;
}
static void
really_add_filter (GstPad *pad,
		   gboolean blocked,
		   RBGstPipelineOp *op)
{
	GstPad *binsinkpad;
	GstPad *binsrcpad;
	GstPad *realpad;
	GstPad *prevpad;
	GstElement *bin;
	GstElement *identity;
	GstElement *audioconvert;
	GstElement *audioconvert2;
	GstPadLinkReturn link;

	rb_debug ("adding filter %p", op->element);

	/*
	 * it kind of looks like we need audioconvert elements on either side of each filter
	 * to prevent caps renegotiation from causing 'internal data flow error' errors.
	 * this probably means we'd be doing a few unnecessary conversions when there are
	 * multiple filters in the pipeline, but at least it works.
	 */

	/* create containing bin */
	bin = gst_bin_new (NULL);
	audioconvert = gst_element_factory_make ("audioconvert", NULL);
	audioconvert2 = gst_element_factory_make ("audioconvert", NULL);
	gst_bin_add_many (GST_BIN (bin), audioconvert, op->element, audioconvert2, NULL);
	gst_element_link_many (audioconvert, op->element, audioconvert2, NULL);

	/* create ghost pads */
	realpad = gst_element_get_static_pad (audioconvert, "sink");
	binsinkpad = gst_ghost_pad_new ("sink", realpad);
	gst_element_add_pad (bin, binsinkpad);
	gst_object_unref (realpad);

	realpad = gst_element_get_static_pad (audioconvert2, "src");
	binsrcpad = gst_ghost_pad_new ("src", realpad);
	gst_element_add_pad (bin, binsrcpad);
	gst_object_unref (realpad);

	/* chuck it into the filter bin */
	gst_bin_add (GST_BIN (op->fixture), bin);
	identity = gst_bin_get_by_name (GST_BIN (op->fixture), "filteridentity");
	realpad = gst_element_get_static_pad (identity, "sink");
	prevpad = gst_pad_get_peer (realpad);
	gst_object_unref (identity);

	gst_pad_unlink (prevpad, realpad);

	link = gst_pad_link (prevpad, binsinkpad);
	gst_object_unref (prevpad);
	if (link != GST_PAD_LINK_OK) {
		g_warning ("couldn't link new filter into pipeline (sink): %d", link);
		/* make some attempt at cleaning up; probably won't work though */
		gst_pad_link (prevpad, realpad);
		gst_object_unref (realpad);
		gst_bin_remove (GST_BIN (op->fixture), bin);
		gst_object_unref (bin);

		free_pipeline_op (op);
		return;
	}

	link = gst_pad_link (binsrcpad, realpad);
	gst_object_unref (realpad);
	if (link != GST_PAD_LINK_OK) {
		g_warning ("couldn't link new filter into pipeline (src): %d", link);
		/* doubt we can do anything helpful here.. */
	}

	/* if we're supposed to be playing, unblock the sink */
	if (blocked) {
		rb_debug ("unblocking pad after adding filter");
		gst_element_set_state (bin, GST_STATE_PLAYING);
		gst_pad_set_blocked_async (pad, FALSE, (GstPadBlockCallback)pipeline_op_done, NULL);
	} else {
		gst_element_set_state (bin, GST_STATE_PAUSED);
	}

	_rb_player_gst_filter_emit_filter_inserted (RB_PLAYER_GST_FILTER (op->player), op->element);

	free_pipeline_op (op);
}
Example #4
0
static gboolean
construct_pipeline (RBPlayerGst *mp, GError **error)
{
	GstElement *sink;
	GList *l;

	mp->priv->playbin = gst_element_factory_make ("playbin", NULL);
	if (mp->priv->playbin == NULL) {
		g_set_error (error,
			     RB_PLAYER_ERROR,
			     RB_PLAYER_ERROR_GENERAL,
			     _("Failed to create playbin element; check your GStreamer installation"));
		return FALSE;
	}
	g_signal_connect_object (G_OBJECT (mp->priv->playbin),
				 "about-to-finish",
				 G_CALLBACK (about_to_finish_cb),
				 mp, 0);
	g_signal_connect_object (G_OBJECT (mp->priv->playbin),
				 "deep-notify::volume",
				 G_CALLBACK (volume_notify_cb),
				 mp, 0);
	g_signal_connect_object (G_OBJECT (mp->priv->playbin),
				 "source-setup",
				 G_CALLBACK (source_setup_cb),
				 mp, 0);

	gst_bus_add_watch (gst_element_get_bus (mp->priv->playbin),
			   (GstBusFunc) bus_cb,
			   mp);

	/* let plugins add bits to playbin */
	g_object_notify (G_OBJECT (mp), "playbin");
	g_object_notify (G_OBJECT (mp), "bus");

	g_object_get (mp->priv->playbin, "audio-sink", &mp->priv->audio_sink, NULL);
	if (mp->priv->audio_sink == NULL) {
		mp->priv->audio_sink = rb_player_gst_try_audio_sink ("autoaudiosink", NULL);
		if (mp->priv->audio_sink == NULL) {
			g_set_error (error,
				     RB_PLAYER_ERROR,
				     RB_PLAYER_ERROR_GENERAL,
				     _("Failed to create %s element; check your GStreamer installation"),
				     "autoaudiosink");
			return FALSE;
		}
		g_object_set (mp->priv->playbin, "audio-sink", mp->priv->audio_sink, NULL);
	} else {
		rb_debug ("existing audio sink found");
		g_object_unref (mp->priv->audio_sink);
	}
	g_object_set (mp->priv->playbin, "audio-sink", mp->priv->audio_sink, NULL);

	/* setup filterbin */
	mp->priv->filterbin = rb_gst_create_filter_bin ();
	g_object_set (mp->priv->playbin, "audio-filter", mp->priv->filterbin, NULL);

	/* add any filters that have already been added */
	for (l = mp->priv->waiting_filters; l != NULL; l = g_list_next (l)) {
		rb_player_gst_filter_add_filter (RB_PLAYER_GST_FILTER(mp), GST_ELEMENT (l->data));
	}
	g_list_free (mp->priv->waiting_filters);
	mp->priv->waiting_filters = NULL;

	/* Use fakesink for video if there's no video sink yet */
	g_object_get (mp->priv->playbin, "video-sink", &sink, NULL);
	if (sink == NULL) {
		sink = gst_element_factory_make ("fakesink", NULL);
		g_object_set (mp->priv->playbin, "video-sink", sink, NULL);
	} else {
		g_object_unref (sink);
	}

	if (mp->priv->cur_volume > 1.0)
		mp->priv->cur_volume = 1.0;
	if (mp->priv->cur_volume < 0.0)
		mp->priv->cur_volume = 0;

	rb_debug ("pipeline construction complete");
	return TRUE;
}