From 3a45434834999e1ac7c7a99cdaa644d939b859b0 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang Date: Tue, 25 Sep 2012 18:18:23 +0200 Subject: Move tools from test/ to tools/ directory --- tools/gui/control.c | 350 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 350 insertions(+) create mode 100644 tools/gui/control.c (limited to 'tools/gui/control.c') diff --git a/tools/gui/control.c b/tools/gui/control.c new file mode 100644 index 0000000..75b3cde --- /dev/null +++ b/tools/gui/control.c @@ -0,0 +1,350 @@ +/* Copyright (C) 2011, 2012 Matthias Vogelgesang + (Karlsruhe Institute of Technology) + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2.1 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., 51 + Franklin St, Fifth Floor, Boston, MA 02110, USA */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "uca-camera.h" +#include "uca-plugin-manager.h" +#include "egg-property-tree-view.h" + + +typedef struct { + gboolean running; + gboolean store; + + guchar *buffer, *pixels; + GdkPixbuf *pixbuf; + GtkWidget *image; + GtkTreeModel *property_model; + UcaCamera *camera; + + GtkStatusbar *statusbar; + guint statusbar_context_id; + + int timestamp; + int width; + int height; + int pixel_size; +} ThreadData; + +enum { + COLUMN_NAME = 0, + COLUMN_VALUE, + COLUMN_EDITABLE, + NUM_COLUMNS +}; + +static UcaPluginManager *plugin_manager; + +static void +convert_8bit_to_rgb (guchar *output, guchar *input, int width, int height) +{ + for (int i = 0, j = 0; i < width*height; i++) { + output[j++] = input[i]; + output[j++] = input[i]; + output[j++] = input[i]; + } +} + +static void +convert_16bit_to_rgb (guchar *output, guchar *input, int width, int height) +{ + guint16 *in = (guint16 *) input; + guint16 min = G_MAXUINT16, max = 0; + gfloat spread = 0.0f; + + for (int i = 0; i < width * height; i++) { + guint16 v = in[i]; + if (v < min) + min = v; + if (v > max) + max = v; + } + + spread = (gfloat) max - min; + + if (spread > 0.0f) { + for (int i = 0, j = 0; i < width*height; i++) { + guchar val = (guint8) (((in[i] - min) / spread) * 255.0f); + output[j++] = val; + output[j++] = val; + output[j++] = val; + } + } +} + +static void * +grab_thread (void *args) +{ + ThreadData *data = (ThreadData *) args; + gchar filename[FILENAME_MAX] = {0,}; + gint counter = 0; + + while (data->running) { + uca_camera_grab (data->camera, (gpointer) &data->buffer, NULL); + + if (data->store) { + snprintf (filename, FILENAME_MAX, "frame-%i-%08i.raw", data->timestamp, counter++); + FILE *fp = fopen (filename, "wb"); + fwrite (data->buffer, data->width*data->height, data->pixel_size, fp); + fclose (fp); + } + + /* FIXME: We should actually check if this is really a new frame and + * just do nothing if it is an already displayed one. */ + if (data->pixel_size == 1) + convert_8bit_to_rgb (data->pixels, data->buffer, data->width, data->height); + else if (data->pixel_size == 2) { + convert_16bit_to_rgb (data->pixels, data->buffer, data->width, data->height); + } + + gdk_threads_enter (); + gdk_flush (); + gtk_image_clear (GTK_IMAGE (data->image)); + gtk_image_set_from_pixbuf (GTK_IMAGE (data->image), data->pixbuf); + gtk_widget_queue_draw_area (data->image, 0, 0, data->width, data->height); + gdk_threads_leave (); + } + return NULL; +} + +gboolean +on_delete_event (GtkWidget *widget, GdkEvent *event, gpointer data) +{ + return FALSE; +} + +void +on_destroy (GtkWidget *widget, gpointer data) +{ + ThreadData *td = (ThreadData *) data; + td->running = FALSE; + g_object_unref (td->camera); + gtk_main_quit (); +} + +static void +on_toolbutton_run_clicked (GtkWidget *widget, gpointer args) +{ + ThreadData *data = (ThreadData *) args; + + if (data->running) + return; + + GError *error = NULL; + data->running = TRUE; + + uca_camera_start_recording (data->camera, &error); + + if (error != NULL) { + g_printerr ("Failed to start recording: %s\n", error->message); + return; + } + + if (!g_thread_create (grab_thread, data, FALSE, &error)) { + g_printerr ("Failed to create thread: %s\n", error->message); + return; + } +} + +static void +on_toolbutton_stop_clicked (GtkWidget *widget, gpointer args) +{ + ThreadData *data = (ThreadData *) args; + data->running = FALSE; + data->store = FALSE; + GError *error = NULL; + uca_camera_stop_recording (data->camera, &error); + + if (error != NULL) + g_printerr ("Failed to stop: %s\n", error->message); +} + +static void +on_toolbutton_record_clicked (GtkWidget *widget, gpointer args) +{ + ThreadData *data = (ThreadData *) args; + data->timestamp = (int) time (0); + data->store = TRUE; + GError *error = NULL; + + gtk_statusbar_push (data->statusbar, data->statusbar_context_id, "Recording..."); + + if (data->running != TRUE) { + data->running = TRUE; + uca_camera_start_recording (data->camera, &error); + + if (!g_thread_create (grab_thread, data, FALSE, &error)) + g_printerr ("Failed to create thread: %s\n", error->message); + } +} + +static void +create_main_window (GtkBuilder *builder, const gchar* camera_name) +{ + static ThreadData td; + + GError *error = NULL; + UcaCamera *camera = uca_plugin_manager_new_camera (plugin_manager, camera_name, &error); + + if ((camera == NULL) || (error != NULL)) { + g_error ("%s\n", error->message); + gtk_main_quit (); + } + + guint bits_per_sample; + g_object_get (camera, + "roi-width", &td.width, + "roi-height", &td.height, + "sensor-bitdepth", &bits_per_sample, + NULL); + + GtkWidget *window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); + GtkWidget *image = GTK_WIDGET (gtk_builder_get_object (builder, "image")); + GtkWidget *property_tree_view = egg_property_tree_view_new (G_OBJECT (camera)); + GtkContainer *scrolled_property_window = GTK_CONTAINER (gtk_builder_get_object (builder, "scrolledwindow2")); + + gtk_container_add (scrolled_property_window, property_tree_view); + gtk_widget_show_all (GTK_WIDGET (scrolled_property_window)); + + GdkPixbuf *pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, td.width, td.height); + gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf); + + td.pixel_size = bits_per_sample > 8 ? 2 : 1; + td.image = image; + td.pixbuf = pixbuf; + td.buffer = (guchar *) g_malloc (td.pixel_size * td.width * td.height); + td.pixels = gdk_pixbuf_get_pixels (pixbuf); + td.running = FALSE; + td.statusbar = GTK_STATUSBAR (gtk_builder_get_object (builder, "statusbar")); + td.statusbar_context_id = gtk_statusbar_get_context_id (td.statusbar, "Recording Information"); + td.store = FALSE; + td.camera = camera; + td.property_model = GTK_TREE_MODEL (gtk_builder_get_object (builder, "camera-properties")); + + g_signal_connect (window, "destroy", G_CALLBACK (on_destroy), &td); + g_signal_connect (gtk_builder_get_object (builder, "toolbutton_run"), + "clicked", G_CALLBACK (on_toolbutton_run_clicked), &td); + g_signal_connect (gtk_builder_get_object (builder, "toolbutton_stop"), + "clicked", G_CALLBACK (on_toolbutton_stop_clicked), &td); + g_signal_connect (gtk_builder_get_object (builder, "toolbutton_record"), + "clicked", G_CALLBACK (on_toolbutton_record_clicked), &td); + + gtk_widget_show (image); + gtk_widget_show (window); +} + +static void +on_button_proceed_clicked (GtkWidget *widget, gpointer data) +{ + GtkBuilder *builder = GTK_BUILDER (data); + GtkWidget *choice_window = GTK_WIDGET (gtk_builder_get_object (builder, "choice-window")); + GtkTreeView *treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder, "treeview-cameras")); + GtkListStore *list_store = GTK_LIST_STORE (gtk_builder_get_object (builder, "camera-types")); + + GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview); + GList *selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL); + GtkTreeIter iter; + + gtk_widget_destroy (choice_window); + gboolean valid = gtk_tree_model_get_iter (GTK_TREE_MODEL (list_store), &iter, selected_rows->data); + + if (valid) { + gchar *data; + gtk_tree_model_get (GTK_TREE_MODEL (list_store), &iter, 0, &data, -1); + create_main_window (builder, data); + g_free (data); + } + + g_list_foreach (selected_rows, (GFunc) gtk_tree_path_free, NULL); + g_list_free (selected_rows); +} + +static void +on_treeview_keypress (GtkWidget *widget, GdkEventKey *event, gpointer data) +{ + if (event->keyval == GDK_KEY_Return) + gtk_widget_grab_focus (GTK_WIDGET (data)); +} + +static void +create_choice_window (GtkBuilder *builder) +{ + GList *camera_types = uca_plugin_manager_get_available_cameras (plugin_manager); + + GtkWidget *choice_window = GTK_WIDGET (gtk_builder_get_object (builder, "choice-window")); + GtkTreeView *treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder, "treeview-cameras")); + GtkListStore *list_store = GTK_LIST_STORE (gtk_builder_get_object (builder, "camera-types")); + GtkButton *proceed_button = GTK_BUTTON (gtk_builder_get_object (builder, "button-proceed")); + GtkTreeIter iter; + + for (GList *it = g_list_first (camera_types); it != NULL; it = g_list_next (it)) { + gtk_list_store_append (list_store, &iter); + gtk_list_store_set (list_store, &iter, 0, g_strdup ((gchar *) it->data), -1); + } + + gboolean valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (list_store), &iter); + + if (valid) { + GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview); + gtk_tree_selection_unselect_all (selection); + gtk_tree_selection_select_path (selection, gtk_tree_model_get_path (GTK_TREE_MODEL (list_store), &iter)); + } + + g_signal_connect (proceed_button, "clicked", G_CALLBACK (on_button_proceed_clicked), builder); + g_signal_connect (treeview, "key-press-event", G_CALLBACK (on_treeview_keypress), proceed_button); + gtk_widget_show_all (GTK_WIDGET (choice_window)); + + g_list_foreach (camera_types, (GFunc) g_free, NULL); + g_list_free (camera_types); +} + +int +main (int argc, char *argv[]) +{ + GError *error = NULL; + + g_thread_init (NULL); + gdk_threads_init (); + gtk_init (&argc, &argv); + + GtkBuilder *builder = gtk_builder_new (); + + if (!gtk_builder_add_from_file (builder, CONTROL_GLADE_PATH, &error)) { + g_print ("Error: %s\n", error->message); + return 1; + } + + plugin_manager = uca_plugin_manager_new (); + create_choice_window (builder); + gtk_builder_connect_signals (builder, NULL); + + gdk_threads_enter (); + gtk_main (); + gdk_threads_leave (); + + g_object_unref (plugin_manager); + return 0; +} -- cgit v1.2.3 From b3dbedeec78a55802565a3824ab52188e8b9bd4d Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang Date: Mon, 8 Oct 2012 14:38:16 +0200 Subject: Generate introspection files Unfortunately, the gir tools recognize anything with $PREFIX_new_$SUFFIX as some kind of constructor. This means that we have to rename uca_plugin_manager_new_camera() to uca_plugin_manager_get_camera(). --- CMakeLists.txt | 1 + NEWS | 2 +- src/CMakeLists.txt | 57 ++++++++++++++++++++++++++++++++++++++++++++++++ src/uca-plugin-manager.c | 13 +++++------ src/uca-plugin-manager.h | 2 +- test/test-mock.c | 4 ++-- tools/benchmark.c | 2 +- tools/gen-doc.c | 2 +- tools/grab-async.c | 2 +- tools/grab.c | 2 +- tools/gui/control.c | 2 +- tools/perf-overhead.c | 2 +- 12 files changed, 74 insertions(+), 17 deletions(-) (limited to 'tools/gui/control.c') diff --git a/CMakeLists.txt b/CMakeLists.txt index bb53b40..bef3712 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,7 @@ set(UCA_ENUM_HDRS ${CMAKE_CURRENT_SOURCE_DIR}/src/uca-camera.h ${CMAKE_CURRENT_SOURCE_DIR}/plugins/pco/uca-pco-camera.h) + # --- Common configuration --------------------------------------------------- configure_file(${CMAKE_CURRENT_SOURCE_DIR}/package.sh.in diff --git a/NEWS b/NEWS index e7c7243..624242b 100644 --- a/NEWS +++ b/NEWS @@ -13,7 +13,7 @@ looks in pre- and user-defined directories for DSOs that match UcaCamera *camera; manager = uca_plugin_manager_new (); - camera = uca_plugin_manager_new_camera (manager, "foo", &error); + camera = uca_plugin_manager_get_camera (manager, "foo", &error); The plugin manager adds a dependency on GModule (pkg-config package `gmodule-2.0`) that is part of GLib. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4bf5820..dd2f464 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -37,6 +37,9 @@ add_custom_command( # --- Configure --------------------------------------------------------------- +find_program(INTROSPECTION_SCANNER "g-ir-scanner") +find_program(INTROSPECTION_COMPILER "g-ir-compiler") + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) @@ -67,7 +70,51 @@ set_target_properties(uca PROPERTIES target_link_libraries(uca ${UCA_DEPS}) +# --- Build introspection files ----------------------------------------------- + +if (INTROSPECTION_SCANNER AND INTROSPECTION_COMPILER) + option(WITH_GIR "Build introspection files" ON) + + if (WITH_GIR) + set(GIR_PREFIX "Uca-${UCA_ABI_VERSION}") + set(GIR_XML "${GIR_PREFIX}.gir") + set(GIR_TYPELIB "${GIR_PREFIX}.typelib") + set(_gir_input) + + foreach(_src ${uca_SRCS} ${uca_HDRS}) + list(APPEND _gir_input "${CMAKE_CURRENT_SOURCE_DIR}/${_src}") + endforeach() + + add_custom_command(OUTPUT ${GIR_XML} + COMMAND ${INTROSPECTION_SCANNER} + --namespace=Uca + --nsversion=${UCA_ABI_VERSION} + --library=uca + --no-libtool + --include=GObject-2.0 + --include=GModule-2.0 + --output ${GIR_XML} + --warn-all + ${_gir_input} + DEPENDS ${uca_SRCS} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + + add_custom_command(OUTPUT ${GIR_TYPELIB} + COMMAND ${INTROSPECTION_COMPILER} + -o ${GIR_TYPELIB} + ${GIR_XML} + DEPENDS ${GIR_XML} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + + add_custom_target(gir ALL DEPENDS ${GIR_XML} ${GIR_TYPELIB}) + add_dependencies(gir uca) + + endif() +endif() + + # --- Build documentation ----------------------------------------------------- + pkg_check_modules(GTK_DOC gtk-doc) if(GTK_DOC_FOUND) @@ -170,6 +217,16 @@ install(FILES ${uca_HDRS} DESTINATION include/uca COMPONENT headers) +if(WITH_GIR) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${GIR_XML} + DESTINATION share/gir-1.0 + COMPONENT libraries) + + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${GIR_TYPELIB} + DESTINATION ${LIB_INSTALL_DIR}/girepository-1.0 + COMPONENT libraries) +endif() + # --- Generate package description -------------------------------------------- diff --git a/src/uca-plugin-manager.c b/src/uca-plugin-manager.c index 5678e83..cb7e518 100644 --- a/src/uca-plugin-manager.c +++ b/src/uca-plugin-manager.c @@ -49,9 +49,7 @@ uca_plugin_manager_error_quark (void) * uca_plugin_manager_new: * @config: (allow-none): A #UcaConfiguration object or %NULL. * - * Create a plugin manager object to instantiate filter objects. When a config - * object is passed to the constructor, its search-path property is added to the - * internal search paths. + * Create a plugin manager object to instantiate camera objects. * * Return value: A new plugin manager object. */ @@ -147,9 +145,10 @@ list_free_full (GList *list) * * @manager: A #UcaPluginManager * - * Return: A list with strings of available camera names. You have to free the - * individual strings with g_list_foreach(list, (GFunc) g_free, NULL) and the - * list itself with g_list_free. + * Returns: (element-type utf8) (transfer full): A list with strings of + * available camera names. You have to free the individual strings with + * g_list_foreach(list, (GFunc) g_free, NULL) and the list itself with + * g_list_free. */ GList * uca_plugin_manager_get_available_cameras (UcaPluginManager *manager) @@ -201,7 +200,7 @@ find_camera_module_path (GList *search_paths, const gchar *name) * @error: Location for a #GError */ UcaCamera * -uca_plugin_manager_new_camera (UcaPluginManager *manager, +uca_plugin_manager_get_camera (UcaPluginManager *manager, const gchar *name, GError **error) { diff --git a/src/uca-plugin-manager.h b/src/uca-plugin-manager.h index 9291857..6c3ab4e 100644 --- a/src/uca-plugin-manager.h +++ b/src/uca-plugin-manager.h @@ -55,7 +55,7 @@ void uca_plugin_manager_add_path (UcaPluginManager *manager const gchar *path); GList *uca_plugin_manager_get_available_cameras (UcaPluginManager *manager); -UcaCamera *uca_plugin_manager_new_camera (UcaPluginManager *manager, +UcaCamera *uca_plugin_manager_get_camera (UcaPluginManager *manager, const gchar *name, GError **error); GType uca_plugin_manager_get_type (void); diff --git a/test/test-mock.c b/test/test-mock.c index ca16c59..711364d 100644 --- a/test/test-mock.c +++ b/test/test-mock.c @@ -16,7 +16,7 @@ fixture_setup (Fixture *fixture, gconstpointer data) fixture->manager = uca_plugin_manager_new (); uca_plugin_manager_add_path (fixture->manager, "./src"); - fixture->camera = uca_plugin_manager_new_camera (fixture->manager, "mock", &error); + fixture->camera = uca_plugin_manager_get_camera (fixture->manager, "mock", &error); g_assert (error == NULL); g_assert (fixture->camera); } @@ -39,7 +39,7 @@ static void test_factory (Fixture *fixture, gconstpointer data) { GError *error = NULL; - UcaCamera *camera = uca_plugin_manager_new_camera (fixture->manager, "fox994m3a0yxmy", &error); + UcaCamera *camera = uca_plugin_manager_get_camera (fixture->manager, "fox994m3a0yxmy", &error); g_assert_error (error, UCA_PLUGIN_MANAGER_ERROR, UCA_PLUGIN_MANAGER_ERROR_MODULE_NOT_FOUND); g_assert (camera == NULL); } diff --git a/tools/benchmark.c b/tools/benchmark.c index ef99fd1..bff8b50 100644 --- a/tools/benchmark.c +++ b/tools/benchmark.c @@ -250,7 +250,7 @@ main (int argc, char *argv[]) g_log_set_handler (NULL, G_LOG_LEVEL_MASK, log_handler, log_channel); manager = uca_plugin_manager_new (); - camera = uca_plugin_manager_new_camera (manager, argv[1], &error); + camera = uca_plugin_manager_get_camera (manager, argv[1], &error); if (camera == NULL) { g_error ("Initialization: %s", error->message); diff --git a/tools/gen-doc.c b/tools/gen-doc.c index 86d6ff9..f555a5f 100644 --- a/tools/gen-doc.c +++ b/tools/gen-doc.c @@ -136,7 +136,7 @@ int main(int argc, char *argv[]) } else { name = argv[1]; - camera = uca_plugin_manager_new_camera (manager, name, &error); + camera = uca_plugin_manager_get_camera (manager, name, &error); } if (camera == NULL) { diff --git a/tools/grab-async.c b/tools/grab-async.c index 6132829..2c4bf04 100644 --- a/tools/grab-async.c +++ b/tools/grab-async.c @@ -94,7 +94,7 @@ main(int argc, char *argv[]) } manager = uca_plugin_manager_new (); - camera = uca_plugin_manager_new_camera (manager, argv[1], &error); + camera = uca_plugin_manager_get_camera (manager, argv[1], &error); if (camera == NULL) { g_print("Error during initialization: %s\n", error->message); diff --git a/tools/grab.c b/tools/grab.c index 1f5c917..1518997 100644 --- a/tools/grab.c +++ b/tools/grab.c @@ -75,7 +75,7 @@ int main(int argc, char *argv[]) } manager = uca_plugin_manager_new (); - camera = uca_plugin_manager_new_camera (manager, argv[1], &error); + camera = uca_plugin_manager_get_camera (manager, argv[1], &error); if (camera == NULL) { g_print("Error during initialization: %s\n", error->message); diff --git a/tools/gui/control.c b/tools/gui/control.c index 75b3cde..178c809 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -207,7 +207,7 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) static ThreadData td; GError *error = NULL; - UcaCamera *camera = uca_plugin_manager_new_camera (plugin_manager, camera_name, &error); + UcaCamera *camera = uca_plugin_manager_get_camera (plugin_manager, camera_name, &error); if ((camera == NULL) || (error != NULL)) { g_error ("%s\n", error->message); diff --git a/tools/perf-overhead.c b/tools/perf-overhead.c index f8bdcbd..6735e6f 100644 --- a/tools/perf-overhead.c +++ b/tools/perf-overhead.c @@ -163,7 +163,7 @@ main (int argc, char *argv[]) } manager = uca_plugin_manager_new (); - camera = uca_plugin_manager_new_camera (manager, argv[1], &error); + camera = uca_plugin_manager_get_camera (manager, argv[1], &error); if (camera == NULL) { g_print ("Error during initialization: %s\n", error->message); -- cgit v1.2.3 From 0badcd14dc0ba8b3b6894be035237b846e3fb0e6 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang Date: Tue, 9 Oct 2012 16:52:17 +0200 Subject: Remove unneccessary variable --- tools/gui/control.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'tools/gui/control.c') diff --git a/tools/gui/control.c b/tools/gui/control.c index 178c809..89e932a 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -37,7 +37,6 @@ typedef struct { guchar *buffer, *pixels; GdkPixbuf *pixbuf; GtkWidget *image; - GtkTreeModel *property_model; UcaCamera *camera; GtkStatusbar *statusbar; @@ -242,7 +241,6 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) td.statusbar_context_id = gtk_statusbar_get_context_id (td.statusbar, "Recording Information"); td.store = FALSE; td.camera = camera; - td.property_model = GTK_TREE_MODEL (gtk_builder_get_object (builder, "camera-properties")); g_signal_connect (window, "destroy", G_CALLBACK (on_destroy), &td); g_signal_connect (gtk_builder_get_object (builder, "toolbutton_run"), -- cgit v1.2.3 From 46a6d028c5591b0775ef5862ff5c9e95fd68e7fd Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang Date: Wed, 10 Oct 2012 10:20:08 +0200 Subject: (De-) activate tool buttons according to state --- tools/gui/control.c | 99 +++++++++++++++++++++++++++---------------------- tools/gui/control.glade | 20 +++------- 2 files changed, 59 insertions(+), 60 deletions(-) (limited to 'tools/gui/control.c') diff --git a/tools/gui/control.c b/tools/gui/control.c index 89e932a..f7d3618 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -31,21 +31,22 @@ typedef struct { - gboolean running; - gboolean store; - - guchar *buffer, *pixels; - GdkPixbuf *pixbuf; - GtkWidget *image; - UcaCamera *camera; - - GtkStatusbar *statusbar; - guint statusbar_context_id; - - int timestamp; - int width; - int height; - int pixel_size; + UcaCamera *camera; + GdkPixbuf *pixbuf; + GtkWidget *image; + GtkWidget *start_button; + GtkWidget *stop_button; + GtkWidget *record_button; + + guchar *buffer; + guchar *pixels; + gboolean running; + gboolean store; + + int timestamp; + int width; + int height; + int pixel_size; } ThreadData; enum { @@ -145,16 +146,22 @@ on_destroy (GtkWidget *widget, gpointer data) } static void -on_toolbutton_run_clicked (GtkWidget *widget, gpointer args) +set_tool_button_state (ThreadData *data) { - ThreadData *data = (ThreadData *) args; - - if (data->running) - return; + gtk_widget_set_sensitive (data->start_button, !data->running); + gtk_widget_set_sensitive (data->stop_button, data->running); + gtk_widget_set_sensitive (data->record_button, !data->running); +} +static void +on_start_button_clicked (GtkWidget *widget, gpointer args) +{ + ThreadData *data = (ThreadData *) args; GError *error = NULL; + data->running = TRUE; + set_tool_button_state (data); uca_camera_start_recording (data->camera, &error); if (error != NULL) { @@ -169,12 +176,15 @@ on_toolbutton_run_clicked (GtkWidget *widget, gpointer args) } static void -on_toolbutton_stop_clicked (GtkWidget *widget, gpointer args) +on_stop_button_clicked (GtkWidget *widget, gpointer args) { ThreadData *data = (ThreadData *) args; + GError *error = NULL; + data->running = FALSE; data->store = FALSE; - GError *error = NULL; + + set_tool_button_state (data); uca_camera_stop_recording (data->camera, &error); if (error != NULL) @@ -182,22 +192,20 @@ on_toolbutton_stop_clicked (GtkWidget *widget, gpointer args) } static void -on_toolbutton_record_clicked (GtkWidget *widget, gpointer args) +on_record_button_clicked (GtkWidget *widget, gpointer args) { ThreadData *data = (ThreadData *) args; - data->timestamp = (int) time (0); - data->store = TRUE; GError *error = NULL; - gtk_statusbar_push (data->statusbar, data->statusbar_context_id, "Recording..."); + data->timestamp = (int) time (0); + data->store = TRUE; + data->running = TRUE; - if (data->running != TRUE) { - data->running = TRUE; - uca_camera_start_recording (data->camera, &error); + set_tool_button_state (data); + uca_camera_start_recording (data->camera, &error); - if (!g_thread_create (grab_thread, data, FALSE, &error)) - g_printerr ("Failed to create thread: %s\n", error->message); - } + if (!g_thread_create (grab_thread, data, FALSE, &error)) + g_printerr ("Failed to create thread: %s\n", error->message); } static void @@ -215,10 +223,10 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) guint bits_per_sample; g_object_get (camera, - "roi-width", &td.width, - "roi-height", &td.height, - "sensor-bitdepth", &bits_per_sample, - NULL); + "roi-width", &td.width, + "roi-height", &td.height, + "sensor-bitdepth", &bits_per_sample, + NULL); GtkWidget *window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); GtkWidget *image = GTK_WIDGET (gtk_builder_get_object (builder, "image")); @@ -237,18 +245,19 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) td.buffer = (guchar *) g_malloc (td.pixel_size * td.width * td.height); td.pixels = gdk_pixbuf_get_pixels (pixbuf); td.running = FALSE; - td.statusbar = GTK_STATUSBAR (gtk_builder_get_object (builder, "statusbar")); - td.statusbar_context_id = gtk_statusbar_get_context_id (td.statusbar, "Recording Information"); td.store = FALSE; td.camera = camera; g_signal_connect (window, "destroy", G_CALLBACK (on_destroy), &td); - g_signal_connect (gtk_builder_get_object (builder, "toolbutton_run"), - "clicked", G_CALLBACK (on_toolbutton_run_clicked), &td); - g_signal_connect (gtk_builder_get_object (builder, "toolbutton_stop"), - "clicked", G_CALLBACK (on_toolbutton_stop_clicked), &td); - g_signal_connect (gtk_builder_get_object (builder, "toolbutton_record"), - "clicked", G_CALLBACK (on_toolbutton_record_clicked), &td); + + td.start_button = GTK_WIDGET (gtk_builder_get_object (builder, "start-button")); + td.stop_button = GTK_WIDGET (gtk_builder_get_object (builder, "stop-button")); + td.record_button = GTK_WIDGET (gtk_builder_get_object (builder, "record-button")); + set_tool_button_state (&td); + + g_signal_connect (td.start_button, "clicked", G_CALLBACK (on_start_button_clicked), &td); + g_signal_connect (td.stop_button, "clicked", G_CALLBACK (on_stop_button_clicked), &td); + g_signal_connect (td.record_button, "clicked", G_CALLBACK (on_record_button_clicked), &td); gtk_widget_show (image); gtk_widget_show (window); @@ -295,7 +304,7 @@ create_choice_window (GtkBuilder *builder) GtkWidget *choice_window = GTK_WIDGET (gtk_builder_get_object (builder, "choice-window")); GtkTreeView *treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder, "treeview-cameras")); GtkListStore *list_store = GTK_LIST_STORE (gtk_builder_get_object (builder, "camera-types")); - GtkButton *proceed_button = GTK_BUTTON (gtk_builder_get_object (builder, "button-proceed")); + GtkButton *proceed_button = GTK_BUTTON (gtk_builder_get_object (builder, "proceed-button")); GtkTreeIter iter; for (GList *it = g_list_first (camera_types); it != NULL; it = g_list_next (it)) { diff --git a/tools/gui/control.glade b/tools/gui/control.glade index ad5a91f..ee888e8 100644 --- a/tools/gui/control.glade +++ b/tools/gui/control.glade @@ -117,7 +117,7 @@ True - + True Run True @@ -129,7 +129,7 @@ - + True Record True @@ -141,7 +141,7 @@ - + True Stop True @@ -208,16 +208,6 @@ 2 - - - True - 2 - - - False - 3 - - @@ -271,7 +261,7 @@ 6 end - + gtk-quit True True @@ -286,7 +276,7 @@ - + gtk-ok True True -- cgit v1.2.3 From 95a22bf2f02ad11c2602df5ac5ffd04fee93588c Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang Date: Wed, 10 Oct 2012 17:44:34 +0200 Subject: Implement experimental histogram view --- plugins/mock/uca-mock-camera.c | 4 - plugins/pf/uca-pf-camera.c | 1 + src/uca-camera.c | 10 +- tools/gui/control.c | 47 ++++--- tools/gui/control.glade | 75 ++++++++-- tools/gui/egg-histogram-view.c | 301 +++++++++++++++++++++++++++++++++++++++-- tools/gui/egg-histogram-view.h | 5 + 7 files changed, 400 insertions(+), 43 deletions(-) (limited to 'tools/gui/control.c') diff --git a/plugins/mock/uca-mock-camera.c b/plugins/mock/uca-mock-camera.c index 7ab1d4a..65c4240 100644 --- a/plugins/mock/uca-mock-camera.c +++ b/plugins/mock/uca-mock-camera.c @@ -37,7 +37,6 @@ static const gint mock_overrideables[] = { PROP_SENSOR_HORIZONTAL_BINNINGS, PROP_SENSOR_VERTICAL_BINNING, PROP_SENSOR_VERTICAL_BINNINGS, - PROP_TRIGGER_MODE, PROP_EXPOSURE_TIME, PROP_ROI_X, PROP_ROI_Y, @@ -301,9 +300,6 @@ static void uca_mock_camera_get_property(GObject *object, guint property_id, GVa case PROP_EXPOSURE_TIME: g_value_set_double(value, priv->exposure_time); break; - case PROP_TRIGGER_MODE: - g_value_set_enum(value, UCA_CAMERA_TRIGGER_AUTO); - break; case PROP_ROI_X: g_value_set_uint(value, priv->roi_x); break; diff --git a/plugins/pf/uca-pf-camera.c b/plugins/pf/uca-pf-camera.c index 35b5edd..473ffd3 100644 --- a/plugins/pf/uca-pf-camera.c +++ b/plugins/pf/uca-pf-camera.c @@ -234,6 +234,7 @@ static void uca_pf_camera_get_property(GObject *object, guint property_id, GValu g_value_set_boolean(value, FALSE); break; case PROP_EXPOSURE_TIME: + g_value_set_double(value, 1. / 488.0); break; case PROP_ROI_X: g_value_set_uint(value, 0); diff --git a/src/uca-camera.c b/src/uca-camera.c index 6d92e6a..5684888 100644 --- a/src/uca-camera.c +++ b/src/uca-camera.c @@ -132,15 +132,19 @@ uca_camera_get_property(GObject *object, guint property_id, GValue *value, GPara switch (property_id) { case PROP_IS_RECORDING: - g_value_set_boolean(value, priv->is_recording); + g_value_set_boolean (value, priv->is_recording); break; case PROP_IS_READOUT: - g_value_set_boolean(value, priv->is_readout); + g_value_set_boolean (value, priv->is_readout); break; case PROP_TRANSFER_ASYNCHRONOUSLY: - g_value_set_boolean(value, priv->transfer_async); + g_value_set_boolean (value, priv->transfer_async); + break; + + case PROP_TRIGGER_MODE: + g_value_set_enum (value, UCA_CAMERA_TRIGGER_AUTO); break; case PROP_FRAMES_PER_SECOND: diff --git a/tools/gui/control.c b/tools/gui/control.c index f7d3618..b36d188 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -28,6 +28,7 @@ #include "uca-camera.h" #include "uca-plugin-manager.h" #include "egg-property-tree-view.h" +#include "egg-histogram-view.h" typedef struct { @@ -37,6 +38,8 @@ typedef struct { GtkWidget *start_button; GtkWidget *stop_button; GtkWidget *record_button; + GtkWidget *histogram_view; + GtkToggleButton *histogram_button; guchar *buffer; guchar *pixels; @@ -49,15 +52,9 @@ typedef struct { int pixel_size; } ThreadData; -enum { - COLUMN_NAME = 0, - COLUMN_VALUE, - COLUMN_EDITABLE, - NUM_COLUMNS -}; - static UcaPluginManager *plugin_manager; + static void convert_8bit_to_rgb (guchar *output, guchar *input, int width, int height) { @@ -106,7 +103,7 @@ grab_thread (void *args) uca_camera_grab (data->camera, (gpointer) &data->buffer, NULL); if (data->store) { - snprintf (filename, FILENAME_MAX, "frame-%i-%08i.raw", data->timestamp, counter++); + snprintf (filename, FILENAME_MAX, "frame-%i-%08i.raw", data->timestamp, counter); FILE *fp = fopen (filename, "wb"); fwrite (data->buffer, data->width*data->height, data->pixel_size, fp); fclose (fp); @@ -121,11 +118,18 @@ grab_thread (void *args) } gdk_threads_enter (); + gdk_flush (); gtk_image_clear (GTK_IMAGE (data->image)); gtk_image_set_from_pixbuf (GTK_IMAGE (data->image), data->pixbuf); gtk_widget_queue_draw_area (data->image, 0, 0, data->width, data->height); + + if (gtk_toggle_button_get_active (data->histogram_button)) + gtk_widget_queue_draw (data->histogram_view); + gdk_threads_leave (); + + counter++; } return NULL; } @@ -211,6 +215,12 @@ on_record_button_clicked (GtkWidget *widget, gpointer args) static void create_main_window (GtkBuilder *builder, const gchar* camera_name) { + GtkWidget *window; + GtkWidget *image; + GtkWidget *property_tree_view; + GdkPixbuf *pixbuf; + GtkBox *histogram_box; + GtkContainer *scrolled_property_window; static ThreadData td; GError *error = NULL; @@ -228,15 +238,12 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) "sensor-bitdepth", &bits_per_sample, NULL); - GtkWidget *window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); - GtkWidget *image = GTK_WIDGET (gtk_builder_get_object (builder, "image")); - GtkWidget *property_tree_view = egg_property_tree_view_new (G_OBJECT (camera)); - GtkContainer *scrolled_property_window = GTK_CONTAINER (gtk_builder_get_object (builder, "scrolledwindow2")); - + property_tree_view = egg_property_tree_view_new (G_OBJECT (camera)); + scrolled_property_window = GTK_CONTAINER (gtk_builder_get_object (builder, "scrolledwindow2")); gtk_container_add (scrolled_property_window, property_tree_view); - gtk_widget_show_all (GTK_WIDGET (scrolled_property_window)); - GdkPixbuf *pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, td.width, td.height); + image = GTK_WIDGET (gtk_builder_get_object (builder, "image")); + pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, td.width, td.height); gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf); td.pixel_size = bits_per_sample > 8 ? 2 : 1; @@ -247,7 +254,14 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) td.running = FALSE; td.store = FALSE; td.camera = camera; + td.histogram_view = egg_histogram_view_new (); + td.histogram_button = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "histogram-checkbutton")); + + histogram_box = GTK_BOX (gtk_builder_get_object (builder, "histogram-box")); + gtk_box_pack_start (histogram_box, td.histogram_view, TRUE, TRUE, 6); + egg_histogram_view_set_data (EGG_HISTOGRAM_VIEW (td.histogram_view), td.buffer, td.width * td.height, bits_per_sample, 256); + window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); g_signal_connect (window, "destroy", G_CALLBACK (on_destroy), &td); td.start_button = GTK_WIDGET (gtk_builder_get_object (builder, "start-button")); @@ -259,8 +273,7 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) g_signal_connect (td.stop_button, "clicked", G_CALLBACK (on_stop_button_clicked), &td); g_signal_connect (td.record_button, "clicked", G_CALLBACK (on_record_button_clicked), &td); - gtk_widget_show (image); - gtk_widget_show (window); + gtk_widget_show_all (window); } static void diff --git a/tools/gui/control.glade b/tools/gui/control.glade index ee888e8..6d6d791 100644 --- a/tools/gui/control.glade +++ b/tools/gui/control.glade @@ -164,28 +164,83 @@ True 6 - - 300 + True True - automatic - automatic - + + 640 + 480 True - queue + True + automatic + automatic - + True - gtk-missing-image + queue + + + 640 + 480 + True + gtk-missing-image + + + + True + True + + + + + True + True + + + True + + + + + + Enable Live Update + True + True + False + 6 + True + True + + + end + 1 + + + + + + + True + Histogram + + + False + + + + + True + True + - True - False + False + True diff --git a/tools/gui/egg-histogram-view.c b/tools/gui/egg-histogram-view.c index 809a2d9..d3cb18b 100644 --- a/tools/gui/egg-histogram-view.c +++ b/tools/gui/egg-histogram-view.c @@ -15,17 +15,33 @@ with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA */ -#include +#include #include "egg-histogram-view.h" -G_DEFINE_TYPE (EggHistogramView, egg_histogram_view, GTK_TYPE_CELL_RENDERER) +G_DEFINE_TYPE (EggHistogramView, egg_histogram_view, GTK_TYPE_DRAWING_AREA) #define EGG_HISTOGRAM_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), EGG_TYPE_HISTOGRAM_VIEW, EggHistogramViewPrivate)) +#define MIN_WIDTH 128 +#define MIN_HEIGHT 128 +#define BORDER 2 struct _EggHistogramViewPrivate { - guint foo; + GdkCursorType cursor_type; + gboolean grabbing; + + /* This could be moved into a real histogram class */ + guint n_bins; + gint *bins; + gint min_value; + gint max_value; + gint min_border; + gint max_border; + + gpointer data; + gint n_elements; + gint n_bits; }; enum @@ -46,9 +62,178 @@ egg_histogram_view_new (void) return GTK_WIDGET (view); } +void +egg_histogram_view_set_data (EggHistogramView *view, + gpointer data, + guint n_elements, + guint n_bits, + guint n_bins) +{ + EggHistogramViewPrivate *priv; + + priv = view->priv; + + if (priv->bins != NULL) + g_free (priv->bins); + + priv->data = data; + priv->bins = g_malloc0 (n_bins * sizeof (guint)); + priv->n_bins = n_bins; + priv->n_bits = n_bits; + priv->n_elements = n_elements; + + priv->min_value = 0; + priv->max_value = (gint) pow(2, n_bits) - 1; + + priv->min_border = 20; + priv->max_border = priv->max_value - 20; +} + +static void +compute_histogram (EggHistogramViewPrivate *priv) +{ + for (guint i = 0; i < priv->n_bins; i++) + priv->bins[i] = 0; + + if (priv->n_bits == 8) { + guint8 *data = (guint8 *) priv->data; + + for (guint i = 0; i < priv->n_elements; i++) { + guint8 v = data[i]; + guint index = (guint) round (((gdouble) v) / priv->max_value * (priv->n_bins - 1)); + priv->bins[index]++; + } + } + else if (priv->n_bits == 16) { + guint16 *data = (guint16 *) priv->data; + + for (guint i = 0; i < priv->n_elements; i++) { + guint16 v = data[i]; + guint index = (guint) floor (((gdouble ) v) / priv->max_value * (priv->n_bins - 1)); + priv->bins[index]++; + } + } + else + g_warning ("%i number of bits unsupported", priv->n_bits); +} + +static void +set_cursor_type (EggHistogramView *view, GdkCursorType cursor_type) +{ + if (cursor_type != view->priv->cursor_type) { + GdkCursor *cursor = gdk_cursor_new (cursor_type); + + gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET(view)), cursor); + gdk_cursor_unref (cursor); + view->priv->cursor_type = cursor_type; + } +} + +static void +egg_histogram_view_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + requisition->width = MIN_WIDTH; + requisition->height = MIN_HEIGHT; +} + +static gboolean +egg_histogram_view_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + EggHistogramViewPrivate *priv; + GtkAllocation allocation; + GtkStyle *style; + cairo_t *cr; + gint width, height; + gint max_value = 0; + + priv = EGG_HISTOGRAM_VIEW_GET_PRIVATE (widget); + cr = gdk_cairo_create (gtk_widget_get_window (widget)); + + gdk_cairo_region (cr, event->region); + cairo_clip (cr); + + style = gtk_widget_get_style (widget); + gdk_cairo_set_source_color (cr, &style->base[GTK_STATE_NORMAL]); + cairo_paint (cr); + + /* Draw the background */ + gdk_cairo_set_source_color (cr, &style->base[GTK_STATE_NORMAL]); + cairo_paint (cr); + + gtk_widget_get_allocation (widget, &allocation); + width = allocation.width - 2 * BORDER; + height = allocation.height - 2 * BORDER; + + gdk_cairo_set_source_color (cr, &style->dark[GTK_STATE_NORMAL]); + cairo_set_line_width (cr, 1.0); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); + cairo_translate (cr, 0.5, 0.5); + cairo_rectangle (cr, BORDER, BORDER, width - 1, height - 1); + cairo_stroke (cr); + + if (priv->bins == NULL) + goto cleanup; + + compute_histogram (priv); + + /* Draw border areas */ + gdk_cairo_set_source_color (cr, &style->dark[GTK_STATE_NORMAL]); + + if (priv->min_border > 0) { + cairo_rectangle (cr, BORDER, BORDER, priv->min_border + 0.5, height - 1); + cairo_fill (cr); + } + + /* Draw spikes */ + for (guint i = 0; i < priv->n_bins; i++) { + if (priv->bins[i] > max_value) + max_value = priv->bins[i]; + } + + if (max_value == 0) + goto cleanup; + + gdk_cairo_set_source_color (cr, &style->black); + + if (width > priv->n_bins) { + gdouble skip = ((gdouble) width) / priv->n_bins; + gdouble x = 1; + + for (guint i = 0; i < priv->n_bins; i++, x += skip) { + if (priv->bins[i] == 0) + continue; + + gint y = (gint) ((height - 2) * priv->bins[i]) / max_value; + cairo_move_to (cr, round (x + BORDER), height + BORDER - 1); + cairo_line_to (cr, round (x + BORDER), height + BORDER - 1 - y); + cairo_stroke (cr); + } + } + +cleanup: + cairo_destroy (cr); + return FALSE; +} + +static void +egg_histogram_view_finalize (GObject *object) +{ + EggHistogramViewPrivate *priv; + + priv = EGG_HISTOGRAM_VIEW_GET_PRIVATE (object); + + if (priv->bins) + g_free (priv->bins); + + G_OBJECT_CLASS (egg_histogram_view_parent_class)->finalize (object); +} + static void egg_histogram_view_dispose (GObject *object) { + G_OBJECT_CLASS (egg_histogram_view_parent_class)->dispose (object); } static void @@ -81,20 +266,118 @@ egg_histogram_view_get_property (GObject *object, } } +static gint +get_mouse_distance (EggHistogramViewPrivate *priv, + gint x) +{ + return (priv->min_border + BORDER) - x; +} + +static gboolean +egg_histogram_view_motion_notify (GtkWidget *widget, + GdkEventMotion *event) +{ + EggHistogramView *view; + EggHistogramViewPrivate *priv; + + view = EGG_HISTOGRAM_VIEW (widget); + priv = view->priv; + + if (priv->grabbing) { + priv->min_border = event->x + BORDER; + gtk_widget_queue_draw (widget); + } + else { + gint distance = get_mouse_distance (priv, event->x); + + if (ABS(distance) < 6) + set_cursor_type (view, GDK_FLEUR); + else + set_cursor_type (view, GDK_ARROW); + } + + return TRUE; +} + +static gboolean +egg_histogram_view_button_release (GtkWidget *widget, + GdkEventButton *event) +{ + EggHistogramView *view; + EggHistogramViewPrivate *priv; + GtkAllocation allocation; + gint width; + + gtk_widget_get_allocation (widget, &allocation); + width = allocation.width - 2 * BORDER; + + view = EGG_HISTOGRAM_VIEW (widget); + priv = view->priv; + + set_cursor_type (view, GDK_ARROW); + priv->grabbing = FALSE; + + return TRUE; +} + +static gboolean +egg_histogram_view_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + EggHistogramView *view; + EggHistogramViewPrivate *priv; + gint distance; + + view = EGG_HISTOGRAM_VIEW (widget); + priv = view->priv; + distance = get_mouse_distance (priv, event->x); + + if (ABS (distance) < 6) { + priv->grabbing = TRUE; + set_cursor_type (view, GDK_FLEUR); + } + + return TRUE; +} + static void egg_histogram_view_class_init (EggHistogramViewClass *klass) { - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - gobject_class->set_property = egg_histogram_view_set_property; - gobject_class->get_property = egg_histogram_view_get_property; - gobject_class->dispose = egg_histogram_view_dispose; + object_class->set_property = egg_histogram_view_set_property; + object_class->get_property = egg_histogram_view_get_property; + object_class->dispose = egg_histogram_view_dispose; + object_class->finalize = egg_histogram_view_finalize; + + widget_class->size_request = egg_histogram_view_size_request; + widget_class->expose_event = egg_histogram_view_expose; + widget_class->button_press_event = egg_histogram_view_button_press; + widget_class->button_release_event = egg_histogram_view_button_release; + widget_class->motion_notify_event = egg_histogram_view_motion_notify; g_type_class_add_private (klass, sizeof (EggHistogramViewPrivate)); } static void -egg_histogram_view_init (EggHistogramView *renderer) +egg_histogram_view_init (EggHistogramView *view) { - renderer->priv = EGG_HISTOGRAM_VIEW_GET_PRIVATE (renderer); + EggHistogramViewPrivate *priv; + + view->priv = priv = EGG_HISTOGRAM_VIEW_GET_PRIVATE (view); + + priv->bins = NULL; + priv->data = NULL; + priv->n_bins = 0; + priv->n_elements = 0; + + priv->cursor_type = GDK_ARROW; + priv->grabbing = FALSE; + + gtk_widget_add_events (GTK_WIDGET (view), + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_BUTTON1_MOTION_MASK | + GDK_POINTER_MOTION_MASK); } diff --git a/tools/gui/egg-histogram-view.h b/tools/gui/egg-histogram-view.h index 23581dc..a1df0ba 100644 --- a/tools/gui/egg-histogram-view.h +++ b/tools/gui/egg-histogram-view.h @@ -48,6 +48,11 @@ struct _EggHistogramViewClass GType egg_histogram_view_get_type (void); GtkWidget * egg_histogram_view_new (void); +void egg_histogram_view_set_data (EggHistogramView *view, + gpointer data, + guint n_elements, + guint n_bits, + guint n_bins); G_END_DECLS -- cgit v1.2.3 From 13b2833ea9c16750efb923a981ea04d37aaa6789 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang Date: Thu, 11 Oct 2012 16:38:26 +0200 Subject: Implement adjustable histogram --- src/uca-camera.c | 2 +- tools/gui/control.c | 70 ++++++------ tools/gui/control.glade | 112 +++++++++++++++++--- tools/gui/egg-histogram-view.c | 234 +++++++++++++++++++++++++++++++---------- tools/gui/egg-histogram-view.h | 4 + 5 files changed, 316 insertions(+), 106 deletions(-) (limited to 'tools/gui/control.c') diff --git a/src/uca-camera.c b/src/uca-camera.c index 5684888..091ef54 100644 --- a/src/uca-camera.c +++ b/src/uca-camera.c @@ -128,7 +128,7 @@ uca_camera_set_property (GObject *object, guint property_id, const GValue *value static void uca_camera_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { - UcaCameraPrivate *priv = UCA_CAMERA_GET_PRIVATE(object); + UcaCameraPrivate *priv = UCA_CAMERA_GET_PRIVATE (object); switch (property_id) { case PROP_IS_RECORDING: diff --git a/tools/gui/control.c b/tools/gui/control.c index b36d188..214e4da 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -19,10 +19,7 @@ #include #include #include -#include -#include -#include -#include +#include #include "config.h" #include "uca-camera.h" @@ -56,39 +53,28 @@ static UcaPluginManager *plugin_manager; static void -convert_8bit_to_rgb (guchar *output, guchar *input, int width, int height) +convert_8bit_to_rgb (guchar *output, guchar *input, gint width, gint height, gdouble min, gdouble max) { + gdouble factor = 255.0 / (max - min); + for (int i = 0, j = 0; i < width*height; i++) { - output[j++] = input[i]; - output[j++] = input[i]; - output[j++] = input[i]; + guchar val = (guchar) ((input[i] - min) * factor); + output[j++] = val; + output[j++] = val; + output[j++] = val; } } static void -convert_16bit_to_rgb (guchar *output, guchar *input, int width, int height) +convert_16bit_to_rgb (guchar *output, guchar *input, gint width, gint height, gdouble min, gdouble max) { - guint16 *in = (guint16 *) input; - guint16 min = G_MAXUINT16, max = 0; - gfloat spread = 0.0f; - - for (int i = 0; i < width * height; i++) { - guint16 v = in[i]; - if (v < min) - min = v; - if (v > max) - max = v; - } - - spread = (gfloat) max - min; + gdouble factor = 255.0 / (max - min); - if (spread > 0.0f) { - for (int i = 0, j = 0; i < width*height; i++) { - guchar val = (guint8) (((in[i] - min) / spread) * 255.0f); - output[j++] = val; - output[j++] = val; - output[j++] = val; - } + for (int i = 0, j = 0; i < width*height; i++) { + guchar val = (guint8) ((input[i] - min) * factor); + output[j++] = val; + output[j++] = val; + output[j++] = val; } } @@ -100,6 +86,9 @@ grab_thread (void *args) gint counter = 0; while (data->running) { + gdouble min_value; + gdouble max_value; + uca_camera_grab (data->camera, (gpointer) &data->buffer, NULL); if (data->store) { @@ -111,11 +100,12 @@ grab_thread (void *args) /* FIXME: We should actually check if this is really a new frame and * just do nothing if it is an already displayed one. */ + egg_histogram_get_visible_range (EGG_HISTOGRAM_VIEW (data->histogram_view), &min_value, &max_value); + if (data->pixel_size == 1) - convert_8bit_to_rgb (data->pixels, data->buffer, data->width, data->height); - else if (data->pixel_size == 2) { - convert_16bit_to_rgb (data->pixels, data->buffer, data->width, data->height); - } + convert_8bit_to_rgb (data->pixels, data->buffer, data->width, data->height, min_value, max_value); + else if (data->pixel_size == 2) + convert_16bit_to_rgb (data->pixels, data->buffer, data->width, data->height, min_value, max_value); gdk_threads_enter (); @@ -221,6 +211,7 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) GdkPixbuf *pixbuf; GtkBox *histogram_box; GtkContainer *scrolled_property_window; + GtkAdjustment *max_bin_adjustment; static ThreadData td; GError *error = NULL; @@ -259,7 +250,8 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) histogram_box = GTK_BOX (gtk_builder_get_object (builder, "histogram-box")); gtk_box_pack_start (histogram_box, td.histogram_view, TRUE, TRUE, 6); - egg_histogram_view_set_data (EGG_HISTOGRAM_VIEW (td.histogram_view), td.buffer, td.width * td.height, bits_per_sample, 256); + egg_histogram_view_set_data (EGG_HISTOGRAM_VIEW (td.histogram_view), + td.buffer, td.width * td.height, bits_per_sample, 256); window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); g_signal_connect (window, "destroy", G_CALLBACK (on_destroy), &td); @@ -269,6 +261,16 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) td.record_button = GTK_WIDGET (gtk_builder_get_object (builder, "record-button")); set_tool_button_state (&td); + g_object_bind_property (gtk_builder_get_object (builder, "min_bin_value_adjustment"), "value", + td.histogram_view, "minimum-bin-value", + G_BINDING_DEFAULT); + + max_bin_adjustment = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "max_bin_value_adjustment")); + gtk_adjustment_set_value (max_bin_adjustment, pow (2, bits_per_sample) - 1); + g_object_bind_property (max_bin_adjustment, "value", + td.histogram_view, "maximum-bin-value", + G_BINDING_DEFAULT); + g_signal_connect (td.start_button, "clicked", G_CALLBACK (on_start_button_clicked), &td); g_signal_connect (td.stop_button, "clicked", G_CALLBACK (on_stop_button_clicked), &td); g_signal_connect (td.record_button, "clicked", G_CALLBACK (on_record_button_clicked), &td); diff --git a/tools/gui/control.glade b/tools/gui/control.glade index 7ef712d..ebe2cc8 100644 --- a/tools/gui/control.glade +++ b/tools/gui/control.glade @@ -204,17 +204,97 @@ - - Enable Live Update + True - True - False 6 - True - True + 3 + 2 + 6 + 6 + + + True + 1 + Minimum Value: + + + GTK_FILL + + 6 + 6 + + + + + 100 + True + True + + min_bin_value_adjustment + + + 1 + 2 + GTK_EXPAND + + + + + + True + 1 + Maximum Value: + + + 1 + 2 + GTK_FILL + + 6 + 6 + + + + + 100 + True + True + + max_bin_value_adjustment + + + 1 + 2 + 1 + 2 + GTK_EXPAND + + + + + + Live Update + True + True + False + 6 + True + True + + + 2 + 3 + + + + + + + - end + False + False 1 @@ -264,13 +344,6 @@ - - 65535 - 1 - 65535 - 1 - 10 - 6 @@ -352,4 +425,15 @@ + + 65535 + 1 + 10 + + + 256 + 65535 + 1 + 10 + diff --git a/tools/gui/egg-histogram-view.c b/tools/gui/egg-histogram-view.c index 7abc2be..91e61e8 100644 --- a/tools/gui/egg-histogram-view.c +++ b/tools/gui/egg-histogram-view.c @@ -34,11 +34,14 @@ struct _EggHistogramViewPrivate /* This could be moved into a real histogram class */ guint n_bins; gint *bins; - gint min_value; - gint max_value; - gint min_border; + gint *grabbed; + gint min_border; /* threshold set in screen units */ gint max_border; + gdouble min_value; /* lowest value of the first bin */ + gdouble max_value; /* highest value of the last bin */ + gdouble range; + gpointer data; gint n_elements; gint n_bits; @@ -47,6 +50,8 @@ struct _EggHistogramViewPrivate enum { PROP_0, + PROP_MINIMUM_BIN_VALUE, + PROP_MAXIMUM_BIN_VALUE, N_PROPERTIES }; @@ -71,6 +76,7 @@ egg_histogram_view_set_data (EggHistogramView *view, { EggHistogramViewPrivate *priv; + g_return_if_fail (EGG_IS_HISTOGRAM_VIEW (view)); priv = view->priv; if (priv->bins != NULL) @@ -82,16 +88,46 @@ egg_histogram_view_set_data (EggHistogramView *view, priv->n_bits = n_bits; priv->n_elements = n_elements; - priv->min_value = 0; + priv->min_value = 0.0; priv->max_value = (gint) pow(2, n_bits) - 1; - priv->min_border = 20; - priv->max_border = priv->max_value - 20; + priv->min_border = 0; + priv->max_border = 256; + priv->range = priv->max_value - priv->min_value; +} + +void +egg_histogram_get_visible_range (EggHistogramView *view, gdouble *min, gdouble *max) +{ + EggHistogramViewPrivate *priv; + GtkAllocation allocation; + gdouble width; + + g_return_if_fail (EGG_IS_HISTOGRAM_VIEW (view)); + + gtk_widget_get_allocation (GTK_WIDGET (view), &allocation); + width = (gdouble) allocation.width - 2 * BORDER; + priv = view->priv; + + *min = (priv->min_border - 2) / width * priv->range; + *max = (priv->max_border - 2) / width * priv->range; +} + +static void +set_max_border (EggHistogramView *view) +{ + GtkAllocation allocation; + + g_return_if_fail (EGG_IS_HISTOGRAM_VIEW (view)); + gtk_widget_get_allocation (GTK_WIDGET (view), &allocation); + view->priv->max_border = allocation.width - 2 * BORDER; } static void compute_histogram (EggHistogramViewPrivate *priv) { + guint n_bins = priv->n_bins - 1; + for (guint i = 0; i < priv->n_bins; i++) priv->bins[i] = 0; @@ -100,8 +136,11 @@ compute_histogram (EggHistogramViewPrivate *priv) for (guint i = 0; i < priv->n_elements; i++) { guint8 v = data[i]; - guint index = (guint) round (((gdouble) v) / priv->max_value * (priv->n_bins - 1)); - priv->bins[index]++; + + if (v >= priv->min_value && v <= priv->max_value) { + guint index = (guint) round (((gdouble) v) / priv->max_value * n_bins); + priv->bins[index]++; + } } } else if (priv->n_bits == 16) { @@ -109,8 +148,11 @@ compute_histogram (EggHistogramViewPrivate *priv) for (guint i = 0; i < priv->n_elements; i++) { guint16 v = data[i]; - guint index = (guint) floor (((gdouble ) v) / priv->max_value * (priv->n_bins - 1)); - priv->bins[index]++; + + if (v >= priv->min_value && v <= priv->max_value) { + guint index = (guint) floor (((gdouble ) v) / priv->max_value * n_bins); + priv->bins[index]++; + } } } else @@ -137,6 +179,36 @@ egg_histogram_view_size_request (GtkWidget *widget, requisition->height = MIN_HEIGHT; } +static void +draw_bins (EggHistogramViewPrivate *priv, + cairo_t *cr, + gint width, + gint height) +{ + gdouble skip = ((gdouble) width) / priv->n_bins; + gdouble x = BORDER; + gdouble ys = height + BORDER - 1; + gint max_value = 0; + + for (guint i = 0; i < priv->n_bins; i++) { + if (priv->bins[i] > max_value) + max_value = priv->bins[i]; + } + + if (max_value == 0) + return; + + for (guint i = 0; i < priv->n_bins && x < (width - BORDER); i++, x += skip) { + if (priv->bins[i] == 0) + continue; + + gint y = (gint) ((height - 2) * priv->bins[i]) / max_value; + cairo_move_to (cr, round (x), ys); + cairo_line_to (cr, round (x), ys - y); + cairo_stroke (cr); + } +} + static gboolean egg_histogram_view_expose (GtkWidget *widget, GdkEventExpose *event) @@ -146,7 +218,6 @@ egg_histogram_view_expose (GtkWidget *widget, GtkStyle *style; cairo_t *cr; gint width, height; - gint max_value = 0; priv = EGG_HISTOGRAM_VIEW_GET_PRIVATE (widget); cr = gdk_cairo_create (gtk_widget_get_window (widget)); @@ -181,36 +252,15 @@ egg_histogram_view_expose (GtkWidget *widget, /* Draw border areas */ gdk_cairo_set_source_color (cr, &style->dark[GTK_STATE_NORMAL]); - if (priv->min_border > 0) { - cairo_rectangle (cr, BORDER, BORDER, priv->min_border + 0.5, height - 1); - cairo_fill (cr); - } - - /* Draw spikes */ - for (guint i = 0; i < priv->n_bins; i++) { - if (priv->bins[i] > max_value) - max_value = priv->bins[i]; - } + cairo_rectangle (cr, BORDER, BORDER, priv->min_border + 0.5, height - 1); + cairo_fill (cr); - if (max_value == 0) - goto cleanup; + cairo_rectangle (cr, priv->max_border + 0.5, BORDER, width - priv->min_border - 0.5, height - 1); + cairo_fill (cr); + /* Draw spikes */ gdk_cairo_set_source_color (cr, &style->black); - - if (width > priv->n_bins) { - gdouble skip = ((gdouble) width) / priv->n_bins; - gdouble x = 1; - - for (guint i = 0; i < priv->n_bins; i++, x += skip) { - if (priv->bins[i] == 0) - continue; - - gint y = (gint) ((height - 2) * priv->bins[i]) / max_value; - cairo_move_to (cr, round (x + BORDER), height + BORDER - 1); - cairo_line_to (cr, round (x + BORDER), height + BORDER - 1 - y); - cairo_stroke (cr); - } - } + draw_bins (priv, cr, width, height); cleanup: cairo_destroy (cr); @@ -242,9 +292,42 @@ egg_histogram_view_set_property (GObject *object, const GValue *value, GParamSpec *pspec) { + EggHistogramViewPrivate *priv; + g_return_if_fail (EGG_IS_HISTOGRAM_VIEW (object)); + priv = EGG_HISTOGRAM_VIEW_GET_PRIVATE (object); switch (property_id) { + case PROP_MINIMUM_BIN_VALUE: + { + gdouble v = g_value_get_double (value); + + if (v > priv->max_value) + g_warning ("Minimum value `%f' larger than maximum value `%f'", + v, priv->max_value); + else { + priv->min_value = v; + priv->range = priv->max_value - v; + priv->min_border = 0; + } + } + break; + + case PROP_MAXIMUM_BIN_VALUE: + { + gdouble v = g_value_get_double (value); + + if (v < priv->min_value) + g_warning ("Maximum value `%f' larger than minimum value `%f'", + v, priv->min_value); + else { + priv->max_value = v; + priv->range = v - priv->min_value; + set_max_border (EGG_HISTOGRAM_VIEW (object)); + } + } + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); return; @@ -257,20 +340,48 @@ egg_histogram_view_get_property (GObject *object, GValue *value, GParamSpec *pspec) { + EggHistogramViewPrivate *priv; + g_return_if_fail (EGG_IS_HISTOGRAM_VIEW (object)); + priv = EGG_HISTOGRAM_VIEW_GET_PRIVATE (object); switch (property_id) { + case PROP_MINIMUM_BIN_VALUE: + g_value_set_double (value, priv->min_value); + break; + + case PROP_MAXIMUM_BIN_VALUE: + g_value_set_double (value, priv->max_value); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); return; } } -static gint -get_mouse_distance (EggHistogramViewPrivate *priv, +static gboolean +is_on_border (EggHistogramViewPrivate *priv, + gint x) +{ + gint d1 = (priv->min_border + BORDER) - x; + gint d2 = (priv->max_border + BORDER) - x; + return ABS (d1) < 6 || ABS (d2) < 6; +} + +static gint * +get_grabbed_border (EggHistogramViewPrivate *priv, gint x) { - return (priv->min_border + BORDER) - x; + gint d1 = (priv->min_border + BORDER) - x; + gint d2 = (priv->max_border + BORDER) - x; + + if (ABS (d1) < 6) + return &priv->min_border; + else if (ABS (d2) < 6) + return &priv->max_border; + + return NULL; } static gboolean @@ -284,13 +395,12 @@ egg_histogram_view_motion_notify (GtkWidget *widget, priv = view->priv; if (priv->grabbing) { - priv->min_border = event->x + BORDER; + *priv->grabbed = event->x; + gtk_widget_queue_draw (widget); } else { - gint distance = get_mouse_distance (priv, event->x); - - if (ABS(distance) < 6) + if (is_on_border (priv, event->x)) set_cursor_type (view, GDK_FLEUR); else set_cursor_type (view, GDK_ARROW); @@ -304,18 +414,10 @@ egg_histogram_view_button_release (GtkWidget *widget, GdkEventButton *event) { EggHistogramView *view; - EggHistogramViewPrivate *priv; - /* GtkAllocation allocation; */ - /* gint width; */ - - /* gtk_widget_get_allocation (widget, &allocation); */ - /* width = allocation.width - 2 * BORDER; */ view = EGG_HISTOGRAM_VIEW (widget); - priv = view->priv; - set_cursor_type (view, GDK_ARROW); - priv->grabbing = FALSE; + view->priv->grabbing = FALSE; return TRUE; } @@ -326,14 +428,13 @@ egg_histogram_view_button_press (GtkWidget *widget, { EggHistogramView *view; EggHistogramViewPrivate *priv; - gint distance; view = EGG_HISTOGRAM_VIEW (widget); priv = view->priv; - distance = get_mouse_distance (priv, event->x); - if (ABS (distance) < 6) { + if (is_on_border (priv, event->x)) { priv->grabbing = TRUE; + priv->grabbed = get_grabbed_border (priv, event->x); set_cursor_type (view, GDK_FLEUR); } @@ -357,6 +458,23 @@ egg_histogram_view_class_init (EggHistogramViewClass *klass) widget_class->button_release_event = egg_histogram_view_button_release; widget_class->motion_notify_event = egg_histogram_view_motion_notify; + egg_histogram_view_properties[PROP_MINIMUM_BIN_VALUE] = + g_param_spec_double ("minimum-bin-value", + "Smallest possible bin value", + "Smallest possible bin value, everything below is discarded.", + 0.0, G_MAXDOUBLE, 0.0, + G_PARAM_READWRITE); + + egg_histogram_view_properties[PROP_MAXIMUM_BIN_VALUE] = + g_param_spec_double ("maximum-bin-value", + "Largest possible bin value", + "Largest possible bin value, everything above is discarded.", + 0.0, G_MAXDOUBLE, 256.0, + G_PARAM_READWRITE); + + g_object_class_install_property (object_class, PROP_MINIMUM_BIN_VALUE, egg_histogram_view_properties[PROP_MINIMUM_BIN_VALUE]); + g_object_class_install_property (object_class, PROP_MAXIMUM_BIN_VALUE, egg_histogram_view_properties[PROP_MAXIMUM_BIN_VALUE]); + g_type_class_add_private (klass, sizeof (EggHistogramViewPrivate)); } @@ -371,6 +489,8 @@ egg_histogram_view_init (EggHistogramView *view) priv->data = NULL; priv->n_bins = 0; priv->n_elements = 0; + priv->min_value = priv->min_border = 0; + priv->max_value = priv->max_border = 256; priv->cursor_type = GDK_ARROW; priv->grabbing = FALSE; diff --git a/tools/gui/egg-histogram-view.h b/tools/gui/egg-histogram-view.h index a1df0ba..61a1c8c 100644 --- a/tools/gui/egg-histogram-view.h +++ b/tools/gui/egg-histogram-view.h @@ -53,6 +53,10 @@ void egg_histogram_view_set_data (EggHistogramView *view, guint n_elements, guint n_bits, guint n_bins); +void egg_histogram_get_visible_range + (EggHistogramView *view, + gdouble *min, + gdouble *max); G_END_DECLS -- cgit v1.2.3 From ef7ff789e9c15f4f4b8c65585de7e7fa4f9c9438 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang Date: Fri, 12 Oct 2012 14:47:07 +0200 Subject: Add ring buffer recording for assessment --- plugins/mock/uca-mock-camera.c | 5 +- tools/gui/CMakeLists.txt | 1 + tools/gui/control.c | 190 ++++++++++++++++++++++++++--------------- tools/gui/control.glade | 33 ++++++- tools/gui/ring-buffer.c | 64 ++++++++++++++ tools/gui/ring-buffer.h | 28 ++++++ 6 files changed, 246 insertions(+), 75 deletions(-) create mode 100644 tools/gui/ring-buffer.c create mode 100644 tools/gui/ring-buffer.h (limited to 'tools/gui/control.c') diff --git a/plugins/mock/uca-mock-camera.c b/plugins/mock/uca-mock-camera.c index 65c4240..38caf0d 100644 --- a/plugins/mock/uca-mock-camera.c +++ b/plugins/mock/uca-mock-camera.c @@ -146,9 +146,10 @@ static void print_number(gchar *buffer, guint number, guint x, guint y, guint wi static void print_current_frame(UcaMockCameraPrivate *priv, gchar *buffer) { guint number = priv->current_frame; - guint divisor = 100000000; + guint divisor = 10000000; int x = 10; - while (divisor > 1) { + + while (divisor > 0) { print_number(buffer, number / divisor, x, 10, priv->width); number = number % divisor; divisor = divisor / 10; diff --git a/tools/gui/CMakeLists.txt b/tools/gui/CMakeLists.txt index ff5e9f6..1000ac6 100644 --- a/tools/gui/CMakeLists.txt +++ b/tools/gui/CMakeLists.txt @@ -25,6 +25,7 @@ if (GTK2_FOUND) add_executable(control control.c + ring-buffer.c egg-property-cell-renderer.c egg-property-tree-view.c egg-histogram-view.c) diff --git a/tools/gui/control.c b/tools/gui/control.c index 214e4da..84799cb 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -22,11 +22,17 @@ #include #include "config.h" +#include "ring-buffer.h" #include "uca-camera.h" #include "uca-plugin-manager.h" #include "egg-property-tree-view.h" #include "egg-histogram-view.h" +typedef enum { + IDLE, + RUNNING, + RECORDING +} State; typedef struct { UcaCamera *camera; @@ -35,13 +41,14 @@ typedef struct { GtkWidget *start_button; GtkWidget *stop_button; GtkWidget *record_button; - GtkWidget *histogram_view; + + GtkWidget *histogram_view; GtkToggleButton *histogram_button; + GtkAdjustment *frame_slider; - guchar *buffer; + RingBuffer *buffer; guchar *pixels; - gboolean running; - gboolean store; + State state; int timestamp; int width; @@ -53,70 +60,66 @@ static UcaPluginManager *plugin_manager; static void -convert_8bit_to_rgb (guchar *output, guchar *input, gint width, gint height, gdouble min, gdouble max) +convert_grayscale_to_rgb (ThreadData *data, gpointer buffer) { - gdouble factor = 255.0 / (max - min); - - for (int i = 0, j = 0; i < width*height; i++) { - guchar val = (guchar) ((input[i] - min) * factor); - output[j++] = val; - output[j++] = val; - output[j++] = val; + gdouble min; + gdouble max; + gdouble factor; + guint8 *output; + + egg_histogram_get_visible_range (EGG_HISTOGRAM_VIEW (data->histogram_view), &min, &max); + factor = 255.0 / (max - min); + output = data->pixels; + + if (data->pixel_size == 1) { + guint8 *input = (guint8 *) buffer; + + for (int i = 0, j = 0; i < data->width * data->height; i++) { + guchar val = (guchar) ((input[i] - min) * factor); + output[j++] = val; + output[j++] = val; + output[j++] = val; + } + } + else if (data->pixel_size == 2) { + guint16 *input = (guint16 *) buffer; + + for (int i = 0, j = 0; i < data->width * data->height; i++) { + guchar val = (guint8) ((input[i] - min) * factor); + output[j++] = val; + output[j++] = val; + output[j++] = val; + } } } static void -convert_16bit_to_rgb (guchar *output, guchar *input, gint width, gint height, gdouble min, gdouble max) +update_pixbuf (ThreadData *data) { - gdouble factor = 255.0 / (max - min); + gdk_flush (); + gtk_image_clear (GTK_IMAGE (data->image)); + gtk_image_set_from_pixbuf (GTK_IMAGE (data->image), data->pixbuf); + gtk_widget_queue_draw_area (data->image, 0, 0, data->width, data->height); - for (int i = 0, j = 0; i < width*height; i++) { - guchar val = (guint8) ((input[i] - min) * factor); - output[j++] = val; - output[j++] = val; - output[j++] = val; - } + if (gtk_toggle_button_get_active (data->histogram_button)) + gtk_widget_queue_draw (data->histogram_view); } -static void * -grab_thread (void *args) +static gpointer +preview_frames (void *args) { ThreadData *data = (ThreadData *) args; - gchar filename[FILENAME_MAX] = {0,}; gint counter = 0; - while (data->running) { - gdouble min_value; - gdouble max_value; + while (data->state == RUNNING) { + gpointer buffer; - uca_camera_grab (data->camera, (gpointer) &data->buffer, NULL); - - if (data->store) { - snprintf (filename, FILENAME_MAX, "frame-%i-%08i.raw", data->timestamp, counter); - FILE *fp = fopen (filename, "wb"); - fwrite (data->buffer, data->width*data->height, data->pixel_size, fp); - fclose (fp); - } - - /* FIXME: We should actually check if this is really a new frame and - * just do nothing if it is an already displayed one. */ - egg_histogram_get_visible_range (EGG_HISTOGRAM_VIEW (data->histogram_view), &min_value, &max_value); - - if (data->pixel_size == 1) - convert_8bit_to_rgb (data->pixels, data->buffer, data->width, data->height, min_value, max_value); - else if (data->pixel_size == 2) - convert_16bit_to_rgb (data->pixels, data->buffer, data->width, data->height, min_value, max_value); + buffer = ring_buffer_get_current_pointer (data->buffer); + uca_camera_grab (data->camera, &buffer, NULL); + convert_grayscale_to_rgb (data, buffer); gdk_threads_enter (); - - gdk_flush (); - gtk_image_clear (GTK_IMAGE (data->image)); - gtk_image_set_from_pixbuf (GTK_IMAGE (data->image), data->pixbuf); - gtk_widget_queue_draw_area (data->image, 0, 0, data->width, data->height); - - if (gtk_toggle_button_get_active (data->histogram_button)) - gtk_widget_queue_draw (data->histogram_view); - + update_pixbuf (data); gdk_threads_leave (); counter++; @@ -124,6 +127,33 @@ grab_thread (void *args) return NULL; } +static gpointer +record_frames (gpointer args) +{ + ThreadData *data; + gpointer buffer; + guint n_frames = 0; + + data = (ThreadData *) args; + ring_buffer_reset (data->buffer); + + while (data->state == RECORDING) { + buffer = ring_buffer_get_current_pointer (data->buffer); + uca_camera_grab (data->camera, &buffer, NULL); + ring_buffer_proceed (data->buffer); + n_frames++; + } + + n_frames = ring_buffer_get_num_blocks (data->buffer); + + gdk_threads_enter (); + gtk_adjustment_set_upper (data->frame_slider, n_frames - 1); + gtk_adjustment_set_value (data->frame_slider, n_frames - 1); + gdk_threads_leave (); + + return NULL; +} + gboolean on_delete_event (GtkWidget *widget, GdkEvent *event, gpointer data) { @@ -134,17 +164,39 @@ void on_destroy (GtkWidget *widget, gpointer data) { ThreadData *td = (ThreadData *) data; - td->running = FALSE; + + td->state = IDLE; g_object_unref (td->camera); + ring_buffer_free (td->buffer); + gtk_main_quit (); } static void set_tool_button_state (ThreadData *data) { - gtk_widget_set_sensitive (data->start_button, !data->running); - gtk_widget_set_sensitive (data->stop_button, data->running); - gtk_widget_set_sensitive (data->record_button, !data->running); + gtk_widget_set_sensitive (data->start_button, + data->state == IDLE); + gtk_widget_set_sensitive (data->stop_button, + data->state == RUNNING || data->state == RECORDING); + gtk_widget_set_sensitive (data->record_button, + data->state == IDLE); +} + +static void +on_frame_slider_changed (GtkAdjustment *adjustment, gpointer user_data) +{ + ThreadData *data = (ThreadData *) user_data; + + if (data->state == IDLE) { + gpointer buffer; + gint index; + + index = (gint) gtk_adjustment_get_value (adjustment); + buffer = ring_buffer_get_pointer (data->buffer, index); + convert_grayscale_to_rgb (data, buffer); + update_pixbuf (data); + } } static void @@ -153,7 +205,7 @@ on_start_button_clicked (GtkWidget *widget, gpointer args) ThreadData *data = (ThreadData *) args; GError *error = NULL; - data->running = TRUE; + data->state = RUNNING; set_tool_button_state (data); uca_camera_start_recording (data->camera, &error); @@ -163,7 +215,7 @@ on_start_button_clicked (GtkWidget *widget, gpointer args) return; } - if (!g_thread_create (grab_thread, data, FALSE, &error)) { + if (!g_thread_create (preview_frames, data, FALSE, &error)) { g_printerr ("Failed to create thread: %s\n", error->message); return; } @@ -175,8 +227,7 @@ on_stop_button_clicked (GtkWidget *widget, gpointer args) ThreadData *data = (ThreadData *) args; GError *error = NULL; - data->running = FALSE; - data->store = FALSE; + data->state = IDLE; set_tool_button_state (data); uca_camera_stop_recording (data->camera, &error); @@ -192,13 +243,12 @@ on_record_button_clicked (GtkWidget *widget, gpointer args) GError *error = NULL; data->timestamp = (int) time (0); - data->store = TRUE; - data->running = TRUE; + data->state = RECORDING; set_tool_button_state (data); uca_camera_start_recording (data->camera, &error); - if (!g_thread_create (grab_thread, data, FALSE, &error)) + if (!g_thread_create (record_frames, data, FALSE, &error)) g_printerr ("Failed to create thread: %s\n", error->message); } @@ -240,18 +290,19 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) td.pixel_size = bits_per_sample > 8 ? 2 : 1; td.image = image; td.pixbuf = pixbuf; - td.buffer = (guchar *) g_malloc (td.pixel_size * td.width * td.height); + td.buffer = ring_buffer_new (td.pixel_size * td.width * td.height, 256); td.pixels = gdk_pixbuf_get_pixels (pixbuf); - td.running = FALSE; - td.store = FALSE; + td.state = IDLE; td.camera = camera; td.histogram_view = egg_histogram_view_new (); td.histogram_button = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "histogram-checkbutton")); + td.frame_slider = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "frames-adjustment")); histogram_box = GTK_BOX (gtk_builder_get_object (builder, "histogram-box")); gtk_box_pack_start (histogram_box, td.histogram_view, TRUE, TRUE, 6); egg_histogram_view_set_data (EGG_HISTOGRAM_VIEW (td.histogram_view), - td.buffer, td.width * td.height, bits_per_sample, 256); + ring_buffer_get_current_pointer (td.buffer), + td.width * td.height, bits_per_sample, 256); window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); g_signal_connect (window, "destroy", G_CALLBACK (on_destroy), &td); @@ -261,16 +312,17 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) td.record_button = GTK_WIDGET (gtk_builder_get_object (builder, "record-button")); set_tool_button_state (&td); - g_object_bind_property (gtk_builder_get_object (builder, "min_bin_value_adjustment"), "value", + g_object_bind_property (gtk_builder_get_object (builder, "min-bin-value-adjustment"), "value", td.histogram_view, "minimum-bin-value", G_BINDING_DEFAULT); - max_bin_adjustment = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "max_bin_value_adjustment")); + max_bin_adjustment = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "max-bin-value-adjustment")); gtk_adjustment_set_value (max_bin_adjustment, pow (2, bits_per_sample) - 1); g_object_bind_property (max_bin_adjustment, "value", td.histogram_view, "maximum-bin-value", G_BINDING_DEFAULT); + g_signal_connect (td.frame_slider, "value-changed", G_CALLBACK (on_frame_slider_changed), &td); g_signal_connect (td.start_button, "clicked", G_CALLBACK (on_start_button_clicked), &td); g_signal_connect (td.stop_button, "clicked", G_CALLBACK (on_stop_button_clicked), &td); g_signal_connect (td.record_button, "clicked", G_CALLBACK (on_record_button_clicked), &td); diff --git a/tools/gui/control.glade b/tools/gui/control.glade index ebe2cc8..c3008ec 100644 --- a/tools/gui/control.glade +++ b/tools/gui/control.glade @@ -230,7 +230,7 @@ True True - min_bin_value_adjustment + min-bin-value-adjustment 1 @@ -260,7 +260,7 @@ True True - max_bin_value_adjustment + max-bin-value-adjustment 1 @@ -309,6 +309,27 @@ False + + + True + True + frames-adjustment + 0 + + + 1 + + + + + True + Preview + + + 1 + False + + True @@ -425,15 +446,19 @@ - + 65535 1 10 - + 256 65535 1 10 + + 1 + 10 + diff --git a/tools/gui/ring-buffer.c b/tools/gui/ring-buffer.c new file mode 100644 index 0000000..56c7620 --- /dev/null +++ b/tools/gui/ring-buffer.c @@ -0,0 +1,64 @@ + +#include +#include "ring-buffer.h" + +RingBuffer * +ring_buffer_new (gsize block_size, + gsize n_blocks) +{ + RingBuffer *buffer; + + buffer = g_new0 (RingBuffer, 1); + buffer->block_size = block_size; + buffer->n_blocks_total = n_blocks; + buffer->n_blocks_used = 0; + buffer->start_index = 0; + buffer->data = g_malloc0 (n_blocks * buffer->block_size); + + return buffer; +} + +void +ring_buffer_free (RingBuffer *buffer) +{ + g_free (buffer->data); + g_free (buffer); +} + +void +ring_buffer_reset (RingBuffer *buffer) +{ + buffer->n_blocks_used = 0; + buffer->start_index = 0; +} + +gpointer +ring_buffer_get_current_pointer (RingBuffer *buffer) +{ + return ring_buffer_get_pointer (buffer, 0); +} + +gpointer +ring_buffer_get_pointer (RingBuffer *buffer, + guint index) +{ + g_assert (index < buffer->n_blocks_total); + return buffer->data + ((buffer->start_index + index) % buffer->n_blocks_total) * buffer->block_size; +} + +guint +ring_buffer_get_num_blocks (RingBuffer *buffer) +{ + return buffer->n_blocks_used; +} + +void +ring_buffer_proceed (RingBuffer *buffer) +{ + buffer->start_index++; + + if (buffer->n_blocks_used < buffer->n_blocks_total) + buffer->n_blocks_used++; + else + buffer->start_index = buffer->start_index % buffer->n_blocks_total; +} diff --git a/tools/gui/ring-buffer.h b/tools/gui/ring-buffer.h new file mode 100644 index 0000000..22cbde7 --- /dev/null +++ b/tools/gui/ring-buffer.h @@ -0,0 +1,28 @@ +#ifndef RING_BUFFER_H +#define RING_BUFFER_H + +#include + +G_BEGIN_DECLS + +typedef struct { + guchar *data; + gsize block_size; + guint n_blocks_total; + guint n_blocks_used; + guint start_index; +} RingBuffer; + +RingBuffer * ring_buffer_new (gsize block_size, + gsize n_blocks); +void ring_buffer_free (RingBuffer *buffer); +void ring_buffer_reset (RingBuffer *buffer); +gpointer ring_buffer_get_current_pointer (RingBuffer *buffer); +gpointer ring_buffer_get_pointer (RingBuffer *buffer, + guint index); +guint ring_buffer_get_num_blocks (RingBuffer *buffer); +void ring_buffer_proceed (RingBuffer *buffer); + +G_END_DECLS + +#endif -- cgit v1.2.3 From c48496b50a72575438f87da69080a48e0878a121 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang Date: Fri, 12 Oct 2012 16:17:53 +0200 Subject: Control memory size via command line --- tools/gui/control.c | 110 ++++++++++++++++++++++++++++++++---------------- tools/gui/control.glade | 2 +- tools/gui/ring-buffer.c | 2 +- 3 files changed, 76 insertions(+), 38 deletions(-) (limited to 'tools/gui/control.c') diff --git a/tools/gui/control.c b/tools/gui/control.c index 84799cb..eab2be7 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -57,7 +57,7 @@ typedef struct { } ThreadData; static UcaPluginManager *plugin_manager; - +static gsize mem_size = 2048; static void convert_grayscale_to_rgb (ThreadData *data, gpointer buffer) @@ -255,69 +255,86 @@ on_record_button_clicked (GtkWidget *widget, gpointer args) static void create_main_window (GtkBuilder *builder, const gchar* camera_name) { + static ThreadData td; + UcaCamera *camera; GtkWidget *window; GtkWidget *image; + GtkWidget *histogram_view; GtkWidget *property_tree_view; GdkPixbuf *pixbuf; GtkBox *histogram_box; - GtkContainer *scrolled_property_window; + GtkContainer *property_window; GtkAdjustment *max_bin_adjustment; - static ThreadData td; + RingBuffer *ring_buffer; + gsize image_size; + guint n_frames; + guint bits_per_sample; + guint pixel_size; + guint width, height; + GError *error = NULL; - GError *error = NULL; - UcaCamera *camera = uca_plugin_manager_get_camera (plugin_manager, camera_name, &error); + camera = uca_plugin_manager_get_camera (plugin_manager, camera_name, &error); if ((camera == NULL) || (error != NULL)) { g_error ("%s\n", error->message); gtk_main_quit (); } - guint bits_per_sample; g_object_get (camera, - "roi-width", &td.width, - "roi-height", &td.height, + "roi-width", &width, + "roi-height", &height, "sensor-bitdepth", &bits_per_sample, NULL); - property_tree_view = egg_property_tree_view_new (G_OBJECT (camera)); - scrolled_property_window = GTK_CONTAINER (gtk_builder_get_object (builder, "scrolledwindow2")); - gtk_container_add (scrolled_property_window, property_tree_view); + histogram_view = egg_histogram_view_new (); + property_tree_view = egg_property_tree_view_new (G_OBJECT (camera)); + property_window = GTK_CONTAINER (gtk_builder_get_object (builder, "property-window")); + image = GTK_WIDGET (gtk_builder_get_object (builder, "image")); + histogram_box = GTK_BOX (gtk_builder_get_object (builder, "histogram-box")); + window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); + max_bin_adjustment = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "max-bin-value-adjustment")); + + td.start_button = GTK_WIDGET (gtk_builder_get_object (builder, "start-button")); + td.stop_button = GTK_WIDGET (gtk_builder_get_object (builder, "stop-button")); + td.record_button = GTK_WIDGET (gtk_builder_get_object (builder, "record-button")); + td.histogram_button = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "histogram-checkbutton")); + td.frame_slider = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "frames-adjustment")); + + /* Set initial data */ + pixel_size = bits_per_sample > 8 ? 2 : 1; + image_size = pixel_size * width * height; + n_frames = mem_size * 1024 * 1024 / image_size; + ring_buffer = ring_buffer_new (image_size, n_frames); + + set_tool_button_state (&td); + + egg_histogram_view_set_data (EGG_HISTOGRAM_VIEW (histogram_view), + ring_buffer_get_current_pointer (ring_buffer), + width * height, bits_per_sample, 256); - image = GTK_WIDGET (gtk_builder_get_object (builder, "image")); - pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, td.width, td.height); + pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width, height); gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf); - td.pixel_size = bits_per_sample > 8 ? 2 : 1; + gtk_adjustment_set_value (max_bin_adjustment, pow (2, bits_per_sample) - 1); + + g_message ("Allocated memory for %d frames", n_frames); + + td.pixel_size = pixel_size; td.image = image; td.pixbuf = pixbuf; - td.buffer = ring_buffer_new (td.pixel_size * td.width * td.height, 256); + td.buffer = ring_buffer; td.pixels = gdk_pixbuf_get_pixels (pixbuf); td.state = IDLE; td.camera = camera; - td.histogram_view = egg_histogram_view_new (); - td.histogram_button = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "histogram-checkbutton")); - td.frame_slider = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "frames-adjustment")); - - histogram_box = GTK_BOX (gtk_builder_get_object (builder, "histogram-box")); - gtk_box_pack_start (histogram_box, td.histogram_view, TRUE, TRUE, 6); - egg_histogram_view_set_data (EGG_HISTOGRAM_VIEW (td.histogram_view), - ring_buffer_get_current_pointer (td.buffer), - td.width * td.height, bits_per_sample, 256); - - window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); - g_signal_connect (window, "destroy", G_CALLBACK (on_destroy), &td); - - td.start_button = GTK_WIDGET (gtk_builder_get_object (builder, "start-button")); - td.stop_button = GTK_WIDGET (gtk_builder_get_object (builder, "stop-button")); - td.record_button = GTK_WIDGET (gtk_builder_get_object (builder, "record-button")); - set_tool_button_state (&td); + td.width = width; + td.height = height; + td.histogram_view = histogram_view; + /* Hook up signals */ g_object_bind_property (gtk_builder_get_object (builder, "min-bin-value-adjustment"), "value", td.histogram_view, "minimum-bin-value", G_BINDING_DEFAULT); - max_bin_adjustment = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "max-bin-value-adjustment")); - gtk_adjustment_set_value (max_bin_adjustment, pow (2, bits_per_sample) - 1); g_object_bind_property (max_bin_adjustment, "value", td.histogram_view, "maximum-bin-value", G_BINDING_DEFAULT); @@ -326,6 +343,11 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) g_signal_connect (td.start_button, "clicked", G_CALLBACK (on_start_button_clicked), &td); g_signal_connect (td.stop_button, "clicked", G_CALLBACK (on_stop_button_clicked), &td); g_signal_connect (td.record_button, "clicked", G_CALLBACK (on_record_button_clicked), &td); + g_signal_connect (window, "destroy", G_CALLBACK (on_destroy), &td); + + /* Layout */ + gtk_container_add (property_window, property_tree_view); + gtk_box_pack_start (histogram_box, td.histogram_view, TRUE, TRUE, 6); gtk_widget_show_all (window); } @@ -398,16 +420,32 @@ create_choice_window (GtkBuilder *builder) int main (int argc, char *argv[]) { + GtkBuilder *builder; + GOptionContext *context; GError *error = NULL; + static GOptionEntry entries[] = + { + { "mem-size", 'm', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT, &mem_size, "Memory in megabytes to allocate for frame storage", "M" }, + { NULL } + }; + + context = g_option_context_new ("- control libuca cameras"); + g_option_context_add_main_entries (context, entries, NULL); + g_option_context_add_group (context, gtk_get_option_group (TRUE)); + if (!g_option_context_parse (context, &argc, &argv, &error)) { + g_print ("Option parsing failed: %s\n", error->message); + return 1; + } + g_thread_init (NULL); gdk_threads_init (); gtk_init (&argc, &argv); - GtkBuilder *builder = gtk_builder_new (); + builder = gtk_builder_new (); if (!gtk_builder_add_from_file (builder, CONTROL_GLADE_PATH, &error)) { - g_print ("Error: %s\n", error->message); + g_print ("Could not load UI file: %s\n", error->message); return 1; } diff --git a/tools/gui/control.glade b/tools/gui/control.glade index c3008ec..90d9511 100644 --- a/tools/gui/control.glade +++ b/tools/gui/control.glade @@ -343,7 +343,7 @@ - + True True automatic diff --git a/tools/gui/ring-buffer.c b/tools/gui/ring-buffer.c index 56c7620..5915d2a 100644 --- a/tools/gui/ring-buffer.c +++ b/tools/gui/ring-buffer.c @@ -13,7 +13,7 @@ ring_buffer_new (gsize block_size, buffer->n_blocks_total = n_blocks; buffer->n_blocks_used = 0; buffer->start_index = 0; - buffer->data = g_malloc0 (n_blocks * buffer->block_size); + buffer->data = g_malloc0_n (n_blocks, block_size); return buffer; } -- cgit v1.2.3 From be1bfae1ecef5032e667174da4b4ad016d47887b Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang Date: Fri, 12 Oct 2012 16:31:06 +0200 Subject: Reflect correct state of camera --- tools/gui/control.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools/gui/control.c') diff --git a/tools/gui/control.c b/tools/gui/control.c index eab2be7..5e8860f 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -205,8 +205,6 @@ on_start_button_clicked (GtkWidget *widget, gpointer args) ThreadData *data = (ThreadData *) args; GError *error = NULL; - data->state = RUNNING; - set_tool_button_state (data); uca_camera_start_recording (data->camera, &error); @@ -219,6 +217,8 @@ on_start_button_clicked (GtkWidget *widget, gpointer args) g_printerr ("Failed to create thread: %s\n", error->message); return; } + + data->state = RUNNING; } static void -- cgit v1.2.3 From 6d4826f326f981a207ed6d64d5c481d0b1bddd00 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang Date: Fri, 12 Oct 2012 16:47:51 +0200 Subject: Fix button states --- tools/gui/control.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'tools/gui/control.c') diff --git a/tools/gui/control.c b/tools/gui/control.c index 5e8860f..e01bc7d 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -191,7 +191,7 @@ on_frame_slider_changed (GtkAdjustment *adjustment, gpointer user_data) if (data->state == IDLE) { gpointer buffer; gint index; - + index = (gint) gtk_adjustment_get_value (adjustment); buffer = ring_buffer_get_pointer (data->buffer, index); convert_grayscale_to_rgb (data, buffer); @@ -205,7 +205,6 @@ on_start_button_clicked (GtkWidget *widget, gpointer args) ThreadData *data = (ThreadData *) args; GError *error = NULL; - set_tool_button_state (data); uca_camera_start_recording (data->camera, &error); if (error != NULL) { @@ -213,12 +212,14 @@ on_start_button_clicked (GtkWidget *widget, gpointer args) return; } + data->state = RUNNING; + set_tool_button_state (data); + if (!g_thread_create (preview_frames, data, FALSE, &error)) { g_printerr ("Failed to create thread: %s\n", error->message); - return; + data->state = IDLE; + set_tool_button_state (data); } - - data->state = RUNNING; } static void @@ -242,14 +243,21 @@ on_record_button_clicked (GtkWidget *widget, gpointer args) ThreadData *data = (ThreadData *) args; GError *error = NULL; + uca_camera_start_recording (data->camera, &error); + + if (error != NULL) { + g_printerr ("Failed to start recording: %s\n", error->message); + } + data->timestamp = (int) time (0); data->state = RECORDING; - set_tool_button_state (data); - uca_camera_start_recording (data->camera, &error); - if (!g_thread_create (record_frames, data, FALSE, &error)) + if (!g_thread_create (record_frames, data, FALSE, &error)) { g_printerr ("Failed to create thread: %s\n", error->message); + data->state = IDLE; + set_tool_button_state (data); + } } static void @@ -434,7 +442,7 @@ main (int argc, char *argv[]) g_option_context_add_main_entries (context, entries, NULL); g_option_context_add_group (context, gtk_get_option_group (TRUE)); if (!g_option_context_parse (context, &argc, &argv, &error)) { - g_print ("Option parsing failed: %s\n", error->message); + g_print ("Option parsing failed: %s\n", error->message); return 1; } -- cgit v1.2.3 From 33a90d8dc20a513722f5fdf66a99cff91be422d5 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang Date: Mon, 15 Oct 2012 10:33:14 +0200 Subject: Fix replay feature --- tools/gui/control.c | 54 ++++++++++++++++++++++++------------------ tools/gui/egg-histogram-view.c | 29 ++++++++++++++++++++--- tools/gui/egg-histogram-view.h | 3 +++ tools/gui/ring-buffer.c | 12 +++++----- tools/gui/ring-buffer.h | 2 +- 5 files changed, 67 insertions(+), 33 deletions(-) (limited to 'tools/gui/control.c') diff --git a/tools/gui/control.c b/tools/gui/control.c index e01bc7d..f26cafc 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -79,6 +79,9 @@ convert_grayscale_to_rgb (ThreadData *data, gpointer buffer) output[j++] = val; output[j++] = val; output[j++] = val; + /* if (i < 10) { */ + /* g_print ("%i->%i ", input[i], val); */ + /* } */ } } else if (data->pixel_size == 2) { @@ -161,13 +164,11 @@ on_delete_event (GtkWidget *widget, GdkEvent *event, gpointer data) } void -on_destroy (GtkWidget *widget, gpointer data) +on_destroy (GtkWidget *widget, ThreadData *data) { - ThreadData *td = (ThreadData *) data; - - td->state = IDLE; - g_object_unref (td->camera); - ring_buffer_free (td->buffer); + data->state = IDLE; + g_object_unref (data->camera); + ring_buffer_free (data->buffer); gtk_main_quit (); } @@ -184,25 +185,27 @@ set_tool_button_state (ThreadData *data) } static void -on_frame_slider_changed (GtkAdjustment *adjustment, gpointer user_data) +update_current_frame (ThreadData *data) { - ThreadData *data = (ThreadData *) user_data; + gpointer buffer; + gint index; - if (data->state == IDLE) { - gpointer buffer; - gint index; + index = (gint) gtk_adjustment_get_value (data->frame_slider); + buffer = ring_buffer_get_pointer (data->buffer, index); + convert_grayscale_to_rgb (data, buffer); + update_pixbuf (data); +} - index = (gint) gtk_adjustment_get_value (adjustment); - buffer = ring_buffer_get_pointer (data->buffer, index); - convert_grayscale_to_rgb (data, buffer); - update_pixbuf (data); - } +static void +on_frame_slider_changed (GtkAdjustment *adjustment, ThreadData *data) +{ + if (data->state == IDLE) + update_current_frame (data); } static void -on_start_button_clicked (GtkWidget *widget, gpointer args) +on_start_button_clicked (GtkWidget *widget, ThreadData *data) { - ThreadData *data = (ThreadData *) args; GError *error = NULL; uca_camera_start_recording (data->camera, &error); @@ -223,13 +226,11 @@ on_start_button_clicked (GtkWidget *widget, gpointer args) } static void -on_stop_button_clicked (GtkWidget *widget, gpointer args) +on_stop_button_clicked (GtkWidget *widget, ThreadData *data) { - ThreadData *data = (ThreadData *) args; GError *error = NULL; data->state = IDLE; - set_tool_button_state (data); uca_camera_stop_recording (data->camera, &error); @@ -238,9 +239,8 @@ on_stop_button_clicked (GtkWidget *widget, gpointer args) } static void -on_record_button_clicked (GtkWidget *widget, gpointer args) +on_record_button_clicked (GtkWidget *widget, ThreadData *data) { - ThreadData *data = (ThreadData *) args; GError *error = NULL; uca_camera_start_recording (data->camera, &error); @@ -260,6 +260,13 @@ on_record_button_clicked (GtkWidget *widget, gpointer args) } } +static void +on_histogram_changed (EggHistogramView *view, ThreadData *data) +{ + if (data->state == IDLE) + update_current_frame (data); +} + static void create_main_window (GtkBuilder *builder, const gchar* camera_name) { @@ -351,6 +358,7 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) g_signal_connect (td.start_button, "clicked", G_CALLBACK (on_start_button_clicked), &td); g_signal_connect (td.stop_button, "clicked", G_CALLBACK (on_stop_button_clicked), &td); g_signal_connect (td.record_button, "clicked", G_CALLBACK (on_record_button_clicked), &td); + g_signal_connect (histogram_view, "changed", G_CALLBACK (on_histogram_changed), &td); g_signal_connect (window, "destroy", G_CALLBACK (on_destroy), &td); /* Layout */ diff --git a/tools/gui/egg-histogram-view.c b/tools/gui/egg-histogram-view.c index 5041ba2..812af7a 100644 --- a/tools/gui/egg-histogram-view.c +++ b/tools/gui/egg-histogram-view.c @@ -55,8 +55,16 @@ enum N_PROPERTIES }; +enum +{ + CHANGED, + LAST_SIGNAL +}; + static GParamSpec *egg_histogram_view_properties[N_PROPERTIES] = { NULL, }; +static guint egg_histogram_view_signals[LAST_SIGNAL] = { 0 }; + GtkWidget * egg_histogram_view_new (void) @@ -253,7 +261,7 @@ egg_histogram_view_expose (GtkWidget *widget, cairo_rectangle (cr, BORDER, BORDER, priv->min_border + 0.5, height - 1); cairo_fill (cr); - cairo_rectangle (cr, priv->max_border + 0.5, BORDER, width - priv->min_border - 0.5, height - 1); + cairo_rectangle (cr, priv->max_border + 0.5, BORDER, width - priv->max_border + 0.5, height - 1); cairo_fill (cr); /* Draw spikes */ @@ -393,9 +401,14 @@ egg_histogram_view_motion_notify (GtkWidget *widget, priv = view->priv; if (priv->grabbing) { - *priv->grabbed = event->x; + GtkAllocation allocation; + + gtk_widget_get_allocation (widget, &allocation); - gtk_widget_queue_draw (widget); + if ((event->x + BORDER > 0) && (event->x + BORDER < allocation.width)) { + *priv->grabbed = event->x; + gtk_widget_queue_draw (widget); + } } else { if (is_on_border (priv, event->x)) @@ -416,6 +429,7 @@ egg_histogram_view_button_release (GtkWidget *widget, view = EGG_HISTOGRAM_VIEW (widget); set_cursor_type (view, GDK_ARROW); view->priv->grabbing = FALSE; + g_signal_emit (widget, egg_histogram_view_signals[CHANGED], 0); return TRUE; } @@ -473,6 +487,15 @@ egg_histogram_view_class_init (EggHistogramViewClass *klass) g_object_class_install_property (object_class, PROP_MINIMUM_BIN_VALUE, egg_histogram_view_properties[PROP_MINIMUM_BIN_VALUE]); g_object_class_install_property (object_class, PROP_MAXIMUM_BIN_VALUE, egg_histogram_view_properties[PROP_MAXIMUM_BIN_VALUE]); + egg_histogram_view_signals[CHANGED] = + g_signal_new ("changed", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE, + G_STRUCT_OFFSET (EggHistogramViewClass, changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + g_type_class_add_private (klass, sizeof (EggHistogramViewPrivate)); } diff --git a/tools/gui/egg-histogram-view.h b/tools/gui/egg-histogram-view.h index 61a1c8c..7a62fca 100644 --- a/tools/gui/egg-histogram-view.h +++ b/tools/gui/egg-histogram-view.h @@ -44,6 +44,9 @@ struct _EggHistogramView struct _EggHistogramViewClass { GtkDrawingAreaClass parent_class; + + /* signals */ + void (* changed) (EggHistogramView *view); }; GType egg_histogram_view_get_type (void); diff --git a/tools/gui/ring-buffer.c b/tools/gui/ring-buffer.c index 5915d2a..ec2638c 100644 --- a/tools/gui/ring-buffer.c +++ b/tools/gui/ring-buffer.c @@ -12,7 +12,7 @@ ring_buffer_new (gsize block_size, buffer->block_size = block_size; buffer->n_blocks_total = n_blocks; buffer->n_blocks_used = 0; - buffer->start_index = 0; + buffer->current_index = 0; buffer->data = g_malloc0_n (n_blocks, block_size); return buffer; @@ -29,13 +29,13 @@ void ring_buffer_reset (RingBuffer *buffer) { buffer->n_blocks_used = 0; - buffer->start_index = 0; + buffer->current_index = 0; } gpointer ring_buffer_get_current_pointer (RingBuffer *buffer) { - return ring_buffer_get_pointer (buffer, 0); + return buffer->data + (buffer->current_index % buffer->n_blocks_total) * buffer->block_size; } gpointer @@ -43,7 +43,7 @@ ring_buffer_get_pointer (RingBuffer *buffer, guint index) { g_assert (index < buffer->n_blocks_total); - return buffer->data + ((buffer->start_index + index) % buffer->n_blocks_total) * buffer->block_size; + return buffer->data + ((buffer->current_index - buffer->n_blocks_used + index) % buffer->n_blocks_total) * buffer->block_size; } guint @@ -55,10 +55,10 @@ ring_buffer_get_num_blocks (RingBuffer *buffer) void ring_buffer_proceed (RingBuffer *buffer) { - buffer->start_index++; + buffer->current_index++; if (buffer->n_blocks_used < buffer->n_blocks_total) buffer->n_blocks_used++; else - buffer->start_index = buffer->start_index % buffer->n_blocks_total; + buffer->current_index = buffer->current_index % buffer->n_blocks_total; } diff --git a/tools/gui/ring-buffer.h b/tools/gui/ring-buffer.h index 22cbde7..9966eb7 100644 --- a/tools/gui/ring-buffer.h +++ b/tools/gui/ring-buffer.h @@ -10,7 +10,7 @@ typedef struct { gsize block_size; guint n_blocks_total; guint n_blocks_used; - guint start_index; + guint current_index; } RingBuffer; RingBuffer * ring_buffer_new (gsize block_size, -- cgit v1.2.3 From e1ab5f557171c94c0b86203cd2ecb50bb9a52ab0 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang Date: Tue, 16 Oct 2012 11:09:39 +0200 Subject: Add zoom functionality --- tools/gui/control.c | 103 ++++++++++++++++++++++++++++++++++++------------ tools/gui/control.glade | 90 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 163 insertions(+), 30 deletions(-) (limited to 'tools/gui/control.c') diff --git a/tools/gui/control.c b/tools/gui/control.c index f26cafc..c9fd2f6 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -41,6 +41,7 @@ typedef struct { GtkWidget *start_button; GtkWidget *stop_button; GtkWidget *record_button; + GtkComboBox *zoom_box; GtkWidget *histogram_view; GtkToggleButton *histogram_button; @@ -48,12 +49,13 @@ typedef struct { RingBuffer *buffer; guchar *pixels; + gint display_width, display_height; + gdouble zoom_factor; State state; - int timestamp; - int width; - int height; - int pixel_size; + gint timestamp; + gint width, height; + gint pixel_size; } ThreadData; static UcaPluginManager *plugin_manager; @@ -66,32 +68,42 @@ convert_grayscale_to_rgb (ThreadData *data, gpointer buffer) gdouble max; gdouble factor; guint8 *output; + gint i = 0; + gint stride; egg_histogram_get_visible_range (EGG_HISTOGRAM_VIEW (data->histogram_view), &min, &max); factor = 255.0 / (max - min); output = data->pixels; + stride = (gint) 1 / data->zoom_factor; if (data->pixel_size == 1) { guint8 *input = (guint8 *) buffer; - for (int i = 0, j = 0; i < data->width * data->height; i++) { - guchar val = (guchar) ((input[i] - min) * factor); - output[j++] = val; - output[j++] = val; - output[j++] = val; - /* if (i < 10) { */ - /* g_print ("%i->%i ", input[i], val); */ - /* } */ + for (gint y = 0; y < data->display_height; y++) { + gint offset = y * stride * data->width; + + for (gint x = 0; x < data->display_width; x++, offset += stride) { + guchar val = (guchar) ((input[offset] - min) * factor); + + output[i++] = val; + output[i++] = val; + output[i++] = val; + } } } else if (data->pixel_size == 2) { guint16 *input = (guint16 *) buffer; - for (int i = 0, j = 0; i < data->width * data->height; i++) { - guchar val = (guint8) ((input[i] - min) * factor); - output[j++] = val; - output[j++] = val; - output[j++] = val; + for (gint y = 0; y < data->display_height; y++) { + gint offset = y * stride * data->width; + + for (gint x = 0; x < data->display_width; x++, offset += stride) { + guchar val = (guchar) ((input[offset] - min) * factor); + + output[i++] = val; + output[i++] = val; + output[i++] = val; + } } } } @@ -100,14 +112,24 @@ static void update_pixbuf (ThreadData *data) { gdk_flush (); - gtk_image_clear (GTK_IMAGE (data->image)); gtk_image_set_from_pixbuf (GTK_IMAGE (data->image), data->pixbuf); - gtk_widget_queue_draw_area (data->image, 0, 0, data->width, data->height); + gtk_widget_queue_draw_area (data->image, 0, 0, data->display_width, data->display_height); if (gtk_toggle_button_get_active (data->histogram_button)) gtk_widget_queue_draw (data->histogram_view); } +static void +update_pixbuf_dimensions (ThreadData *data) +{ + if (data->pixbuf != NULL) + g_object_unref (data->pixbuf); + + data->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, data->display_width, data->display_height); + data->pixels = gdk_pixbuf_get_pixels (data->pixbuf); + gtk_image_set_from_pixbuf (GTK_IMAGE (data->image), data->pixbuf); +} + static gpointer preview_frames (void *args) { @@ -182,6 +204,8 @@ set_tool_button_state (ThreadData *data) data->state == RUNNING || data->state == RECORDING); gtk_widget_set_sensitive (data->record_button, data->state == IDLE); + gtk_widget_set_sensitive (GTK_WIDGET (data->zoom_box), + data->state == IDLE); } static void @@ -267,6 +291,28 @@ on_histogram_changed (EggHistogramView *view, ThreadData *data) update_current_frame (data); } +static void +on_zoom_changed (GtkComboBox *widget, ThreadData *data) +{ + GtkTreeModel *model; + GtkTreeIter iter; + gdouble factor; + + enum { + DISPLAY_COLUMN, + FACTOR_COLUMN + }; + + model = gtk_combo_box_get_model (widget); + gtk_combo_box_get_active_iter (widget, &iter); + gtk_tree_model_get (model, &iter, FACTOR_COLUMN, &factor, -1); + + data->display_width = (gint) data->width * factor; + data->display_height = (gint) data->height * factor; + data->zoom_factor = factor; + update_pixbuf_dimensions (data); +} + static void create_main_window (GtkBuilder *builder, const gchar* camera_name) { @@ -278,9 +324,9 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) GtkWidget *property_tree_view; GdkPixbuf *pixbuf; GtkBox *histogram_box; - GtkContainer *property_window; - GtkAdjustment *max_bin_adjustment; - RingBuffer *ring_buffer; + GtkContainer *property_window; + GtkAdjustment *max_bin_adjustment; + RingBuffer *ring_buffer; gsize image_size; guint n_frames; guint bits_per_sample; @@ -309,6 +355,7 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); max_bin_adjustment = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "max-bin-value-adjustment")); + td.zoom_box = GTK_COMBO_BOX (gtk_builder_get_object (builder, "zoom-box")); td.start_button = GTK_WIDGET (gtk_builder_get_object (builder, "start-button")); td.stop_button = GTK_WIDGET (gtk_builder_get_object (builder, "stop-button")); td.record_button = GTK_WIDGET (gtk_builder_get_object (builder, "record-button")); @@ -336,15 +383,18 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) td.pixel_size = pixel_size; td.image = image; - td.pixbuf = pixbuf; + td.pixbuf = NULL; + td.pixels = NULL; td.buffer = ring_buffer; - td.pixels = gdk_pixbuf_get_pixels (pixbuf); td.state = IDLE; td.camera = camera; - td.width = width; - td.height = height; + td.width = td.display_width = width; + td.height = td.display_height = height; + td.zoom_factor = 1.0; td.histogram_view = histogram_view; + update_pixbuf_dimensions (&td); + /* Hook up signals */ g_object_bind_property (gtk_builder_get_object (builder, "min-bin-value-adjustment"), "value", td.histogram_view, "minimum-bin-value", @@ -358,6 +408,7 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) g_signal_connect (td.start_button, "clicked", G_CALLBACK (on_start_button_clicked), &td); g_signal_connect (td.stop_button, "clicked", G_CALLBACK (on_stop_button_clicked), &td); g_signal_connect (td.record_button, "clicked", G_CALLBACK (on_record_button_clicked), &td); + g_signal_connect (td.zoom_box, "changed", G_CALLBACK (on_zoom_changed), &td); g_signal_connect (histogram_view, "changed", G_CALLBACK (on_histogram_changed), &td); g_signal_connect (window, "destroy", G_CALLBACK (on_destroy), &td); diff --git a/tools/gui/control.glade b/tools/gui/control.glade index 90d9511..37f8150 100644 --- a/tools/gui/control.glade +++ b/tools/gui/control.glade @@ -200,6 +200,7 @@ True + 10 @@ -310,11 +311,70 @@ - + True - True - frames-adjustment - 0 + 10 + 2 + 2 + 6 + 6 + + + True + True + frames-adjustment + 0 + + + 1 + 2 + 1 + 2 + GTK_FILL + + + + + True + 1 + Frame: + + + 1 + 2 + GTK_FILL + + + + + + True + 1 + Zoom: + + + GTK_FILL + + + + + + True + zoom-values + + + + 0 + + + + + 1 + 2 + GTK_FILL + GTK_FILL + + 1 @@ -365,6 +425,28 @@ + + + + + + + + + + 100 % + 1 + + + 50 % + 0.5 + + + 25 % + 0.25 + + + 6 -- cgit v1.2.3 From a1ab005916ba3aa50923294c5be3da0ded16fbc0 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang Date: Thu, 18 Oct 2012 10:56:30 +0200 Subject: Add download button and make dimax work --- plugins/pco/uca-pco-camera.c | 3 ++- src/uca-camera.c | 5 +++++ src/uca-camera.h | 3 ++- tools/gui/control.c | 48 ++++++++++++++++++++++++++++++++++++++++---- tools/gui/control.glade | 12 +++++++++++ 5 files changed, 65 insertions(+), 6 deletions(-) (limited to 'tools/gui/control.c') diff --git a/plugins/pco/uca-pco-camera.c b/plugins/pco/uca-pco-camera.c index 92f814e..d5f5593 100644 --- a/plugins/pco/uca-pco-camera.c +++ b/plugins/pco/uca-pco-camera.c @@ -554,7 +554,8 @@ uca_pco_camera_grab(UcaCamera *camera, gpointer *data, GError **error) if (is_readout) { if (priv->current_image == priv->num_recorded_images) { - *data = NULL; + g_set_error (error, UCA_CAMERA_ERROR, UCA_CAMERA_ERROR_END_OF_STREAM, + "End of data stream"); return; } diff --git a/src/uca-camera.c b/src/uca-camera.c index 8b08359..9210a05 100644 --- a/src/uca-camera.c +++ b/src/uca-camera.c @@ -47,6 +47,7 @@ G_DEFINE_TYPE(UcaCamera, uca_camera, G_TYPE_OBJECT) * @UCA_CAMERA_ERROR_NOT_RECORDING: Camera is not recording * @UCA_CAMERA_ERROR_NO_GRAB_FUNC: No grab callback was set * @UCA_CAMERA_ERROR_NOT_IMPLEMENTED: Virtual function is not implemented + * @UCA_CAMERA_ERROR_END_OF_STREAM: Data stream has ended. */ GQuark uca_camera_error_quark() { @@ -602,6 +603,10 @@ uca_camera_trigger (UcaCamera *camera, GError **error) * * You must have called uca_camera_start_recording() before, otherwise you will * get a #UCA_CAMERA_ERROR_NOT_RECORDING error. + * + * If *data is %NULL after returning from uca_camera_grab() and error is also + * %NULL, the data stream has ended. For example, with cameras that support + * in-camera memory, all frames have been transfered. */ void uca_camera_grab (UcaCamera *camera, gpointer *data, GError **error) diff --git a/src/uca-camera.h b/src/uca-camera.h index d84b5f2..ef3bf14 100644 --- a/src/uca-camera.h +++ b/src/uca-camera.h @@ -40,7 +40,8 @@ typedef enum { UCA_CAMERA_ERROR_RECORDING, UCA_CAMERA_ERROR_NOT_RECORDING, UCA_CAMERA_ERROR_NO_GRAB_FUNC, - UCA_CAMERA_ERROR_NOT_IMPLEMENTED + UCA_CAMERA_ERROR_NOT_IMPLEMENTED, + UCA_CAMERA_ERROR_END_OF_STREAM } UcaCameraError; typedef enum { diff --git a/tools/gui/control.c b/tools/gui/control.c index c9fd2f6..930c4d0 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -41,6 +41,7 @@ typedef struct { GtkWidget *start_button; GtkWidget *stop_button; GtkWidget *record_button; + GtkWidget *download_button; GtkComboBox *zoom_box; GtkWidget *histogram_view; @@ -52,6 +53,7 @@ typedef struct { gint display_width, display_height; gdouble zoom_factor; State state; + gboolean data_in_camram; gint timestamp; gint width, height; @@ -88,7 +90,7 @@ convert_grayscale_to_rgb (ThreadData *data, gpointer buffer) output[i++] = val; output[i++] = val; output[i++] = val; - } + } } } else if (data->pixel_size == 2) { @@ -103,7 +105,7 @@ convert_grayscale_to_rgb (ThreadData *data, gpointer buffer) output[i++] = val; output[i++] = val; output[i++] = val; - } + } } } } @@ -204,6 +206,8 @@ set_tool_button_state (ThreadData *data) data->state == RUNNING || data->state == RECORDING); gtk_widget_set_sensitive (data->record_button, data->state == IDLE); + gtk_widget_set_sensitive (data->download_button, + data->data_in_camram); gtk_widget_set_sensitive (GTK_WIDGET (data->zoom_box), data->state == IDLE); } @@ -254,12 +258,14 @@ on_stop_button_clicked (GtkWidget *widget, ThreadData *data) { GError *error = NULL; + g_object_get (data->camera, "has-camram-recording", &data->data_in_camram, NULL); data->state = IDLE; set_tool_button_state (data); uca_camera_stop_recording (data->camera, &error); if (error != NULL) g_printerr ("Failed to stop: %s\n", error->message); + } static void @@ -284,6 +290,38 @@ on_record_button_clicked (GtkWidget *widget, ThreadData *data) } } +static void +on_download_button_clicked (GtkWidget *widget, ThreadData *data) +{ + gpointer buffer; + GError *error = NULL; + + uca_camera_start_readout (data->camera, &error); + + if (error != NULL) { + g_printerr ("Failed to start read out of camera memory: %s\n", error->message); + return; + } + + ring_buffer_reset (data->buffer); + + while (error == NULL) { + buffer = ring_buffer_get_current_pointer (data->buffer); + uca_camera_grab (data->camera, &buffer, &error); + ring_buffer_proceed (data->buffer); + } + + if (error->code != UCA_CAMERA_ERROR_END_OF_STREAM) { + guint n_frames = ring_buffer_get_num_blocks (data->buffer); + + gtk_adjustment_set_upper (data->frame_slider, n_frames - 1); + gtk_adjustment_set_value (data->frame_slider, n_frames - 1); + } + else { + g_printerr ("Error while reading out frames: %s\n", error->message); + } +} + static void on_histogram_changed (EggHistogramView *view, ThreadData *data) { @@ -359,6 +397,7 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) td.start_button = GTK_WIDGET (gtk_builder_get_object (builder, "start-button")); td.stop_button = GTK_WIDGET (gtk_builder_get_object (builder, "stop-button")); td.record_button = GTK_WIDGET (gtk_builder_get_object (builder, "record-button")); + td.download_button = GTK_WIDGET (gtk_builder_get_object (builder, "download-button")); td.histogram_button = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "histogram-checkbutton")); td.frame_slider = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "frames-adjustment")); @@ -368,8 +407,6 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) n_frames = mem_size * 1024 * 1024 / image_size; ring_buffer = ring_buffer_new (image_size, n_frames); - set_tool_button_state (&td); - egg_histogram_view_set_data (EGG_HISTOGRAM_VIEW (histogram_view), ring_buffer_get_current_pointer (ring_buffer), width * height, bits_per_sample, 256); @@ -392,8 +429,10 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) td.height = td.display_height = height; td.zoom_factor = 1.0; td.histogram_view = histogram_view; + td.data_in_camram = FALSE; update_pixbuf_dimensions (&td); + set_tool_button_state (&td); /* Hook up signals */ g_object_bind_property (gtk_builder_get_object (builder, "min-bin-value-adjustment"), "value", @@ -408,6 +447,7 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) g_signal_connect (td.start_button, "clicked", G_CALLBACK (on_start_button_clicked), &td); g_signal_connect (td.stop_button, "clicked", G_CALLBACK (on_stop_button_clicked), &td); g_signal_connect (td.record_button, "clicked", G_CALLBACK (on_record_button_clicked), &td); + g_signal_connect (td.download_button, "clicked", G_CALLBACK (on_download_button_clicked), &td); g_signal_connect (td.zoom_box, "changed", G_CALLBACK (on_zoom_changed), &td); g_signal_connect (histogram_view, "changed", G_CALLBACK (on_histogram_changed), &td); g_signal_connect (window, "destroy", G_CALLBACK (on_destroy), &td); diff --git a/tools/gui/control.glade b/tools/gui/control.glade index 37f8150..2d2aaac 100644 --- a/tools/gui/control.glade +++ b/tools/gui/control.glade @@ -152,6 +152,18 @@ True + + + True + Download + True + network-receive + + + False + True + + False -- cgit v1.2.3 From 983005dfbc3b07093145c0b964063e334b928d48 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang Date: Thu, 18 Oct 2012 12:44:40 +0200 Subject: Fix download of in-camera frames --- NEWS | 2 ++ plugins/pco/uca-pco-camera.c | 25 ++++++++++++++++++++++--- src/uca-camera.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/uca-camera.h | 3 +++ tools/gui/control.c | 10 +++++++--- 5 files changed, 78 insertions(+), 6 deletions(-) (limited to 'tools/gui/control.c') diff --git a/NEWS b/NEWS index f0a4c30..7a91e80 100644 --- a/NEWS +++ b/NEWS @@ -23,6 +23,8 @@ Minor changes - It is now possible to generate GObject introspection meta data to bind libuca to all languages that support GObject introspection. +- Added uca_camera_stop_readout() to cleanup after using + uca_camera_start_readout(). Changes in libuca 1.0 aka 0.6 diff --git a/plugins/pco/uca-pco-camera.c b/plugins/pco/uca-pco-camera.c index d5f5593..03a1a17 100644 --- a/plugins/pco/uca-pco-camera.c +++ b/plugins/pco/uca-pco-camera.c @@ -385,7 +385,7 @@ check_pco_property_error (guint err, guint property_id) { if (err != PCO_NOERROR) { g_warning ("Call to libpco failed with error code %x for property `%s'", - err, + err, pco_properties[property_id]->name); } } @@ -523,9 +523,27 @@ uca_pco_camera_start_readout(UcaCamera *camera, GError **error) err = pco_get_num_images(priv->pco, priv->active_segment, &priv->num_recorded_images); HANDLE_PCO_ERROR(err); + err = Fg_AcquireEx(priv->fg, priv->fg_port, GRAB_INFINITE, ACQ_STANDARD, priv->fg_mem); + FG_SET_ERROR(err, priv->fg, UCA_PCO_CAMERA_ERROR_FG_ACQUISITION); + + priv->last_frame = 0; priv->current_image = 1; } +static void +uca_pco_camera_stop_readout(UcaCamera *camera, GError **error) +{ + g_return_if_fail(UCA_IS_PCO_CAMERA(camera)); + UcaPcoCameraPrivate *priv = UCA_PCO_CAMERA_GET_PRIVATE(camera); + + guint err = Fg_stopAcquireEx(priv->fg, priv->fg_port, priv->fg_mem, STOP_SYNC); + FG_SET_ERROR(err, priv->fg, UCA_PCO_CAMERA_ERROR_FG_ACQUISITION); + + err = Fg_setStatusEx(priv->fg, FG_UNBLOCK_ALL, 0, priv->fg_port, priv->fg_mem); + if (err == FG_INVALID_PARAMETER) + g_warning(" Unable to unblock all\n"); +} + static void uca_pco_camera_trigger(UcaCamera *camera, GError **error) { @@ -568,7 +586,7 @@ uca_pco_camera_grab(UcaCamera *camera, gpointer *data, GError **error) } pco_request_image(priv->pco); - priv->last_frame = Fg_getLastPicNumberBlockingEx(priv->fg, priv->last_frame+1, priv->fg_port, MAX_TIMEOUT, priv->fg_mem); + priv->last_frame = Fg_getLastPicNumberBlockingEx(priv->fg, priv->last_frame + 1, priv->fg_port, MAX_TIMEOUT, priv->fg_mem); if (priv->last_frame <= 0) { guint err = FG_OK + 1; @@ -1189,6 +1207,7 @@ uca_pco_camera_class_init(UcaPcoCameraClass *klass) camera_class->start_recording = uca_pco_camera_start_recording; camera_class->stop_recording = uca_pco_camera_stop_recording; camera_class->start_readout = uca_pco_camera_start_readout; + camera_class->stop_readout = uca_pco_camera_stop_readout; camera_class->trigger = uca_pco_camera_trigger; camera_class->grab = uca_pco_camera_grab; @@ -1383,7 +1402,7 @@ uca_pco_camera_init(UcaPcoCamera *self) camera = UCA_CAMERA (self); uca_camera_register_unit (camera, "sensor-width-extended", UCA_UNIT_PIXEL); uca_camera_register_unit (camera, "sensor-height-extended", UCA_UNIT_PIXEL); - uca_camera_register_unit (camera, "temperature", UCA_UNIT_DEGREE_CELSIUS); + uca_camera_register_unit (camera, "sensor-temperature", UCA_UNIT_DEGREE_CELSIUS); uca_camera_register_unit (camera, "cooling-point", UCA_UNIT_DEGREE_CELSIUS); uca_camera_register_unit (camera, "cooling-point-min", UCA_UNIT_DEGREE_CELSIUS); uca_camera_register_unit (camera, "cooling-point-max", UCA_UNIT_DEGREE_CELSIUS); diff --git a/src/uca-camera.c b/src/uca-camera.c index 9210a05..053dcca 100644 --- a/src/uca-camera.c +++ b/src/uca-camera.c @@ -542,6 +542,50 @@ uca_camera_start_readout (UcaCamera *camera, GError **error) g_static_mutex_unlock (&mutex); } +/** + * uca_camera_stop_readout: + * @camera: A #UcaCamera object + * @error: Location to store a #UcaCameraError error or %NULL + * + * Stop reading out frames. + * + * Since: 1.1 + */ +void +uca_camera_stop_readout (UcaCamera *camera, GError **error) +{ + UcaCameraClass *klass; + static GStaticMutex mutex = G_STATIC_MUTEX_INIT; + + g_return_if_fail (UCA_IS_CAMERA(camera)); + + klass = UCA_CAMERA_GET_CLASS(camera); + + g_return_if_fail (klass != NULL); + g_return_if_fail (klass->start_readout != NULL); + + g_static_mutex_lock (&mutex); + + if (camera->priv->is_recording) { + g_set_error (error, UCA_CAMERA_ERROR, UCA_CAMERA_ERROR_RECORDING, + "Camera is still recording"); + } + else { + GError *tmp_error = NULL; + + (*klass->stop_readout) (camera, &tmp_error); + + if (tmp_error == NULL) { + camera->priv->is_readout = FALSE; + g_object_notify (G_OBJECT (camera), "is-readout"); + } + else + g_propagate_error (error, tmp_error); + } + + g_static_mutex_unlock (&mutex); +} + /** * uca_camera_set_grab_func: * @camera: A #UcaCamera object diff --git a/src/uca-camera.h b/src/uca-camera.h index ef3bf14..78edd95 100644 --- a/src/uca-camera.h +++ b/src/uca-camera.h @@ -126,6 +126,7 @@ struct _UcaCameraClass { void (*start_recording) (UcaCamera *camera, GError **error); void (*stop_recording) (UcaCamera *camera, GError **error); void (*start_readout) (UcaCamera *camera, GError **error); + void (*stop_readout) (UcaCamera *camera, GError **error); void (*trigger) (UcaCamera *camera, GError **error); void (*grab) (UcaCamera *camera, gpointer *data, GError **error); @@ -141,6 +142,8 @@ void uca_camera_stop_recording (UcaCamera *camera, GError **error); void uca_camera_start_readout (UcaCamera *camera, GError **error); +void uca_camera_stop_readout (UcaCamera *camera, + GError **error); void uca_camera_trigger (UcaCamera *camera, GError **error); void uca_camera_grab (UcaCamera *camera, diff --git a/tools/gui/control.c b/tools/gui/control.c index 930c4d0..aaeeb75 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -311,15 +311,19 @@ on_download_button_clicked (GtkWidget *widget, ThreadData *data) ring_buffer_proceed (data->buffer); } - if (error->code != UCA_CAMERA_ERROR_END_OF_STREAM) { + if (error->code == UCA_CAMERA_ERROR_END_OF_STREAM) { guint n_frames = ring_buffer_get_num_blocks (data->buffer); gtk_adjustment_set_upper (data->frame_slider, n_frames - 1); gtk_adjustment_set_value (data->frame_slider, n_frames - 1); } - else { + else g_printerr ("Error while reading out frames: %s\n", error->message); - } + + uca_camera_stop_readout (data->camera, &error); + + if (error != NULL) + g_printerr ("Failed to stop reading out of camera memory: %s\n", error->message); } static void -- cgit v1.2.3 From 694d4b4edd93bc8fdba6f578454d6b7b9f95003f Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang Date: Thu, 18 Oct 2012 13:40:58 +0200 Subject: Free error that will be set during download --- tools/gui/control.c | 1 + 1 file changed, 1 insertion(+) (limited to 'tools/gui/control.c') diff --git a/tools/gui/control.c b/tools/gui/control.c index aaeeb75..a5ef410 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -320,6 +320,7 @@ on_download_button_clicked (GtkWidget *widget, ThreadData *data) else g_printerr ("Error while reading out frames: %s\n", error->message); + g_error_free (error); uca_camera_stop_readout (data->camera, &error); if (error != NULL) -- cgit v1.2.3 From 4db2ac7026ae3bc85807016cb2510fed996a2a20 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang Date: Thu, 18 Oct 2012 13:44:44 +0200 Subject: Don't make memory argument optional If `-m' is supplied, a number must follow. --- tools/gui/control.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/gui/control.c') diff --git a/tools/gui/control.c b/tools/gui/control.c index a5ef410..0d08893 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -538,7 +538,7 @@ main (int argc, char *argv[]) static GOptionEntry entries[] = { - { "mem-size", 'm', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_INT, &mem_size, "Memory in megabytes to allocate for frame storage", "M" }, + { "mem-size", 'm', 0, G_OPTION_ARG_INT, &mem_size, "Memory in megabytes to allocate for frame storage", "M" }, { NULL } }; -- cgit v1.2.3 From 2c3028f55ae1985315b8e350c1cdb26c9f7aa1a3 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang Date: Thu, 18 Oct 2012 13:47:44 +0200 Subject: Set error NULL to avoid printing false message --- tools/gui/control.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tools/gui/control.c') diff --git a/tools/gui/control.c b/tools/gui/control.c index 0d08893..07b7937 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -321,6 +321,8 @@ on_download_button_clicked (GtkWidget *widget, ThreadData *data) g_printerr ("Error while reading out frames: %s\n", error->message); g_error_free (error); + error = NULL; + uca_camera_stop_readout (data->camera, &error); if (error != NULL) -- cgit v1.2.3 From bcf80f7ddb66ee213dc493904e1b743e99d90082 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang Date: Thu, 18 Oct 2012 16:07:13 +0200 Subject: Launch download dialog to ease waiting --- tools/gui/control.c | 34 ++++++++++++++++++++-- tools/gui/control.glade | 77 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+), 3 deletions(-) (limited to 'tools/gui/control.c') diff --git a/tools/gui/control.c b/tools/gui/control.c index 07b7937..0b59837 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -44,6 +44,11 @@ typedef struct { GtkWidget *download_button; GtkComboBox *zoom_box; + GtkDialog *download_dialog; + GtkProgressBar *download_progressbar; + GtkWidget *download_close_button; + GtkAdjustment *download_adjustment; + GtkWidget *histogram_view; GtkToggleButton *histogram_button; GtkAdjustment *frame_slider; @@ -290,17 +295,21 @@ on_record_button_clicked (GtkWidget *widget, ThreadData *data) } } -static void -on_download_button_clicked (GtkWidget *widget, ThreadData *data) +static gpointer +download_frames (ThreadData *data) { gpointer buffer; + guint n_frames; GError *error = NULL; + g_object_get (data->camera, "recorded-frames", &n_frames, NULL); + g_print ("recorded %i frames\n", n_frames); + uca_camera_start_readout (data->camera, &error); if (error != NULL) { g_printerr ("Failed to start read out of camera memory: %s\n", error->message); - return; + return NULL; } ring_buffer_reset (data->buffer); @@ -327,6 +336,22 @@ on_download_button_clicked (GtkWidget *widget, ThreadData *data) if (error != NULL) g_printerr ("Failed to stop reading out of camera memory: %s\n", error->message); + + return NULL; +} + +static void +on_download_button_clicked (GtkWidget *widget, ThreadData *data) +{ + GError *error = NULL; + + if (!g_thread_create ((GThreadFunc) download_frames, data, FALSE, &error)) { + g_printerr ("Failed to create thread: %s\n", error->message); + } + + gtk_window_set_modal (GTK_WINDOW (data->download_dialog), TRUE); + gtk_dialog_run (data->download_dialog); + gtk_window_set_modal (GTK_WINDOW (data->download_dialog), FALSE); } static void @@ -408,6 +433,9 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) td.histogram_button = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "histogram-checkbutton")); td.frame_slider = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "frames-adjustment")); + td.download_dialog = GTK_DIALOG (gtk_builder_get_object (builder, "download-dialog")); + td.download_adjustment = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "download-adjustment")); + /* Set initial data */ pixel_size = bits_per_sample > 8 ? 2 : 1; image_size = pixel_size * width * height; diff --git a/tools/gui/control.glade b/tools/gui/control.glade index 2d2aaac..eec9dde 100644 --- a/tools/gui/control.glade +++ b/tools/gui/control.glade @@ -555,4 +555,81 @@ 1 10 + + 5 + normal + + + True + 2 + + + True + 10 + 6 + + + True + 0 + Downloading Frames … + + + False + False + 0 + + + + + True + download-adjustment + + + False + 1 + + + + + 1 + + + + + True + end + + + gtk-close + True + True + True + True + + + False + False + 0 + + + + + False + False + end + 0 + + + + + + download-close-button + + + + 100 + 1 + 10 + 10 + -- cgit v1.2.3 From a7a48c55df8dc3e34a2ce50b18b70c0cd101766d Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang Date: Thu, 18 Oct 2012 16:27:45 +0200 Subject: Show download progress --- plugins/pco/uca-pco-camera.c | 4 ++++ tools/gui/control.c | 20 +++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) (limited to 'tools/gui/control.c') diff --git a/plugins/pco/uca-pco-camera.c b/plugins/pco/uca-pco-camera.c index d34e0f4..5d08acf 100644 --- a/plugins/pco/uca-pco-camera.c +++ b/plugins/pco/uca-pco-camera.c @@ -506,7 +506,11 @@ uca_pco_camera_stop_recording(UcaCamera *camera, GError **error) if (err == FG_INVALID_PARAMETER) g_warning(" Unable to unblock all\n"); + err = pco_get_active_segment(priv->pco, &priv->active_segment); + HANDLE_PCO_ERROR(err); + err = pco_get_num_images(priv->pco, priv->active_segment, &priv->num_recorded_images); + g_print ("images: %i\n", priv->num_recorded_images); HANDLE_PCO_ERROR(err); } diff --git a/tools/gui/control.c b/tools/gui/control.c index 0b59837..877473e 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -36,6 +36,7 @@ typedef enum { typedef struct { UcaCamera *camera; + GtkWidget *main_window; GdkPixbuf *pixbuf; GtkWidget *image; GtkWidget *start_button; @@ -300,10 +301,14 @@ download_frames (ThreadData *data) { gpointer buffer; guint n_frames; + guint current_frame = 1; GError *error = NULL; g_object_get (data->camera, "recorded-frames", &n_frames, NULL); - g_print ("recorded %i frames\n", n_frames); + gdk_threads_enter (); + gtk_widget_set_sensitive (data->download_close_button, FALSE); + gtk_adjustment_set_upper (data->download_adjustment, n_frames); + gdk_threads_leave (); uca_camera_start_readout (data->camera, &error); @@ -318,6 +323,9 @@ download_frames (ThreadData *data) buffer = ring_buffer_get_current_pointer (data->buffer); uca_camera_grab (data->camera, &buffer, &error); ring_buffer_proceed (data->buffer); + gdk_threads_enter (); + gtk_adjustment_set_value (data->download_adjustment, current_frame++); + gdk_threads_leave (); } if (error->code == UCA_CAMERA_ERROR_END_OF_STREAM) { @@ -337,6 +345,10 @@ download_frames (ThreadData *data) if (error != NULL) g_printerr ("Failed to stop reading out of camera memory: %s\n", error->message); + gdk_threads_enter (); + gtk_widget_set_sensitive (data->download_close_button, TRUE); + gdk_threads_leave (); + return NULL; } @@ -349,9 +361,13 @@ on_download_button_clicked (GtkWidget *widget, ThreadData *data) g_printerr ("Failed to create thread: %s\n", error->message); } + gtk_widget_set_sensitive (data->main_window, FALSE); gtk_window_set_modal (GTK_WINDOW (data->download_dialog), TRUE); gtk_dialog_run (data->download_dialog); + gtk_widget_hide (GTK_WIDGET (data->download_dialog)); gtk_window_set_modal (GTK_WINDOW (data->download_dialog), FALSE); + gtk_widget_set_sensitive (data->main_window, TRUE); + gtk_window_set_modal (GTK_WINDOW (data->download_dialog), TRUE); } static void @@ -435,6 +451,7 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) td.download_dialog = GTK_DIALOG (gtk_builder_get_object (builder, "download-dialog")); td.download_adjustment = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "download-adjustment")); + td.download_close_button = GTK_WIDGET (gtk_builder_get_object (builder, "download-close-button")); /* Set initial data */ pixel_size = bits_per_sample > 8 ? 2 : 1; @@ -465,6 +482,7 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) td.zoom_factor = 1.0; td.histogram_view = histogram_view; td.data_in_camram = FALSE; + td.main_window = window; update_pixbuf_dimensions (&td); set_tool_button_state (&td); -- cgit v1.2.3