Hello, I would like to get the stream from a XIMEA camera using gstreamer. There is an example (in the XIMEA Linux Software Package) that use gstreamer to get the stream. This example works fine on Ubuntu 12.04 (with kernel 3.8) and Ubuntu 13.04. But i would like to get the stream with v4l2sink/v4l2src from gstreamer with pdgst (or better, from [pix_video] ??? :). My skills in C++ are bad and if someone can help me to modify the source code (attached, dependencies : GTK+-2 and GStreamer-0.10) to make it work only with v4l2src, it would be very nice. The XIMEA Linux Software Package can be downloaded from : http://www.ximea.com/support/wiki/apis/XIMEA_Linux_Software_Package Thanx. ++
Jack
#include <sys/time.h> #include <pthread.h> #include <gtk/gtk.h> #ifdef GDK_WINDOWING_X11 #include <gdk/gdkx.h> #endif #include <gst/app/gstappsrc.h> #include <gst/interfaces/xoverlay.h> #include <m3api/xiApi.h> #include <m3api/xiExt.h> BOOL acquire, quitting, render = TRUE; int maxcx, maxcy, roix0, roiy0, roicx, roicy; pthread_t videoThread; HANDLE handle = INVALID_HANDLE_VALUE; guintptr window_handle; GstBusSyncReply bus_sync_handler(GstBus* bus, GstMessage* message, gpointer) { if(GST_MESSAGE_TYPE(message) != GST_MESSAGE_ELEMENT || !gst_structure_has_name(message->structure, "prepare-xwindow-id")) return GST_BUS_PASS; #if GST_CHECK_VERSION(0,10,31) gst_x_overlay_set_window_handle(GST_X_OVERLAY(GST_MESSAGE_SRC(message)), window_handle); #else gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(GST_MESSAGE_SRC(message)), window_handle); #endif gst_message_unref(message); return GST_BUS_DROP; } #if defined(GDK_WINDOWING_X11) void video_widget_realize_cb(GtkWidget* widget, gpointer) { GdkWindow *window = gtk_widget_get_window(widget); if (!gdk_window_ensure_native(window)) g_error ("Couldn't create native window needed for GstXOverlay!"); window_handle = GDK_WINDOW_XID(window); } #elif defined(GDK_WINDOWING_QUARTZ) void video_widget_realize_cb(GtkWidget*, gpointer); #else #error Unsupported GDK backend #endif inline unsigned long getcurus() { struct timeval now; gettimeofday(&now, NULL); return now.tv_sec * 1000000 + now.tv_usec; } gboolean close_cb(GtkWidget*, GdkEvent*, gpointer quit) { quitting = quit ? TRUE : FALSE; if(videoThread) acquire = FALSE; else gtk_main_quit(); return TRUE; } void* videoDisplay(void*) { GtkWidget *videoWindow; GdkScreen *screen; GstElement *pipeline, *appsrc/*, *fpssink*/; GstFlowReturn ret; GstBuffer *buffer; GstBus *bus; GstCaps *caps = 0; int max_width, max_height; int prev_width = -1; int prev_height = -1; unsigned long frames = 0; unsigned long prevframes = 0; unsigned long lostframes = 0; unsigned long curtime, prevtime; long lastframe = -1; gchar/* *videofps,*/ title[256]; XI_IMG_FORMAT prev_format = XI_RAW8; XI_IMG image; image.size = sizeof(XI_IMG); image.bp = NULL; image.bp_size = 0; gdk_threads_enter(); videoWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(videoWindow), "streamViewer"); gtk_widget_set_double_buffered(videoWindow, FALSE); g_signal_connect(videoWindow, "realize", G_CALLBACK(video_widget_realize_cb), NULL); g_signal_connect(videoWindow, "delete-event", G_CALLBACK(close_cb), NULL); gtk_widget_show_all(videoWindow); gtk_widget_realize(videoWindow); screen = gdk_screen_get_default(); max_width = 0.8*gdk_screen_get_width(screen); max_height = 0.8*gdk_screen_get_width(screen); gdk_threads_leave(); if(xiStartAcquisition(handle) != XI_OK) goto exit; //pipeline = gst_parse_launch("appsrc is-live=TRUE name=streamViewer ! queue max-size-buffers=2 leaky=2 ! ffmpegcolorspace ! videoscale add-borders=TRUE ! fpsdisplaysink name=fpssink text-overlay=FALSE sync=FALSE", NULL); pipeline = gst_parse_launch("appsrc is-live=TRUE name=streamViewer ! queue max-size-buffers=2 leaky=2 ! ffmpegcolorspace ! videoscale add-borders=TRUE ! autovideosink", NULL); if(!pipeline) goto exit; bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline)); gst_bus_set_sync_handler(bus, (GstBusSyncHandler)bus_sync_handler, NULL); gst_object_unref(bus); appsrc = gst_bin_get_by_name(GST_BIN(pipeline), "streamViewer"); //fpssink = gst_bin_get_by_name(GST_BIN(pipeline), "fpssink"); gst_element_set_state(pipeline, GST_STATE_PLAYING); prevtime = getcurus(); while(acquire) { if(xiGetImage(handle, 5000, &image) != XI_OK) break; if(render) { buffer = gst_buffer_new(); gst_buffer_set_data(buffer, (guint8*)image.bp, image.width*image.height*(image.frm == XI_RAW8 ? 1 : 3)); GST_BUFFER_TIMESTAMP(buffer) = GST_CLOCK_TIME_NONE; if(prev_width != image.width || prev_height != image.height || prev_format != image.frm) { if(caps) gst_caps_unref(caps); if(image.frm == XI_RAW8) caps = gst_caps_new_simple ("video/x-raw-gray", "bpp", G_TYPE_INT, 8, "depth", G_TYPE_INT, 8, "framerate", GST_TYPE_FRACTION, 0, 1, "width", G_TYPE_INT, image.width, "height", G_TYPE_INT, image.height, NULL); else if(image.frm == XI_RGB24) caps = gst_caps_new_simple ("video/x-raw-rgb", "bpp", G_TYPE_INT, 24, "depth", G_TYPE_INT, 24, "endianness", G_TYPE_INT, G_BIG_ENDIAN, "red_mask", G_TYPE_INT, 0x0000ff, "green_mask", G_TYPE_INT, 0x00ff00, "blue_mask", G_TYPE_INT, 0xff0000, "framerate", GST_TYPE_FRACTION, 0, 1, "width", G_TYPE_INT, image.width, "height", G_TYPE_INT, image.height, NULL); else break; gst_buffer_set_caps(buffer, caps); prev_width = image.width; prev_height = image.height; prev_format = image.frm; int width = image.width; int height = image.height; while(width > max_width || height > max_height) { width /= 2; height /=2; } gdk_threads_enter(); gtk_window_resize(GTK_WINDOW(videoWindow), width, height); gdk_threads_leave(); } ret = gst_app_src_push_buffer(GST_APP_SRC(appsrc), buffer); if(ret != GST_FLOW_OK) break; } frames++; if(image.nframe > lastframe) lostframes += image.nframe - (lastframe + 1); lastframe = image.nframe; curtime = getcurus(); if(curtime - prevtime > 1000000) { //g_object_get(G_OBJECT(fpssink), "last-message", &videofps, NULL); //snprintf(title, 256, "Acquisition [ captured: %lu, skipped: %lu, fps: %.2f ]; Video [ %s ]", frames, lostframes, 1000000.0 * (frames - prevframes) / (curtime - prevtime), videofps); snprintf(title, 256, "Acquisition [ captured: %lu, skipped: %lu, fps: %.2f ]", frames, lostframes, 1000000.0 * (frames - prevframes) / (curtime - prevtime)); gtk_window_set_title(GTK_WINDOW(videoWindow), title); //g_free(videofps); prevframes = frames; prevtime = curtime; } } if(caps) gst_caps_unref(caps); gst_app_src_end_of_stream(GST_APP_SRC(appsrc)); gst_element_set_state(pipeline, GST_STATE_NULL); gst_object_unref(GST_OBJECT(pipeline)); exit: gdk_threads_enter(); gtk_widget_destroy(videoWindow); if(quitting) gtk_main_quit(); xiStopAcquisition(handle); acquire = FALSE; xiCloseDevice(handle); handle = INVALID_HANDLE_VALUE; videoThread = 0; gdk_threads_leave(); return 0; } struct ctrl_window { GtkWidget *window, *boxmain, *boxgpi, *boxx, *boxy, *gpi1, *gpi2, *gpi3, *gpi4, *labelexp, *exp, *labelgain, *gain, *labelx0, *x0, *labely0, *y0, *labelcx, *cx, *labelcy, *cy, *raw, *show, *run; }; gboolean time_handler(ctrl_window *ctrl) { int level = 0; if(acquire && handle != INVALID_HANDLE_VALUE) { xiSetParamInt(handle, XI_PRM_GPI_SELECTOR, 1); xiGetParamInt(handle, XI_PRM_GPI_LEVEL, &level); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ctrl->gpi1), level); xiSetParamInt(handle, XI_PRM_GPI_SELECTOR, 2); xiGetParamInt(handle, XI_PRM_GPI_LEVEL, &level); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ctrl->gpi2), level); xiSetParamInt(handle, XI_PRM_GPI_SELECTOR, 3); xiGetParamInt(handle, XI_PRM_GPI_LEVEL, &level); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ctrl->gpi3), level); xiSetParamInt(handle, XI_PRM_GPI_SELECTOR, 4); xiGetParamInt(handle, XI_PRM_GPI_LEVEL, &level); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ctrl->gpi4), level); } gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(ctrl->run), gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ctrl->run)) != acquire); gtk_widget_set_sensitive(ctrl->boxx, acquire); gtk_widget_set_sensitive(ctrl->boxy, acquire); gtk_widget_set_sensitive(ctrl->exp, acquire); gtk_widget_set_sensitive(ctrl->gain, acquire); return TRUE; } gboolean update_x0(GtkAdjustment *adj, gpointer) { roix0 = gtk_adjustment_get_value(adj); if(roicx + roix0 > maxcx){ roix0 = maxcx - roicx; gtk_adjustment_set_value(adj, roix0); } xiSetParamInt(handle, XI_PRM_OFFSET_X, roix0); return TRUE; } gboolean update_y0(GtkAdjustment *adj, gpointer) { roiy0 = gtk_adjustment_get_value(adj); if(roicy + roiy0 > maxcy){ roiy0 = maxcy - roicy; gtk_adjustment_set_value(adj, roiy0); } xiSetParamInt(handle, XI_PRM_OFFSET_Y, roiy0); return TRUE; } gboolean update_cx(GtkAdjustment *adj, gpointer) { roicx = gtk_adjustment_get_value(adj); if(roix0 + roicx > maxcx){ roicx = maxcx - roix0; gtk_adjustment_set_value(adj, roicx); } xiSetParamInt(handle, XI_PRM_WIDTH, roicx); return TRUE; } gboolean update_cy(GtkAdjustment *adj, gpointer) { roicy = gtk_adjustment_get_value(adj); if(roiy0 + roicy > maxcy) { roicy = maxcy - roiy0; gtk_adjustment_set_value(adj, roicy); } xiSetParamInt(handle, XI_PRM_HEIGHT, roicy); return TRUE; } gboolean update_exposure(GtkAdjustment *adj, gpointer) { xiSetParamInt(handle, XI_PRM_EXPOSURE, 1000*gtk_adjustment_get_value(adj)); return TRUE; } gboolean update_gain(GtkAdjustment *adj, gpointer) { xiSetParamFloat(handle, XI_PRM_GAIN, gtk_adjustment_get_value(adj)); return TRUE; } gboolean update_raw(GtkToggleButton *raw, ctrl_window *ctrl) { if(handle != INVALID_HANDLE_VALUE) { float mingain, maxgain; xiSetParamInt(handle, XI_PRM_IMAGE_DATA_FORMAT, gtk_toggle_button_get_active(raw) ? XI_RAW8 : XI_RGB24); xiGetParamFloat(handle, XI_PRM_GAIN XI_PRM_INFO_MIN, &mingain); xiGetParamFloat(handle, XI_PRM_GAIN XI_PRM_INFO_MAX, &maxgain); xiGetParamInt(handle, XI_PRM_WIDTH XI_PRM_INFO_MAX, &maxcx); xiGetParamInt(handle, XI_PRM_HEIGHT XI_PRM_INFO_MAX, &maxcy); roicx = maxcx; roicy = maxcy; roix0 = 0; roiy0 = 0; gtk_adjustment_configure(gtk_range_get_adjustment(GTK_RANGE(ctrl->gain)), mingain, mingain, maxgain, 0.1, 1, 0); gtk_adjustment_configure(gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(ctrl->x0)), roix0, 0, maxcx-4, 2, 20, 0); gtk_adjustment_configure(gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(ctrl->y0)), roiy0, 0, maxcy-2, 2, 20, 0); gtk_adjustment_configure(gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(ctrl->cx)), roicx, 4, maxcx, 4, 20, 0); gtk_adjustment_configure(gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(ctrl->cy)), roicy, 2, maxcy, 2, 20, 0); xiSetParamFloat(handle, XI_PRM_GAIN, mingain); xiSetParamInt(handle, XI_PRM_OFFSET_X, roix0); xiSetParamInt(handle, XI_PRM_OFFSET_Y, roiy0); xiSetParamInt(handle, XI_PRM_WIDTH, roicx); xiSetParamInt(handle, XI_PRM_HEIGHT, roicy); //exposure doesn't seem to be affected by format change } return TRUE; } gboolean update_show(GtkToggleButton *show, gpointer) { render = gtk_toggle_button_get_active(show); return TRUE; } gboolean update_run(GtkToggleButton *run, ctrl_window *ctrl) { gtk_toggle_button_set_inconsistent(run, false); acquire = gtk_toggle_button_get_active(run); if(acquire && handle == INVALID_HANDLE_VALUE) { DWORD nIndex = 0; char* env = getenv("CAM_INDEX"); if(env) { nIndex = atoi(env); } DWORD tmp; xiGetNumberDevices(&tmp); //rescan available devices if(xiOpenDevice(nIndex, &handle) != XI_OK) { printf("Couldn't setup camera!\n"); acquire = FALSE; return TRUE; } update_raw(GTK_TOGGLE_BUTTON(ctrl->raw), ctrl); xiSetParamInt(handle, XI_PRM_AUTO_WB, 1); xiSetParamInt(handle, XI_PRM_EXPOSURE, 10000); gtk_adjustment_set_value(gtk_range_get_adjustment(GTK_RANGE(ctrl->exp)), 10); if(pthread_create(&videoThread, NULL, videoDisplay, NULL)) exit(1); } gtk_widget_set_sensitive(ctrl->boxx, acquire); gtk_widget_set_sensitive(ctrl->boxy, acquire); gtk_widget_set_sensitive(ctrl->exp, acquire); gtk_widget_set_sensitive(ctrl->gain, acquire); return TRUE; } gboolean start_cb(ctrl_window* ctrl) { //start acquisition update_run(GTK_TOGGLE_BUTTON(ctrl->run), ctrl); return FALSE; } int main(int argc, char **argv) { ctrl_window ctrl; g_thread_init(NULL); gdk_threads_init(); gdk_threads_enter(); gst_init(&argc, &argv); gtk_init(&argc, &argv); //create widgets ctrl.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); ctrl.boxmain = gtk_vbox_new(FALSE, 0); ctrl.boxgpi = gtk_hbox_new(TRUE, 0); ctrl.boxx = gtk_hbox_new(FALSE, 0); ctrl.boxy = gtk_hbox_new(FALSE, 0); ctrl.labelexp = gtk_label_new("Exposure (ms)"); ctrl.labelgain = gtk_label_new("Gain (dB)"); ctrl.labelx0 = gtk_label_new("x0"); ctrl.labelcx = gtk_label_new("cx"); ctrl.labely0 = gtk_label_new("y0"); ctrl.labelcy = gtk_label_new("cy"); ctrl.gpi1 = gtk_check_button_new_with_label("GPI1"); ctrl.gpi2 = gtk_check_button_new_with_label("GPI2"); ctrl.gpi3 = gtk_check_button_new_with_label("GPI3"); ctrl.gpi4 = gtk_check_button_new_with_label("GPI4"); ctrl.exp = gtk_hscale_new_with_range(1, 1000, 1); ctrl.gain = gtk_hscale_new_with_range(0, 1, 0.1); //use dummy limits ctrl.x0 = gtk_spin_button_new_with_range(0, 128, 2); //use dummy max limit ctrl.y0 = gtk_spin_button_new_with_range(0, 128, 2); //use dummy max limit ctrl.cx = gtk_spin_button_new_with_range(4, 128, 4); //use dummy max limit ctrl.cy = gtk_spin_button_new_with_range(2, 128, 2); //use dummy max limit ctrl.raw = gtk_toggle_button_new_with_label("Display RAW data"); ctrl.show = gtk_toggle_button_new_with_label("Live view"); ctrl.run = gtk_toggle_button_new_with_label("Acquisition"); //tune them gtk_window_set_title(GTK_WINDOW(ctrl.window), "streamViewer control"); gtk_window_set_keep_above(GTK_WINDOW(ctrl.window), TRUE); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ctrl.raw), TRUE); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ctrl.show), TRUE); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ctrl.run), TRUE); //actual start is delayed by 100ms, see below gtk_widget_set_sensitive(ctrl.boxgpi, FALSE); gtk_scale_set_digits(GTK_SCALE(ctrl.exp), 0); gtk_range_set_update_policy(GTK_RANGE(ctrl.exp), GTK_UPDATE_DISCONTINUOUS); gtk_range_set_update_policy(GTK_RANGE(ctrl.gain), GTK_UPDATE_DISCONTINUOUS); gtk_adjustment_set_value(gtk_range_get_adjustment(GTK_RANGE(ctrl.exp)), 10); gtk_scale_set_value_pos(GTK_SCALE(ctrl.exp), GTK_POS_RIGHT); gtk_scale_set_value_pos(GTK_SCALE(ctrl.gain), GTK_POS_RIGHT); gtk_widget_set_sensitive(ctrl.boxx, FALSE); gtk_widget_set_sensitive(ctrl.boxy, FALSE); gtk_widget_set_sensitive(ctrl.exp, FALSE); gtk_widget_set_sensitive(ctrl.gain, FALSE); //pack everything into window gtk_container_add(GTK_CONTAINER(ctrl.boxgpi), ctrl.gpi1); gtk_container_add(GTK_CONTAINER(ctrl.boxgpi), ctrl.gpi2); gtk_container_add(GTK_CONTAINER(ctrl.boxgpi), ctrl.gpi3); gtk_container_add(GTK_CONTAINER(ctrl.boxgpi), ctrl.gpi4); gtk_container_add(GTK_CONTAINER(ctrl.boxmain), ctrl.boxgpi); gtk_container_add(GTK_CONTAINER(ctrl.boxx), ctrl.labelx0); gtk_container_add(GTK_CONTAINER(ctrl.boxx), ctrl.x0); gtk_container_add(GTK_CONTAINER(ctrl.boxy), ctrl.labely0); gtk_container_add(GTK_CONTAINER(ctrl.boxy), ctrl.y0); gtk_container_add(GTK_CONTAINER(ctrl.boxx), ctrl.labelcx); gtk_container_add(GTK_CONTAINER(ctrl.boxx), ctrl.cx); gtk_container_add(GTK_CONTAINER(ctrl.boxy), ctrl.labelcy); gtk_container_add(GTK_CONTAINER(ctrl.boxy), ctrl.cy); gtk_container_add(GTK_CONTAINER(ctrl.boxmain), ctrl.boxx); gtk_container_add(GTK_CONTAINER(ctrl.boxmain), ctrl.boxy); gtk_container_add(GTK_CONTAINER(ctrl.boxmain), ctrl.labelexp); gtk_container_add(GTK_CONTAINER(ctrl.boxmain), ctrl.exp); gtk_container_add(GTK_CONTAINER(ctrl.boxmain), ctrl.labelgain); gtk_container_add(GTK_CONTAINER(ctrl.boxmain), ctrl.gain); gtk_container_add(GTK_CONTAINER(ctrl.boxmain), ctrl.raw); gtk_container_add(GTK_CONTAINER(ctrl.boxmain), ctrl.show); gtk_container_add(GTK_CONTAINER(ctrl.boxmain), ctrl.run); gtk_container_add(GTK_CONTAINER(ctrl.window), ctrl.boxmain); //register handlers gdk_threads_add_timeout(1000, (GSourceFunc)time_handler, (gpointer)&ctrl); gdk_threads_add_timeout(100, (GSourceFunc)start_cb, (gpointer)&ctrl); //only way I found to make sure window is displayed right away g_signal_connect(ctrl.window, "delete_event", G_CALLBACK(close_cb), (gpointer)TRUE); g_signal_connect(gtk_range_get_adjustment(GTK_RANGE(ctrl.gain)), "value_changed", G_CALLBACK(update_gain), NULL); g_signal_connect(gtk_range_get_adjustment(GTK_RANGE(ctrl.exp)), "value_changed", G_CALLBACK(update_exposure), NULL); g_signal_connect(gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(ctrl.x0)), "value_changed", G_CALLBACK(update_x0), NULL); g_signal_connect(gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(ctrl.y0)), "value_changed", G_CALLBACK(update_y0), NULL); g_signal_connect(gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(ctrl.cx)), "value_changed", G_CALLBACK(update_cx), NULL); g_signal_connect(gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(ctrl.cy)), "value_changed", G_CALLBACK(update_cy), NULL); g_signal_connect(ctrl.raw, "toggled", G_CALLBACK(update_raw), (gpointer)&ctrl); g_signal_connect(ctrl.show, "toggled", G_CALLBACK(update_show), NULL); g_signal_connect(ctrl.run, "toggled", G_CALLBACK(update_run), (gpointer)&ctrl); //show window gtk_widget_show_all(ctrl.window); //start the main loop gtk_main(); //exit gdk_threads_leave(); acquire = FALSE; if(videoThread) pthread_join(videoThread, NULL); return 0; }
_______________________________________________ Pd-list@iem.at mailing list UNSUBSCRIBE and account-management -> http://lists.puredata.info/listinfo/pd-list