/*************************************************************************************** * * main.cc is part of SimpleSkyCam. * *****************************************************************************************/ #if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) #else #include /* close() */ #endif #include #include #include #include "gui.h" #include "config.h" #include "video.h" #include "output.h" #include "detect.h" #include "configuration.h" extern GtkBuilder *_builder_; // work around for threads extern Output output; extern Detect detect; // // defines what should happen on clicking a point on the input videodata int video_enterdata = VID_ENTERDATA_NONE; // see VID_ENTERDATA_xxxxx position_2d video_enterdata_pos; detect_movement detectedpos_data = {0}; GtkWidget *detect_da = NULL; GdkPixbuf *detect_pixbuf = NULL; GtkWidget *image_da = NULL; GdkPixbuf *image_pixbuf = NULL; extern GtkWidget *debug_da; extern GdkPixbuf *debug_pixbuf; std::string filename = ""; extern Configuration config; ////////////////////////////////////////////////////////////////////////////////////////////////// // // call back functions // gboolean cb_window_delete_event (GtkWidget *widget, GdkEvent *event, gpointer data) { config.SaveDefault(); gtk_main_quit(); return FALSE; }; // // setup default values // void cb_window_show (GtkWidget *widget, gpointer data) { GtkWidget *btnstart = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "btn-video-rec")); GtkWidget *btnstop = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "btn-video-stop")); GtkWidget *w = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-entry-w")); GtkWidget *h = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-entry-h")); GtkWidget *rbdefdetect = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-pos-cbbright")); GtkWidget *rbdeffolow = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-type-indet2")); // changing the value, will cause the 'change' event to be triggered gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rbdefdetect), true); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rbdeffolow), true); gtk_widget_set_sensitive(btnstart, true); gtk_widget_set_sensitive(btnstop, false); gtk_entry_set_text(GTK_ENTRY(w),"300"); gtk_entry_set_text(GTK_ENTRY(h),"300"); detect.SetObjectSize(300, 300); cb_video_btnrefreshlist (NULL, NULL); // // load config and setup elements config.LoadDefault(); // // show debug output window. if (config.show_debugwin) { printf ("%s:%d show debug window\n", __FILE__, __LINE__); GtkWidget *wnd = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "window-debug")); if (wnd) gtk_widget_show (wnd); } GtkWidget *cfg_rgbenc = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "menu-settings-bilinearrgb")); gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM(cfg_rgbenc), (config.debayer_mode != 0)); // // update the input video controls every 2 seconds. g_timeout_add(2000, videoctrl_update, NULL); }; void cb_menu_set_rgbenc (GtkCheckMenuItem *checkmenuitem, gpointer user_data) { if (gtk_check_menu_item_get_active(checkmenuitem) == TRUE) config.debayer_mode = 1; else config.debayer_mode = 0; } // // callback from filter thread. Data will point to the output VideoFrame. // Access to this data must be Locked before use. // /* gboolean cb_thread_filter (gpointer data) { VideoFrame *vf = (VideoFrame *) data; int pix_h, pix_w; if (image_da == NULL) image_da = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "image-da")); if (vf == NULL) { return false; } output.LockImageMutex(); if (image_pixbuf) { pix_h = gdk_pixbuf_get_height(image_pixbuf); pix_w = gdk_pixbuf_get_width(image_pixbuf); } else pix_h = 0; if (image_pixbuf == NULL || pix_h != vf->h || pix_w != vf->w) { if (image_pixbuf != NULL) g_object_unref (image_pixbuf); printf ("%s:%d %s New Pixbuf: %d x %d\n", __FILE__, __LINE__, __FUNCTION__, vf->w, vf->h); image_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, false, 8, vf->w, vf->h); pix_w = vf->w; pix_h = vf->h; } vf->ToPixbuf(image_pixbuf); gdk_window_invalidate_rect(gtk_widget_get_window(image_da), NULL, true); output.UnLockImageMutex(); return false; }; */ // // callback from detect thread. Data will point to the temp VideoFrame. // this is propabely the object detection // Access to this data must be Locked before use and pointers must be looked to gboolean cb_thread_detect (gpointer data) { GtkWidget *e_x = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-entry-posx")); GtkWidget *e_y = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-entry-posy")); DetectOutput *dout = (DetectOutput *) data; int pix_h, pix_w, x, y; if (detect_da == NULL) detect_da = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "temp-da")); if (dout == NULL) return false; if (dout->image == NULL) return false; detect.LockImageMutex(); gtk_entry_set_text(GTK_ENTRY(e_x), std::to_string(dout->posx).c_str()); gtk_entry_set_text(GTK_ENTRY(e_y), std::to_string(dout->posy).c_str()); x = dout->posx; // save value for later use (unlocked image data) y = dout->posy; if (detect_pixbuf) { pix_h = gdk_pixbuf_get_height(detect_pixbuf); pix_w = gdk_pixbuf_get_width(detect_pixbuf); } else pix_h = 0; if (detect_pixbuf == NULL || pix_h != dout->image->h || pix_w != dout->image->w) { if (detect_pixbuf != NULL) g_object_unref (detect_pixbuf); printf ("%s:%d %s New Pixbuf: %d x %d\n", __FILE__, __LINE__, __FUNCTION__, dout->image->w, dout->image->h); detect_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, false, 8, dout->image->w, dout->image->h); pix_w = dout->image->w; pix_h = dout->image->h; } dout->image->ToPixbuf(&detect_pixbuf); gdk_window_invalidate_rect(gtk_widget_get_window(detect_da), NULL, true); output.NewFrame(dout->rawimage); detect.UnLockImageMutex(); // // detect movements, by creating a ring buffer and we comptare the current // position with the one DETECT_MOVEMENT_SAMPLES frames ago. // struct timeval tv = detectedpos_data.samples[0].ts; float ftime = get_cycletime(&tv); float fdist = sqrtf ( (x-detectedpos_data.samples[DETECT_MOVEMENT_SAMPLES-1].x) * (x-detectedpos_data.samples[DETECT_MOVEMENT_SAMPLES-1].x) + (y-detectedpos_data.samples[DETECT_MOVEMENT_SAMPLES-1].y) * (y-detectedpos_data.samples[DETECT_MOVEMENT_SAMPLES-1].y)); if (fdist > 20.0) { for (int i = 0; i < DETECT_MOVEMENT_SAMPLES; i++) { detectedpos_data.samples[i].x = x; detectedpos_data.samples[i].y = y; detectedpos_data.samples[i].ts = tv; } } detectedpos_data.dx = (float)(x-detectedpos_data.samples[0].x) / ftime; detectedpos_data.dy = (float)(y-detectedpos_data.samples[0].y) / ftime; for (int i = 1; i < DETECT_MOVEMENT_SAMPLES; i++) detectedpos_data.samples[i-1] = detectedpos_data.samples[i]; detectedpos_data.samples[DETECT_MOVEMENT_SAMPLES-1].ts = tv; detectedpos_data.samples[DETECT_MOVEMENT_SAMPLES-1].x = x; detectedpos_data.samples[DETECT_MOVEMENT_SAMPLES-1].y = y; return false; }; void cb_imagetempda_draw(GtkWidget *area, cairo_t *cr, int w, int h, gpointer data) { int clientw, clienth, pixbufw, pixbufh; float clientar, pixbufar; GdkPixbuf *pixbuf = NULL; GdkPixbuf *src = NULL; if (area == image_da) src = image_pixbuf; else if (area == detect_da) src = detect_pixbuf; else if (area == debug_da && debug_pixbuf != NULL) src = debug_pixbuf; else return; clienth = gtk_widget_get_allocated_height(area); clientw = gtk_widget_get_allocated_width(area); clientar = (float)clientw/(float)clienth; pixbufh = gdk_pixbuf_get_height(src); pixbufw = gdk_pixbuf_get_width(src); pixbufar = (float)pixbufw/(float)pixbufh; if (pixbufar < clientar) { clientw = (pixbufar * (float) clienth); } else { clienth = ((float) clientw / pixbufar); } pixbuf = gdk_pixbuf_scale_simple (src, clientw, clienth, GDK_INTERP_NEAREST); gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0); cairo_paint(cr); cairo_fill (cr); g_object_unref (pixbuf); }; void cb_detect_btnsetsize (GtkWidget *widget, gpointer data) { GtkWidget *txtw = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-entry-w")); GtkWidget *txth = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-entry-h")); detect.SetObjectSize( atoi(gtk_entry_get_text(GTK_ENTRY(txtw))), atoi(gtk_entry_get_text(GTK_ENTRY(txth)))); }; void cb_detect_bright (GtkRange *range, gpointer data) { double value; value = gtk_range_get_value(range); detect.SetMinBrightness(value); }; void cb_detect_followtype (GtkWidget *widget, gpointer data) { if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget)) == 1) { if (widget == GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-type-indet0"))) detect.SetFollowType(AUTOFOLLOW_OFF); if (widget == GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-type-indet1"))) detect.SetFollowType(AUTOFOLLOW_BRIGHT); if (widget == GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-type-indet2"))) detect.SetFollowType(AUTOFOLLOW_CROSSC); } }; void cb_detect_detecttype (GtkWidget *widget, gpointer data) { if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget)) == 1) { if (widget == GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-pos-cboff"))) detect.SetDetectType(AUTODETECT_OFF); if (widget == GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-pos-cbbright"))) detect.SetDetectType(AUTODETECT_BRIGHT); } }; void cb_detect_btnsetpos (GtkWidget *widget, gpointer data) { GtkWidget *rboff = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-pos-cboff")); // changing the value, will cause the 'change' event to be triggered gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rboff), true); video_enterdata = VID_ENTERDATA_POS; }; void cb_detect_show_window (GtkWidget *widget, gpointer data) { printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); GtkWidget *wnd = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "window-detect")); gtk_widget_show(wnd); }; /* * setup destination path */ void cb_input_btnsetdestpath (GtkWidget *widget, gpointer data) { GtkBuilder *builder = (GtkBuilder *) data; GtkWindow *window = GTK_WINDOW (gtk_builder_get_object (builder, "windows-input")); GtkWidget *dialog; GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER; gint res; printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); dialog = gtk_file_chooser_dialog_new ("Open Folder", window, action, "_Cancel", GTK_RESPONSE_CANCEL, "_Open", GTK_RESPONSE_ACCEPT, NULL); res = gtk_dialog_run (GTK_DIALOG (dialog)); if (res == GTK_RESPONSE_ACCEPT) { char *filename; GtkFileChooser *chooser = GTK_FILE_CHOOSER (dialog); filename = gtk_file_chooser_get_filename (chooser); config.SetDestPath(filename); GtkWidget *entry = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "input_entry_destpath")); gtk_entry_set_text(GTK_ENTRY(entry), filename); g_free (filename); } gtk_widget_destroy (dialog); }; void cb_input_show_window (GtkWidget *widget, gpointer data) { printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); GtkWidget *wnd = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "window-input")); gtk_widget_show(wnd); }; void draw_text (cairo_t *cr, int x, int y, float border, std::string text) { cairo_pattern_t *t = NULL; double r, g, b, a; t = cairo_get_source(cr); cairo_pattern_get_rgba(t, &r, &g, &b, &a); for (int i = 0; i < 5; i++) { int dx, dy; switch (i) { case 0: cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); dx = -1; dy = 0; break; case 1: dx = +1; dy = 0; break; case 2: dx = 0; dy = -1; break; case 3: dx = 0; dy = +1; break; case 4: cairo_set_source_rgba(cr, r, g, b, a); dx = 0; dy = 0; break; } cairo_move_to (cr, x+dx, y+dy); cairo_show_text(cr, text.c_str()); cairo_stroke(cr); } }; #define DRAW_PRINTF_LEN 512 void draw_printf(cairo_t *cr, int x, int y, float border, char *fmt,...) { va_list args; char buffer[DRAW_PRINTF_LEN]; va_start (args, fmt); vsnprintf (buffer, (DRAW_PRINTF_LEN-1), fmt, args); va_end (args); buffer[DRAW_PRINTF_LEN-1] = 0; draw_text (cr, x, y, border, buffer); };