[gst-devel] [Bug 87882] New - state change in top-level thread not passed down to child bin
bugzilla-daemon at widget.gnome.org
bugzilla-daemon at widget.gnome.org
Thu Jul 11 11:04:05 CEST 2002
Please do not reply to this email- if you want to comment on the bug, go to the
URL shown below and enter your comments there.
http://bugzilla.gnome.org/show_bug.cgi?id=87882
Changed by mromaine at parc.com.
--- shadow/87882 Wed Jul 10 20:12:14 2002
+++ shadow/87882.tmp.31684 Wed Jul 10 20:12:14 2002
@@ -0,0 +1,246 @@
+Bug#: 87882
+Product: GStreamer
+Version: 0.4.0
+OS: Linux
+OS Details: nothing special
+Status: NEW
+Resolution:
+Severity: major
+Priority: Normal
+Component: gstreamer (core)
+AssignedTo: gstreamer-maint at bugzilla.gnome.org
+ReportedBy: mromaine at parc.com
+QAContact: gstreamer-maint at bugzilla.gnome.org
+TargetMilestone: 0.4.0
+URL:
+Cc:
+Summary: state change in top-level thread not passed down to child bin
+
+The following are two files to demonstrate that a bin (containing a
+filesrc, mad decoder, and volume filter) inside a thread which connects the
+bin to an osssink, does not stop when the bin is passed GST_STATE_PAUSED.
+Essentially, it seems the thread's state override's the child's state.
+Debugging output (and further gdb checking) verifies that the bin is
+receiving the correct state-change information, but the loop cycle does not
+seem to recognize this.
+
+This example uses gtk for a simple gui
+
+--------------------- file with main(...) -------------------------
+#include <gtk/gtk.h>
+#include "mixer.h"
+
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE -1
+#endif
+
+gint delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
+{
+ gtk_main_quit();
+ return FALSE;
+}
+
+static void play_src(GtkWidget *widget, gpointer data)
+{
+ start_channel ();
+}
+
+static void pause_src(GtkWidget *widget, gpointer data)
+{
+ pause_channel ();
+}
+
+static void quit(void)
+{
+ quit_everything();
+ gtk_main_quit();
+}
+
+int main( int argc, char *argv[])
+{
+ GtkWidget *window, *mainvbox;
+ GtkWidget *control_buttons_hbox;
+ GtkWidget *play_button, *pause_button;
+ GtkWidget *quit_button;
+
+ if (argc == 1)
+ {
+ g_print ("usage: %s <filename1> \n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ gtk_init (&argc, &argv);
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title (GTK_WINDOW (window), "Tester");
+
+ /* When the window is given the "delete_event" signal (this is given
+ * by the window manager, usually by the "close" option, or on the
+ * titlebar), we ask it to call the delete_event () function
+ * as defined above. The data passed to the callback
+ * function is NULL and is ignored in the callback function. */
+ g_signal_connect (G_OBJECT (window), "delete_event",
+ G_CALLBACK (delete_event), NULL);
+
+ gtk_container_set_border_width (GTK_CONTAINER (window), 5);
+
+ /* main vbox that will hold main hbox (needed so that quit button appears
+ * below everything) */
+ mainvbox = gtk_vbox_new (FALSE, 5);
+ gtk_container_add (GTK_CONTAINER (window), mainvbox);
+
+ play_button = gtk_button_new_with_label("play");
+ g_signal_connect (G_OBJECT (play_button), "clicked",
+ G_CALLBACK (play_src), NULL);
+
+ pause_button = gtk_button_new_with_label("pause");
+ g_signal_connect (G_OBJECT (pause_button), "clicked",
+ G_CALLBACK (pause_src), NULL);
+
+ /* create container for control buttons */
+ control_buttons_hbox = gtk_hbox_new (TRUE, 5);
+ gtk_box_pack_start (GTK_BOX (mainvbox), control_buttons_hbox,
+ FALSE, FALSE, 5);
+
+ gtk_container_add (GTK_CONTAINER (control_buttons_hbox), play_button);
+ gtk_container_add (GTK_CONTAINER (control_buttons_hbox), pause_button);
+
+ gtk_widget_show (play_button);
+ gtk_widget_show (pause_button);
+ gtk_widget_show (control_buttons_hbox);
+
+ /* create quit button */
+ quit_button = gtk_button_new_with_label ("quit");
+ g_signal_connect (G_OBJECT (quit_button), "clicked",
+ G_CALLBACK (quit), NULL);
+ gtk_box_pack_start (GTK_BOX(mainvbox), quit_button, FALSE, FALSE, 5);
+
+ gtk_widget_show (quit_button);
+ gtk_widget_show (mainvbox);
+
+ gtk_window_set_default_size (GTK_WINDOW (window), 100, 100);
+ gtk_widget_show (window);
+
+ init_mixer (argc, argv);
+
+ gtk_main ();
+
+ return 0;
+}
+
+--------------------- mixer.c: where elements are created and stored -----
+
+#include <gst/gst.h>
+
+static GstElement *main_thread;
+static GstElement *channel_bin;
+static GstElement *audiosink;
+static GstElement *filesrc, *mad_decoder, *volume;
+
+init_mixer (int argc, char* argv[])
+{
+ GstPad *temp_pad; /* for connecting to adder */
+
+ gst_init (&argc, &argv);
+ gst_control_init (&argc, &argv);
+
+ /* create main thread to process everything.
+ * this thread will hold a bin and an osssink.
+ * the bin will hold a filesrc, mad, and volume.
+ * a ghost pad will connect the volume's output to
+ * the osssink. */
+ main_thread = gst_thread_new ("mixer_thread");
+ g_assert (main_thread != NULL);
+
+ /* create bin to hold filesrc, volume, and mad */
+ channel_bin = gst_bin_new ("channel_bin");
+ g_assert (channel_bin != NULL);
+
+ /* create a filesrc reader (goes into bin) */
+ filesrc = gst_element_factory_make ("filesrc", "filesrc");
+ g_assert (filesrc != NULL);
+ g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
+
+ /* create a decoder */
+ mad_decoder = gst_element_factory_make ("mad", "mpg123_decoder");
+ g_assert (mad_decoder != NULL);
+
+ /* create a volume controller */
+ volume = gst_element_factory_make ("volume", "volume");
+ g_assert (volume != NULL);
+
+ /* add main part of audio processing to the bin */
+ gst_bin_add_many (GST_BIN (channel_bin),
+ filesrc,
+ mad_decoder,
+ volume,
+ NULL);
+
+ /* actually connect the elements */
+ gst_element_connect_many (filesrc, mad_decoder, volume, NULL);
+
+ /* add ghost pad to connect bin to osssink which is held
+ * in mixer_thread */
+ gst_element_add_ghost_pad (channel_bin,
+ gst_element_get_pad (volume, "src"),
+ "channel_bin_output");
+
+ /* create our audio sink for final output */
+ audiosink = gst_element_factory_make ("osssink", "play_audio");
+ g_assert (audiosink != NULL);
+
+ temp_pad = gst_element_get_static_pad (audiosink, "sink");
+ g_assert (temp_pad != NULL);
+
+ /* try to connect the ghost pad from the channel bin to the
+ * audiosink intake pad */
+ if (!gst_pad_connect (gst_element_get_pad (channel_bin,
+ "channel_bin_output"),
+ temp_pad))
+ {
+ g_print ("error connecting pads!\n");
+ }
+
+ gst_bin_add (GST_BIN (main_thread), GST_ELEMENT (channel_bin));
+ gst_bin_add (GST_BIN (main_thread), GST_ELEMENT (audiosink));
+
+ /* we turn on all pipelines/bins/threads */
+ gst_element_set_state (main_thread, GST_STATE_PLAYING);
+ gst_element_set_state (channel_bin, GST_STATE_PLAYING);
+
+ /* print out the schedule? */
+ gst_scheduler_show (GST_ELEMENT_SCHED (main_thread));
+
+}
+
+void
+start_channel (void)
+{
+ g_print ("starting audio\n");
+ gst_element_set_state (GST_ELEMENT (channel_bin), GST_STATE_PLAYING);
+}
+
+void
+pause_channel (void)
+{
+ g_print ("pausing audio\n");
+ gst_element_set_state (GST_ELEMENT (channel_bin), GST_STATE_PAUSED);
+}
+
+void
+quit_everything(void)
+{
+
+ gst_object_destroy (GST_OBJECT (main_thread));
+
+ gst_main_quit();
+}
+
+------------- mixer.h, as needed by gainctl.c -------------
+#ifndef MIXER_HEADER_
+#define MIXER_HEADER_
+
+void start_channel (void);
+void pause_channel (void);
+
+#endif
More information about the gstreamer-devel
mailing list