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