After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 330598 - [PATCH] crash in playbin and fix
[PATCH] crash in playbin and fix
Status: RESOLVED FIXED
Product: GStreamer
Classification: Platform
Component: gst-plugins-base
0.10.2
Other Linux
: Normal normal
: 0.10.3
Assigned To: GStreamer Maintainers
GStreamer Maintainers
Depends on:
Blocks:
 
 
Reported: 2006-02-09 23:26 UTC by RyanN
Modified: 2006-03-10 16:44 UTC
See Also:
GNOME target: ---
GNOME version: ---



Description RyanN 2006-02-09 23:26:22 UTC
Due to a change to set elements to GST_STATE_NULL in remove_sinks of playbin a crash can be introduced.  The frame member of playbin may be reliant upon the xoverlay or another video element, so if that video element gets detroyed first then when it tries to unref the frame member it could crash, and indeed does in some instances depending on how the elements are layed out -in this case it is because gst_ximagesink_ximage_destroy does not check ximagesink->xcontext for NULL.

Program to reproduce crash in 10.2 (Note that I get this in anther actually well-written application :)):
-----------
#include <gst/gst.h>
#include <gst/interfaces/xoverlay.h>
#include <gtk/gtk.h>
#include <gdk/gdkx.h>

#define TIMEOUT 100 * GST_MSECOND

GstXOverlay *x_overlay;

GtkWindow *window;
GtkWidget *videoarea;

Drawable xwindow_id;

static gboolean crashtime (GstElement * playbin)
{
    gtk_main_quit();
    return FALSE;
}

GstBusSyncReply sync_callback(GstBus *bus, GstMessage *message, 
                              gpointer)
{	
	if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT) 
		return GST_BUS_PASS; 

	if (gst_structure_has_name (gst_message_get_structure(message), 
                                "prepare-xwindow-id")) 
	{
		    gst_x_overlay_set_xwindow_id( GST_X_OVERLAY(GST_MESSAGE_SRC(message)),
                                xwindow_id)
                                ;    
		return GST_BUS_PASS;
	}

	return GST_BUS_DROP;
}

int main(int argc, char* argv[])
{
    gtk_init (&argc, &argv);
	g_thread_init(NULL);
	gdk_threads_init();
    gst_init(&argc, &argv);

    if(argc > 1)
    {
        GtkWindow*    window = (GtkWindow*)gtk_window_new (GTK_WINDOW_TOPLEVEL);
        videoarea = gtk_drawing_area_new (); 
        gtk_widget_set_size_request(videoarea, 320, 200);

    	GdkColor color;
    	gdk_color_parse ("black", &color);
    	gtk_widget_modify_bg (videoarea, GTK_STATE_NORMAL, &color);
        gtk_container_add (GTK_CONTAINER (window), videoarea);       
        gtk_widget_show (videoarea);
        gtk_widget_show ((GtkWidget*)window);
        gtk_widget_set_double_buffered((GtkWidget*)window, FALSE);
	Display *display;

	display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
	xwindow_id = GDK_DRAWABLE_XID((videoarea->window));

        GstElement* playbin = 
            gst_element_factory_make ("playbin", "play");

        gst_bus_set_sync_handler(gst_pipeline_get_bus (GST_PIPELINE (playbin)), (GstBusSyncHandler)sync_callback, NULL);

        GstElement* videosink = 
            gst_element_factory_make("ximagesink", "video-sink");
        GstElement* audiosink = 
            gst_element_factory_make ("gconfaudiosink", "audio-sink");

    if( GST_IS_BIN(videosink) )
        x_overlay = (GstXOverlay*) 
                        gst_bin_get_by_interface (GST_BIN (videosink),
                                                  GST_TYPE_X_OVERLAY);
    else
        x_overlay = (GstXOverlay*) videosink;

        g_object_set (G_OBJECT (playbin), 
                  "video-sink", videosink,
                  "audio-sink", audiosink,
                   NULL);

        gst_element_set_state(playbin, 
                               GST_STATE_READY);
        gst_element_get_state(playbin, NULL, NULL, TIMEOUT);

        GstElement* vis = 
            gst_element_factory_make ("goom", "vis");
        g_object_set(playbin, "vis-plugin", vis, NULL);

        g_object_set (G_OBJECT (playbin), "uri", 
    argv[1], NULL);

        gst_element_set_state(playbin, 
                               GST_STATE_PAUSED);
        gst_element_get_state(playbin, NULL, NULL, TIMEOUT);
        
        gst_element_set_state(playbin, 
                               GST_STATE_PLAYING);
        gst_element_get_state(playbin, NULL, NULL, TIMEOUT);

        g_timeout_add (10000, (GSourceFunc) crashtime, playbin);
        gtk_main ();

        gst_element_set_state(playbin, 
                               GST_STATE_READY); /* will crash here */
        gst_element_get_state(playbin, NULL, NULL, TIMEOUT);
    }
    return 0;
}

---------
Backtrace:
---------
Program received signal SIGSEGV, Segmentation fault.

Thread NaN (LWP 18841)

  • #0 gst_ximage_buffer_finalize
    at ximagesink.c line 491
  • #1 gst_mini_object_unref
    at gstminiobject.c line 264
  • #2 remove_sinks
    at gstplaybin.c line 764
  • #3 gst_play_bin_change_state
    at gstplaybin.c line 1055
  • #4 gst_element_change_state
    at gstelement.c line 2151
  • #5 gst_element_change_state
    at gstelement.c line 2184
  • #6 gst_element_set_state_func
    at gstelement.c line 2113
  • #7 gst_element_set_state
    at gstelement.c line 2030
  • #8 main
    at junk.cpp line 109

   GST_DEBUG ("removesinks");
+
+  /* we need to dispose of the frame before the video
+   * sink as it may be a component of it */
+  if (play_bin->frame) {
+    gst_buffer_unref (play_bin->frame);
+    play_bin->frame = NULL;
+  }
+
   element = g_hash_table_lookup (play_bin->cache, "abin");
   if (element != NULL) {
@@ -761,9 +769,4 @@
   }

-  if (play_bin->frame) {
-    gst_buffer_unref (play_bin->frame);
-    play_bin->frame = NULL;
-  }
-
   play_bin->textoverlay_element = NULL;
}

-----------
2) Change ximagesink to check for NULL for ximagesink->xcontext in gst_ximagesink_ximage_destroy
--- sys/ximage/ximagesinkole.c 2006-01-16 07:28:47.000000000 -0800
+++ sys/ximage/ximagesink.c 2006-02-09 11:32:47.000000000 -0800
@@ -489,5 +489,5 @@

#ifdef HAVE_XSHM
-  if (ximagesink->xcontext->use_xshm) {
+  if (ximagesink->xcontext && ximagesink->xcontext->use_xshm) {
     if (ximage->SHMInfo.shmaddr != ((void *) -1)) {
       XShmDetach (ximagesink->xcontext->disp, &ximage->SHMInfo);
@@ -508,5 +508,7 @@
   }

+  if(ximagesink->xcontext) {
   XSync (ximagesink->xcontext->disp, FALSE);
+  }

   g_mutex_unlock (ximagesink->x_lock);

-----------
3) Or, if this is desired behaviour perhaps a simple 

g_return_if_fail (ximagesink->xcontext != NULL);

or similar could be added to the top of gst_ximagesink_ximage_destroy
Comment 1 Jan Schmidt 2006-02-09 23:55:11 UTC
The X imagesinks have undergone lots of changes recently, including that they should now properly support freeing of buffers after the imagesink itself has been returned to NULL state.

I can't reproduce the issue with your test app. Is it gone?
Comment 2 Jan Schmidt 2006-02-10 00:10:17 UTC
That is to say, is it gone with the 0.10.3 of gst-plugins-base I released today?
Comment 3 RyanN 2006-02-10 01:10:05 UTC
Indeed, one of the two changes to ximagesink.c fixed this -
http://cvs.freedesktop.org/gstreamer/gst-plugins-base/sys/ximage/ximagesink.c?r1=1.150&r2=1.151

(Assuming your 10.3 version includes that diff from HEAD which I'm assuming it does).

Closed, thanks!