From 6c745ca7061232f4390f619e343d06079273d02e Mon Sep 17 00:00:00 2001 From: "Joshua M. Doe" Date: Fri, 25 Jan 2013 14:30:45 -0500 Subject: [PATCH] Initial implementation of NI IMAQdx element --- sys/CMakeLists.txt | 4 + sys/niimaqdx/CMakeLists.txt | 25 + sys/niimaqdx/gstniimaqdx.c | 1072 ++++++++++++++++++++++ sys/niimaqdx/gstniimaqdx.h | 89 ++ vs2010/gst-plugins-vision.sln | 20 +- vs2010/niimaqdx/niimaqdx.props | 17 + vs2010/niimaqdx/niimaqdx.vcxproj | 103 +++ vs2010/niimaqdx/niimaqdx.vcxproj.filters | 27 + 8 files changed, 1356 insertions(+), 1 deletion(-) create mode 100644 sys/niimaqdx/CMakeLists.txt create mode 100644 sys/niimaqdx/gstniimaqdx.c create mode 100644 sys/niimaqdx/gstniimaqdx.h create mode 100644 vs2010/niimaqdx/niimaqdx.props create mode 100644 vs2010/niimaqdx/niimaqdx.vcxproj create mode 100644 vs2010/niimaqdx/niimaqdx.vcxproj.filters diff --git a/sys/CMakeLists.txt b/sys/CMakeLists.txt index 76671d2..59337ef 100644 --- a/sys/CMakeLists.txt +++ b/sys/CMakeLists.txt @@ -10,6 +10,10 @@ if (NIIMAQ_FOUND) add_subdirectory (niimaq) endif (NIIMAQ_FOUND) +if (NIIMAQDX_FOUND) + add_subdirectory (niimaqdx) +endif (NIIMAQDX_FOUND) + if (IOTECHDAQX_FOUND) add_subdirectory (iotechdaqx) endif (IOTECHDAQX_FOUND) diff --git a/sys/niimaqdx/CMakeLists.txt b/sys/niimaqdx/CMakeLists.txt new file mode 100644 index 0000000..c26bb26 --- /dev/null +++ b/sys/niimaqdx/CMakeLists.txt @@ -0,0 +1,25 @@ +add_definitions(-DHAVE_CONFIG_H) + +set ( SOURCES + gstniimaqdx.c ) + +set ( HEADERS + gstniimaqdx.h ) + +include_directories ( AFTER + . + ${NIIMAQDX_INCLUDE_DIR} ) + +add_library ( libgstimaqdx MODULE + ${SOURCES} + ${HEADERS} ) + +target_link_libraries ( libgstimaqdx + general ${GLIB2_LIBRARIES} + general ${GSTREAMER_LIBRARIES} + general ${GSTREAMER_BASE_LIBRARY} + general ${GSTREAMER_INTERFACE_LIBRARY} + general ${NIIMAQDX_LIBRARIES} ) + +install (TARGETS libgstimaqdx + LIBRARY DESTINATION lib/gstreamer-0.10) diff --git a/sys/niimaqdx/gstniimaqdx.c b/sys/niimaqdx/gstniimaqdx.c new file mode 100644 index 0000000..165e443 --- /dev/null +++ b/sys/niimaqdx/gstniimaqdx.c @@ -0,0 +1,1072 @@ +/* GStreamer + * Copyright (C) <2006> Eric Jonas + * Copyright (C) <2006> Antoine Tremblay + * Copyright (C) 2013 United States Government, Joshua M. Doe + * + * 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. + */ + +/** + * SECTION:element-niimaqdxdxsrc + * + * Source for National Instruments IMAQdx (FireWire, USB, GigE Vision) + * + * + * Example launch line + * |[ + * gst-launch -v niimaqdxdxsrc ! ffmpegcolorspace ! autovideosink + * ]| + * + */ + +/* FIXME: timestamps sent in GST_TAG_DATE_TIME are off, need to adjust for time of first buffer */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstniimaqdx.h" + +#include +#include + +#include +#include + +GST_DEBUG_CATEGORY (niimaqdxsrc_debug); +#define GST_CAT_DEFAULT niimaqdxsrc_debug + +static GstElementDetails niimaqdxsrc_details = +GST_ELEMENT_DETAILS ("NI-IMAQdx Video Source", + "Source/Video", + "National Instruments IMAQdx source, supports FireWire, USB, and GigE Vision cameras", + "Joshua M. Doe "); + +enum +{ + PROP_0, + PROP_DEVICE, + PROP_RING_BUFFER_COUNT +}; + +#define DEFAULT_PROP_DEVICE "cam0" +#define DEFAULT_PROP_BUFSIZE 3 + +static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_VIDEO_CAPS_GRAY8 ";" + GST_VIDEO_CAPS_GRAY16 ("BIG_ENDIAN")) + ); + +static void gst_niimaqdxsrc_init_interfaces (GType type); + +GST_BOILERPLATE_FULL (GstNiImaqDxSrc, gst_niimaqdxsrc, GstPushSrc, + GST_TYPE_PUSH_SRC, gst_niimaqdxsrc_init_interfaces); + +/* GObject virtual methods */ +static void gst_niimaqdxsrc_dispose (GObject * object); +static void gst_niimaqdxsrc_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_niimaqdxsrc_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +/* GstBaseSrc virtual methods */ +static GstCaps *gst_niimaqdxsrc_get_caps (GstBaseSrc * bsrc); +static gboolean gst_niimaqdxsrc_set_caps (GstBaseSrc * bsrc, GstCaps * caps); +static gboolean gst_niimaqdxsrc_start (GstBaseSrc * src); +static gboolean gst_niimaqdxsrc_stop (GstBaseSrc * src); +static gboolean gst_niimaqdxsrc_query (GstBaseSrc * src, GstQuery * query); + +/* GstPushSrc virtual methods */ +static GstFlowReturn gst_niimaqdxsrc_create (GstPushSrc * psrc, + GstBuffer ** buffer); + +/* GstNiImaqDx methods */ +static GstCaps *gst_niimaqdxsrc_get_cam_caps (GstNiImaqDxSrc * src); +static gboolean gst_niimaqdxsrc_close_interface (GstNiImaqDxSrc * niimaqdxsrc); + +IMAQdxError +gst_niimaqdxsrc_report_imaq_error (IMAQdxError code) +{ + static char imaqdx_error_string[IMAQDX_MAX_API_STRING_LENGTH]; + if (code) { + IMAQdxGetErrorString (code, imaqdx_error_string, + IMAQDX_MAX_API_STRING_LENGTH); + GST_ERROR ("IMAQdx error: %s", imaqdx_error_string); + } + return code; +} + +/* This will be called "when a frame done event occurs." + * FIXME true?: If acquisition blocks because we don't copy buffers fast enough, the number + * of times this function is called will be less than the IMAQ cumulative + * buffer count. */ +uInt32 +gst_niimaqdxsrc_frame_done_callback (IMAQdxSession session, uInt32 bufferNumber, + void *userdata) +{ + GstNiImaqDxSrc *niimaqdxsrc = GST_NIIMAQDXSRC (userdata); + GstClockTime abstime; + static guint32 index = 0; + + g_mutex_lock (niimaqdxsrc->mutex); + + /* time hasn't been read yet, this frame will be dropped */ + if (niimaqdxsrc->times[index] != GST_CLOCK_TIME_NONE) { + g_mutex_unlock (niimaqdxsrc->mutex); + return 1; + } + + /* get clock time */ + abstime = gst_clock_get_time (GST_ELEMENT_CLOCK (niimaqdxsrc)); + niimaqdxsrc->times[index] = abstime; + + if (G_UNLIKELY (niimaqdxsrc->start_time == NULL)) + niimaqdxsrc->start_time = gst_date_time_new_now_utc (); + + /* first frame, use as element base time */ + if (niimaqdxsrc->base_time == GST_CLOCK_TIME_NONE) + niimaqdxsrc->base_time = abstime; + + index = (index + 1) % niimaqdxsrc->ringbuffer_count; + + g_mutex_unlock (niimaqdxsrc->mutex); + + /* return 1 to rearm the callback */ + return 1; +} + +static void _____BEGIN_FUNCTIONS_____ (); + +/** +* gst_niimaqdxsrc_probe_get_properties: +* @probe: #GstPropertyProbe +* +* Gets list of properties that can be probed +* +* Returns: #GList of properties that can be probed +*/ +static const GList * +gst_niimaqdxsrc_probe_get_properties (GstPropertyProbe * probe) +{ + GObjectClass *klass = G_OBJECT_GET_CLASS (probe); + static GList *list = NULL; + + if (!list) { + list = g_list_append (NULL, g_object_class_find_property (klass, "device")); + } + + return list; +} + +static gboolean _imaqdx_init = FALSE; +static GList *_imaqdx_devices = NULL; + +/** +* gst_niimaqdxsrc_class_probe_devices: +* @klass: #GstNiImaqDxClass +* @check: whether to enumerate devices +* +* Probes NI-IMAQdx driver for available interfaces +* +* Returns: TRUE always +*/ +static gboolean +gst_niimaqdxsrc_class_probe_devices (GstNiImaqDxSrcClass * klass, + gboolean check) +{ + if (!check) { + guint32 i; + uInt32 count; + IMAQdxError rval = IMAQdxErrorSuccess; + IMAQdxCameraInformation *cameraInformationArray = NULL; + + /* clear device list */ + while (_imaqdx_devices) { + gchar *iface = _imaqdx_devices->data; + _imaqdx_devices = g_list_remove (_imaqdx_devices, iface); + g_free (iface); + } + + GST_LOG_OBJECT (klass, "About to probe for IMAQdx interfaces"); + + // get count of connected cameras + rval = IMAQdxEnumerateCameras (NULL, &count, TRUE); + if (rval != IMAQdxErrorSuccess) { + gst_niimaqdxsrc_report_imaq_error (rval); + return FALSE; + } + + cameraInformationArray = g_new (IMAQdxCameraInformation, count); + + rval = IMAQdxEnumerateCameras (cameraInformationArray, &count, TRUE); + if (rval != IMAQdxErrorSuccess) { + gst_niimaqdxsrc_report_imaq_error (rval); + return FALSE; + } + + /* enumerate devices */ + for (i = 0; i < count; i++) { + gchar *iname; + IMAQdxCameraInformation *info = &cameraInformationArray[i]; + + GST_DEBUG_OBJECT (klass, "Found camera %s: %s, %s, %s, %s", + info->InterfaceName, info->VendorName, info->ModelName, + info->CameraFileName, info->CameraAttributeURL); + + iname = g_strdup (info->InterfaceName); + _imaqdx_devices = g_list_append (_imaqdx_devices, iname); + } + g_free (cameraInformationArray); + + _imaqdx_init = TRUE; + } + + klass->devices = _imaqdx_devices; + + return _imaqdx_init; +} + +/** +* gst_niimaqdxsrc_probe_probe_property: +* @probe: #GstPropertyProbe +* @prop_id: Property id +* @pspec: #GParamSpec +* +* GstPropertyProbe _probe_proprty vmethod implementation that probes a +* property for possible values +*/ +static void +gst_niimaqdxsrc_probe_probe_property (GstPropertyProbe * probe, + guint prop_id, const GParamSpec * pspec) +{ + GstNiImaqDxSrcClass *klass = GST_NIIMAQDXSRC_GET_CLASS (probe); + + switch (prop_id) { + case PROP_DEVICE: + gst_niimaqdxsrc_class_probe_devices (klass, FALSE); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); + break; + } +} + +/** +* gst_niimaqdxsrc_probe_needs_probe: +* @probe: #GstPropertyProbe +* @prop_id: Property id +* @pspec: #GParamSpec +* +* GstPropertyProbe _needs_probe vmethod implementation that indicates if +* a property needs to be updated +* +* Returns: TRUE if a property needs to be updated +*/ +static gboolean +gst_niimaqdxsrc_probe_needs_probe (GstPropertyProbe * probe, + guint prop_id, const GParamSpec * pspec) +{ + GstNiImaqDxSrcClass *klass = GST_NIIMAQDXSRC_GET_CLASS (probe); + gboolean ret = FALSE; + + switch (prop_id) { + case PROP_DEVICE: + ret = !gst_niimaqdxsrc_class_probe_devices (klass, TRUE); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); + break; + } + + return ret; +} + +/** +* gst_niimaqdxsrc_class_list_interfaces: +* @klass: #GstNiImaqDxClass +* +* Returns: #GValueArray of interface names +*/ +static GValueArray * +gst_niimaqdxsrc_class_list_devices (GstNiImaqDxSrcClass * klass) +{ + GValueArray *array; + GValue value = { 0 }; + GList *item; + + if (!klass->devices) + return NULL; + + array = g_value_array_new (g_list_length (klass->devices)); + item = klass->devices; + g_value_init (&value, G_TYPE_STRING); + while (item) { + gchar *iface = item->data; + + g_value_set_string (&value, iface); + g_value_array_append (array, &value); + + item = item->next; + } + g_value_unset (&value); + + return array; +} + +/** +* gst_niimaqdxsrc_probe_get_values: +* @probe: #GstPropertyProbe +* @prop_id: Property id +* @pspec: #GParamSpec +* +* GstPropertyProbe _get_values vmethod implementation that gets possible +* values for a property +* +* Returns: #GValueArray containing possible values for requested property +*/ +static GValueArray * +gst_niimaqdxsrc_probe_get_values (GstPropertyProbe * probe, + guint prop_id, const GParamSpec * pspec) +{ + GstNiImaqDxSrcClass *klass = GST_NIIMAQDXSRC_GET_CLASS (probe); + GValueArray *array = NULL; + + switch (prop_id) { + case PROP_DEVICE: + array = gst_niimaqdxsrc_class_list_devices (klass); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); + break; + } + + return array; +} + +/** +* gst_v4l_property_probe_interface_init: +* @iface: #GstPropertyProbeInterface +* +* Install property probe interfaces functions +*/ +static void +gst_niimaqdxsrc_property_probe_interface_init (GstPropertyProbeInterface * + iface) +{ + iface->get_properties = gst_niimaqdxsrc_probe_get_properties; + iface->probe_property = gst_niimaqdxsrc_probe_probe_property; + iface->needs_probe = gst_niimaqdxsrc_probe_needs_probe; + iface->get_values = gst_niimaqdxsrc_probe_get_values; +} + +/** +* gst_niimaqdxsrc_init_interfaces: +* @type: #GType +* +* Initialize all GStreamer interfaces +*/ +static void +gst_niimaqdxsrc_init_interfaces (GType type) +{ + static const GInterfaceInfo niimaqdx_propertyprobe_info = { + (GInterfaceInitFunc) gst_niimaqdxsrc_property_probe_interface_init, + NULL, + NULL, + }; + + g_type_add_interface_static (type, + GST_TYPE_PROPERTY_PROBE, &niimaqdx_propertyprobe_info); +} + +/** +* gst_niimaqdxsrc_base_init: +* g_class: +* +* Base GObject initialization +*/ +static void +gst_niimaqdxsrc_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_set_details (element_class, &niimaqdxsrc_details); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&src_factory)); +} + +/** +* gst_niimaqdxsrc_class_init: +* klass: #GstNiImaqDxClass to initialize +* +* Initialize #GstNiImaqDxClass, which occurs only once no matter how many +* instances of the class there are +*/ +static void +gst_niimaqdxsrc_class_init (GstNiImaqDxSrcClass * klass) +{ + /* get pointers to base classes */ + GObjectClass *gobject_class = (GObjectClass *) klass; + GstBaseSrcClass *gstbasesrc_class = (GstBaseSrcClass *) klass; + GstPushSrcClass *gstpushsrc_class = (GstPushSrcClass *) klass; + + /* install GObject vmethod implementations */ + gobject_class->dispose = gst_niimaqdxsrc_dispose; + gobject_class->set_property = gst_niimaqdxsrc_set_property; + gobject_class->get_property = gst_niimaqdxsrc_get_property; + + /* install GObject properties */ + g_object_class_install_property (G_OBJECT_CLASS (klass), + PROP_DEVICE, g_param_spec_string ("device", + "Device", "NI-IMAQdx camera to open", DEFAULT_PROP_DEVICE, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), + PROP_RING_BUFFER_COUNT, g_param_spec_int ("ring-buffer-count", + "Ring Buffer Count", + "The number of buffers in the internal IMAQdx ringbuffer", 1, + G_MAXINT, DEFAULT_PROP_BUFSIZE, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE)); + + /* install GstBaseSrc vmethod implementations */ + gstbasesrc_class->get_caps = gst_niimaqdxsrc_get_caps; + gstbasesrc_class->set_caps = gst_niimaqdxsrc_set_caps; + gstbasesrc_class->start = gst_niimaqdxsrc_start; + gstbasesrc_class->stop = gst_niimaqdxsrc_stop; + gstbasesrc_class->query = gst_niimaqdxsrc_query; + + /* install GstPushSrc vmethod implementations */ + gstpushsrc_class->create = gst_niimaqdxsrc_create; +} + +/** +* gst_niimaqdxsrc_init: +* src: the #GstNiImaqDx instance to initialize +* g_class: #GstNiImaqDxClass +* +* Initialize this instance of #GstNiImaqDx +*/ +static void +gst_niimaqdxsrc_init (GstNiImaqDxSrc * niimaqdxsrc, + GstNiImaqDxSrcClass * g_class) +{ + GstPad *srcpad = GST_BASE_SRC_PAD (niimaqdxsrc); + + /* set source as live (no preroll) */ + gst_base_src_set_live (GST_BASE_SRC (niimaqdxsrc), TRUE); + + /* override default of BYTES to operate in time mode */ + gst_base_src_set_format (GST_BASE_SRC (niimaqdxsrc), GST_FORMAT_TIME); + + niimaqdxsrc->mutex = g_mutex_new (); + + /* initialize properties */ + niimaqdxsrc->ringbuffer_count = DEFAULT_PROP_BUFSIZE; + niimaqdxsrc->device_name = g_strdup (DEFAULT_PROP_DEVICE); +} + +/** +* gst_niimaqdxsrc_dispose: +* object: #GObject to dispose +* +* Disposes of the #GObject as part of object destruction +*/ +static void +gst_niimaqdxsrc_dispose (GObject * object) +{ + GstNiImaqDxSrc *niimaqdxsrc = GST_NIIMAQDXSRC (object); + + gst_niimaqdxsrc_close_interface (niimaqdxsrc); + + /* free memory allocated */ + g_free (niimaqdxsrc->device_name); + niimaqdxsrc->device_name = NULL; + + /* unref objects */ + if (niimaqdxsrc->start_time) { + gst_date_time_unref (niimaqdxsrc->start_time); + niimaqdxsrc->start_time = NULL; + } + + /* chain dispose fuction of parent class */ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gst_niimaqdxsrc_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstNiImaqDxSrc *niimaqdxsrc = GST_NIIMAQDXSRC (object); + + switch (prop_id) { + case PROP_DEVICE: + if (niimaqdxsrc->device_name) + g_free (niimaqdxsrc->device_name); + niimaqdxsrc->device_name = g_strdup (g_value_get_string (value)); + break; + case PROP_RING_BUFFER_COUNT: + niimaqdxsrc->ringbuffer_count = g_value_get_int (value); + break; + default: + break; + } +} + +static void +gst_niimaqdxsrc_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + GstNiImaqDxSrc *niimaqdxsrc = GST_NIIMAQDXSRC (object); + + switch (prop_id) { + case PROP_DEVICE: + g_value_set_string (value, niimaqdxsrc->device_name); + break; + case PROP_RING_BUFFER_COUNT: + g_value_set_int (value, niimaqdxsrc->ringbuffer_count); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GstCaps * +gst_niimaqdxsrc_get_caps (GstBaseSrc * bsrc) +{ + GstNiImaqDxSrc *niimaqdxsrc = GST_NIIMAQDXSRC (bsrc); + + GST_LOG_OBJECT (bsrc, "Entering function get_caps"); + + /* return template caps if the session hasn't started yet */ + if (!niimaqdxsrc->session) { + return + gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD + (niimaqdxsrc))); + } + + return gst_niimaqdxsrc_get_cam_caps (niimaqdxsrc); +} + + +static gboolean +gst_niimaqdxsrc_set_caps (GstBaseSrc * bsrc, GstCaps * caps) +{ + GstNiImaqDxSrc *niimaqdxsrc = GST_NIIMAQDXSRC (bsrc); + gboolean res = TRUE; + + gst_video_format_parse_caps (caps, &niimaqdxsrc->format, &niimaqdxsrc->width, + &niimaqdxsrc->height); + + /* this will handle byte alignment (i.e. row multiple of 4 bytes) */ + niimaqdxsrc->framesize = + gst_video_format_get_size (niimaqdxsrc->format, niimaqdxsrc->width, + niimaqdxsrc->height); + + GST_LOG_OBJECT (niimaqdxsrc, "Caps set, framesize=%d", + niimaqdxsrc->framesize); + + return res; +} + +static void +gst_niimaqdxsrc_reset (GstNiImaqDxSrc * niimaqdxsrc) +{ + GST_LOG_OBJECT (niimaqdxsrc, "Resetting instance"); + + /* initialize member variables */ + niimaqdxsrc->n_frames = 0; + niimaqdxsrc->cumbufnum = 0; + niimaqdxsrc->n_dropped_frames = 0; + niimaqdxsrc->session = 0; + niimaqdxsrc->session_started = FALSE; + niimaqdxsrc->format = GST_VIDEO_FORMAT_UNKNOWN; + niimaqdxsrc->width = 0; + niimaqdxsrc->height = 0; + niimaqdxsrc->start_time = NULL; + niimaqdxsrc->start_time_sent = FALSE; + niimaqdxsrc->base_time = GST_CLOCK_TIME_NONE; + + g_free (niimaqdxsrc->times); + niimaqdxsrc->times = NULL; +} + +static gboolean +gst_niimaqdxsrc_start_acquisition (GstNiImaqDxSrc * niimaqdxsrc) +{ + int i; + IMAQdxError rval; + + g_assert (!niimaqdxsrc->session_started); + + GST_DEBUG_OBJECT (niimaqdxsrc, "Starting acquisition"); + + /* try to open the camera five times */ + for (i = 0; i < 5; i++) { + rval = IMAQdxStartAcquisition (niimaqdxsrc->session); + if (rval == IMAQdxErrorSuccess) { + niimaqdxsrc->session_started = TRUE; + return TRUE; + } else { + gst_niimaqdxsrc_report_imaq_error (rval); + GST_LOG_OBJECT (niimaqdxsrc, "camera is still off , wait 50ms and retry"); + g_usleep (50000); + } + } + + /* we tried five times and failed, so we error */ + gst_niimaqdxsrc_close_interface (niimaqdxsrc); + + return FALSE; +} + +static GstClockTime +gst_niimaqdxsrc_get_timestamp_from_buffer_number (GstNiImaqDxSrc * niimaqdxsrc, + guint32 buffer_number) +{ + GstClockTime abstime; + + abstime = niimaqdxsrc->times[(buffer_number) % niimaqdxsrc->ringbuffer_count]; + niimaqdxsrc->times[(buffer_number) % niimaqdxsrc->ringbuffer_count] = + GST_CLOCK_TIME_NONE; + + if (abstime == GST_CLOCK_TIME_NONE) + GST_WARNING_OBJECT (niimaqdxsrc, + "No valid time found for buffer %d, callback failed?", buffer_number); + + return abstime; +} + +static GstFlowReturn +gst_niimaqdxsrc_create (GstPushSrc * psrc, GstBuffer ** buffer) +{ + GstNiImaqDxSrc *niimaqdxsrc = GST_NIIMAQDXSRC (psrc); + GstFlowReturn ret = GST_FLOW_OK; + GstClockTime timestamp = GST_CLOCK_TIME_NONE; + GstClockTime duration; + uInt32 copied_number; + IMAQdxError rval; + uInt32 dropped; + + /* start the IMAQ acquisition session if we haven't done so yet */ + if (!niimaqdxsrc->session_started) { + if (!gst_niimaqdxsrc_start_acquisition (niimaqdxsrc)) { + GST_ELEMENT_ERROR (niimaqdxsrc, RESOURCE, FAILED, + ("Unable to start acquisition."), (NULL)); + return GST_FLOW_ERROR; + } + } + + GST_LOG_OBJECT (niimaqdxsrc, "Copying IMAQ buffer #%d", + niimaqdxsrc->cumbufnum); + ret = + gst_pad_alloc_buffer (GST_BASE_SRC_PAD (niimaqdxsrc), 0, + niimaqdxsrc->framesize, GST_PAD_CAPS (GST_BASE_SRC_PAD (niimaqdxsrc)), + buffer); + if (ret != GST_FLOW_OK) { + GST_ELEMENT_ERROR (niimaqdxsrc, RESOURCE, FAILED, + ("Failed to get downstream pad to allocate buffer"), (NULL)); + goto error; + } + + g_mutex_lock (niimaqdxsrc->mutex); + rval = IMAQdxGetImageData (niimaqdxsrc->session, GST_BUFFER_DATA (*buffer), + GST_BUFFER_SIZE (*buffer), IMAQdxBufferNumberModeBufferNumber, + niimaqdxsrc->cumbufnum, &copied_number); + //FIXME: handle timestamps + //timestamp = niimaqdxsrc->times[copied_index]; + //niimaqdxsrc->times[copied_index] = GST_CLOCK_TIME_NONE; + g_mutex_unlock (niimaqdxsrc->mutex); + + + if (rval) { + gst_niimaqdxsrc_report_imaq_error (rval); + GST_ELEMENT_ERROR (niimaqdxsrc, RESOURCE, FAILED, + ("failed to copy buffer %d", niimaqdxsrc->cumbufnum), (NULL)); + goto error; + } + + /* make guess of duration from timestamp and cumulative buffer number */ + if (GST_CLOCK_TIME_IS_VALID (timestamp)) { + duration = timestamp / (copied_number + 1); + } else { + duration = 33 * GST_MSECOND; + } + + GST_BUFFER_OFFSET (*buffer) = copied_number; + GST_BUFFER_OFFSET_END (*buffer) = copied_number + 1; + //TODO: handle timestamps + //GST_BUFFER_TIMESTAMP (*buffer) = + // timestamp - gst_element_get_base_time (GST_ELEMENT (niimaqdxsrc)); + GST_BUFFER_DURATION (*buffer) = duration; + + /* the negotiate() method already set caps on the source pad */ + gst_buffer_set_caps (*buffer, GST_PAD_CAPS (GST_BASE_SRC_PAD (niimaqdxsrc))); + + dropped = copied_number - niimaqdxsrc->cumbufnum; + if (dropped > 0) { + niimaqdxsrc->n_dropped_frames += dropped; + GST_WARNING_OBJECT (niimaqdxsrc, + "Asked to copy buffer #%d but was given #%d; just dropped %d frames (%d total)", + niimaqdxsrc->cumbufnum, copied_number, dropped, + niimaqdxsrc->n_dropped_frames); + } + + /* set cumulative buffer number to get next frame */ + niimaqdxsrc->cumbufnum = copied_number + 1; + niimaqdxsrc->n_frames++; + + if (G_UNLIKELY (niimaqdxsrc->start_time && !niimaqdxsrc->start_time_sent)) { + GstTagList *tl = + gst_tag_list_new_full (GST_TAG_DATE_TIME, niimaqdxsrc->start_time, + NULL); + GstEvent *e = gst_event_new_tag (tl); + GST_DEBUG_OBJECT (niimaqdxsrc, "Sending start time event: %" GST_PTR_FORMAT, + e); + gst_pad_push_event (GST_BASE_SRC_PAD (niimaqdxsrc), e); + niimaqdxsrc->start_time_sent = TRUE; + } + return ret; + +error: + { + return ret; + } +} + +void +listAttributes (IMAQdxSession session) +{ + IMAQdxAttributeInformation *attributeInfoArray = NULL; + uInt32 attributeCount; + int i; + IMAQdxError rval; + char *attributeTypeStrings[] = { "U32", "I64", + "F64", + "String", + "Enum", + "Bool", + "Command", + "Blob" + }; + char attributeString[IMAQDX_MAX_API_STRING_LENGTH]; + + rval = + IMAQdxEnumerateAttributes2 (session, NULL, &attributeCount, "", + IMAQdxAttributeVisibilityAdvanced); + GST_DEBUG ("Found %d attributes", attributeCount); + attributeInfoArray = g_new (IMAQdxAttributeInformation, attributeCount); + rval = + IMAQdxEnumerateAttributes2 (session, attributeInfoArray, &attributeCount, + "", IMAQdxAttributeVisibilityAdvanced); + GST_DEBUG ("Enumerating %d attributes", attributeCount); + for (i = 0; i < attributeCount; i++) { + IMAQdxAttributeInformation *info = attributeInfoArray + i; + g_assert (info); + + rval = + IMAQdxGetAttribute (session, info->Name, IMAQdxValueTypeString, + attributeString); + if (rval != IMAQdxErrorSuccess) { + GST_WARNING ("Failed to read value of attribute %s", info->Name); + continue; + } + printf ("%s, %s/%s, %s, %s\n", info->Name, info->Readable ? "R" : "-", + info->Writable ? "W" : "-", attributeTypeStrings[info->Type], + attributeString); + //gchar *newOutput = g_strconcat(output, line, NULL); + //g_free (output); + //g_free (line); + //output = newOutput; + } + g_free (attributeInfoArray); +} + + +GstVideoFormat +convert_PixelFormat_to_VideoFormat (char *pixelFormat) +{ + if (g_strcmp0 (pixelFormat, "Mono 8") == 0) + return GST_VIDEO_FORMAT_GRAY8; + else if (g_strcmp0 (pixelFormat, "Mono 16") == 0) + return GST_VIDEO_FORMAT_GRAY16_BE; //TODO: always BE? + else + return GST_VIDEO_FORMAT_UNKNOWN; +} + +/** +* gst_niimaqdxsrc_get_cam_caps: +* src: #GstNiImaqDx instance +* +* Get caps of camera attached to open IMAQ interface +* +* Returns: the #GstCaps of the src pad. Unref the caps when you no longer need it. +*/ +GstCaps * +gst_niimaqdxsrc_get_cam_caps (GstNiImaqDxSrc * niimaqdxsrc) +{ + GstCaps *gcaps = NULL; + IMAQdxError rval; + uInt32 val; + char pixelFormat[IMAQDX_MAX_API_STRING_LENGTH]; + gint width, height; + GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN; + + if (!niimaqdxsrc->session) { + GST_ELEMENT_ERROR (niimaqdxsrc, RESOURCE, FAILED, + ("Camera not open"), (NULL)); + goto error; + } + + GST_LOG_OBJECT (niimaqdxsrc, "Retrieving attributes from IMAQdx device"); + + listAttributes (niimaqdxsrc->session); + + rval = IMAQdxGetAttribute (niimaqdxsrc->session, IMAQdxAttributePixelFormat, + IMAQdxValueTypeString, &pixelFormat); + gst_niimaqdxsrc_report_imaq_error (rval); + + format = convert_PixelFormat_to_VideoFormat (pixelFormat); + + rval &= IMAQdxGetAttribute (niimaqdxsrc->session, IMAQdxAttributeWidth, + IMAQdxValueTypeU32, &val); + gst_niimaqdxsrc_report_imaq_error (rval); + width = val; + rval &= IMAQdxGetAttribute (niimaqdxsrc->session, IMAQdxAttributeHeight, + IMAQdxValueTypeU32, &val); + gst_niimaqdxsrc_report_imaq_error (rval); + height = val; + + if (rval) { + GST_ELEMENT_ERROR (niimaqdxsrc, STREAM, FAILED, + ("attempt to read attributes failed"), + ("attempt to read attributes failed")); + goto error; + } + + if (format == GST_VIDEO_FORMAT_UNKNOWN) { + GST_ERROR_OBJECT (niimaqdxsrc, "PixelFormat '%s' not supported yet", + pixelFormat); + goto error; + } + + /* hard code framerate and par as IMAQ doesn't tell us anything about it */ + gcaps = gst_video_format_new_caps (format, width, height, 30, 1, 1, 1); + + GST_LOG_OBJECT (gcaps, "are the camera caps"); + + return gcaps; + +error: + + if (gcaps) { + gst_caps_unref (gcaps); + } + + return NULL; +} + +/** +* gst_niimaqdxsrc_start: +* src: #GstBaseSrc instance +* +* Open necessary resources +* +* Returns: TRUE on success +*/ +static gboolean +gst_niimaqdxsrc_start (GstBaseSrc * src) +{ + GstNiImaqDxSrc *niimaqdxsrc = GST_NIIMAQDXSRC (src); + IMAQdxError rval; + gint i; + + gst_niimaqdxsrc_reset (niimaqdxsrc); + + GST_LOG_OBJECT (niimaqdxsrc, "Opening IMAQ interface: %s", + niimaqdxsrc->device_name); + + /* open IMAQ interface */ + rval = IMAQdxOpenCamera (niimaqdxsrc->device_name, + IMAQdxCameraControlModeController, &niimaqdxsrc->session); + if (rval != IMAQdxErrorSuccess) { + gst_niimaqdxsrc_report_imaq_error (rval); + GST_ELEMENT_ERROR (niimaqdxsrc, RESOURCE, FAILED, + ("Failed to open IMAQdx interface"), + ("Failed to open camera interface %s", niimaqdxsrc->device_name)); + goto error; + } + + GST_LOG_OBJECT (niimaqdxsrc, "Creating ring with %d buffers", + niimaqdxsrc->ringbuffer_count); + + /* create array of times */ + niimaqdxsrc->times = g_new (GstClockTime, niimaqdxsrc->ringbuffer_count); + for (i = 0; i < niimaqdxsrc->ringbuffer_count; i++) { + niimaqdxsrc->times[i] = GST_CLOCK_TIME_NONE; + } + + rval = IMAQdxConfigureAcquisition (niimaqdxsrc->session, TRUE, + niimaqdxsrc->ringbuffer_count); + if (rval) { + gst_niimaqdxsrc_report_imaq_error (rval); + GST_ELEMENT_ERROR (niimaqdxsrc, RESOURCE, FAILED, + ("Failed to create ring buffer"), + ("Failed to create ring buffer with %d buffers", + niimaqdxsrc->ringbuffer_count)); + goto error; + } + + GST_LOG_OBJECT (niimaqdxsrc, "Registering callback functions"); + //TODO: enable this callback + //rval = IMAQdxRegisterFrameDoneEvent (niimaqdxsrc->session, 1, gst_niimaqdxsrc_frame_done_callback, niimaqdxsrc); + if (rval) { + gst_niimaqdxsrc_report_imaq_error (rval); + GST_ELEMENT_ERROR (niimaqdxsrc, RESOURCE, FAILED, + ("Failed to register callback(s)"), (NULL)); + goto error; + } + + return TRUE; + +error: + gst_niimaqdxsrc_close_interface (niimaqdxsrc); + + return FALSE;; + +} + +/** +* gst_niimaqdxsrc_stop: +* src: #GstBaseSrc instance +* +* Close resources opened by gst_niimaqdxsrc_start +* +* Returns: TRUE on success +*/ +static gboolean +gst_niimaqdxsrc_stop (GstBaseSrc * src) +{ + GstNiImaqDxSrc *niimaqdxsrc = GST_NIIMAQDXSRC (src); + IMAQdxError rval; + gboolean result = TRUE; + + /* stop IMAQ session */ + if (niimaqdxsrc->session_started) { + rval = IMAQdxStopAcquisition (niimaqdxsrc->session); + if (rval != IMAQdxErrorSuccess) { + gst_niimaqdxsrc_report_imaq_error (rval); + GST_ELEMENT_ERROR (niimaqdxsrc, RESOURCE, FAILED, + ("Unable to stop acquisition"), (NULL)); + result = FALSE; + } + niimaqdxsrc->session_started = FALSE; + GST_DEBUG_OBJECT (niimaqdxsrc, "Acquisition stopped"); + } + + result &= gst_niimaqdxsrc_close_interface (niimaqdxsrc); + + gst_niimaqdxsrc_reset (niimaqdxsrc); + + return result; +} + +static gboolean +gst_niimaqdxsrc_query (GstBaseSrc * src, GstQuery * query) +{ + GstNiImaqDxSrc *niimaqdxsrc = GST_NIIMAQDXSRC (src); + gboolean res; + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_LATENCY:{ + if (!niimaqdxsrc->session_started) { + GST_WARNING_OBJECT (niimaqdxsrc, + "Can't give latency since device isn't open!"); + res = FALSE; + } else { + GstClockTime min_latency, max_latency; + /* TODO: this is a ballpark figure, estimate from FVAL times */ + min_latency = 33 * GST_MSECOND; + max_latency = 33 * GST_MSECOND * niimaqdxsrc->ringbuffer_count; + + GST_LOG_OBJECT (niimaqdxsrc, + "report latency min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, + GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency)); + + gst_query_set_latency (query, TRUE, min_latency, max_latency); + + res = TRUE; + } + } + default: + res = FALSE; + break; + } + + return res; +} + +/** +* gst_niimaqdxsrc_close_interface: +* niimaqdxsrc: #GstNiImaqDxSrc instance +* +* Close IMAQ session and interface +* +*/ +static gboolean +gst_niimaqdxsrc_close_interface (GstNiImaqDxSrc * niimaqdxsrc) +{ + IMAQdxError rval; + gboolean result = TRUE; + + /* close IMAQ session and interface */ + if (niimaqdxsrc->session) { + rval = IMAQdxCloseCamera (niimaqdxsrc->session); + if (rval != IMAQdxErrorSuccess) { + gst_niimaqdxsrc_report_imaq_error (rval); + result = FALSE; + } else + GST_LOG_OBJECT (niimaqdxsrc, "IMAQdx session closed"); + niimaqdxsrc->session = 0; + } + + return result; +} + +/** +* plugin_init: +* plugin: #GstPlugin +* +* Initialize plugin by registering elements +* +* Returns: TRUE on success +*/ +static gboolean +plugin_init (GstPlugin * plugin) +{ + GST_DEBUG_CATEGORY_INIT (niimaqdxsrc_debug, "niimaqdxsrc", 0, + "NI-IMAQdx interface"); + + /* we only have one element in this plugin */ + return gst_element_register (plugin, "niimaqdxsrc", GST_RANK_NONE, + GST_TYPE_NIIMAQDXSRC); + +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, "niimaqdx", + "NI-IMAQdx source element", plugin_init, VERSION, GST_LICENSE, PACKAGE_NAME, + GST_PACKAGE_ORIGIN) diff --git a/sys/niimaqdx/gstniimaqdx.h b/sys/niimaqdx/gstniimaqdx.h new file mode 100644 index 0000000..6a58d1a --- /dev/null +++ b/sys/niimaqdx/gstniimaqdx.h @@ -0,0 +1,89 @@ +/* GStreamer + * Copyright (C) <2006> Eric Jonas + * Copyright (C) <2006> Antoine Tremblay + * Copyright (C) 2013 United States Government, Joshua M. Doe + * + * 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_NIIMAQDXSRC_H__ +#define __GST_NIIMAQDXSRC_H__ + +#include +#include +#include + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_NIIMAQDXSRC \ + (gst_niimaqdxsrc_get_type()) +#define GST_NIIMAQDXSRC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_NIIMAQDXSRC,GstNiImaqDxSrc)) +#define GST_NIIMAQDXSRC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_NIIMAQDXSRC,GstNiImaqDxSrcClass)) +#define GST_IS_NIIMAQDXSRC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_NIIMAQDXSRC)) +#define GST_IS_NIIMAQDXSRC_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_NIIMAQDXSRC)) +#define GST_NIIMAQDXSRC_GET_CLASS(klass) \ + (G_TYPE_INSTANCE_GET_CLASS ((klass), GST_TYPE_NIIMAQDXSRC, GstNiImaqDxSrcClass)) + +typedef struct _GstNiImaqDxSrc GstNiImaqDxSrc; +typedef struct _GstNiImaqDxSrcClass GstNiImaqDxSrcClass; + +struct _GstNiImaqDxSrc { + GstPushSrc element; + + /* properties */ + gchar *device_name; + gint ringbuffer_count; + + /* image info */ + GstVideoFormat format; + int width; + int height; + gint framesize; + + gint64 n_frames; /* total frames sent */ + uInt32 cumbufnum; + gint64 n_dropped_frames; + + GstClockTime *times; + IMAQdxSession session; + + gboolean session_started; + GstClockTime base_time; + + GstDateTime *start_time; + gboolean start_time_sent; + + GMutex *mutex; +}; + +struct _GstNiImaqDxSrcClass { + GstPushSrcClass parent_class; + + /* probed interfaces */ + GList *devices; +}; + +GType gst_niimaqdxsrc_get_type (void); + +G_END_DECLS + +#endif /* __GST_NIIMAQDXSRC_H__ */ diff --git a/vs2010/gst-plugins-vision.sln b/vs2010/gst-plugins-vision.sln index 8e057ad..701fad6 100644 --- a/vs2010/gst-plugins-vision.sln +++ b/vs2010/gst-plugins-vision.sln @@ -1,6 +1,6 @@  Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual C++ Express 2010 +# Visual Studio 2010 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "niimaq", "niimaq\niimaq.vcxproj", "{C617FD30-1297-417A-99F0-4F45B48EA8DF}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "videoadjust", "videoadjust\videoadjust.vcxproj", "{B77B6B47-9CB4-4A0B-B76F-877E57F90ADD}" @@ -9,28 +9,46 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "phoenix", "phoenix\phoenix. EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "edt", "edt\edt.vcxproj", "{351947AF-6445-4644-987D-FFE4FDDD3B4C}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libniimaqdx", "niimaqdx\niimaqdx.vcxproj", "{A212EA33-4648-42CB-83C8-72F484AB7855}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 Release|Win32 = Release|Win32 + Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {C617FD30-1297-417A-99F0-4F45B48EA8DF}.Debug|Win32.ActiveCfg = Debug|Win32 {C617FD30-1297-417A-99F0-4F45B48EA8DF}.Debug|Win32.Build.0 = Debug|Win32 + {C617FD30-1297-417A-99F0-4F45B48EA8DF}.Debug|x64.ActiveCfg = Debug|Win32 {C617FD30-1297-417A-99F0-4F45B48EA8DF}.Release|Win32.ActiveCfg = Release|Win32 {C617FD30-1297-417A-99F0-4F45B48EA8DF}.Release|Win32.Build.0 = Release|Win32 + {C617FD30-1297-417A-99F0-4F45B48EA8DF}.Release|x64.ActiveCfg = Release|Win32 {B77B6B47-9CB4-4A0B-B76F-877E57F90ADD}.Debug|Win32.ActiveCfg = Debug|Win32 {B77B6B47-9CB4-4A0B-B76F-877E57F90ADD}.Debug|Win32.Build.0 = Debug|Win32 + {B77B6B47-9CB4-4A0B-B76F-877E57F90ADD}.Debug|x64.ActiveCfg = Debug|Win32 {B77B6B47-9CB4-4A0B-B76F-877E57F90ADD}.Release|Win32.ActiveCfg = Release|Win32 {B77B6B47-9CB4-4A0B-B76F-877E57F90ADD}.Release|Win32.Build.0 = Release|Win32 + {B77B6B47-9CB4-4A0B-B76F-877E57F90ADD}.Release|x64.ActiveCfg = Release|Win32 {55049618-6388-411C-818C-9140D6F8CE99}.Debug|Win32.ActiveCfg = Debug|Win32 {55049618-6388-411C-818C-9140D6F8CE99}.Debug|Win32.Build.0 = Debug|Win32 + {55049618-6388-411C-818C-9140D6F8CE99}.Debug|x64.ActiveCfg = Debug|Win32 {55049618-6388-411C-818C-9140D6F8CE99}.Release|Win32.ActiveCfg = Release|Win32 {55049618-6388-411C-818C-9140D6F8CE99}.Release|Win32.Build.0 = Release|Win32 + {55049618-6388-411C-818C-9140D6F8CE99}.Release|x64.ActiveCfg = Release|Win32 {351947AF-6445-4644-987D-FFE4FDDD3B4C}.Debug|Win32.ActiveCfg = Debug|Win32 {351947AF-6445-4644-987D-FFE4FDDD3B4C}.Debug|Win32.Build.0 = Debug|Win32 + {351947AF-6445-4644-987D-FFE4FDDD3B4C}.Debug|x64.ActiveCfg = Debug|Win32 {351947AF-6445-4644-987D-FFE4FDDD3B4C}.Release|Win32.ActiveCfg = Release|Win32 {351947AF-6445-4644-987D-FFE4FDDD3B4C}.Release|Win32.Build.0 = Release|Win32 + {351947AF-6445-4644-987D-FFE4FDDD3B4C}.Release|x64.ActiveCfg = Release|Win32 + {A212EA33-4648-42CB-83C8-72F484AB7855}.Debug|Win32.ActiveCfg = Debug|Win32 + {A212EA33-4648-42CB-83C8-72F484AB7855}.Debug|Win32.Build.0 = Debug|Win32 + {A212EA33-4648-42CB-83C8-72F484AB7855}.Debug|x64.ActiveCfg = Debug|Win32 + {A212EA33-4648-42CB-83C8-72F484AB7855}.Release|Win32.ActiveCfg = Release|Win32 + {A212EA33-4648-42CB-83C8-72F484AB7855}.Release|Win32.Build.0 = Release|Win32 + {A212EA33-4648-42CB-83C8-72F484AB7855}.Release|x64.ActiveCfg = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/vs2010/niimaqdx/niimaqdx.props b/vs2010/niimaqdx/niimaqdx.props new file mode 100644 index 0000000..f53ed90 --- /dev/null +++ b/vs2010/niimaqdx/niimaqdx.props @@ -0,0 +1,17 @@ + + + + + true + + + + C:\Program Files (x86)\National Instruments\NI-IMAQdx\include;%(AdditionalIncludeDirectories) + + + C:\Program Files (x86)\National Instruments\NI-IMAQdx\lib\msvc;%(AdditionalLibraryDirectories) + niimaqdx.lib;%(AdditionalDependencies) + + + + diff --git a/vs2010/niimaqdx/niimaqdx.vcxproj b/vs2010/niimaqdx/niimaqdx.vcxproj new file mode 100644 index 0000000..763ab1f --- /dev/null +++ b/vs2010/niimaqdx/niimaqdx.vcxproj @@ -0,0 +1,103 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + + + + + + Win32Proj + {A212EA33-4648-42CB-83C8-72F484AB7855} + v4.0 + libniimaqdx + + + + DynamicLibrary + true + Unicode + + + DynamicLibrary + false + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + false + + + + + + Level3 + Disabled + HAVE_CONFIG_H;_DEBUG;%(PreprocessorDefinitions) + $(SolutionDir)\..\;%(AdditionalIncludeDirectories) + + + Console + true + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + + + + + Level3 + + + MaxSpeed + true + true + HAVE_CONFIG_H;%(PreprocessorDefinitions) + $(SolutionDir)\..\;%(AdditionalIncludeDirectories) + + + Console + false + true + + + + + + \ No newline at end of file diff --git a/vs2010/niimaqdx/niimaqdx.vcxproj.filters b/vs2010/niimaqdx/niimaqdx.vcxproj.filters new file mode 100644 index 0000000..3677ad2 --- /dev/null +++ b/vs2010/niimaqdx/niimaqdx.vcxproj.filters @@ -0,0 +1,27 @@ + + + + + {f49096c0-8698-4459-8a7c-b799838532bf} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {c8c60a9e-7c9b-4932-afca-9b3e73adfac0} + h;hpp;hxx;hm;inl;inc;xsd + + + {159c54cd-3e1e-4614-997b-fee4b885b408} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + + + Header Files + + + \ No newline at end of file