From a649df60d5496de414bcc1aa9761dcd2e15d0f2a Mon Sep 17 00:00:00 2001 From: "Joshua M. Doe" Date: Wed, 3 Jul 2013 10:45:16 -0400 Subject: [PATCH] pixci: Initial untested pixcisrc element for EPIX PIXCI framegrabbers --- CMakeLists.txt | 2 + cmake/modules/FindXCLIB.cmake | 51 +++ sys/CMakeLists.txt | 4 + sys/pixci/CMakeLists.txt | 26 ++ sys/pixci/gstpixcisrc.c | 674 +++++++++++++++++++++++++++++ sys/pixci/gstpixcisrc.h | 99 +++++ vs2010/gst-plugins-vision.sln | 8 + vs2010/pixci/pixci.props | 17 + vs2010/pixci/pixci.vcxproj | 79 ++++ vs2010/pixci/pixci.vcxproj.filters | 27 ++ 10 files changed, 987 insertions(+) create mode 100644 cmake/modules/FindXCLIB.cmake create mode 100644 sys/pixci/CMakeLists.txt create mode 100644 sys/pixci/gstpixcisrc.c create mode 100644 sys/pixci/gstpixcisrc.h create mode 100644 vs2010/pixci/pixci.props create mode 100644 vs2010/pixci/pixci.vcxproj create mode 100644 vs2010/pixci/pixci.vcxproj.filters diff --git a/CMakeLists.txt b/CMakeLists.txt index e114277..3fead3a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,6 +40,8 @@ macro_log_feature(IOTECHDAQX_FOUND "IOtech DaqX" "Required to build IOtech DaqX find_package(Phoenix) macro_log_feature(PHOENIX_FOUND "Active Silicon Phoenix" "Required to build Active Silicon Phoenix source element" "http://www.activesilicon.com/" FALSE) +find_package(XCLIB) +macro_log_feature(XCLIB_FOUND "EPIX PIXCI" "Required to build EPIX PIXCI source element" "http://www.epixinc.com/" FALSE) # Setup common environment diff --git a/cmake/modules/FindXCLIB.cmake b/cmake/modules/FindXCLIB.cmake new file mode 100644 index 0000000..fb45b55 --- /dev/null +++ b/cmake/modules/FindXCLIB.cmake @@ -0,0 +1,51 @@ +# - Try to find EPIX XCLIB +# Once done this will define +# +# XCLIB_FOUND - system has EPIX XCLIB +# XCLIB_INCLUDE_DIR - the EPIX XCLIB include directory +# XCLIB_LIBRARIES - the libraries needed to use EPIX XCLIB +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +# TODO: properly handle 32-/64-bit differences, and Linux + +IF (XCLIB_INCLUDE_DIR AND XCLIB_LIBRARIES) + # in cache already + SET(XCLIB_FIND_QUIETLY TRUE) +ELSE (XCLIB_INCLUDE_DIR AND XCLIB_LIBRARIES) + SET(XCLIB_FIND_QUIETLY FALSE) +ENDIF (XCLIB_INCLUDE_DIR AND XCLIB_LIBRARIES) + +IF (NOT XCLIB_DIR) + SET (XCLIB_DIR "C:/Program Files/EPIX/XCLIB" CACHE PATH "Directory containing EPIX XCLIB") +ENDIF (NOT XCLIB_DIR) + +FIND_PATH (XCLIB_INCLUDE_DIR xcliball.h + PATHS + "${XCLIB_DIR}" + "C:/Program Files/EPIX/XCLIB" + DOC "Directory containing xcliball.h include file") + +FIND_LIBRARY (XCLIB_LIBRARIES NAMES XCLIBW64 + PATHS + "${XCLIB_DIR}" + "C:/Program Files/EPIX/XCLIB" + DOC "XCLIB library to link with") + +IF (XCLIB_INCLUDE_DIR) + #MESSAGE(STATUS "DEBUG: Found EPIX XCLIB include dir: ${XCLIB_INCLUDE_DIR}") +ELSE (XCLIB_INCLUDE_DIR) + MESSAGE(STATUS "XCLIB: WARNING: include dir not found") +ENDIF (XCLIB_INCLUDE_DIR) + +IF (XCLIB_LIBRARIES) + #MESSAGE(STATUS "DEBUG: Found EPIX XCLIB library: ${XCLIB_LIBRARIES}") +ELSE (XCLIB_LIBRARIES) + MESSAGE(STATUS "XCLIB: WARNING: library not found") +ENDIF (XCLIB_LIBRARIES) + +INCLUDE (FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS (XCLIB DEFAULT_MSG XCLIB_INCLUDE_DIR XCLIB_LIBRARIES) + +MARK_AS_ADVANCED(XCLIB_INCLUDE_DIR XCLIB_LIBRARIES) diff --git a/sys/CMakeLists.txt b/sys/CMakeLists.txt index 59337ef..dd3b10a 100644 --- a/sys/CMakeLists.txt +++ b/sys/CMakeLists.txt @@ -21,3 +21,7 @@ endif (IOTECHDAQX_FOUND) if (PHOENIX_FOUND) add_subdirectory(phoenix) endif (PHOENIX_FOUND) + +if (XCLIB_FOUND) + add_subdirectory(pixci) +endif (XCLIB_FOUND) diff --git a/sys/pixci/CMakeLists.txt b/sys/pixci/CMakeLists.txt new file mode 100644 index 0000000..4a96fde --- /dev/null +++ b/sys/pixci/CMakeLists.txt @@ -0,0 +1,26 @@ +add_definitions(-DHAVE_CONFIG_H) + +set ( SOURCES + gstpixcisrc.c ) + +set ( HEADERS + gstpixcisrc.h ) + +include_directories ( AFTER + ${PIXCI_INCLUDE_DIR} + .) + +add_library ( libgstpixci MODULE + ${SOURCES} + ${HEADERS} ) + +target_link_libraries ( libgstpixci + ${GLIB2_LIBRARIES} + ${GSTREAMER_LIBRARIES} + ${GSTREAMER_BASE_LIBRARY} + ${GSTREAMER_INTERFACE_LIBRARY} + ${GSTREAMER_VIDEO_LIBRARY} + ${PIXCI_LIBRARIES}) + +install (TARGETS libgstpixci + LIBRARY DESTINATION lib/gstreamer-0.10) diff --git a/sys/pixci/gstpixcisrc.c b/sys/pixci/gstpixcisrc.c new file mode 100644 index 0000000..de27deb --- /dev/null +++ b/sys/pixci/gstpixcisrc.c @@ -0,0 +1,674 @@ +/* GStreamer + * Copyright (C) 2011 FIXME + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Suite 500, + * Boston, MA 02110-1335, USA. + */ +/** + * SECTION:element-gstpixcisrc + * + * The pixcisrc element is a source for EPIX PIXCI framegrabbers supported by EPIX XCLIB. + * + * + * Example launch line + * |[ + * gst-launch -v pixcisrc ! ffmpegcolorspace ! autovideosink + * ]| + * Shows video from the default Pixci framegrabber + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "gstpixcisrc.h" + +GST_DEBUG_CATEGORY_STATIC (gst_pixcisrc_debug); +#define GST_CAT_DEFAULT gst_pixcisrc_debug + +/* prototypes */ +static void gst_pixcisrc_set_property (GObject * object, + guint property_id, const GValue * value, GParamSpec * pspec); +static void gst_pixcisrc_get_property (GObject * object, + guint property_id, GValue * value, GParamSpec * pspec); +static void gst_pixcisrc_dispose (GObject * object); +static void gst_pixcisrc_finalize (GObject * object); + +static gboolean gst_pixcisrc_start (GstBaseSrc * src); +static gboolean gst_pixcisrc_stop (GstBaseSrc * src); +static GstCaps *gst_pixcisrc_get_caps (GstBaseSrc * src, GstCaps * filter); +static gboolean gst_pixcisrc_set_caps (GstBaseSrc * src, GstCaps * caps); + +static GstFlowReturn gst_pixcisrc_create (GstPushSrc * src, GstBuffer ** buf); + +static GstCaps *gst_pixcisrc_create_caps (GstPixciSrc * src); +enum +{ + PROP_0, + PROP_FORMAT_NAME, + PROP_FORMAT_FILE, + PROP_DRIVER_PARAMS, + PROP_NUM_CAPTURE_BUFFERS, + PROP_BOARD, + PROP_CHANNEL +}; + +#define DEFAULT_PROP_FORMAT_NAME "" +#define DEFAULT_PROP_FORMAT_FILE "" +#define DEFAULT_PROP_DRIVER_PARAMS "" +#define DEFAULT_PROP_NUM_CAPTURE_BUFFERS 2 +#define DEFAULT_PROP_BOARD 0 +#define DEFAULT_PROP_CHANNEL 0 + +/* pad templates */ + +static GstStaticPadTemplate gst_pixcisrc_src_template = + GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE + ("{ GRAY8, GRAY16_LE, GRAY16_BE, RGB, xRGB, RGB_15, RGB_16 }") ";" + "video/x-bayer,format=(string){bggr,grbg,gbrg,rggb}," + "width=(int)[1,MAX],height=(int)[1,MAX],framerate=(fraction)[0/1,MAX];" + "video/x-bayer,format=(string){bggr16,grbg16,gbrg16,rggb16}," + "bpp=(int){10,12,14,16},endianness={1234,4321}," + "width=(int)[1,MAX],height=(int)[1,MAX],framerate=(fraction)[0/1,MAX]") + ); + +/* class initialization */ + +G_DEFINE_TYPE (GstPixciSrc, gst_pixcisrc, GST_TYPE_PUSH_SRC); + +static void +gst_pixcisrc_class_init (GstPixciSrcClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); + GstBaseSrcClass *gstbasesrc_class = GST_BASE_SRC_CLASS (klass); + GstPushSrcClass *gstpushsrc_class = GST_PUSH_SRC_CLASS (klass); + + gobject_class->set_property = gst_pixcisrc_set_property; + gobject_class->get_property = gst_pixcisrc_get_property; + gobject_class->dispose = gst_pixcisrc_dispose; + gobject_class->finalize = gst_pixcisrc_finalize; + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&gst_pixcisrc_src_template)); + + gst_element_class_set_static_metadata (gstelement_class, + "EPIX PIXCI Video Source", "Source/Video", + "EPIX PIXCI framegrabber video source", + "Joshua M. Doe "); + + gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_pixcisrc_start); + gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_pixcisrc_stop); + gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_pixcisrc_get_caps); + gstbasesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_pixcisrc_set_caps); + + gstpushsrc_class->create = GST_DEBUG_FUNCPTR (gst_pixcisrc_create); + + /* Install GObject properties */ + g_object_class_install_property (gobject_class, PROP_FORMAT_NAME, + g_param_spec_string ("format-name", "Format name", + "Name of the video format for the selected camera " + "(specify only one of format-name or format-file)", + DEFAULT_PROP_FORMAT_NAME, + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_MUTABLE_READY))); + g_object_class_install_property (gobject_class, PROP_FORMAT_FILE, + g_param_spec_string ("format-file", "Format file", + "Filepath of the video file for the selected camera " + "(specify only one of format-name or format-file)", + DEFAULT_PROP_FORMAT_FILE, + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_MUTABLE_READY))); + g_object_class_install_property (gobject_class, PROP_DRIVER_PARAMS, + g_param_spec_string ("driver-params", "Driver parameters", + "Driver parameters to use when initializing XCLIB", + DEFAULT_PROP_DRIVER_PARAMS, + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_MUTABLE_READY))); + g_object_class_install_property (gobject_class, PROP_NUM_CAPTURE_BUFFERS, + g_param_spec_uint ("num-capture-buffers", "Number of capture buffers", + "Number of capture buffers", 1, G_MAXUINT, + DEFAULT_PROP_NUM_CAPTURE_BUFFERS, + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + g_object_class_install_property (gobject_class, PROP_BOARD, + g_param_spec_uint ("board", "Board", "Board number (0 for auto)", 0, 7, + DEFAULT_PROP_BOARD, + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + g_object_class_install_property (gobject_class, PROP_CHANNEL, + g_param_spec_uint ("channel", "Channel", "Channel number (0 for auto)", 0, + 2, DEFAULT_PROP_CHANNEL, + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); +} + +static void +gst_pixcisrc_init (GstPixciSrc * src) +{ + /* set source as live (no preroll) */ + gst_base_src_set_live (GST_BASE_SRC (src), TRUE); + + /* override default of BYTES to operate in time mode */ + gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME); + + /* initialize member variables */ + src->format_name = g_strdup (DEFAULT_PROP_FORMAT_NAME); + src->format_file = g_strdup (DEFAULT_PROP_FORMAT_FILE); + src->driver_params = g_strdup (DEFAULT_PROP_DRIVER_PARAMS); + src->num_capture_buffers = DEFAULT_PROP_NUM_CAPTURE_BUFFERS; + + /* this selects the first unit, make this a property? */ + src->unitmap = 1; + src->pixci_open = FALSE; + + src->first_pixci_ts = GST_CLOCK_TIME_NONE; + src->frame_start_times = g_new (guint64, src->num_capture_buffers); + src->frame_end_times = g_new (guint64, src->num_capture_buffers); + src->buffer_ready = FALSE; + src->timeout_occurred = FALSE; + src->fifo_overflow_occurred = FALSE; + + src->buffer_ready_count = 0; + src->buffer_processed_count = 0; + src->frame_end_count = 0; + src->frame_start_count = 0; + /*pixcisrc->frame_count = 0; */ + + g_mutex_init (&src->mutex); + g_cond_init (&src->cond); +} + +void +gst_pixcisrc_set_property (GObject * object, guint property_id, + const GValue * value, GParamSpec * pspec) +{ + GstPixciSrc *src; + + src = GST_PIXCI_SRC (object); + + switch (property_id) { + case PROP_FORMAT_NAME: + g_free (src->format_name); + src->format_name = g_strdup (g_value_get_string (value)); + break; + case PROP_FORMAT_FILE: + g_free (src->format_file); + src->format_file = g_strdup (g_value_get_string (value)); + break; + case PROP_DRIVER_PARAMS: + g_free (src->driver_params); + src->driver_params = g_strdup (g_value_get_string (value)); + break; + case PROP_NUM_CAPTURE_BUFFERS: + if (src->acq_started) { + GST_ELEMENT_WARNING (src, RESOURCE, SETTINGS, + ("Number of capture buffers cannot be changed after acquisition has started."), + (NULL)); + } else { + src->num_capture_buffers = g_value_get_uint (value); + + g_free (src->frame_start_times); + src->frame_start_times = g_new (guint64, src->num_capture_buffers); + + g_free (src->frame_end_times); + src->frame_end_times = g_new (guint64, src->num_capture_buffers); + } + break; + case PROP_BOARD: + src->board = g_value_get_uint (value); + break; + case PROP_CHANNEL: + src->channel = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +void +gst_pixcisrc_get_property (GObject * object, guint property_id, + GValue * value, GParamSpec * pspec) +{ + GstPixciSrc *src; + + g_return_if_fail (GST_IS_PIXCI_SRC (object)); + src = GST_PIXCI_SRC (object); + + switch (property_id) { + case PROP_FORMAT_NAME: + g_value_set_string (value, src->format_name); + break; + case PROP_FORMAT_FILE: + g_value_set_string (value, src->format_file); + break; + case PROP_DRIVER_PARAMS: + g_value_set_string (value, src->driver_params); + break; + case PROP_NUM_CAPTURE_BUFFERS: + g_value_set_uint (value, src->num_capture_buffers); + break; + case PROP_BOARD: + g_value_set_uint (value, src->board); + break; + case PROP_CHANNEL: + g_value_set_uint (value, src->channel); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +void +gst_pixcisrc_dispose (GObject * object) +{ + GstPixciSrc *src; + + g_return_if_fail (GST_IS_PIXCI_SRC (object)); + src = GST_PIXCI_SRC (object); + + /* clean up as possible. may be called multiple times */ + + G_OBJECT_CLASS (gst_pixcisrc_parent_class)->dispose (object); +} + +void +gst_pixcisrc_finalize (GObject * object) +{ + GstPixciSrc *src; + + g_return_if_fail (GST_IS_PIXCI_SRC (object)); + src = GST_PIXCI_SRC (object); + + /* clean up object here */ + g_free (src->format_name); + g_free (src->format_file); + g_free (src->driver_params); + + g_free (src->frame_start_times); + g_free (src->frame_end_times); + + G_OBJECT_CLASS (gst_pixcisrc_parent_class)->finalize (object); +} + +//static inline GstClockTime +//gst_pixci_get_timestamp (GstPixciSrc * pixcisrc) +//{ +// ui32 dwParam; +// guint64 timestamp; +// +// /* get time in microseconds from start of acquisition */ +// /* TODO: check for rollover */ +// PHX_ParameterGet (pixcisrc->hCamera, PHX_EVENTCOUNT, &dwParam); +// timestamp = (guint64) 1000 *dwParam; +// +// if (pixcisrc->first_pixci_ts == GST_CLOCK_TIME_NONE) { +// pixcisrc->first_pixci_ts = timestamp; +// } +// return timestamp - pixcisrc->first_pixci_ts; +//} + +/* Callback function to handle image capture events. */ +//void +//phx_callback (tHandle hCamera, ui32 dwMask, void *pvParams) +//{ +// GstPixciSrc *pixcisrc = GST_PIXCI_SRC (pvParams); +// GstClockTime ct = gst_pixci_get_timestamp (pixcisrc); +// gboolean signal_create_func = FALSE; +// guint n; +// +// g_mutex_lock (&pixcisrc->mutex); +// +// /* Note that more than one interrupt can be sent, so no "else if" */ +// +// /* called when frame valid signal goes high */ +// if (PHX_INTRPT_FRAME_START & dwMask) { +// /* FIXME: this will work until frames are dropped */ +// n = pixcisrc->frame_start_count % pixcisrc->num_capture_buffers; +// pixcisrc->frame_start_times[n] = ct; +// +// pixcisrc->frame_start_count++; +// } +// +// /* called when frame valid signal goes low */ +// if (PHX_INTRPT_FRAME_END & dwMask) { +// /* FIXME: this will work until frames are dropped */ +// n = (pixcisrc->frame_end_count - 1) % pixcisrc->num_capture_buffers; +// pixcisrc->frame_end_times[n] = ct; +// +// pixcisrc->frame_end_count++; +// } +// +// if (PHX_INTRPT_BUFFER_READY & dwMask) { +// /* we have a buffer */ +// pixcisrc->buffer_ready = TRUE; +// pixcisrc->buffer_ready_count++; +// signal_create_func = TRUE; +// } +// +// if (PHX_INTRPT_TIMEOUT & dwMask) { +// /* TODO: we could offer to try and ABORT then re-START capture */ +// pixcisrc->timeout_occurred = TRUE; +// signal_create_func = TRUE; +// } +// +// if (PHX_INTRPT_FIFO_OVERFLOW & dwMask) { +// pixcisrc->fifo_overflow_occurred = TRUE; +// signal_create_func = TRUE; +// } +// +// +// +// if (signal_create_func) +// g_cond_signal (&pixcisrc->cond); +// g_mutex_unlock (&pixcisrc->mutex); +// /* after unlocking, _create will check for these errors and copy data */ +//} + +static gboolean +gst_pixcisrc_start (GstBaseSrc * bsrc) +{ + GstPixciSrc *src = GST_PIXCI_SRC (bsrc); + int pxerr; + + GST_DEBUG_OBJECT (src, "start"); + + if (strlen (src->format_name) && strlen (src->format_file)) { + GST_ERROR_OBJECT (src, + "Only one of format name and format file can be specified"); + return FALSE; + } else if (!strlen (src->format_name) && !strlen (src->format_file)) { + GST_ERROR_OBJECT (src, + "One of format name or format file must be specified"); + return FALSE; + } + + if (strlen (src->format_file) + && !g_file_test (src->format_file, G_FILE_TEST_EXISTS)) { + GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, + ("Format file does not exist: %s", src->format_file), (NULL)); + return FALSE; + } + + /* open XCLIB library and driver */ + pxerr = + pxd_PIXCIopen (src->driver_params, src->format_name, src->format_file); + if (pxerr) { + char buf[1024]; + pxd_mesgFaultText (src->unitmap, buf, 1024); + GST_ELEMENT_ERROR (src, LIBRARY, INIT, + ("Failed to open XCLIB library and driver"), ("%s", buf)); + return FALSE; + } + src->pixci_open = TRUE; + + GST_DEBUG_OBJECT (src, "DriverId: %s", pxd_infoDriverId ()); + GST_DEBUG_OBJECT (src, "LibraryId: %s", pxd_infoLibraryId ()); + GST_DEBUG_OBJECT (src, "Frame buffer memory: %d", + pxd_infoMemsize (src->unitmap)); + GST_DEBUG_OBJECT (src, "Model: %d", pxd_infoModel (src->unitmap)); + GST_DEBUG_OBJECT (src, "SubModel: %d", pxd_infoSubmodel (src->unitmap)); + GST_DEBUG_OBJECT (src, "Units: %d", pxd_infoUnits ()); + + return TRUE; +} + +static gboolean +gst_pixcisrc_stop (GstBaseSrc * bsrc) +{ + GstPixciSrc *src = GST_PIXCI_SRC (bsrc); + + GST_DEBUG_OBJECT (src, "stop"); + + pxd_PIXCIclose (); + src->pixci_open = FALSE; + + /* TODO: stop acq/release cam? */ + + src->dropped_frame_count = 0; + /*pixcisrc->last_time_code = -1; */ + + return TRUE; +} + +static GstCaps * +gst_pixcisrc_get_caps (GstBaseSrc * bsrc, GstCaps * filter) +{ + GstPixciSrc *src = GST_PIXCI_SRC (bsrc); + GstCaps *caps; + + if (!src->pixci_open) { + caps = gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD (src)); + } else { + gint components, bits_per_component; + gdouble par; + GstVideoInfo vinfo; + + /* Create video info */ + gst_video_info_init (&vinfo); + + vinfo.width = pxd_imageXdim (); + vinfo.height = pxd_imageYdim (); + + par = pxd_imageAspectRatio (); + if (par != 0) { + vinfo.par_d = 10000; + vinfo.par_n = (gint) (par * vinfo.par_d); + } + + bits_per_component = pxd_imageBdim (); + components = pxd_imageCdim (); + + if (components == 1 && bits_per_component <= 8) { + vinfo.finfo = gst_video_format_get_info (GST_VIDEO_FORMAT_GRAY8); + caps = gst_video_info_to_caps (&vinfo); + } else if (components == 1 && + bits_per_component > 8 && bits_per_component <= 16) { + GValue val = G_VALUE_INIT; + GstStructure *s; + + if (G_BYTE_ORDER == G_LITTLE_ENDIAN) + vinfo.finfo = gst_video_format_get_info (GST_VIDEO_FORMAT_GRAY16_LE); + else if (G_BYTE_ORDER == G_BIG_ENDIAN) + vinfo.finfo = gst_video_format_get_info (GST_VIDEO_FORMAT_GRAY16_BE); + caps = gst_video_info_to_caps (&vinfo); + + /* set bpp, extra info for GRAY16 so elements can scale properly */ + s = gst_caps_get_structure (caps, 0); + g_value_init (&val, G_TYPE_INT); + g_value_set_int (&val, bits_per_component); + gst_structure_set_value (s, "bpp", &val); + g_value_unset (&val); + } else { + GST_ELEMENT_ERROR (src, STREAM, WRONG_TYPE, + (("Unknown or unsupported color format.")), (NULL)); + goto Error; + } + + } + + GST_DEBUG_OBJECT (src, "The caps before filtering are %" GST_PTR_FORMAT, + caps); + + if (filter) { + GstCaps *tmp = gst_caps_intersect (caps, filter); + gst_caps_unref (caps); + caps = tmp; + } + + GST_DEBUG_OBJECT (src, "The caps after filtering are %" GST_PTR_FORMAT, caps); + + return caps; + +Error: + return NULL; +} + +static gboolean +gst_pixcisrc_set_caps (GstBaseSrc * bsrc, GstCaps * caps) +{ + GstPixciSrc *src = GST_PIXCI_SRC (bsrc); + GstVideoInfo vinfo; + GstStructure *s = gst_caps_get_structure (caps, 0); + + GST_DEBUG_OBJECT (src, "The caps being set are %" GST_PTR_FORMAT, caps); + + gst_video_info_from_caps (&vinfo, caps); + + if (GST_VIDEO_INFO_FORMAT (&vinfo) != GST_VIDEO_FORMAT_UNKNOWN) { + src->gst_stride = GST_VIDEO_INFO_COMP_STRIDE (&vinfo, 0); + src->height = vinfo.height; + } else { + goto unsupported_caps; + } + + return TRUE; + +unsupported_caps: + GST_ERROR_OBJECT (src, "Unsupported caps: %" GST_PTR_FORMAT, caps); + return FALSE; +} + +static GstFlowReturn +gst_pixcisrc_create (GstPushSrc * psrc, GstBuffer ** buf) +{ + GstPixciSrc *src = GST_PIXCI_SRC (psrc); + guint dropped_frame_count = 0; + guint new_dropped_frames; + gint i; + guint n; + GstMapInfo minfo; + pxbuffer_t buffer = 1; + int pxerr; + + /* Start acquisition */ + if (!src->acq_started) { + /* TODO: start capture, goLive? */ + src->acq_started = TRUE; + } + + /* about to read/write variables modified by phx_callback */ + //g_mutex_lock (&src->mutex); + + /* wait for callback (we should always get at least a timeout( */ + /*g_cond_wait (&src->cond, &src->mutex); */ + + //if (src->fifo_overflow_occurred) { + // /* TODO: we could offer to try and ABORT then re-START capture */ + // GST_ELEMENT_ERROR (src, RESOURCE, FAILED, + // (("Acquisition failure due to FIFO overflow.")), (NULL)); + // g_mutex_unlock (&src->mutex); + // return GST_FLOW_ERROR; + //} + + //if (src->timeout_occurred) { + // /* TODO: we could offer to try and ABORT then re-START capture */ + // GST_ELEMENT_ERROR (src, RESOURCE, FAILED, + // (("Acquisition failure due to timeout.")), (NULL)); + // g_mutex_unlock (&src->mutex); + // return GST_FLOW_ERROR; + //} + + //if (!src->buffer_ready) { + // GST_ELEMENT_ERROR (src, RESOURCE, FAILED, + // (("You should not see this error, something very bad happened.")), + // (NULL)); + // g_mutex_unlock (&src->mutex); + // return GST_FLOW_ERROR; + //} + + //GST_LOG_OBJECT (src, + // "Processing new buffer %d (Frame start: %d), ready-processed = %d", + // src->buffer_ready_count, src->frame_start_count, + // src->buffer_ready_count - src->buffer_processed_count); + //src->buffer_ready = FALSE; + + ///* frame_start is always >= buffer_ready */ + //dropped_frame_count = + // src->frame_start_count - src->buffer_ready_count; + + //g_mutex_unlock (&src->mutex); + pxerr = pxd_doSnap (src->unitmap, buffer, 0); + if (pxerr) { + GST_ELEMENT_ERROR (src, RESOURCE, FAILED, + (("Failed to get buffer.")), (NULL)); + return GST_FLOW_ERROR; + } + + /* TODO: use allocator or use from Pixci pool */ + *buf = gst_buffer_new_and_alloc (src->height * src->gst_stride); + + /* Copy image to buffer from surface TODO: use orc_memcpy */ + gst_buffer_map (*buf, &minfo, GST_MAP_WRITE); + GST_LOG_OBJECT (src, + "GstBuffer size=%d, gst_stride=%d, phx_stride=%d", minfo.size, + src->gst_stride, src->px_stride); + pxd_readuchar (src->unitmap, buffer, 0, 0, -1, -1, minfo.data, minfo.size, + "Grey"); + //for (i = 0; i < src->height; i++) { + // memcpy (minfo.data + i * src->gst_stride, + // ((guint8 *) buffer.pvAddress) + i * src->px_stride, + // src->gst_stride); + //} + gst_buffer_unmap (*buf, &minfo); + + /* Having processed the data, release the buffer ready for further image data */ + //src->buffer_processed_count++; + + /* check for dropped frames (can only detect more than one) */ + //new_dropped_frames = dropped_frame_count - src->dropped_frame_count; + //if (new_dropped_frames > 0) { + // src->dropped_frame_count = dropped_frame_count; + // GST_WARNING ("Dropped %d frames (%d total)", new_dropped_frames, + // src->dropped_frame_count); + // /* TODO: emit message here about dropped frames */ + //} + + /* use time from capture board */ + //n = (src->buffer_processed_count - + // 1) % src->num_capture_buffers; + //GST_BUFFER_TIMESTAMP (*buf) = src->frame_start_times[n]; + //GST_BUFFER_DURATION (*buf) = + // GST_CLOCK_DIFF (src->frame_start_times[n], + // src->frame_end_times[n]); + //GST_BUFFER_OFFSET (*buf) = src->buffer_processed_count - 1; + //GST_BUFFER_OFFSET_END (*buf) = GST_BUFFER_OFFSET (*buf); + + return GST_FLOW_OK; +} + +static gboolean +plugin_init (GstPlugin * plugin) +{ + GST_DEBUG_CATEGORY_INIT (gst_pixcisrc_debug, "pixcisrc", 0, + "debug category for pixcisrc element"); + gst_element_register (plugin, "pixcisrc", GST_RANK_NONE, + gst_pixcisrc_get_type ()); + + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + pixci, + "Pixci frame grabber source", + plugin_init, VERSION, "LGPL", PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/sys/pixci/gstpixcisrc.h b/sys/pixci/gstpixcisrc.h new file mode 100644 index 0000000..f6b8647 --- /dev/null +++ b/sys/pixci/gstpixcisrc.h @@ -0,0 +1,99 @@ +/* GStreamer + * Copyright (C) 2011 FIXME + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _GST_PIXCI_SRC_H_ +#define _GST_PIXCI_SRC_H_ + +#include + +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_PIXCI_SRC (gst_pixcisrc_get_type()) +#define GST_PIXCI_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PIXCI_SRC,GstPixciSrc)) +#define GST_PIXCI_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PIXCI_SRC,GstPixciSrcClass)) +#define GST_IS_PIXCI_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PIXCI_SRC)) +#define GST_IS_PIXCI_SRC_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PIXCI_SRC)) + +typedef struct _GstPixciSrc GstPixciSrc; +typedef struct _GstPixciSrcClass GstPixciSrcClass; + +/** +* GstPixciSrcConnector: +* @MC_Connector_VID<1..16>: channel is linked to camera at the VID<1..16> input +* @MC_Connector_YC: channel is linked to a camera at the YC input +* +* +* Identifies the connector that the camera is connected to. +*/ +typedef enum { + +} GstPixciSrcConnector; + +struct _GstPixciSrc +{ + GstPushSrc base_pixcisrc; + + gint dropped_frame_count; + gboolean acq_started; + + /* camera handle */ + + /* properties */ + gchar *format_name; + gchar *format_file; + gchar *driver_params; + guint num_capture_buffers; + guint board; + guint channel; + + gboolean pixci_open; + int unitmap; + + GstClockTime first_pixci_ts; + guint64 *frame_start_times; + guint64 *frame_end_times; + gboolean buffer_ready; + guint buffer_ready_count; + guint frame_start_count; + guint frame_end_count; + guint buffer_processed_count; + gboolean timeout_occurred; + gboolean fifo_overflow_occurred; + + gint height; + gint gst_stride; + guint px_stride; + + GMutex mutex; + GCond cond; +}; + +struct _GstPixciSrcClass +{ + GstPushSrcClass base_pixcisrc_class; +}; + +GType gst_pixcisrc_get_type (void); + +G_END_DECLS + +#endif diff --git a/vs2010/gst-plugins-vision.sln b/vs2010/gst-plugins-vision.sln index cb1799a..6172b77 100644 --- a/vs2010/gst-plugins-vision.sln +++ b/vs2010/gst-plugins-vision.sln @@ -13,6 +13,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libniimaqdx", "niimaqdx\nii EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "euresys", "euresys\euresys.vcxproj", "{8E42AB09-CE84-48E9-9D55-C0AAC12379D8}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pixci", "pixci\pixci.vcxproj", "{6D883DC5-A8E1-4A42-B247-CBBD243DE1C1}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -58,6 +60,12 @@ Global {8E42AB09-CE84-48E9-9D55-C0AAC12379D8}.Release|Win32.ActiveCfg = Release|Win32 {8E42AB09-CE84-48E9-9D55-C0AAC12379D8}.Release|Win32.Build.0 = Release|Win32 {8E42AB09-CE84-48E9-9D55-C0AAC12379D8}.Release|x64.ActiveCfg = Release|x64 + {6D883DC5-A8E1-4A42-B247-CBBD243DE1C1}.Debug|Win32.ActiveCfg = Debug|Win32 + {6D883DC5-A8E1-4A42-B247-CBBD243DE1C1}.Debug|Win32.Build.0 = Debug|Win32 + {6D883DC5-A8E1-4A42-B247-CBBD243DE1C1}.Debug|x64.ActiveCfg = Debug|Win32 + {6D883DC5-A8E1-4A42-B247-CBBD243DE1C1}.Release|Win32.ActiveCfg = Release|Win32 + {6D883DC5-A8E1-4A42-B247-CBBD243DE1C1}.Release|Win32.Build.0 = Release|Win32 + {6D883DC5-A8E1-4A42-B247-CBBD243DE1C1}.Release|x64.ActiveCfg = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/vs2010/pixci/pixci.props b/vs2010/pixci/pixci.props new file mode 100644 index 0000000..eed204c --- /dev/null +++ b/vs2010/pixci/pixci.props @@ -0,0 +1,17 @@ + + + + + true + + + + C:\Program Files (x86)\EPIX\XCLIB;%(AdditionalIncludeDirectories) + + + C:\Program Files (x86)\EPIX\XCLIB;%(AdditionalLibraryDirectories) + XCLIBWNT.lib;%(AdditionalDependencies) + + + + diff --git a/vs2010/pixci/pixci.vcxproj b/vs2010/pixci/pixci.vcxproj new file mode 100644 index 0000000..830a985 --- /dev/null +++ b/vs2010/pixci/pixci.vcxproj @@ -0,0 +1,79 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {6D883DC5-A8E1-4A42-B247-CBBD243DE1C1} + pixci + + + + Application + true + MultiByte + + + DynamicLibrary + false + true + MultiByte + + + + + + + + + + + + + + + + + + + Level3 + Disabled + HAVE_CONFIG_H;_MBCS;%(PreprocessorDefinitions) + $(SolutionDir)\..\;C:\Program Files\EPIX\XCLIB;%(AdditionalIncludeDirectories) + + + true + + + + + Level3 + MaxSpeed + true + true + HAVE_CONFIG_H;_MBCS;%(PreprocessorDefinitions) + $(SolutionDir)\..\;C:\Program Files\EPIX\XCLIB;%(AdditionalIncludeDirectories) + + + true + true + true + + + + + + + + + + + + \ No newline at end of file diff --git a/vs2010/pixci/pixci.vcxproj.filters b/vs2010/pixci/pixci.vcxproj.filters new file mode 100644 index 0000000..073235e --- /dev/null +++ b/vs2010/pixci/pixci.vcxproj.filters @@ -0,0 +1,27 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + + + Header Files + + + \ No newline at end of file