/*************************************************************************************** * * video.cc is part of SimpleSkyCam. * *****************************************************************************************/ #include #include #include #include #include #include "config.h" #include "gui.h" #include "output.h" #include "detect.h" #include "configuration.h" #include "video.h" #include "videodev.h" #include "histogram.h" #include "simpleskycam.h" VideoDev *videodev = NULL; GThread *videodev_thread = NULL; GtkWidget *video_da = NULL; GdkPixbuf *video_pixbuf = NULL; extern GtkBuilder *_builder_; // work around for threads extern Detect detect; extern int video_enterdata; extern position_2d video_enterdata_pos; extern detect_movement detectedpos_data; extern Configuration config; void videoctrl_grid_delete (); void videoctrl_grid_build (); /* * stop video recording */ void video_stoprecord() { 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")); if (videodev == NULL) return; videodev->Stop(); gtk_widget_set_sensitive(btnstart, true); gtk_widget_set_sensitive(btnstop, false); if (videodev_thread != NULL) g_thread_join (videodev_thread); videodev_thread = NULL; delete videodev; videoctrl_grid_delete(); videodev = NULL; } /* * return selected driver and device from GUI */ void video_get_driverdevice(std::string *driver, std::string *device) { GtkWidget *cbox = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "cb-videodev")); GtkWidget *cbdevice = gtk_bin_get_child(GTK_BIN(cbox)); if (driver == NULL || device == NULL) return; // read values from GUI elements, and start videodev with the correct driver int i; *device = gtk_entry_get_text(GTK_ENTRY(cbdevice)); i = device->find(' '); *driver = device->substr (0, i); *device = device->substr (i+1, std::string::npos); *device = device->substr (0, device->find(' ')); } /* * will be called every 2000ms hardcoded @gui.cc function cb_window_show */ gboolean videoctrl_update(gpointer data) { GtkWidget *grid = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "vidctrl-grid")); GtkWidget *scale = NULL; GtkWidget *entry = NULL; GtkWidget *label = NULL; int value; int min; int max; int i; if (videodev == NULL) return TRUE; for (i = 0; (label = gtk_grid_get_child_at(GTK_GRID(grid), 0, i)) != NULL; i++) { if (videodev->GetCtrlMinMaxValue(gtk_label_get_text(GTK_LABEL(label)), &min, &max, &value) == VDEV_STATUS_OK) { if ((scale = gtk_grid_get_child_at(GTK_GRID(grid), 1, i)) != NULL) { if (!gtk_widget_has_focus(scale)) gtk_range_set_value(GTK_RANGE(scale), value); } if ((entry = gtk_grid_get_child_at(GTK_GRID(grid), 2, i)) != NULL) { if (!gtk_widget_has_focus(entry)) gtk_entry_set_text(GTK_ENTRY(entry), std::to_string(value).c_str()); } } } return TRUE; } #define S_X(_x_) (((_x_) * clientw / pixbufw)) #define S_Y(_y_) (((_y_) * clienth / pixbufh)) void cb_videoda_draw(GtkWidget *area, cairo_t *cr, int w, int h, gpointer data) { int clientw, clienth, pixbufw, pixbufh; float clientar, pixbufar; GdkPixbuf *pixbuf = NULL; char txt1[255]; char txt2[255]; GdkRGBA color; static GtkWidget *e_x = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-entry-posx")); static GtkWidget *e_y = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-entry-posy")); static GtkWidget *e_w = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-entry-w")); static GtkWidget *e_h = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-entry-h")); static GtkWidget *lbX = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "lb_input_xdelta")); static GtkWidget *lbY = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "lb_input_ydelta")); int x, y, w1, h1; if (video_da == NULL) return; clienth = gtk_widget_get_allocated_height(video_da); clientw = gtk_widget_get_allocated_width(video_da); clientar = (float)clientw/(float)clienth; pixbufh = gdk_pixbuf_get_height(video_pixbuf); pixbufw = gdk_pixbuf_get_width(video_pixbuf); pixbufar = (float)pixbufw/(float)pixbufh; if (pixbufar < clientar) { clientw = (pixbufar * (float) clienth); } else { clienth = ((float) clientw / pixbufar); } pixbuf = gdk_pixbuf_scale_simple (video_pixbuf, clientw, clienth, GDK_INTERP_NEAREST); gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0); cairo_paint(cr); cairo_fill (cr); g_object_unref (pixbuf); // // need to draw the new destination? if (video_enterdata == VID_ENTERDATA_SETDEST) { color.blue = 1.0; color.red = 0.0; color.green = 1.0; color.alpha = 1.0; gdk_cairo_set_source_rgba(cr, &color); cairo_move_to(cr, S_X(video_enterdata_pos.x)-10, S_Y(video_enterdata_pos.y)-10); cairo_line_to(cr, S_X(video_enterdata_pos.x)+10, S_Y(video_enterdata_pos.y)+10); cairo_move_to(cr, S_X(video_enterdata_pos.x)+10, S_Y(video_enterdata_pos.y)-10); cairo_line_to(cr, S_X(video_enterdata_pos.x)-10, S_Y(video_enterdata_pos.y)+10); cairo_stroke(cr); } else if (posctl_threaddata.target_pos.x != -1 and posctl_threaddata.target_pos.y != -1) { color.blue = 0.0; color.red = 0.0; color.green = 0.5; color.alpha = 1.0; gdk_cairo_set_source_rgba(cr, &color); cairo_move_to(cr, S_X(posctl_threaddata.target_pos.x), S_Y(posctl_threaddata.target_pos.y)-5); cairo_line_to(cr, S_X(posctl_threaddata.target_pos.x), S_Y(posctl_threaddata.target_pos.y)+5); cairo_move_to(cr, S_X(posctl_threaddata.target_pos.x)-5, S_Y(posctl_threaddata.target_pos.y)); cairo_line_to(cr, S_X(posctl_threaddata.target_pos.x)+5, S_Y(posctl_threaddata.target_pos.y)); cairo_stroke(cr); } // // need to draw the select new position cross if (video_enterdata == VID_ENTERDATA_POS) { color.blue = 1.0; color.red = 0.0; color.green = 1.0; color.alpha = 1.0; gdk_cairo_set_source_rgba(cr, &color); cairo_move_to(cr, S_X(video_enterdata_pos.x)-10, S_Y(video_enterdata_pos.y)-10); cairo_line_to(cr, S_X(video_enterdata_pos.x)+10, S_Y(video_enterdata_pos.y)+10); cairo_move_to(cr, S_X(video_enterdata_pos.x)+10, S_Y(video_enterdata_pos.y)-10); cairo_line_to(cr, S_X(video_enterdata_pos.x)-10, S_Y(video_enterdata_pos.y)+10); cairo_move_to(cr, S_X(video_enterdata_pos.x)-15, S_Y(video_enterdata_pos.y)-20); cairo_line_to(cr, S_X(video_enterdata_pos.x)-20, S_Y(video_enterdata_pos.y)-20); cairo_line_to(cr, S_X(video_enterdata_pos.x)-20, S_Y(video_enterdata_pos.y)-15); cairo_move_to(cr, S_X(video_enterdata_pos.x)+15, S_Y(video_enterdata_pos.y)-20); cairo_line_to(cr, S_X(video_enterdata_pos.x)+20, S_Y(video_enterdata_pos.y)-20); cairo_line_to(cr, S_X(video_enterdata_pos.x)+20, S_Y(video_enterdata_pos.y)-15); cairo_move_to(cr, S_X(video_enterdata_pos.x)-15, S_Y(video_enterdata_pos.y)+20); cairo_line_to(cr, S_X(video_enterdata_pos.x)-20, S_Y(video_enterdata_pos.y)+20); cairo_line_to(cr, S_X(video_enterdata_pos.x)-20, S_Y(video_enterdata_pos.y)+15); cairo_move_to(cr, S_X(video_enterdata_pos.x)+15, S_Y(video_enterdata_pos.y)+20); cairo_line_to(cr, S_X(video_enterdata_pos.x)+20, S_Y(video_enterdata_pos.y)+20); cairo_line_to(cr, S_X(video_enterdata_pos.x)+20, S_Y(video_enterdata_pos.y)+15); cairo_stroke(cr); } else { x = atoi (gtk_entry_get_text(GTK_ENTRY(e_x))); y = atoi (gtk_entry_get_text(GTK_ENTRY(e_y))); w1 = atoi (gtk_entry_get_text(GTK_ENTRY(e_w))); h1 = atoi (gtk_entry_get_text(GTK_ENTRY(e_h))); if (x >= (w1/2) && x < (pixbufw-w1/2) && y >= (h1/2) && y < (pixbufh-h1/2)) { // // draw red cross cairo_set_line_width(cr, 1.0); color.blue = 0.0; color.red = 1.0; color.green = 0.0; color.alpha = 1.0; gdk_cairo_set_source_rgba(cr, &color); cairo_move_to(cr, S_X(x), S_Y(y)-10); cairo_line_to(cr, S_X(x), S_Y(y)+10); cairo_move_to(cr, S_X(x)-10, S_Y(y)); cairo_line_to(cr, S_X(x)+10, S_Y(y)); cairo_stroke(cr); // // green width border color.blue = 0.0; color.red = 0.0; color.green = 1.0; color.alpha = 1.0; gdk_cairo_set_source_rgba(cr, &color); cairo_move_to(cr, S_X(x-w1/2), S_Y(y-h1/2)+10); cairo_line_to(cr, S_X(x-w1/2), S_Y(y-h1/2)); cairo_line_to(cr, S_X(x+w1/2), S_Y(y-h1/2)); cairo_line_to(cr, S_X(x+w1/2), S_Y(y-h1/2)+10); cairo_move_to(cr, S_X(x-w1/2), S_Y(y+h1/2)-10); cairo_line_to(cr, S_X(x-w1/2), S_Y(y+h1/2)); cairo_line_to(cr, S_X(x+w1/2), S_Y(y+h1/2)); cairo_line_to(cr, S_X(x+w1/2), S_Y(y+h1/2)-10); cairo_stroke(cr); } } // draw movement vector to screen snprintf (txt1, 255, "X: %f", detectedpos_data.dx); snprintf (txt2, 255, "Y: %f", detectedpos_data.dy); gtk_label_set_text(GTK_LABEL(lbX), txt1); gtk_label_set_text(GTK_LABEL(lbY), txt2); if (config.GetCalibrationShowData()) { // printf ("%s:%d posctl_threaddata.c : %d \t %d -> \t %d \t %d\n", __FILE__, __LINE__, // posctl_threaddata.c[0].x, posctl_threaddata.c[0].y, // posctl_threaddata.c[1].x, posctl_threaddata.c[1].y); // printf ("%s:%d posctl_threaddata.a1: %d \t %d -> \t %d \t %d\n", __FILE__, __LINE__, // posctl_threaddata.a1[0].x, posctl_threaddata.a1[0].y, // posctl_threaddata.a1[1].x, posctl_threaddata.a1[1].y); // printf ("%s:%d posctl_threaddata.a2: %d \t %d -> \t %d \t %d\n", __FILE__, __LINE__, // posctl_threaddata.a2[0].x, posctl_threaddata.a2[0].y, // posctl_threaddata.a2[1].x, posctl_threaddata.a2[1].y); if (posctl_threaddata.c[0].x != -1 && posctl_threaddata.c[0].y != -1 && posctl_threaddata.c[1].x != -1 && posctl_threaddata.c[1].y != -1) { cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); cairo_set_line_width(cr, 1.0); cairo_move_to(cr, S_X(posctl_threaddata.c[0].x), S_Y(posctl_threaddata.c[0].y)); cairo_line_to(cr, S_X(posctl_threaddata.c[1].x), S_Y(posctl_threaddata.c[1].y)); cairo_stroke(cr); } if (posctl_threaddata.a1[0].x != -1 && posctl_threaddata.a1[0].y != -1 && posctl_threaddata.a1[1].x != -1 && posctl_threaddata.a1[1].y != -1) { cairo_set_source_rgb(cr, 1.0, 0.5, 1.0); cairo_set_line_width(cr, 1.0); cairo_move_to(cr, S_X(posctl_threaddata.a1[0].x), S_Y(posctl_threaddata.a1[0].y)); cairo_line_to(cr, S_X(posctl_threaddata.a1[1].x), S_Y(posctl_threaddata.a1[1].y)); cairo_stroke(cr); } if (posctl_threaddata.a2[0].x != -1 && posctl_threaddata.a2[0].y != -1 && posctl_threaddata.a2[1].x != -1 && posctl_threaddata.a2[1].y != -1) { cairo_set_source_rgb(cr, 1.0, 0.5, 1.0); cairo_set_line_width(cr, 1.0); cairo_move_to(cr, S_X(posctl_threaddata.a2[0].x), S_Y(posctl_threaddata.a2[0].y)); cairo_line_to(cr, S_X(posctl_threaddata.a2[1].x), S_Y(posctl_threaddata.a2[1].y)); cairo_stroke(cr); } } #ifdef DEBUG_ANGLES debug_angles_draw(cr); #endif }; // fixme: refresh format list. /* * refresh the possible devices */ void cb_video_btnrefreshlist (GtkWidget *widget, gpointer data) { GtkWidget *cbox = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "cb-videodev")); GtkListStore *model = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(cbox))); std::list devlist; std::list::iterator iter; printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); if (model == NULL) { model = gtk_list_store_new(1, G_TYPE_STRING); gtk_combo_box_set_model(GTK_COMBO_BOX(cbox),GTK_TREE_MODEL(model)); } gtk_list_store_clear(GTK_LIST_STORE(model)); devlist.clear(); VideoDev_Dumpfile vdef1; vdef1.GetDeviceList(&devlist); #ifdef USE_V4L2 VideoDev_V4L2 vdef2; vdef2.GetDeviceList(&devlist); #endif #ifdef USE_SVBONY VideoDev_SVBCam vdef3; vdef3.GetDeviceList(&devlist); #endif #ifdef USE_VFW VideoDev_VFW vdef4; vdef4.GetDeviceList(&devlist); #endif VideoDev_Simulation vdef5; vdef5.GetDeviceList(&devlist); for (iter = devlist.begin(); iter != devlist.end(); iter++) { gtk_list_store_insert_with_values(GTK_LIST_STORE(model), NULL, -1, 0, iter->c_str(), -1); } }; gpointer videodev_threadprocess_wrapper (gpointer data) { if (videodev == NULL) return NULL; videodev->ThreadProcess(); return NULL; } /* * start recording from the videodev (will start a new thread) * load list of controls from the video device and create the GtkGrid * with all elements. Also connect the signals to the callback functions. */ void cb_video_btnrec (GtkWidget *widget, gpointer data) { GtkWidget *cbres = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "cb-videores")); GtkWidget *cbresentry = gtk_bin_get_child(GTK_BIN(cbres)); GtkWidget *cbfmt = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "cb-videofmt")); GtkWidget *cbfmtentry = gtk_bin_get_child(GTK_BIN(cbfmt)); 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")); int w, h; // get device and driver information std::string device, driver; std::string parameter; video_get_driverdevice(&driver, &device); // stop recording video_stoprecord(); // // load the selected driver if (driver.compare("VIDEODUMP") == 0) videodev = new VideoDev_Dumpfile; #ifdef USE_V4L2 else if (driver.compare("V4L2") == 0) videodev = new VideoDev_V4L2; #endif #ifdef USE_SVBONY else if (driver.compare("SVBCAM") == 0) videodev = new VideoDev_SVBCam; #endif #ifdef USE_VFW else if (driver.compare("VFW") == 0) videodev = new VideoDev_VFW; #endif else if (driver.compare("SIMULATION") == 0) videodev = new VideoDev_Simulation; else videodev = new VideoDev; std::string format = gtk_entry_get_text(GTK_ENTRY(cbfmtentry)); std::string resolution = gtk_entry_get_text(GTK_ENTRY(cbresentry)); w = h = -1; if (resolution.compare ("MAX") != 0) sscanf (resolution.c_str(), "%dx%d", &w, &h); printf ("%s:%d %s open device: '%s'\n", __FILE__, __LINE__, __FUNCTION__, device.c_str()); gtk_widget_set_sensitive(btnstart, false); gtk_widget_set_sensitive(btnstop, true); videodev->SetConfig(device, w, h, format, parameter, cb_thread_video); videodev_thread = g_thread_new(driver.c_str(), videodev_threadprocess_wrapper, NULL); // FIXME: workaround, soltuion should be: create a timer and request all controls }; /* * clear all elements in the controls grid */ void videoctrl_grid_delete () { GtkWidget *grid = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "vidctrl-grid")); GtkWidget *gridchild = NULL; // // clear grid while ((gridchild = gtk_grid_get_child_at(GTK_GRID(grid), 0, 0)) != NULL) { gtk_grid_remove_row (GTK_GRID(grid), 0); } }; /* * after the video is started and we get the first callback from the VideoDev thread * we will call this function to read all ctrls and creade the grid table. * function gets called if: threaddata.runnin == 1 */ void videoctrl_grid_build () { std::list list; std::list::iterator iter; GtkWidget *cbres = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "cb-videores")); GtkWidget *cbresentry = gtk_bin_get_child(GTK_BIN(cbres)); GtkWidget *cbfmt = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "cb-videofmt")); GtkWidget *cbfmtentry = gtk_bin_get_child(GTK_BIN(cbfmt)); GtkWidget *grid = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "vidctrl-grid")); int i, w, h; std::string format; std::string resolution; if (videodev == NULL) return; videodev->GetCtrlList(&list); videoctrl_grid_delete(); // // add elements for (i = 0, iter = list.begin(); iter != list.end(); iter++, i++) { int min = 0; int max = 100; int value = 50; videodev->GetCtrlMinMaxValue((*iter), &min, &max, &value); // // label GtkWidget *label = gtk_label_new(iter->c_str()); GtkWidget *scale = NULL; // // scale/range if (min < max) { scale = gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL, min, max, 1); gtk_range_set_value(GTK_RANGE(scale),value); gtk_widget_set_hexpand (scale,true); gtk_scale_set_draw_value(GTK_SCALE(scale), false); g_signal_connect (GTK_RANGE(scale), "value-changed", G_CALLBACK(cb_vidctrl_scale_change), (void*)(size_t)i); } else { printf ("%s:%d control %s check not valid min[%d] < max[%d]\n", __FILE__, __LINE__, iter->c_str(), min, max); } // // entry field GtkWidget *entry = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(entry), std::to_string(value).c_str()); g_signal_connect (entry, "activate", G_CALLBACK(cb_vidctrl_entry_change), (void*)(size_t)i); gtk_grid_insert_row(GTK_GRID(grid), i); if (i == 0) { gtk_grid_insert_column(GTK_GRID(grid), 0); gtk_grid_insert_column(GTK_GRID(grid), 0); gtk_grid_insert_column(GTK_GRID(grid), 0); } gtk_grid_attach(GTK_GRID(grid), label, 0, i, 1, 1); if (scale) gtk_grid_attach(GTK_GRID(grid), scale, 1, i, 1, 1); gtk_grid_attach(GTK_GRID(grid), entry, 2, i, 1, 1); gtk_widget_show (label); if (scale) gtk_widget_show (scale); gtk_widget_show (entry); } // // read video information videodev->GetVideoInfo(&w, &h, &format); resolution = std::to_string(w) + "x" + std::to_string(h); gtk_entry_set_text (GTK_ENTRY(cbresentry), resolution.c_str()); gtk_entry_set_text (GTK_ENTRY(cbfmtentry), format.c_str()); }; /* * stop recording from the videodev (will stop the running thread) * we need to wait for the thread to complete and then we can delete this object. */ void cb_video_btnstop (GtkWidget *widget, gpointer data) { printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); video_stoprecord(); }; /* * callback from videodev thread. data will point to the latest VideoFrame. * Access to this data must be Locked before use. */ gboolean cb_thread_video (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")); VideoDevThreadData *cbdata = (VideoDevThreadData*) data; VideoFrame *vf = NULL; VideoFrameRaw *vfr = NULL; if (videodev == NULL) return false; // // after video starts, on the first frame // read out all controls if (cbdata != NULL) { vf = &cbdata->vf; vfr = &cbdata->vfr; if (cbdata->running == 1) { videoctrl_grid_build(); cbdata->running = 2; } if (vf->w <= 0 || vf->h <= 0 || vf->data == NULL) vf = NULL; if (vfr->w <= 0 || vfr->h <= 0 || vfr->data == NULL) vfr = NULL; } // // create video drawarea if needed if (video_da == NULL) video_da = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "video-da")); if (video_pixbuf == NULL) { video_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, false, 8, 100, 100); memset (gdk_pixbuf_get_pixels(video_pixbuf), 0, 3 * gdk_pixbuf_get_height(video_pixbuf) * gdk_pixbuf_get_width(video_pixbuf)); } // // if cbdata not set, we have a error on the video stream // stop recording. Else push framedata into the detect thread. if (cbdata == NULL) { printf ("%s:%d %s something went wrong CBData == NULL\n", __FILE__, __LINE__, __FUNCTION__); videodev->Stop(); memset (gdk_pixbuf_get_pixels(video_pixbuf), 0, 3 * gdk_pixbuf_get_height(video_pixbuf) * gdk_pixbuf_get_width(video_pixbuf)); gtk_widget_set_sensitive(btnstart, true); gtk_widget_set_sensitive(btnstop, false); gdk_window_invalidate_rect(gtk_widget_get_window(video_da), NULL, true); } else if (vf != NULL) { int pix_h, pix_w; videodev->LockMutex(); // // check and resize video_drawarea if needed if (video_pixbuf) { pix_h = gdk_pixbuf_get_height(video_pixbuf); pix_w = gdk_pixbuf_get_width(video_pixbuf); } else pix_h = 0; if (video_pixbuf == NULL || pix_h != vf->h || pix_w != vf->w) { if (video_pixbuf != NULL) g_object_unref (video_pixbuf); printf ("%s:%d %s New Pixbuf: %d x %d\n", __FILE__, __LINE__, __FUNCTION__, vf->w, vf->h); video_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, false, 8, vf->w, vf->h); pix_w = vf->w; pix_h = vf->h; } vf->ToPixbuf(video_pixbuf); // convert Frame to pixeldata histogram_update(vf); // update histogram detect.CopyNewFrame(vf, vfr); // push new data to detect object videodev->UnLockMutex(); // redraw drawarea on screen. gdk_window_invalidate_rect(gtk_widget_get_window(video_da), NULL, true); } return false; }; /* * set ctrl on the device */ void videoctrl_set(std::string name, int value) { if (videodev == NULL) return; videodev->SetCtrlValue(name, value); } /* * callback video control scale change */ void cb_vidctrl_scale_change (GtkRange *range, gpointer data) { GtkWidget *grid = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "vidctrl-grid")); GtkWidget *scale = NULL; GtkWidget *label = NULL; int64_t idx = (int64_t)data; double value; label = gtk_grid_get_child_at(GTK_GRID(grid), 0, idx); scale = gtk_grid_get_child_at(GTK_GRID(grid), 1, idx); if (scale == NULL) return; value = gtk_range_get_value(GTK_RANGE(scale)); videoctrl_set((std::string)gtk_label_get_text(GTK_LABEL(label)), (int)value); }; /* * callback video control entry change */ void cb_vidctrl_entry_change (GtkWidget *widget, gpointer data) { GtkWidget *grid = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "vidctrl-grid")); GtkWidget *label = NULL; GtkWidget *entry = NULL; int64_t idx = (int64_t)data; int value; label = gtk_grid_get_child_at(GTK_GRID(grid), 0, idx); entry = gtk_grid_get_child_at(GTK_GRID(grid), 2, idx); if (entry == NULL) return; value = atoi(gtk_entry_get_text(GTK_ENTRY(entry))); videoctrl_set((std::string)gtk_label_get_text(GTK_LABEL(label)), (int)value); }; /* * */ void cb_videoda_motionevent (GtkWidget *widget, GdkEvent *event, gpointer data) { int dw, dh, sw, sh; float sar, dar; if (video_pixbuf != NULL) { sh = gtk_widget_get_allocated_height(video_da); sw = gtk_widget_get_allocated_width(video_da); dw = gdk_pixbuf_get_width(video_pixbuf); dh = gdk_pixbuf_get_height(video_pixbuf); sar = (float)sw/(float)sh; dar = (float)dw/(float)dh; if (dar < sar) { sw = (dar * (float) sh); } else { sh = ((float) sw / dar); } video_enterdata_pos.x = event->motion.x * dw / sw; video_enterdata_pos.y = event->motion.y * dh / sh; gdk_window_invalidate_rect(gtk_widget_get_window(video_da), NULL, true); } #ifdef DEBUG_ANGLES debug_angles_motionevent(event); #endif }; void cb_videoda_btnpress (GtkWidget *widget, GdkEvent *event, gpointer data) { int x = event->motion.x; int y = event->motion.y; #ifdef DEBUG_ANGLES debug_angles_btnpress(event); #endif printf ("%s:%d %s %d, %d\n", __FILE__, __LINE__, __FUNCTION__, x, y); }; void cb_videoda_btnrelease (GtkWidget *widget, GdkEvent *event, gpointer data) { if (video_enterdata == VID_ENTERDATA_POS) { detect.SetObjectPos(video_enterdata_pos.x, video_enterdata_pos.y); video_enterdata = VID_ENTERDATA_NONE; } }; /* * cb_video_pre_click/cb_video_pre_pressed, are needed to detect is we press * the button longer as two seconds. If it is, all settings will be saved. */ #define BTNDOWN_TIME 1.0 struct { int idx; struct timeval tv; guint timer; } presetbtn; void cb_video_pre_click (GtkWidget *widget, gpointer data) { float pushtime = get_cycletime(&presetbtn.tv); std::string s; int idx; GtkWidget *btn; if (videodev == NULL) return; if (pushtime > BTNDOWN_TIME && presetbtn.idx >= 0 && presetbtn.idx < BTN_PRESET_MAX) { // // save the settings // std::list ctrls = videodev->GetCtrlsMinMaxValue(); config.SetPresetButton(presetbtn.idx, &ctrls); // // reset button label // for (idx = 0; idx < BTN_PRESET_MAX; idx++) { s = "btn-video-pre"+std::to_string(idx+1); if ((btn = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), s.c_str()))) != NULL) { gtk_button_set_label(GTK_BUTTON(btn), std::to_string(idx+1).c_str()); } } } else if (presetbtn.idx >= 0 && presetbtn.idx < BTN_PRESET_MAX) { // // callup settings // int i, retry = 5, again = 1; std::list ctrls = config.GetPresetButton(presetbtn.idx); std::list::iterator iter; presetbtn.idx = -1; for (retry = 5; retry > 0 && again; retry--) { again = 0; for (iter = ctrls.begin(); iter != ctrls.end(); iter++) { videodev->SetCtrlValue(iter->name, iter->value); usleep(10000); videodev->GetCtrlMinMaxValue(iter->name, NULL, NULL, &i); if (i != iter->value) again = 1; } } } }; /* * should determine the pressed button and save it together with the current * time in structure presetbtn. */ void cb_video_pre_pressed (GtkWidget *widget, gpointer data) { int idx = -1; std::string s; GtkWidget *btn; for (idx = 0; idx < BTN_PRESET_MAX; idx++) { s = "btn-video-pre"+std::to_string(idx+1); if ((btn = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), s.c_str()))) == widget) { if (presetbtn.timer <= 0) presetbtn.timer = g_timeout_add((int)(BTNDOWN_TIME*1000.0), video_pre_long, NULL); break; } } presetbtn.idx = idx; gettimeofday (&presetbtn.tv, NULL); }; /* * gnome timer callback if any presetbutton was pressed down * in case the button is still pressed, we write SAVED in the buttons label. */ gboolean video_pre_long(gpointer data) { std::string s = "btn-video-pre"+std::to_string(presetbtn.idx+1); GtkWidget *btn = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), s.c_str())); if (btn && presetbtn.idx >= 0 && presetbtn.idx < BTN_PRESET_MAX) gtk_button_set_label(GTK_BUTTON(btn), "Saved"); presetbtn.timer = 0; return FALSE; }; /* * videodevice changed */ void cb_video_cbox_videodev (GtkWidget *widget, gpointer data) { // GtkWidget *cbres = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "cb-videores")); // GtkWidget *cbresentry = gtk_bin_get_child(GTK_BIN(cbres)); GtkWidget *cbfmt = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "cb-videofmt")); GtkWidget *cbfmtentry = gtk_bin_get_child(GTK_BIN(cbfmt)); GtkListStore *model; std::list lst_format; std::list lst_resolution; std::list::iterator iter; std::string device, driver; std::string parameter; printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); video_stoprecord(); // // open device video_get_driverdevice(&driver, &device); // // load the selected driver if (driver.compare("DUMMY") == 0) videodev = new VideoDev; #ifdef USE_V4L2 else if (driver.compare("V4L2") == 0) videodev = new VideoDev_V4L2; #endif #ifdef USE_SVBONY else if (driver.compare("SVBCAM") == 0) videodev = new VideoDev_SVBCam; #endif #ifdef USE_VFW else if (driver.compare("VFW") == 0) videodev = new VideoDev_VFW; #endif else videodev = new VideoDev; videodev->GetDeviceFormats(device, &lst_format); model = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(cbfmt))); gtk_list_store_clear(GTK_LIST_STORE(model)); gtk_entry_set_text (GTK_ENTRY(cbfmtentry), ""); for (iter = lst_format.begin(); iter != lst_format.end(); iter++) { gtk_list_store_insert_with_values(GTK_LIST_STORE(model), NULL, -1, 0, iter->c_str(), -1); } videodev->GetDeviceResolutions(device, &lst_format); delete videodev; videodev = NULL; }; /* * resize windows depending on the button which was pressed */ void cb_input_btnscale (GtkWidget *widget, gpointer data) { int dw, dh, ww, wh; float scale = 1.0; printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); if (videodev == NULL || video_da == NULL) return; // // what scale button was pressed GtkWidget *btn11 = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "btn_inputscale11")); GtkWidget *btn12 = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "btn_inputscale12")); GtkWidget *btn14 = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "btn_inputscale14")); if (widget == btn11) scale = 1.0; if (widget == btn12) scale = 0.5; if (widget == btn14) scale = 0.25; // // read our video size from gui and calculate size of gui elements GtkWidget *win = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "window-input")); gtk_window_get_size(GTK_WINDOW(win), &ww, &wh); dh = gtk_widget_get_allocated_height(video_da); dw = gtk_widget_get_allocated_width(video_da); dw = ww-dw; dh = wh-dh; videodev->GetVideoInfo(&ww, &wh, NULL); ww = dw + (scale * ww) + 1; wh = dh + (scale * wh); gtk_window_resize(GTK_WINDOW(win), ww, wh); };