#include #include #include #include "uca.h" #include "uca-cam.h" struct ThreadData { guchar *buffer, *pixels; GtkWidget *image; GdkPixbuf *pixbuf; int width; int height; int bits; struct uca_camera_t *cam; }; enum { COLUMN_NAME = 0, COLUMN_VALUE, COLUMN_UNIT, COLUMN_UCA_ID, NUM_COLUMNS }; static gboolean delete_event(GtkWidget *widget, GdkEvent *event, gpointer data) { return FALSE; } static void destroy(GtkWidget *widget, gpointer data) { struct uca_t *uca = (struct uca_t *) data; uca_destroy(uca); gtk_main_quit (); } void convert_8bit_to_rgb(guchar *output, guchar *input, int width, int height) { for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { const int off = y*width + x; output[off*3] = input[off]; output[off*3+1] = input[off]; output[off*3+2] = input[off]; } } } void convert_16bit_to_rgb(guchar *output, guchar *input, int width, int height) { uint16_t *in = (uint16_t *) input; for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { const int off = y*width + x; guchar val = (uint8_t) ((in[off]/65536.0f)*256.0f); output[off*3] = val; output[off*3+1] = val; output[off*3+2] = val; } } } void *grab_thread(void *args) { struct ThreadData *data = (struct ThreadData *) args; struct uca_camera_t *cam = data->cam; while (TRUE) { cam->grab(cam, (char *) data->buffer); if (data->bits == 8) convert_8bit_to_rgb(data->pixels, data->buffer, data->width, data->height); else if (data->bits == 16) 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(); } } void get_first_level_root(GtkTreeStore *store, GtkTreeIter *iter, gchar *group) { GtkTreeIter root; if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &root)) { gchar *str; gtk_tree_model_get(GTK_TREE_MODEL(store), &root, 0, &str, -1); if (g_strcmp0(group, str) == 0) { *iter = root; return; } /* Iterate through all groups */ while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &root)) { gtk_tree_model_get(GTK_TREE_MODEL(store), &root, 0, &str, -1); if (g_strcmp0(group, str) == 0) { *iter = root; g_free(str); return; } } /* Not found, append the group */ g_free(str); } /* Tree is empty or group is not found */ gtk_tree_store_append(store, iter, NULL); gtk_tree_store_set(store, iter, 0, group, -1); } void find_recursively(GtkTreeStore *store, GtkTreeIter *root, GtkTreeIter *result, gchar **tokens, int depth) { GtkTreeIter iter; gchar *str; gchar *current_token = tokens[depth]; if (current_token == NULL) { *result = *root; return; } if (!gtk_tree_model_iter_has_child(GTK_TREE_MODEL(store), root)) { gtk_tree_store_append(store, &iter, root); if (tokens[depth+1] == NULL) { *result = iter; return; } else { gtk_tree_store_set(store, &iter, 0, current_token, -1); find_recursively(store, &iter, result, tokens, depth+1); } } gtk_tree_model_iter_children(GTK_TREE_MODEL(store), &iter, root); do { gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 0, &str, -1); if (g_strcmp0(current_token, str) == 0) { find_recursively(store, &iter, result, tokens, depth+1); g_free(str); return; } } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter)); g_free(str); gtk_tree_store_append(store, &iter, root); gtk_tree_store_set(store, &iter, COLUMN_NAME, current_token, -1); find_recursively(store, &iter, result, tokens, depth+1); } void fill_tree_store(GtkTreeStore *tree_store, struct uca_camera_t *cam) { GtkTreeIter iter, child; struct uca_property_t *property; gchar *value_string = g_malloc(256); guint8 value_8; guint32 value_32; for (int prop_id = 0; prop_id < UCA_PROP_LAST; prop_id++) { property = uca_get_full_property(prop_id); uint32_t result = UCA_NO_ERROR; switch (property->type) { case uca_string: result = cam->get_property(cam, prop_id, value_string); break; case uca_uint8t: result = cam->get_property(cam, prop_id, &value_8); g_sprintf(value_string, "%d", value_8); break; case uca_uint32t: result = cam->get_property(cam, prop_id, &value_32); g_sprintf(value_string, "%d", value_32); break; } /* Find first level root */ gchar **tokens = g_strsplit(property->name, ".", 0); get_first_level_root(tree_store, &iter, tokens[0]); find_recursively(tree_store, &iter, &child, tokens, 1); if (result == UCA_ERR_PROP_INVALID) g_sprintf(value_string, "n/a"); int count = 0; while (tokens[count++] != NULL); gtk_tree_store_set(tree_store, &child, COLUMN_NAME, tokens[count-2], COLUMN_VALUE, value_string, COLUMN_UNIT, uca_unit_map[property->unit], COLUMN_UCA_ID, prop_id, -1); g_strfreev(tokens); } g_free(value_string); } void value_cell_data_func(GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data) { uint32_t prop_id; gtk_tree_model_get(model, iter, COLUMN_UCA_ID, &prop_id, -1); struct uca_property_t *property = uca_get_full_property(prop_id); if (property->access & uca_write) { g_object_set(cell, "mode", GTK_CELL_RENDERER_MODE_EDITABLE, NULL); g_object_set(GTK_CELL_RENDERER_TEXT(cell), "editable", TRUE, NULL); g_object_set(GTK_CELL_RENDERER_TEXT(cell), "style", PANGO_STYLE_NORMAL, NULL); } else { g_object_set(cell, "mode", GTK_CELL_RENDERER_MODE_INERT, NULL); g_object_set(GTK_CELL_RENDERER_TEXT(cell), "editable", FALSE, NULL); g_object_set(GTK_CELL_RENDERER_TEXT(cell), "style", PANGO_STYLE_ITALIC, NULL); } } int main(int argc, char *argv[]) { struct uca_t *uca = uca_init(); if (uca == NULL) { g_print("Couldn't initialize frame grabber and/or cameras\n"); return 1; } int width, height, bits_per_sample; struct uca_camera_t *cam = uca->cameras; cam->get_property(cam, UCA_PROP_WIDTH, &width); cam->get_property(cam, UCA_PROP_HEIGHT, &height); cam->get_property(cam, UCA_PROP_BITDEPTH, &bits_per_sample); g_thread_init(NULL); gdk_threads_init(); gtk_init (&argc, &argv); GtkBuilder *builder = gtk_builder_new(); GError *error = NULL; if (!gtk_builder_add_from_file(builder, "control.glade", &error)) { g_print("Couldn't load UI file!\n"); g_print("Message: %s\n", error->message); g_free(error); } GtkWidget *window = GTK_WIDGET(gtk_builder_get_object(builder, "window")); GtkWidget *image = GTK_WIDGET(gtk_builder_get_object(builder, "image")); GtkTreeStore *tree_store = GTK_TREE_STORE(gtk_builder_get_object(builder, "cameraproperties")); GtkTreeViewColumn *value_column = GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(builder, "valuecolumn")); GtkCellRendererText *value_renderer = GTK_CELL_RENDERER_TEXT(gtk_builder_get_object(builder, "valuecell")); fill_tree_store(tree_store, cam); gtk_tree_view_column_set_cell_data_func(value_column, GTK_CELL_RENDERER(value_renderer), value_cell_data_func, NULL, NULL); g_signal_connect (window, "delete-event", G_CALLBACK (delete_event), NULL); g_signal_connect (window, "destroy", G_CALLBACK (destroy), uca); GdkPixbuf *pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, width, height); gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf); gtk_widget_show(image); gtk_widget_show(window); /* start grabbing and thread */ int mem_size = bits_per_sample == 8 ? 1 : 2; struct ThreadData td; uca_cam_alloc(cam, 20); td.image = image; td.pixbuf = pixbuf; td.buffer = (guchar *) g_malloc(mem_size * width * height); td.pixels = gdk_pixbuf_get_pixels(pixbuf); td.width = width; td.height = height; td.bits = bits_per_sample; td.cam = cam; cam->start_recording(cam); if (!g_thread_create(grab_thread, &td, FALSE, &error)) { g_printerr("Failed to create thread: %s\n", error->message); uca_destroy(uca); return 1; } gdk_threads_enter(); gtk_main (); gdk_threads_leave(); return 0; }