GNOME Bugzilla – Bug 330598
[PATCH] crash in playbin and fix
Last modified: 2006-03-10 16:44:59 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.
+ Trace 66050
Thread NaN (LWP 18841)
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
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?
That is to say, is it gone with the 0.10.3 of gst-plugins-base I released today?
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!