Hi all, I'm currently hacking on a system that can analyse images coming from a camera (on the fly), or from a pre-recorded set of images (pos-analysis). I want to be able to use either source transparently. But as I don't know how much time the pre-recorded images will take to process, I'd like to have the processing be asynchronous.
Given these requirements, I thought of using GSource, because an image arrival would be seen like an asynchronous event source. So, I'm currently doing a small GUI application, but I have problems displaying the images provided by the camera source. Note that in a non-GUI application, everything works, and I'm able to save every image on the hard disk for post analysis. Currently, I'm doing everything in the main loop (there's no other thread), but the results are bad. Either the GUI freezes and the other controls are not drawn (as if too much time was spent processing the camera source events), or if I lower the acquisition period, I only get 3 or 4 frames incompletely drawn. Maybe I'm not using GSource as I should, but I couldn't find much documentation on it. Especially since I'm using it with no file descriptor to poll. I read the glib code for timeout sources, and could not find something I'm doing wrong. So if someone could give me some hints on how I may be using it in a bad way, or tell me if my approach and choice of GSource was a good one, it would be very appreciated. Here is the code for the caera event source, and for the GUI app. Thanks in advance. /***************** * camera-source.c ******************/ static GSourceFuncs camera_source_funcs = { camera_source_prepare, camera_source_check, camera_source_dispatch, NULL }; GSource * camera_source_new(CamDevice *camdev) { GSource *source = g_source_new(&camera_source_funcs, sizeof(CameraSource)); CameraSource* self = CAMERASOURCE(source); self->device = camdev; self->pixbuf = NULL; self->frame_number = -1; return source; } inline void camera_source_free(gpointer source) { if (source != NULL) { CameraSource *self = source; if (self->pixbuf != NULL) g_object_unref(self->pixbuf); g_free(self); } } static gboolean camera_source_prepare (GSource *source, gint *timeout) { CamDevice *camdev; g_assert(source != NULL); camdev = CAMERASOURCE(source)->device; *timeout = ACQUISITION_PERIOD; /* milisecondes */ camdevice_request_image(camdev); return FALSE; } static gboolean camera_source_check (GSource *source) { CameraSource *self; gboolean result; g_assert(source != NULL); self = CAMERASOURCE(source); result = camdevice_get_pending_image(self->device, &self->pixbuf); /* camdevice_get_pending_image returns FALSE if no image is ready, as I had to workaround the implementation of the 3rd part vendor of the camera which only proposes a blocking, synchronous API to get images */ self->frame_number++; return result; } static gboolean camera_source_dispatch (GSource *source, GSourceFunc callback, gpointer user_data) { g_assert(source != NULL); if (!callback) { g_warning("No callback defined.\n" "Call g_source_set_callback"); return FALSE; } if (callback(user_data)) return TRUE; return FALSE; } /********** * gt-dif.c ***********/ #include "camdevice.h" /* for CamDevice */ #include "camera-source.h" /* for CameraSource */ static void on_quit (gpointer user_data) { gtk_main_quit (); } static gboolean on_image_received (gpointer data) { GtkWidget *da = data; g_assert (da != NULL); g_debug (G_STRFUNC); gdk_window_invalidate_rect (da->window, &da->allocation, FALSE); return TRUE; } gboolean on_drawing_area_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer data) { CameraSource *camsrc = data; g_assert (camsrc != NULL); g_debug ("%s : expose-event", G_STRFUNC); if (camsrc->pixbuf == NULL) return FALSE; gdk_draw_pixbuf (widget->window, widget->style->fg_gc[GTK_WIDGET_STATE (widget)], camsrc->pixbuf, 0, 0, 0, 0, -1, -1, GDK_RGB_DITHER_NONE, 0, 0); return TRUE; } static GPtrArray* recorder_autodetect_sources (void) { CamDevice *camdev; GPtrArray *sources = NULL; /* Discover every camera connected */ while ((camdev = camdevice_new ()) != NULL) { GSource *source = camera_source_new (camdev); g_source_attach (source, NULL); if (G_UNLIKELY (sources == NULL)) sources = g_ptr_array_new (); g_ptr_array_add (sources, source); g_print ("Camera '%s' was detected\n", camdevice_get_serial (camdev)); } return sources; } static GtkWidget * make_gui (const GPtrArray *camsources) { GtkWidget *main_window; GtkWidget *box; main_window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (main_window), "gtk-dif"); gtk_window_set_default_size (GTK_WINDOW (main_window), 320, 240); box = gtk_vbox_new (FALSE, 10); gtk_container_add (GTK_CONTAINER (main_window), box); if (camsources != NULL) { gint i = 0; for (i = 0; i < camsources->len; i++) { GtkWidget *label; GtkWidget *da; GSource *camsource; camsource = g_ptr_array_index (camsources, i); g_debug ("Adding camera '%s'", camdevice_get_serial (CAMERASOURCE (camsource)->device)); /* Label avec le nom de la caméra */ label = gtk_label_new (camdevice_get_serial (CAMERASOURCE (camsource)->device)); gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0); /* Image de la caméra */ da = gtk_drawing_area_new (); gtk_widget_set_size_request (da, 320, 240); gtk_box_pack_start (GTK_BOX (box), da, FALSE, FALSE, 0); /* Signaux */ g_signal_connect (da, "expose-event", G_CALLBACK (on_drawing_area_expose_event), camsource); g_source_set_callback (camsource, on_image_received, da, NULL); } } gtk_widget_show_all (main_window); g_signal_connect (main_window, "destroy", G_CALLBACK (on_quit), NULL); return main_window; } int main (int argc, char *argv[]) { GPtrArray *camera_sources = NULL; GtkWidget *main_window; /* Locale management */ setlocale (LC_ALL, ""); g_type_init (); gtk_init (&argc, &argv); /* Image sources creation */ camera_sources = recorder_autodetect_sources (); if (camera_sources == NULL) g_debug ("No camera détected"); main_window = make_gui (camera_sources); gtk_main (); /* FIXME: Leaking camera sources */ return EXIT_SUCCESS; } _______________________________________________ gtk-app-devel-list mailing list gtk-app-devel-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-app-devel-list