static void stop_visualizer_cb (RBVisualizerPage *page, RBVisualizerPlugin *plugin) { if (plugin->visualizer == NULL) { return; } if (plugin->playbin_notify_id) { int playbin_flags; g_object_get (plugin->playbin, "flags", &playbin_flags, NULL); playbin_flags &= ~PLAYBIN2_FLAG_VIS; rb_debug ("disabling vis; new playbin2 flags %d", playbin_flags); g_object_set (plugin->playbin, "flags", playbin_flags, "vis-plugin", NULL, NULL); } else { rb_debug ("removing visualizer bin from pipeline"); rb_player_gst_tee_remove_tee (RB_PLAYER_GST_TEE (plugin->player), plugin->visualizer); } if (plugin->visualizer) { g_object_unref (plugin->visualizer); plugin->visualizer = NULL; } }
static void really_remove_tee (GstPad *pad, gboolean blocked, RBGstPipelineOp *op) { GstElement *bin; GstElement *parent; rb_debug ("really removing tee %p", op->element); _rb_player_gst_tee_emit_tee_pre_remove (RB_PLAYER_GST_TEE (op->player), op->element); /* find bin, remove everything */ bin = GST_ELEMENT_PARENT (op->element); g_object_ref (bin); parent = GST_ELEMENT_PARENT (bin); gst_bin_remove (GST_BIN (parent), bin); gst_element_set_state (bin, GST_STATE_NULL); gst_bin_remove (GST_BIN (bin), op->element); g_object_unref (bin); /* if we're supposed to be playing, unblock the sink */ if (blocked) { rb_debug ("unblocking pad after removing tee"); gst_pad_set_blocked_async (pad, FALSE, (GstPadBlockCallback)pipeline_op_done, NULL); } free_pipeline_op (op); }
static void really_add_tee (GstPad *pad, gboolean blocked, RBGstPipelineOp *op) { GstElement *queue; GstElement *audioconvert; GstElement *bin; GstElement *parent_bin; GstPad *sinkpad; GstPad *ghostpad; rb_debug ("really adding tee %p", op->element); /* set up containing bin */ bin = gst_bin_new (NULL); queue = gst_element_factory_make ("queue", NULL); audioconvert = gst_element_factory_make ("audioconvert", NULL); /* The bin contains elements that change state asynchronously * and not as part of a state change in the entire pipeline. */ g_object_set (bin, "async-handling", TRUE, NULL); g_object_set (queue, "max-size-buffers", 3, NULL); gst_bin_add_many (GST_BIN (bin), queue, audioconvert, op->element, NULL); gst_element_link_many (queue, audioconvert, op->element, NULL); /* add ghost pad */ sinkpad = gst_element_get_static_pad (queue, "sink"); ghostpad = gst_ghost_pad_new ("sink", sinkpad); gst_element_add_pad (bin, ghostpad); gst_object_unref (sinkpad); /* add it into the pipeline */ parent_bin = GST_ELEMENT_PARENT (op->fixture); gst_bin_add (GST_BIN (parent_bin), bin); gst_element_link (op->fixture, bin); /* if we're supposed to be playing, unblock the sink */ if (blocked) { rb_debug ("unblocking pad after adding tee"); gst_element_set_state (parent_bin, GST_STATE_PLAYING); gst_object_ref (ghostpad); gst_pad_set_blocked_async (pad, FALSE, (GstPadBlockCallback)pipeline_op_done, ghostpad); } else { gst_element_set_state (bin, GST_STATE_PAUSED); gst_object_ref (ghostpad); pipeline_op_done (NULL, FALSE, ghostpad); } _rb_player_gst_tee_emit_tee_inserted (RB_PLAYER_GST_TEE (op->player), op->element); free_pipeline_op (op); }
static void start_visualizer_cb (RBVisualizerPage *page, RBVisualizerPlugin *plugin) { GstPad *pad; char *plugin_name; if (plugin->visualizer) { g_object_unref (plugin->visualizer); plugin->visualizer = NULL; plugin->identity = NULL; plugin->capsfilter = NULL; plugin->vis_plugin = NULL; } plugin->visualizer = gst_bin_new (NULL); /* create common bits of visualizer bin: identity ! <effect> ! capsfilter */ plugin->identity = gst_element_factory_make ("identity", NULL); plugin->capsfilter = gst_element_factory_make ("capsfilter", NULL); plugin_name = g_settings_get_string (plugin->settings, "vis-plugin"); if (plugin_name != NULL) { plugin->vis_plugin = gst_element_factory_make (plugin_name, NULL); if (plugin->vis_plugin == NULL) { g_warning ("Configured visualizer plugin %s not available", plugin_name); } g_free (plugin_name); } if (plugin->vis_plugin == NULL) { plugin->vis_plugin = gst_element_factory_make ("goom", NULL); if (plugin->vis_plugin == NULL) { g_warning ("Fallback visualizer plugin (goom) not available"); return; } } /* set up capsfilter */ gst_bin_add_many (GST_BIN (plugin->visualizer), plugin->identity, plugin->vis_plugin, plugin->capsfilter, NULL); pad = gst_element_get_static_pad (plugin->identity, "sink"); gst_element_add_pad (plugin->visualizer, gst_ghost_pad_new ("sink", pad)); gst_object_unref (pad); /* XXX check errors etc. */ if (gst_element_link_many (plugin->identity, plugin->vis_plugin, plugin->capsfilter, NULL) == FALSE) { g_warning ("couldn't link visualizer bin elements"); return; } fixate_vis_caps (plugin); g_object_ref (plugin->visualizer); if (plugin->playbin_notify_id) { GstPad *pad; int playbin_flags; pad = gst_element_get_static_pad (plugin->capsfilter, "src"); gst_element_add_pad (plugin->visualizer, gst_ghost_pad_new ("src", pad)); gst_object_unref (pad); g_object_get (plugin->playbin, "flags", &playbin_flags, NULL); if (plugin->playbin != NULL) { playbin_flags |= PLAYBIN2_FLAG_VIS; rb_debug ("enabling vis; new playbin2 flags %x", playbin_flags); g_object_set (plugin->playbin, "vis-plugin", plugin->visualizer, "flags", playbin_flags, NULL); } else { rb_debug ("playback hasn't started yet"); } } else { GstElement *colorspace; GstElement *queue; colorspace = gst_element_factory_make ("ffmpegcolorspace", NULL); queue = gst_element_factory_make ("queue", NULL); g_object_set (queue, "max-size-buffers", 3, "max-size-bytes", 0, "max-size-time", (gint64) 0, NULL); gst_bin_add_many (GST_BIN (plugin->visualizer), queue, colorspace, plugin->sink, NULL); gst_element_link_many (plugin->capsfilter, queue, colorspace, plugin->sink, NULL); rb_debug ("adding visualizer bin to the pipeline"); rb_player_gst_tee_add_tee (RB_PLAYER_GST_TEE (plugin->player), plugin->visualizer); } }
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; }