From 1417f0d3302b6c4b4150f45b7617e7585a6b5f0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thies=20M=C3=B6ller?= Date: Mon, 10 Jan 2022 09:02:45 +0100 Subject: [PATCH 01/20] gst-pylonsrc: add MaxTransferSize for USB3Vison devices increasing MaxTransferSize allows to lower the system overhead to receive video data in case of larger images --- sys/pylon/gstpylonsrc.c | 72 +++++++++++++++++++++++++++++++++++++---- sys/pylon/gstpylonsrc.h | 5 +-- 2 files changed, 68 insertions(+), 9 deletions(-) diff --git a/sys/pylon/gstpylonsrc.c b/sys/pylon/gstpylonsrc.c index daff9e0..338c211 100644 --- a/sys/pylon/gstpylonsrc.c +++ b/sys/pylon/gstpylonsrc.c @@ -39,8 +39,10 @@ #include #include +#include "genapic/GenApiC.h" #include "common/genicampixelformat.h" + static int plugin_counter = 0; int @@ -177,6 +179,7 @@ typedef enum _GST_PYLONSRC_PROP PROP_FRAMETRANSDELAY, PROP_BANDWIDTHRESERVE, PROP_BANDWIDTHRESERVEACC, + PROP_MAXTRANSFERSIZE, PROP_CONFIGFILE, PROP_IGNOREDEFAULTS, @@ -363,6 +366,7 @@ ascii_strdown (gchar * *str, gssize len) #define DEFAULT_PROP_FRAMETRANSDELAY 0 #define DEFAULT_PROP_BANDWIDTHRESERVE 10 #define DEFAULT_PROP_BANDWIDTHRESERVEACC 10 +#define DEFAULT_PROP_MAXTRANSFERSIZE 262144 /* pad templates */ static GstStaticPadTemplate gst_pylonsrc_src_template = @@ -748,35 +752,46 @@ gst_pylonsrc_class_init (GstPylonSrcClass * klass) "Specifies the number of miiliseconds to wait for frame to be grabed from the camera.", 0, 60000, DEFAULT_PROP_GRABTIMEOUT, (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + //TODO: Limits may be co-dependent on other transport layer parameters. g_object_class_install_property (gobject_class, PROP_PACKETSIZE, g_param_spec_int ("packet-size", "Maximum size of data packet", "The packetsize parameter specifies the maximum size of a data packet transmitted via Ethernet. The value is in bytes.", 0, 16000, DEFAULT_PROP_PACKETSIZE, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); //TODO: Limits may be co-dependent on other transport layer parameters. + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + //TODO: Limits may be co-dependent on other transport layer parameters. g_object_class_install_property (gobject_class, PROP_INTERPACKETDELAY, g_param_spec_int ("inter-packet-delay", "Inter-Packet Delay between packet transmissions", "If your network hardware can't handle the incoming packet rate, it is useful to increase the delay between packet transmissions.", 0, 3435, DEFAULT_PROP_INTERPACKETDELAY, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); //TODO: Limits may be co-dependent on other transport layer parameters. + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + //TODO: Limits may be co-dependent on other transport layer parameters. g_object_class_install_property (gobject_class, PROP_FRAMETRANSDELAY, g_param_spec_int ("frame-trans-delay", "Delay for begin transmitting frame.", "Sets a delay in ticks between when camera begisn transmitting frame afther acquiring it. By default, one tick equals 8 ns. With PTP enabled, one tick equals 1 ns.", 0, 50000000, DEFAULT_PROP_FRAMETRANSDELAY, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); //TODO: Limits may be co-dependent on other transport layer parameters. + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + //TODO: Limits may be co-dependent on other transport layer parameters. g_object_class_install_property (gobject_class, PROP_BANDWIDTHRESERVE, g_param_spec_int ("bandwidth-reserve", "Portion of bandwidth reserved for packet resends.", "The setting is expressed as a percentage of the assigned bandwidth.", 0, 26, DEFAULT_PROP_BANDWIDTHRESERVE, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); //TODO: Limits may be co-dependent on other transport layer parameters. + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + //TODO: Limits may be co-dependent on other transport layer parameters. g_object_class_install_property (gobject_class, PROP_BANDWIDTHRESERVEACC, g_param_spec_int ("bandwidth-reserve-acc", "Pool of resends for unusual situations", "For situations when the network connection becomes unstable. A larger number of packet resends may be needed to transmit an image", 1, 32, DEFAULT_PROP_BANDWIDTHRESERVEACC, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); //TODO: Limits may be co-dependent on other transport layer parameters. + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + g_object_class_install_property (gobject_class, PROP_MAXTRANSFERSIZE, + g_param_spec_int ("max-transfer-size", + "Maximum USB data transfer size in bytes", + "Use the MaxTransferSize parameter to specify the maximum USB data transfer size in bytes. The default value is appropriate for most applications. Increase the value to lower the CPU load. USB host adapter drivers may require decreasing the value if the application fails to receive the image stream. The maximum value depends on the operating system.", + 0x400, 0x400000, DEFAULT_PROP_MAXTRANSFERSIZE, + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); } static gboolean @@ -872,6 +887,7 @@ gst_pylonsrc_init (GstPylonSrc * src) src->frameTransDelay = DEFAULT_PROP_FRAMETRANSDELAY; src->bandwidthReserve = DEFAULT_PROP_BANDWIDTHRESERVE; src->bandwidthReserveAcc = DEFAULT_PROP_BANDWIDTHRESERVEACC; + src->maxTransferSize = DEFAULT_PROP_MAXTRANSFERSIZE; for (int i = 0; i < PROP_NUM_PROPERTIES; i++) { src->propFlags[i] = GST_PYLONSRC_PROPST_DEFAULT; @@ -1080,7 +1096,7 @@ gst_pylonsrc_set_property (GObject * object, guint property_id, set_prop_implicitly (object, PROP_COLORADJUSTMENTENABLE, pspec); break; case PROP_COLORADJUSTMENTENABLE: - src->colorAdjustment = g_value_get_boolean(value); + src->colorAdjustment = g_value_get_boolean (value); break; case PROP_MAXBANDWIDTH: src->maxBandwidth = g_value_get_int (value); @@ -1214,6 +1230,9 @@ gst_pylonsrc_set_property (GObject * object, guint property_id, case PROP_BANDWIDTHRESERVEACC: src->bandwidthReserveAcc = g_value_get_int (value); break; + case PROP_MAXTRANSFERSIZE: + src->maxTransferSize = g_value_get_int (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); return; @@ -1330,7 +1349,7 @@ gst_pylonsrc_get_property (GObject * object, guint property_id, g_value_set_double (value, src->saturation[COLOUR_MAGENTA]); break; case PROP_COLORADJUSTMENTENABLE: - g_value_set_boolean(value, src->colorAdjustment); + g_value_set_boolean (value, src->colorAdjustment); break; case PROP_MAXBANDWIDTH: g_value_set_int (value, src->maxBandwidth); @@ -1449,6 +1468,9 @@ gst_pylonsrc_get_property (GObject * object, guint property_id, case PROP_BANDWIDTHRESERVEACC: g_value_set_int (value, src->bandwidthReserveAcc); break; + case PROP_MAXTRANSFERSIZE: + g_value_set_int (value, src->maxTransferSize); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -3050,6 +3072,39 @@ error: return FALSE; } +static gboolean +gst_pylonsrc_set_maxTransferSize (GstPylonSrc * src) +{ + GENAPIC_RESULT res; + + if (is_prop_implicit (src, PROP_MAXTRANSFERSIZE)) { + if (is_prop_set (src, PROP_MAXTRANSFERSIZE)) { + NODE_HANDLE phNode = 0; + NODEMAP_HANDLE phStreamGrabberNodeMap = 0; + PylonStreamGrabberGetNodeMap (src->streamGrabber, + &phStreamGrabberNodeMap); + if (!phStreamGrabberNodeMap) + goto error; + GenApiNodeMapGetNode (phStreamGrabberNodeMap, "MaxTransferSize", &phNode); + if (phNode) { + _Bool isWritable = 0; + GenApiNodeIsWritable (phNode, &isWritable); + if (isWritable) { + GST_DEBUG_OBJECT (src, "Setting max transfer size to %d", + src->maxTransferSize); + res = GenApiIntegerSetValue (phNode, src->maxTransferSize); + PYLONC_CHECK_ERROR (src, res); + } + } + } + reset_prop (src, PROP_MAXTRANSFERSIZE); + } + return TRUE; + +error: + return FALSE; +} + static gboolean gst_pylonsrc_configure_start_acquisition (GstPylonSrc * src) { @@ -3074,6 +3129,9 @@ gst_pylonsrc_configure_start_acquisition (GstPylonSrc * src) res = PylonStreamGrabberOpen (src->streamGrabber); PYLONC_CHECK_ERROR (src, res); + // set the max transfer size in case of USB + gst_pylonsrc_set_maxTransferSize (src); + // Get the wait object res = PylonStreamGrabberGetWaitObject (src->streamGrabber, &src->waitObject); PYLONC_CHECK_ERROR (src, res); diff --git a/sys/pylon/gstpylonsrc.h b/sys/pylon/gstpylonsrc.h index 222f0dc..904e896 100644 --- a/sys/pylon/gstpylonsrc.h +++ b/sys/pylon/gstpylonsrc.h @@ -39,7 +39,7 @@ enum GST_PYLONSRC_NUM_CAPTURE_BUFFERS = 10, GST_PYLONSRC_NUM_AUTO_FEATURES = 3, GST_PYLONSRC_NUM_LIMITED_FEATURES = 2, - GST_PYLONSRC_NUM_PROPS = 74 + GST_PYLONSRC_NUM_PROPS = 75 }; typedef enum _GST_PYLONSRC_PROPERTY_STATE @@ -101,7 +101,8 @@ struct _GstPylonSrc GstPylonSrcLimitedFeature limitedFeature[GST_PYLONSRC_NUM_LIMITED_FEATURES]; gint maxBandwidth, testImage, frameDropLimit, grabtimeout, packetSize, - interPacketDelay, frameTransDelay, bandwidthReserve, bandwidthReserveAcc; + interPacketDelay, frameTransDelay, bandwidthReserve, bandwidthReserveAcc, + maxTransferSize; gint size[2]; gint binning[2]; gint maxSize[2]; From ba36bf6a388dfe68143cbde2d991d5a5cab347bd Mon Sep 17 00:00:00 2001 From: AASanchezA Date: Tue, 8 Feb 2022 15:04:29 +0100 Subject: [PATCH 02/20] bugfix: fix linux compilation for method g_utf8_to_ucs4 for gstidsueyesrc --- sys/idsueye/gstidsueyesrc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/idsueye/gstidsueyesrc.c b/sys/idsueye/gstidsueyesrc.c index 90776ff..f8716f0 100644 --- a/sys/idsueye/gstidsueyesrc.c +++ b/sys/idsueye/gstidsueyesrc.c @@ -446,7 +446,7 @@ char_to_ids_unicode (const char *str) void * char_to_ids_unicode (const char *str) { - return g_utf8_to_ucs4 (src->config_file, -1, NULL, NULL, NULL); + return g_utf8_to_ucs4 (str, -1, NULL, NULL, NULL); } #endif From 51c90158dd3ba0432db28cf5840b7dc4560381ad Mon Sep 17 00:00:00 2001 From: Gene VanMeter Date: Thu, 17 Feb 2022 14:03:49 -0500 Subject: [PATCH 03/20] Fixes find_path for Pleora_LIBRARY_DIR on Windows --- cmake/modules/FindPleora.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/modules/FindPleora.cmake b/cmake/modules/FindPleora.cmake index 1d44027..cdc2887 100644 --- a/cmake/modules/FindPleora.cmake +++ b/cmake/modules/FindPleora.cmake @@ -32,7 +32,7 @@ find_path (Pleora_INCLUDE_DIR PvBase.h PATH_SUFFIXES Includes include) message (STATUS "Found Pleora include dir in ${Pleora_INCLUDE_DIR}") -find_path (Pleora_LIBRARY_DIR NAMES libPvBase.so "PvBase${_LIB_NAME}" +find_path (Pleora_LIBRARY_DIR NAMES libPvBase.so "PvBase${_LIB_SUFFIX}.lib" PATHS ${_Pleora_PATHS} PATH_SUFFIXES Libraries lib) From 07f871177491a879a9305d02d78a2c67af6c2a2d Mon Sep 17 00:00:00 2001 From: Thor Tomasarson Date: Tue, 3 Aug 2021 10:12:32 +0000 Subject: [PATCH 04/20] pylonsrc: log error codes as hexadecimal for clarity --- sys/pylon/gstpylonsrc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/pylon/gstpylonsrc.c b/sys/pylon/gstpylonsrc.c index 338c211..c894fed 100644 --- a/sys/pylon/gstpylonsrc.c +++ b/sys/pylon/gstpylonsrc.c @@ -4190,13 +4190,13 @@ gst_pylonsrc_create (GstPushSrc * psrc, GstBuffer ** buf) if (grabResult.Status != Grabbed) { src->failedFrames += 1; GST_WARNING_OBJECT (src, - "Failed capture count=%d. Status=%d, ErrorCode=%d", src->failedFrames, + "Failed capture count=%d. Status=%d, ErrorCode=0x%.8X", src->failedFrames, grabResult.Status, grabResult.ErrorCode); } else src->failedFrames = 0; } else { GST_ERROR_OBJECT (src, - "Error in the image processing loop. Status=%d, ErrorCode=%d", + "Error in the image processing loop. Status=%d, ErrorCode=0x%.8X", grabResult.Status, grabResult.ErrorCode); goto error; } From 8900eeb73c349ead23f4f33cfe1d9e7d6dcd521b Mon Sep 17 00:00:00 2001 From: Thor Tomasarson Date: Tue, 3 Aug 2021 10:46:13 +0000 Subject: [PATCH 05/20] pylonsrc: the emulator does not have a DeviceSerialNumber --- sys/pylon/gstpylonsrc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sys/pylon/gstpylonsrc.c b/sys/pylon/gstpylonsrc.c index c894fed..0b54994 100644 --- a/sys/pylon/gstpylonsrc.c +++ b/sys/pylon/gstpylonsrc.c @@ -4322,8 +4322,7 @@ pylonc_print_camera_info (GstPylonSrc * src, PYLON_DEVICE_HANDLE deviceHandle, size_t siz = 0; GENAPIC_RESULT res; - if (PylonDeviceFeatureIsReadable (deviceHandle, "DeviceModelName") - && PylonDeviceFeatureIsReadable (deviceHandle, "DeviceSerialNumber")) { + if (PylonDeviceFeatureIsAvailable (deviceHandle, "DeviceModelName")) { siz = sizeof (name); res = PylonDeviceFeatureToString (deviceHandle, "DeviceModelName", name, From ee440aa927b9833f1df2a9443de73eb8f24f8f22 Mon Sep 17 00:00:00 2001 From: Thor Tomasarson Date: Tue, 3 Aug 2021 12:24:59 +0000 Subject: [PATCH 06/20] pylonsrc: add in the testimagesource parameter to allow for custom image source --- sys/pylon/gstpylonsrc.c | 41 +++++++++++++++++++++++++++++++++++++++++ sys/pylon/gstpylonsrc.h | 2 +- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/sys/pylon/gstpylonsrc.c b/sys/pylon/gstpylonsrc.c index 0b54994..b021064 100644 --- a/sys/pylon/gstpylonsrc.c +++ b/sys/pylon/gstpylonsrc.c @@ -144,6 +144,7 @@ typedef enum _GST_PYLONSRC_PROP PROP_GAMMA, PROP_RESET, PROP_TESTIMAGE, + PROP_TESTIMAGESOURCE, PROP_CONTINUOUSMODE, PROP_PIXEL_FORMAT, PROP_USERID, @@ -340,6 +341,7 @@ ascii_strdown (gchar * *str, gssize len) #define DEFAULT_PROP_GAMMA 1.0 #define DEFAULT_PROP_RESET "off" #define DEFAULT_PROP_TESTIMAGE 0 +#define DEFAULT_PROP_TESTIMAGESOURCE "" #define DEFAULT_PROP_CONTINUOUSMODE TRUE #define DEFAULT_PROP_PIXEL_FORMAT "auto" #define DEFAULT_PROP_USERID "" @@ -588,6 +590,11 @@ gst_pylonsrc_class_init (GstPylonSrcClass * klass) "(1-6) Specifies a test image to show instead of a video stream. Useful for debugging. Will be disabled by default.", 0, 6, DEFAULT_PROP_TESTIMAGE, (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + g_object_class_install_property (gobject_class, PROP_TESTIMAGESOURCE, + g_param_spec_string ("testimagesource", "Test image source", + "Specifies a test image (or image directory) to show instead of a video stream. Useful for debugging. Will be disabled by default.", + DEFAULT_PROP_TESTIMAGESOURCE, + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); g_object_class_install_property (gobject_class, PROP_CONTINUOUSMODE, g_param_spec_boolean ("continuous", "Continuous mode", "(true/false) Used to switch between triggered and continuous mode. To switch to triggered mode this parameter has to be switched to false.", @@ -829,6 +836,7 @@ gst_pylonsrc_init (GstPylonSrc * src) src->cameraId = DEFAULT_PROP_CAMERA; src->maxBandwidth = DEFAULT_PROP_MAXBANDWIDTH; src->testImage = DEFAULT_PROP_TESTIMAGE; + src->testImageSource = g_strdup (DEFAULT_PROP_TESTIMAGESOURCE); src->sensorMode = g_strdup (DEFAULT_PROP_SENSORREADOUTMODE); src->lightsource = g_strdup (DEFAULT_PROP_LIGHTSOURCE); @@ -998,6 +1006,10 @@ gst_pylonsrc_set_property (GObject * object, guint property_id, case PROP_TESTIMAGE: src->testImage = g_value_get_int (value); break; + case PROP_TESTIMAGESOURCE: + g_free (src->testImageSource); + src->testImageSource = g_value_dup_string (value); + break; case PROP_SENSORREADOUTMODE: g_free (src->sensorMode); src->sensorMode = g_value_dup_string (value); @@ -1273,6 +1285,9 @@ gst_pylonsrc_get_property (GObject * object, guint property_id, case PROP_TESTIMAGE: g_value_set_int (value, src->testImage); break; + case PROP_TESTIMAGESOURCE: + g_value_set_string (value, src->testImageSource); + break; case PROP_SENSORREADOUTMODE: g_value_set_string (value, src->sensorMode); break; @@ -2156,6 +2171,31 @@ error: return FALSE; } +static gboolean +gst_pylonsrc_set_test_image_source (GstPylonSrc * src) +{ + if (is_prop_implicit (src, PROP_TESTIMAGESOURCE)) { + // Set whether test image will be shown + if (feature_supported (src, "ImageFilename")) { + GENAPIC_RESULT res; + res = PylonDeviceFeatureFromString(src->deviceHandle, "TestImageSelector", "Off"); + PYLONC_CHECK_ERROR(src, res); + /* Enable custom test images */ + res = PylonDeviceFeatureFromString(src->deviceHandle, "ImageFileMode", "On"); + PYLONC_CHECK_ERROR(src, res); + + GST_DEBUG_OBJECT (src, "Test image source enabled and set to %s", src->testImageSource); + res = PylonDeviceFeatureFromString(src->deviceHandle, "ImageFilename", src->testImageSource); + PYLONC_CHECK_ERROR (src, res); + } + reset_prop (src, PROP_TESTIMAGESOURCE); + } + return TRUE; + +error: + return FALSE; +} + static gboolean gst_pylonsrc_set_readout (GstPylonSrc * src) { @@ -4056,6 +4096,7 @@ gst_pylonsrc_set_properties (GstPylonSrc * src) gst_pylonsrc_set_reverse (src) && gst_pylonsrc_set_pixel_format (src) && gst_pylonsrc_set_test_image (src) && + gst_pylonsrc_set_test_image_source (src) && gst_pylonsrc_set_packetsize (src) && gst_pylonsrc_set_interPacketDelay (src) && gst_pylonsrc_set_frameTransDelay (src) && diff --git a/sys/pylon/gstpylonsrc.h b/sys/pylon/gstpylonsrc.h index 904e896..aed6aa5 100644 --- a/sys/pylon/gstpylonsrc.h +++ b/sys/pylon/gstpylonsrc.h @@ -108,7 +108,7 @@ struct _GstPylonSrc gint maxSize[2]; gint offset[2]; gchar *pixel_format, *sensorMode, *lightsource, *reset, *autoprofile, - *transformationselector, *userid; + *transformationselector, *userid, *testImageSource; gchar *autoFeature[GST_PYLONSRC_NUM_AUTO_FEATURES]; gchar *configFile; GST_PYLONSRC_PROPERTY_STATE propFlags[GST_PYLONSRC_NUM_PROPS]; From c64f9dda31d48205b7628d8e92ac105ea9fb4409 Mon Sep 17 00:00:00 2001 From: Thor Tomasarson Date: Tue, 3 Aug 2021 13:28:26 +0000 Subject: [PATCH 07/20] pylonsrc: the testimagesource should only be set if explicitly configured --- sys/pylon/gstpylonsrc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/pylon/gstpylonsrc.c b/sys/pylon/gstpylonsrc.c index b021064..5d53442 100644 --- a/sys/pylon/gstpylonsrc.c +++ b/sys/pylon/gstpylonsrc.c @@ -2174,7 +2174,7 @@ error: static gboolean gst_pylonsrc_set_test_image_source (GstPylonSrc * src) { - if (is_prop_implicit (src, PROP_TESTIMAGESOURCE)) { + if (!(is_prop_default (src, PROP_TESTIMAGESOURCE))) { // Set whether test image will be shown if (feature_supported (src, "ImageFilename")) { GENAPIC_RESULT res; From 6f84e34a1fcfc81aed5e0c470d21478686a94c6d Mon Sep 17 00:00:00 2001 From: Thor Tomasarson Date: Tue, 3 Aug 2021 15:46:18 +0000 Subject: [PATCH 08/20] pylonsrc: reduce repeated parameter writes --- sys/pylon/gstpylonsrc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sys/pylon/gstpylonsrc.c b/sys/pylon/gstpylonsrc.c index 5d53442..11ea266 100644 --- a/sys/pylon/gstpylonsrc.c +++ b/sys/pylon/gstpylonsrc.c @@ -2174,7 +2174,8 @@ error: static gboolean gst_pylonsrc_set_test_image_source (GstPylonSrc * src) { - if (!(is_prop_default (src, PROP_TESTIMAGESOURCE))) { + if (is_prop_implicit (src, PROP_TESTIMAGESOURCE) && + !(is_prop_default (src, PROP_TESTIMAGESOURCE))) { // Set whether test image will be shown if (feature_supported (src, "ImageFilename")) { GENAPIC_RESULT res; From ddf2f6857ef28eafe147951dfb3a02ffc5606114 Mon Sep 17 00:00:00 2001 From: "Joshua M. Doe" Date: Tue, 9 Nov 2021 08:37:57 -0500 Subject: [PATCH 09/20] gentlsrc: check first for timestamp in nanoseconds Then fallback to timestamp in ticks if needed. --- sys/gentl/gstgentlsrc.c | 37 ++++++++++++++++++++++--------------- sys/gentl/gstgentlsrc.h | 4 ++-- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/sys/gentl/gstgentlsrc.c b/sys/gentl/gstgentlsrc.c index 259d2dc..ebf84af 100644 --- a/sys/gentl/gstgentlsrc.c +++ b/sys/gentl/gstgentlsrc.c @@ -417,8 +417,8 @@ gst_gentlsrc_class_init (GstGenTlSrcClass * klass) static void gst_gentlsrc_reset (GstGenTlSrc * src) { - src->gentl_latched_ticks = 0; - src->unix_latched_time = 0; + src->gentl_latched_ns = 0; + src->unix_latched_ns = 0; src->error_string[0] = 0; src->last_frame_count = 0; @@ -915,8 +915,9 @@ gst_gentlsrc_src_latch_timestamps (GstGenTlSrc * src) gev_ts = gst_gentlsrc_get_gev_timestamp_ticks (src); if (gev_ts != 0) { - src->unix_latched_time = unix_ts; - src->gentl_latched_ticks = gev_ts; + src->unix_latched_ns = unix_ts; + src->gentl_latched_ns = ((gint64) + (gev_ts * ((double)GST_SECOND / src->tick_frequency)));; } else { GST_WARNING_OBJECT (src, "Failed to latch GEV time, using old latch value"); } @@ -1611,7 +1612,7 @@ gst_gentlsrc_get_buffer (GstGenTlSrc * src) guint8 *data_ptr; GstMapInfo minfo; GstClockTime unix_ts; - uint64_t buf_timestamp_ticks; + uint64_t buf_timestamp_ticks, buf_timestamp_ns; /* sometimes we get non-image payloads, try several times for an image */ @@ -1641,12 +1642,21 @@ gst_gentlsrc_get_buffer (GstGenTlSrc * src) goto error; } - datasize = sizeof (buf_timestamp_ticks); + datasize = sizeof (buf_timestamp_ns); ret = GTL_DSGetBufferInfo (src->hDS, new_buffer_data.BufferHandle, - BUFFER_INFO_TIMESTAMP, &datatype, &buf_timestamp_ticks, &datasize); - HANDLE_GTL_ERROR ("Failed to get buffer timestamp"); - GST_LOG_OBJECT (src, "Buffer GentTL timestamp: %llu", buf_timestamp_ticks); + BUFFER_INFO_TIMESTAMP_NS, &datatype, &buf_timestamp_ns, &datasize); + if (ret == GC_ERR_SUCCESS) { + GST_LOG_OBJECT(src, "Buffer GentTL timestamp: %llu ns", buf_timestamp_ns); + } else { + ret = + GTL_DSGetBufferInfo(src->hDS, new_buffer_data.BufferHandle, + BUFFER_INFO_TIMESTAMP, &datatype, &buf_timestamp_ticks, &datasize); + HANDLE_GTL_ERROR("Failed to get buffer timestamp"); + buf_timestamp_ns = (gint64) + (buf_timestamp_ticks * ((double)GST_SECOND / src->tick_frequency)); + GST_LOG_OBJECT(src, "Buffer GentTL timestamp: %llu ticks, %llu ns", buf_timestamp_ticks, buf_timestamp_ns); + } datasize = sizeof (frame_id); ret = @@ -1695,17 +1705,14 @@ gst_gentlsrc_get_buffer (GstGenTlSrc * src) if (src->tick_frequency) { gint64 nanoseconds_after_latch; - gint64 ticks_after_latch; /* resync system clock and buffer clock periodically */ - if (GST_CLOCK_DIFF (src->unix_latched_time, get_unix_ns ()) > GST_SECOND) { + if (GST_CLOCK_DIFF (src->unix_latched_ns, get_unix_ns ()) > GST_SECOND) { gst_gentlsrc_src_latch_timestamps (src); } - ticks_after_latch = buf_timestamp_ticks - src->gentl_latched_ticks; - nanoseconds_after_latch = (gint64) - (ticks_after_latch * ((double) GST_SECOND / src->tick_frequency)); - unix_ts = src->unix_latched_time + nanoseconds_after_latch; + nanoseconds_after_latch = buf_timestamp_ns - src->gentl_latched_ns; + unix_ts = src->unix_latched_ns + nanoseconds_after_latch; GST_LOG_OBJECT (src, "Adding Unix timestamp: %llu", unix_ts); gst_buffer_add_reference_timestamp_meta (buf, gst_static_caps_get (&unix_reference), unix_ts, GST_CLOCK_TIME_NONE); diff --git a/sys/gentl/gstgentlsrc.h b/sys/gentl/gstgentlsrc.h index 9090c31..c9c8a78 100644 --- a/sys/gentl/gstgentlsrc.h +++ b/sys/gentl/gstgentlsrc.h @@ -105,8 +105,8 @@ struct _GstGenTlSrc guint32 total_dropped_frames; guint64 tick_frequency; - guint64 unix_latched_time; - guint64 gentl_latched_ticks; + guint64 unix_latched_ns; + guint64 gentl_latched_ns; GstCaps *caps; gint height; From 6c5cbad0ad1641a0153bb3948bf4f20486cacdf8 Mon Sep 17 00:00:00 2001 From: "Joshua M. Doe" Date: Tue, 9 Nov 2021 16:20:50 -0500 Subject: [PATCH 10/20] gentlsrc: add support for FLIR Spinnaker cameras This also required changing how we read values, as FLIR uses little endian. Timestamps are handled differently as well. We're even more overdue for moving to properly parse the XML, just a matter of if we'll use the GenApi reference implementation or something else like Aravis. --- sys/gentl/gstgentlsrc.c | 294 ++++++++++++++++++++++++++++------------ sys/gentl/gstgentlsrc.h | 10 +- 2 files changed, 218 insertions(+), 86 deletions(-) diff --git a/sys/gentl/gstgentlsrc.c b/sys/gentl/gstgentlsrc.c index ebf84af..5dea8db 100644 --- a/sys/gentl/gstgentlsrc.c +++ b/sys/gentl/gstgentlsrc.c @@ -64,6 +64,7 @@ initialize_evt_addresses (GstGenTlProducer * producer) producer->cti_path = g_strdup ("C:\\Program Files\\EVT\\eSDK\\bin\\EmergentGenTL.cti"); producer->acquisition_mode_value = 0; + producer->timestamp_control_latch_value = 2; producer->width = 0xA000; producer->height = 0xA004; producer->pixel_format = 0xA008; @@ -76,6 +77,7 @@ initialize_evt_addresses (GstGenTlProducer * producer) producer->timestamp_control_latch = 0x944; producer->timestamp_low = 0x094C; producer->timestamp_high = 0x0948; + producer->port_endianness = G_BIG_ENDIAN; } static void @@ -93,8 +95,31 @@ initialize_basler_addresses (GstGenTlProducer * producer) producer->acquisition_mode = 0x40004; producer->acquisition_start = 0x40024; producer->acquisition_stop = 0x40044; + producer->port_endianness = G_BIG_ENDIAN; } +static void +initialize_flir_addresses (GstGenTlProducer * producer) +{ + memset (producer, 0, sizeof (producer)); + producer->cti_path = + g_strdup + ("C:\\Program Files\\FLIR Systems\\Spinnaker\\cti64\\vs2015\\FLIR_GenTL_v140.cti"); + producer->acquisition_mode_value = 0; + producer->timestamp_control_latch_value = 1; + producer->width = 0x00081084; + producer->height = 0x00081064; + producer->pixel_format = 0x00086008; + producer->payload_size = 0x20002008; + producer->acquisition_mode = 0x000C00C8; + producer->acquisition_start = 0x000C0004; + producer->acquisition_stop = 0x000C0024; + producer->timestamp_control_latch = 0x1F8; + producer->timestamp = 0x1F0; + producer->port_endianness = G_LITTLE_ENDIAN; +} + + #define GST_TYPE_GENTLSRC_PRODUCER (gst_gentlsrc_producer_get_type()) static GType gst_gentlsrc_producer_get_type (void) @@ -103,6 +128,7 @@ gst_gentlsrc_producer_get_type (void) static const GEnumValue gentlsrc_producer[] = { {GST_GENTLSRC_PRODUCER_BASLER, "Basler producer", "basler"}, {GST_GENTLSRC_PRODUCER_EVT, "EVT producer", "evt"}, + {GST_GENTLSRC_PRODUCER_FLIR, "FLIR producer", "flir"}, {0, NULL, NULL}, }; @@ -135,6 +161,7 @@ static GstFlowReturn gst_gentlsrc_create (GstPushSrc * src, GstBuffer ** buf); static gchar *gst_gentlsrc_get_error_string (GstGenTlSrc * src); static void gst_gentlsrc_cleanup_tl (GstGenTlSrc * src); +static gboolean gst_gentlsrc_src_latch_timestamps (GstGenTlSrc * src); enum { @@ -775,6 +802,111 @@ gst_gentl_print_device_info (GstGenTlSrc * src, uint32_t index) //} +static guint32 +read_uint32 (GstGenTlSrc * src, guint64 addr, GC_ERROR * ret) +{ + guint32 value; + size_t datasize = 4; + + *ret = GTL_GCReadPort (src->hDevPort, addr, &value, &datasize); + if (*ret != GC_ERR_SUCCESS) { + GST_ELEMENT_ERROR (src, LIBRARY, FAILED, + ("Failed to read address: %s", gst_gentlsrc_get_error_string (src)), + (NULL)); + goto error; + } + + if (src->producer.port_endianness == G_BIG_ENDIAN) + value = GUINT32_FROM_BE (value); + else + value = GUINT32_FROM_LE (value); + + return value; + +error: + return 0; +} + +static gboolean +write_uint32 (GstGenTlSrc * src, guint64 addr, guint32 value) +{ + GC_ERROR ret; + size_t datasize = 4; + + if (src->producer.port_endianness == G_BIG_ENDIAN) + value = GUINT32_TO_BE (value); + else + value = GUINT32_TO_LE (value); + + ret = GTL_GCWritePort (src->hDevPort, addr, &value, &datasize); + HANDLE_GTL_ERROR ("Failed to write address"); + + return ret; + +error: + return ret; +} + +static guint64 +read_uint64_single (GstGenTlSrc * src, guint64 addr, GC_ERROR * ret) +{ + guint64 value; + size_t datasize = 8; + + *ret = GTL_GCReadPort (src->hDevPort, addr, &value, &datasize); + if (*ret != GC_ERR_SUCCESS) { + GST_ELEMENT_ERROR (src, LIBRARY, FAILED, + ("Failed to read address: %s", gst_gentlsrc_get_error_string (src)), + (NULL)); + goto error; + } + + if (src->producer.port_endianness == G_BIG_ENDIAN) + value = GUINT64_FROM_BE (value); + else + value = GUINT64_FROM_LE (value); + + return value; + +error: + return 0; +} + +static guint64 +read_uint64 (GstGenTlSrc * src, guint64 low_addr, guint64 high_addr, + GC_ERROR * ret) +{ + guint32 low, high; + size_t datasize = 4; + guint64 value; + + *ret = GTL_GCReadPort (src->hDevPort, low_addr, &low, &datasize); + if (*ret != GC_ERR_SUCCESS) { + GST_ELEMENT_ERROR (src, LIBRARY, FAILED, + ("Failed to read lower address: %s", + gst_gentlsrc_get_error_string (src)), (NULL)); + goto error; + } + *ret = GTL_GCReadPort (src->hDevPort, high_addr, &high, &datasize); + if (*ret != GC_ERR_SUCCESS) { + GST_ELEMENT_ERROR (src, LIBRARY, FAILED, + ("Failed to read upper address: %s", + gst_gentlsrc_get_error_string (src)), (NULL)); + goto error; + } + + if (src->producer.port_endianness == G_BIG_ENDIAN) + value = GUINT64_FROM_BE ((guint64) low << 32 | high); + else + value = GUINT64_FROM_LE ((guint64) low << 32 | high); + + return value; + +error: + return 0; +} + + static size_t gst_gentlsrc_get_payload_size (GstGenTlSrc * src) { @@ -798,13 +930,9 @@ gst_gentlsrc_get_payload_size (GstGenTlSrc * src) payload_size); } else { guint32 val = 0; - size_t datasize = 4; // TODO: use node map - ret = - GTL_GCReadPort (src->hDevPort, src->producer.payload_size, &val, - &datasize); + payload_size = read_uint32 (src, src->producer.payload_size, &ret); HANDLE_GTL_ERROR ("Failed to get payload size"); - payload_size = GUINT32_FROM_BE (val); GST_DEBUG_OBJECT (src, "Payload size defined by node map: %d", payload_size); @@ -860,66 +988,79 @@ gst_gentlsrc_get_gev_tick_frequency (GstGenTlSrc * src) { GC_ERROR ret; - if (!src->producer.tick_frequency_high || !src->producer.tick_frequency_low) - return 0; + if (!src->producer.tick_frequency_high || !src->producer.tick_frequency_low) { + // latch timestamps once + if (gst_gentlsrc_src_latch_timestamps (src)) { + GST_DEBUG_OBJECT (src, "Assuming timestamps are in nanoseconds"); + return GST_SECOND; + } else { + GST_ERROR_OBJECT (src, "Tick frequency addresses aren't defined"); + return 0; + } + } - guint32 freq_low, freq_high; - size_t datasize = 4; - ret = GTL_GCReadPort (src->hDevPort, src->producer.tick_frequency_low, &freq_low, &datasize); // GevTimestampTickFrequencyLow - HANDLE_GTL_ERROR ("Failed to get GevTimestampTickFrequencyLow"); - ret = GTL_GCReadPort (src->hDevPort, src->producer.tick_frequency_high, &freq_high, &datasize); // GevTimestampTickFrequencyHigh - HANDLE_GTL_ERROR ("Failed to get GevTimestampTickFrequencyHigh"); - - guint64 tick_frequency = - GUINT64_FROM_BE ((guint64) freq_low << 32 | freq_high); + guint64 tick_frequency = read_uint64 (src, src->producer.tick_frequency_low, + src->producer.tick_frequency_high, &ret); GST_DEBUG_OBJECT (src, "GEV Timestamp tick frequency is %llu", tick_frequency); return tick_frequency; - -error: - return 0; } static guint64 -gst_gentlsrc_get_gev_timestamp_ticks (GstGenTlSrc * src) +gst_gentlsrc_get_gev_timestamp_ns (GstGenTlSrc * src) { GC_ERROR ret; - size_t datasize = 4; - guint32 val, ts_low, ts_high; + guint64 timestamp_ns; - val = GUINT32_TO_BE (2); - datasize = sizeof (val); - ret = GTL_GCWritePort (src->hDevPort, src->producer.timestamp_control_latch, &val, &datasize); // GevTimestampControlLatch + ret = + write_uint32 (src, src->producer.timestamp_control_latch, + src->producer.timestamp_control_latch_value); HANDLE_GTL_WARNING ("Failed to latch timestamp GevTimestampControlLatch"); - ret = GTL_GCReadPort (src->hDevPort, src->producer.timestamp_low, &ts_low, &datasize); // GevTimestampValueLow - HANDLE_GTL_WARNING ("Failed to get GevTimestampValueLow"); - ret = GTL_GCReadPort (src->hDevPort, src->producer.timestamp_high, &ts_high, &datasize); // GevTimestampValueHigh - HANDLE_GTL_WARNING ("Failed to get GevTimestampValueHigh"); - guint64 ticks = GUINT64_FROM_BE ((guint64) ts_low << 32 | ts_high); - GST_LOG_OBJECT (src, "Timestamp ticks are %llu", ticks); + if (src->producer.timestamp) { + timestamp_ns = read_uint64_single (src, src->producer.timestamp, &ret); + HANDLE_GTL_WARNING ("Failed to read device timestamp"); + } else { + guint64 ticks = read_uint64 (src, src->producer.timestamp_low, + src->producer.timestamp_high, &ret); + HANDLE_GTL_WARNING ("Failed to read timestamp ticks"); + GST_LOG_OBJECT (src, "Timestamp ticks are %llu", ticks); - return ticks; + if (src->tick_frequency == 0) { + GST_WARNING_OBJECT (src, + "Tick frequency undefined, can't timestamp accurately"); + goto error; + } + timestamp_ns = ((guint64) + (ticks * ((double) GST_SECOND / src->tick_frequency)));; + } + + GST_LOG_OBJECT (src, "Device timestamp in ns is %llu", timestamp_ns); + + return timestamp_ns; error: return 0; } -static void +static gboolean gst_gentlsrc_src_latch_timestamps (GstGenTlSrc * src) { guint64 unix_ts, gev_ts; unix_ts = get_unix_ns (); - gev_ts = gst_gentlsrc_get_gev_timestamp_ticks (src); + gev_ts = gst_gentlsrc_get_gev_timestamp_ns (src); if (gev_ts != 0) { src->unix_latched_ns = unix_ts; - src->gentl_latched_ns = ((gint64) - (gev_ts * ((double)GST_SECOND / src->tick_frequency)));; + src->gentl_latched_ns = gev_ts; + GST_LOG_OBJECT (src, "Latched system time: %llu", src->unix_latched_ns); + GST_LOG_OBJECT (src, "Latched GenTL time : %llu", src->gentl_latched_ns); + return TRUE; } else { GST_WARNING_OBJECT (src, "Failed to latch GEV time, using old latch value"); + return FALSE; } } @@ -928,8 +1069,6 @@ gst_gentlsrc_set_attributes (GstGenTlSrc * src) { gchar **pairs; int i; - guint32 val; - size_t datasize; GC_ERROR ret; if (!src->attributes || src->attributes == 0) { @@ -956,11 +1095,7 @@ gst_gentlsrc_set_attributes (GstGenTlSrc * src) GST_DEBUG_OBJECT (src, "Setting attribute, '%s'='%s'", pair[0], pair[1]); - val = GUINT32_TO_BE (atoi (pair[1])); - datasize = sizeof (val); - ret = - GTL_GCWritePort (src->hDevPort, strtol (pair[0], NULL, 16), &val, - &datasize); + ret = write_uint32 (src, strtol (pair[0], NULL, 16), atoi (pair[1])); if (ret != GC_ERR_SUCCESS) { GST_WARNING_OBJECT (src, "Failed to set attribute: %s", gst_gentlsrc_get_error_string (src)); @@ -1067,8 +1202,7 @@ gst_gentlsrc_start (GstBaseSrc * bsrc) GstGenTlSrcClass *klass = GST_GENTL_SRC_GET_CLASS (src); GC_ERROR ret; uint32_t i, num_devs; - guint32 width, height, stride; - GstVideoInfo vinfo; + guint32 width, height; GST_DEBUG_OBJECT (src, "start"); @@ -1076,6 +1210,8 @@ gst_gentlsrc_start (GstBaseSrc * bsrc) initialize_basler_addresses (&src->producer); } else if (src->producer_prop == GST_GENTLSRC_PRODUCER_EVT) { initialize_evt_addresses (&src->producer); + } else if (src->producer_prop == GST_GENTLSRC_PRODUCER_FLIR) { + initialize_flir_addresses (&src->producer); } else { g_assert_not_reached (); } @@ -1309,28 +1445,19 @@ gst_gentlsrc_start (GstBaseSrc * bsrc) } } - src->tick_frequency = gst_gentlsrc_get_gev_tick_frequency (src); - gst_gentlsrc_set_attributes (src); { // TODO: use GenTl node map for this - guint32 val = 0; - size_t datasize = 4; - ret = GTL_GCReadPort (src->hDevPort, src->producer.width, &val, &datasize); + width = read_uint32 (src, src->producer.width, &ret); HANDLE_GTL_ERROR ("Failed to get width"); - width = GUINT32_FROM_BE (val); - ret = GTL_GCReadPort (src->hDevPort, src->producer.height, &val, &datasize); + height = read_uint32 (src, src->producer.height, &ret); HANDLE_GTL_ERROR ("Failed to get height"); - height = GUINT32_FROM_BE (val); GST_DEBUG_OBJECT (src, "Width and height %dx%d", width, height); - ret = - GTL_GCReadPort (src->hDevPort, src->producer.pixel_format, &val, - &datasize); - HANDLE_GTL_ERROR ("Failed to get height"); + guint32 pixfmt_enum = read_uint32 (src, src->producer.pixel_format, &ret); + HANDLE_GTL_ERROR ("Failed to get pixel format"); const char *genicam_pixfmt; - guint32 pixfmt_enum = GUINT32_FROM_BE (val); switch (pixfmt_enum) { case 0x1: // Basler Ace case 0x01080001: @@ -1407,25 +1534,17 @@ gst_gentlsrc_start (GstBaseSrc * bsrc) { // TODO: use GenTl node map for this - guint32 val; - size_t datasize; /* set AcquisitionMode to Continuous */ // TODO: "Continuous" value can have different integer values, we need // to look it up in the node map (EVT is 0, Basler is 2) - val = GUINT32_TO_BE (src->producer.acquisition_mode_value); - datasize = sizeof (val); ret = - GTL_GCWritePort (src->hDevPort, src->producer.acquisition_mode, &val, - &datasize); + write_uint32 (src, src->producer.acquisition_mode, + src->producer.acquisition_mode_value); HANDLE_GTL_ERROR ("Failed to start device acquisition"); /* send AcquisitionStart command */ - val = GUINT32_TO_BE (1); - datasize = sizeof (val); - ret = - GTL_GCWritePort (src->hDevPort, src->producer.acquisition_start, &val, - &datasize); + ret = write_uint32 (src, src->producer.acquisition_start, 1); HANDLE_GTL_ERROR ("Failed to start device acquisition"); } @@ -1436,6 +1555,8 @@ gst_gentlsrc_start (GstBaseSrc * bsrc) src->acq_start_time = gst_clock_get_time (gst_element_get_clock (GST_ELEMENT (src))); + src->tick_frequency = gst_gentlsrc_get_gev_tick_frequency (src); + return TRUE; error: @@ -1490,11 +1611,8 @@ gst_gentlsrc_stop (GstBaseSrc * bsrc) if (src->hDS) { /* command AcquisitionStop */ - guint32 val = GUINT32_TO_BE (1); - gsize datasize = sizeof (val); - GC_ERROR ret = - GTL_GCWritePort (src->hDevPort, src->producer.acquisition_stop, &val, - &datasize); + GC_ERROR ret; + ret = write_uint32 (src, src->producer.acquisition_stop, 1); GTL_DSStopAcquisition (src->hDS, ACQ_STOP_FLAGS_DEFAULT); GTL_DSFlushQueue (src->hDS, ACQ_QUEUE_INPUT_TO_OUTPUT); @@ -1557,10 +1675,22 @@ gst_gentlsrc_set_caps (GstBaseSrc * bsrc, GstCaps * caps) GST_DEBUG_OBJECT (src, "The caps being set are %" GST_PTR_FORMAT, caps); + + GST_ERROR ("Stride is %d", src->gst_stride); 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); + int endianness; + const char *genicam_pixfmt = + gst_genicam_pixel_format_from_caps (caps, &endianness); + GST_ERROR ("Format is %s, Stride is %d", genicam_pixfmt, src->gst_stride); + if (genicam_pixfmt) + src->gst_stride = + gst_genicam_pixel_format_get_stride (genicam_pixfmt, G_LITTLE_ENDIAN, + vinfo.width); + else + goto unsupported_caps; + GST_ERROR ("Format is %s, Stride is %d", genicam_pixfmt, src->gst_stride); } else { goto unsupported_caps; } @@ -1647,15 +1777,16 @@ gst_gentlsrc_get_buffer (GstGenTlSrc * src) GTL_DSGetBufferInfo (src->hDS, new_buffer_data.BufferHandle, BUFFER_INFO_TIMESTAMP_NS, &datatype, &buf_timestamp_ns, &datasize); if (ret == GC_ERR_SUCCESS) { - GST_LOG_OBJECT(src, "Buffer GentTL timestamp: %llu ns", buf_timestamp_ns); + GST_LOG_OBJECT (src, "Buffer GentTL timestamp: %llu ns", buf_timestamp_ns); } else { ret = - GTL_DSGetBufferInfo(src->hDS, new_buffer_data.BufferHandle, + GTL_DSGetBufferInfo (src->hDS, new_buffer_data.BufferHandle, BUFFER_INFO_TIMESTAMP, &datatype, &buf_timestamp_ticks, &datasize); - HANDLE_GTL_ERROR("Failed to get buffer timestamp"); + HANDLE_GTL_ERROR ("Failed to get buffer timestamp"); buf_timestamp_ns = (gint64) - (buf_timestamp_ticks * ((double)GST_SECOND / src->tick_frequency)); - GST_LOG_OBJECT(src, "Buffer GentTL timestamp: %llu ticks, %llu ns", buf_timestamp_ticks, buf_timestamp_ns); + (buf_timestamp_ticks * ((double) GST_SECOND / src->tick_frequency)); + GST_LOG_OBJECT (src, "Buffer GentTL timestamp: %llu ticks, %llu ns", + buf_timestamp_ticks, buf_timestamp_ns); } datasize = sizeof (frame_id); @@ -1787,9 +1918,6 @@ gst_gentlsrc_create (GstPushSrc * psrc, GstBuffer ** buf) } return GST_FLOW_OK; - -error: - return GST_FLOW_ERROR; } gchar * diff --git a/sys/gentl/gstgentlsrc.h b/sys/gentl/gstgentlsrc.h index c9c8a78..8e6934e 100644 --- a/sys/gentl/gstgentlsrc.h +++ b/sys/gentl/gstgentlsrc.h @@ -45,6 +45,7 @@ struct _GstGenTlProducer { gchar* cti_path; guint32 acquisition_mode_value; + guint32 timestamp_control_latch_value; guint64 width; guint64 height; @@ -55,9 +56,11 @@ struct _GstGenTlProducer guint64 acquisition_stop; guint64 tick_frequency_low; guint64 tick_frequency_high; - guint64 timestamp_control_latch; - guint64 timestamp_low; - guint64 timestamp_high; + guint64 timestamp_control_latch; // GevTimestampControlLatch + guint64 timestamp; // TimestampLatchValue + guint64 timestamp_low; // GevTimestampValueLow + guint64 timestamp_high; // GevTimestampValueHigh + guint16 port_endianness; }; @@ -71,6 +74,7 @@ struct _GstGenTlProducer typedef enum { GST_GENTLSRC_PRODUCER_BASLER, GST_GENTLSRC_PRODUCER_EVT, + GST_GENTLSRC_PRODUCER_FLIR, } GstGenTlSrcProducer; From ddae5b5105cbe6db7480e11cce39c236a69475d5 Mon Sep 17 00:00:00 2001 From: "Joshua M. Doe" Date: Tue, 9 Nov 2021 16:27:04 -0500 Subject: [PATCH 11/20] gentlsrc: add Mono16, BayerGR16, BayerRG16 --- sys/gentl/gstgentlsrc.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/sys/gentl/gstgentlsrc.c b/sys/gentl/gstgentlsrc.c index 5dea8db..2d737fc 100644 --- a/sys/gentl/gstgentlsrc.c +++ b/sys/gentl/gstgentlsrc.c @@ -1467,6 +1467,9 @@ gst_gentlsrc_start (GstBaseSrc * bsrc) case 0x01100005: genicam_pixfmt = "Mono12"; break; + case 0x1100007: + genicam_pixfmt = "Mono16"; + break; case 0x1100010: // Basler Ace genicam_pixfmt = "BayerGR12"; break; @@ -1476,6 +1479,12 @@ gst_gentlsrc_start (GstBaseSrc * bsrc) case 0x01100011: genicam_pixfmt = "BayerRG12"; break; + case 0x0110002E: + genicam_pixfmt = "BayerGR16"; + break; + case 0x0110002F: + genicam_pixfmt = "BayerRG16"; + break; case 0x02180014: genicam_pixfmt = "RGB8Packed"; break; @@ -1490,7 +1499,7 @@ gst_gentlsrc_start (GstBaseSrc * bsrc) break; default: GST_ELEMENT_ERROR (src, RESOURCE, TOO_LAZY, - ("Unrecognized PixelFormat enum value: %d", pixfmt_enum), (NULL)); + ("Unrecognized PixelFormat enum value: 0x%x", pixfmt_enum), (NULL)); goto error; } From 260c09b1be1e286a1264a0e41f07eda6adaf851f Mon Sep 17 00:00:00 2001 From: "Joshua M. Doe" Date: Tue, 9 Nov 2021 16:30:13 -0500 Subject: [PATCH 12/20] gentlsrc: only send valid image data in case payload size has padding --- sys/gentl/gstgentlsrc.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/sys/gentl/gstgentlsrc.c b/sys/gentl/gstgentlsrc.c index 2d737fc..b10546f 100644 --- a/sys/gentl/gstgentlsrc.c +++ b/sys/gentl/gstgentlsrc.c @@ -1512,7 +1512,6 @@ gst_gentlsrc_start (GstBaseSrc * bsrc) src->caps = gst_genicam_pixel_format_caps_from_pixel_format (genicam_pixfmt, G_LITTLE_ENDIAN, width, height, 30, 1, 1, 1); - gst_video_info_from_caps (&vinfo, src->caps); if (!src->caps) { GST_ELEMENT_ERROR (src, STREAM, WRONG_TYPE, ("Unknown or unsupported pixel format (%s).", genicam_pixfmt), @@ -1520,8 +1519,11 @@ gst_gentlsrc_start (GstBaseSrc * bsrc) goto error; } - src->height = vinfo.height; - src->gst_stride = GST_VIDEO_INFO_COMP_STRIDE (&vinfo, 0); + src->height = height; + src->gst_stride = + gst_genicam_pixel_format_get_stride (genicam_pixfmt, G_LITTLE_ENDIAN, + width); + GST_DEBUG_OBJECT (src, "Height=%d, stride=%d", src->height, src->gst_stride); } if (!gst_gentlsrc_prepare_buffers (src)) { @@ -1827,7 +1829,15 @@ gst_gentlsrc_get_buffer (GstGenTlSrc * src) // TODO: what if strides aren't same? - buf = gst_buffer_new_allocate (NULL, buffer_size, NULL); + guint64 image_size = (size_t) src->height * src->gst_stride; + if (buffer_size < image_size) { + GST_ELEMENT_ERROR (src, STREAM, TOO_LAZY, + ("Buffer size (%d) is smaller than expected image size (%llu)", + buffer_size, image_size), (NULL)); + goto error; + } + + buf = gst_buffer_new_allocate (NULL, image_size, NULL); if (!buf) { GST_ELEMENT_ERROR (src, STREAM, TOO_LAZY, ("Failed to allocate buffer"), (NULL)); From 1bab9b907bfbceafc4ab30e00267422f5a76fd0c Mon Sep 17 00:00:00 2001 From: "Joshua M. Doe" Date: Wed, 10 Nov 2021 10:20:34 -0500 Subject: [PATCH 13/20] gentlsrc: fix bug where two devices wouldn't be found on the same interface --- sys/gentl/gstgentlsrc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sys/gentl/gstgentlsrc.c b/sys/gentl/gstgentlsrc.c index b10546f..f41e5c6 100644 --- a/sys/gentl/gstgentlsrc.c +++ b/sys/gentl/gstgentlsrc.c @@ -734,6 +734,7 @@ gst_gentl_print_device_info (GstGenTlSrc * src, uint32_t index) gint32 access_status; INFO_DATATYPE datatype; + str_size = GTL_MAX_STR_SIZE; ret = GTL_IFGetDeviceID (src->hIF, index, dev_id, &str_size); if (ret != GC_ERR_SUCCESS) { GST_WARNING_OBJECT (src, "Failed to get device id: %s", @@ -1245,6 +1246,7 @@ gst_gentlsrc_start (GstBaseSrc * bsrc) ret = GTL_IFGetNumDevices (src->hIF, &num_devs); HANDLE_GTL_ERROR ("Failed to get number of devices"); if (num_devs > 0) { + GST_DEBUG_OBJECT (src, "Found %d devices on interface", num_devs); for (i = 0; i < num_devs; ++i) { gst_gentl_print_device_info (src, i); } @@ -1523,7 +1525,8 @@ gst_gentlsrc_start (GstBaseSrc * bsrc) src->gst_stride = gst_genicam_pixel_format_get_stride (genicam_pixfmt, G_LITTLE_ENDIAN, width); - GST_DEBUG_OBJECT (src, "Height=%d, stride=%d", src->height, src->gst_stride); + GST_DEBUG_OBJECT (src, "Height=%d, stride=%d", src->height, + src->gst_stride); } if (!gst_gentlsrc_prepare_buffers (src)) { From f3020dbf8234030a68999dca8463b0276f24e32b Mon Sep 17 00:00:00 2001 From: "Joshua M. Doe" Date: Fri, 19 Nov 2021 11:39:07 -0500 Subject: [PATCH 14/20] matroxsrc: show MIL error when failing to allocate digitizer --- sys/matrox/gstmatroxsrc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sys/matrox/gstmatroxsrc.c b/sys/matrox/gstmatroxsrc.c index 6cfa26c..c3004a8 100644 --- a/sys/matrox/gstmatroxsrc.c +++ b/sys/matrox/gstmatroxsrc.c @@ -510,8 +510,10 @@ gst_matroxsrc_start (GstBaseSrc * bsrc) &src->MilDigitizer); } if (ret == M_NULL) { + MIL_TEXT_CHAR err_msg[M_ERROR_MESSAGE_SIZE]; + MappGetError (M_DEFAULT, M_CURRENT | M_MESSAGE, err_msg); GST_ELEMENT_ERROR (src, RESOURCE, FAILED, - ("Failed to allocate a MIL digitizer"), (NULL)); + ("Failed to allocate a MIL digitizer: %s", err_msg), (NULL)); goto error; } From ac4a7b29e343a538e978e9c639fc4e9e72d768d5 Mon Sep 17 00:00:00 2001 From: "Joshua M. Doe" Date: Wed, 1 Dec 2021 14:07:38 -0500 Subject: [PATCH 15/20] gentlsrc: add device-user-id property This will search across all interfaces. --- sys/gentl/gstgentlsrc.c | 131 ++++++++++++++++++++++++++++++++++++++-- sys/gentl/gstgentlsrc.h | 1 + 2 files changed, 126 insertions(+), 6 deletions(-) diff --git a/sys/gentl/gstgentlsrc.c b/sys/gentl/gstgentlsrc.c index f41e5c6..b58fec0 100644 --- a/sys/gentl/gstgentlsrc.c +++ b/sys/gentl/gstgentlsrc.c @@ -171,6 +171,7 @@ enum PROP_INTERFACE_ID, PROP_DEVICE_INDEX, PROP_DEVICE_ID, + PROP_DEVICE_USER_ID, PROP_STREAM_INDEX, PROP_STREAM_ID, PROP_NUM_CAPTURE_BUFFERS, @@ -183,6 +184,7 @@ enum #define DEFAULT_PROP_INTERFACE_ID "" #define DEFAULT_PROP_DEVICE_INDEX 0 #define DEFAULT_PROP_DEVICE_ID "" +#define DEFAULT_PROP_DEVICE_USER_ID "" #define DEFAULT_PROP_STREAM_INDEX 0 #define DEFAULT_PROP_STREAM_ID "" #define DEFAULT_PROP_NUM_CAPTURE_BUFFERS 3 @@ -409,6 +411,12 @@ gst_gentlsrc_class_init (GstGenTlSrcClass * klass) DEFAULT_PROP_DEVICE_ID, (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_MUTABLE_READY))); + g_object_class_install_property (gobject_class, PROP_DEVICE_USER_ID, + g_param_spec_string ("device-user-id", "Device User ID", + "Device User ID, overrides all other interface/device properties", + DEFAULT_PROP_DEVICE_USER_ID, + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_MUTABLE_READY))); g_object_class_install_property (gobject_class, PROP_STREAM_INDEX, g_param_spec_uint ("stream-index", "Stream index", "Stream index number, zero-based, overridden by stream-id", @@ -511,6 +519,10 @@ gst_gentlsrc_set_property (GObject * object, guint property_id, g_free (src->device_id); src->device_id = g_strdup (g_value_get_string (value)); break; + case PROP_DEVICE_USER_ID: + g_free (src->device_user_id); + src->device_user_id = g_strdup (g_value_get_string (value)); + break; case PROP_STREAM_INDEX: src->stream_index = g_value_get_uint (value); break; @@ -560,6 +572,9 @@ gst_gentlsrc_get_property (GObject * object, guint property_id, case PROP_DEVICE_ID: g_value_set_string (value, src->device_id); break; + case PROP_DEVICE_USER_ID: + g_value_set_string (value, src->device_user_id); + break; case PROP_STREAM_INDEX: g_value_set_uint (value, src->stream_index); break; @@ -731,6 +746,7 @@ gst_gentl_print_device_info (GstGenTlSrc * src, uint32_t index) char model[GTL_MAX_STR_SIZE]; char tl_type[GTL_MAX_STR_SIZE]; char display_name[GTL_MAX_STR_SIZE]; + char user_defined_name[GTL_MAX_STR_SIZE]; gint32 access_status; INFO_DATATYPE datatype; @@ -757,13 +773,17 @@ gst_gentl_print_device_info (GstGenTlSrc * src, uint32_t index) str_size = GTL_MAX_STR_SIZE; GTL_IFGetDeviceInfo (src->hIF, dev_id, DEVICE_INFO_DISPLAYNAME, &datatype, display_name, &str_size); + str_size = GTL_MAX_STR_SIZE; + GTL_IFGetDeviceInfo (src->hIF, dev_id, DEVICE_INFO_USER_DEFINED_NAME, + &datatype, user_defined_name, &str_size); str_size = sizeof (access_status); GTL_IFGetDeviceInfo (src->hIF, dev_id, DEVICE_INFO_ACCESS_STATUS, &datatype, &access_status, &str_size); GST_DEBUG_OBJECT (src, - "Device %d: ID=%s, Vendor=%s, Model=%s, TL_Type=%s, Display_Name=%s, Access_Status=%d", - index, id, vendor, model, tl_type, display_name, access_status); + "Device %d: ID=%s, Vendor=%s, Model=%s, TL_Type=%s, Display_Name=%s, User_Name=%s, Access_Status=%d", + index, id, vendor, model, tl_type, display_name, user_defined_name, + access_status); } //void gst_gentl_print_stream_info (GstGenTlSrc * src) @@ -1196,6 +1216,104 @@ error: return FALSE; } +static void +gst_gentlsrc_close_interface (GstGenTlSrc * src) +{ + if (src->hIF) { + GTL_IFClose (src->hIF); + src->hIF = NULL; + } +} + +static void +get_gentlsrc_select_user_id (GstGenTlSrc * src) +{ + GstGenTlSrcClass *klass = GST_GENTL_SRC_GET_CLASS (src); + GC_ERROR ret; + uint32_t num_ifaces, num_devs; + char dev_id[GTL_MAX_STR_SIZE]; + + ret = GTL_TLGetNumInterfaces (src->hTL, &num_ifaces); + HANDLE_GTL_ERROR ("Failed to get number of interfaces"); + + GST_DEBUG_OBJECT (src, + "Trying to find device-user-id='%s' on all %d interfaces", + src->device_user_id, num_ifaces); + + for (src->interface_index = 0; src->interface_index < num_ifaces; + src->interface_index++) { + size_t id_size; + GST_DEBUG_OBJECT (src, "Trying to find interface ID at index %d", + src->interface_index); + + ret = GTL_TLGetInterfaceID (src->hTL, src->interface_index, NULL, &id_size); + HANDLE_GTL_ERROR ("Failed to get interface ID at specified index"); + if (src->interface_id) { + g_free (src->interface_id); + } + src->interface_id = (gchar *) g_malloc (id_size); + ret = + GTL_TLGetInterfaceID (src->hTL, src->interface_index, src->interface_id, + &id_size); + HANDLE_GTL_ERROR ("Failed to get interface ID at specified index"); + GST_DEBUG_OBJECT (src, "Trying to open interface '%s'", src->interface_id); + ret = GTL_TLOpenInterface (src->hTL, src->interface_id, &src->hIF); + if (ret != GC_ERR_SUCCESS) { + GST_WARNING_OBJECT (src, "Interface failed to open"); + continue; + } + + ret = GTL_IFUpdateDeviceList (src->hIF, NULL, src->timeout); + HANDLE_GTL_ERROR ("Failed to update device list within timeout"); + + ret = GTL_IFGetNumDevices (src->hIF, &num_devs); + HANDLE_GTL_ERROR ("Failed to get number of devices"); + if (num_devs == 0) { + gst_gentlsrc_close_interface (src); + continue; + } + GST_DEBUG_OBJECT (src, "Found %d devices on interface", num_devs); + for (src->device_index = 0; src->device_index < num_devs; + ++src->device_index) { + size_t str_size; + char user_defined_name[GTL_MAX_STR_SIZE]; + INFO_DATATYPE datatype; + + str_size = GTL_MAX_STR_SIZE; + ret = GTL_IFGetDeviceID (src->hIF, src->device_index, dev_id, &str_size); + if (ret != GC_ERR_SUCCESS) { + GST_WARNING_OBJECT (src, "Failed to get device id: %s", + gst_gentlsrc_get_error_string (src)); + return; + } + + str_size = GTL_MAX_STR_SIZE; + GTL_IFGetDeviceInfo (src->hIF, dev_id, DEVICE_INFO_USER_DEFINED_NAME, + &datatype, user_defined_name, &str_size); + + GST_DEBUG_OBJECT (src, "Comparing specified user ID='%s', to '%s'", + src->device_user_id, user_defined_name); + + if (g_strcmp0 (src->device_user_id, user_defined_name) == 0) { + GST_DEBUG_OBJECT (src, "Device matches!"); + gst_gentlsrc_close_interface (src); + return; + } else { + GST_DEBUG_OBJECT (src, "Device doesn't match, continuing"); + } + } // looping over devices + gst_gentlsrc_close_interface (src); + } // looping over interfaces + + GST_ELEMENT_ERROR (src, RESOURCE, TOO_LAZY, + ("Failed to find device using device-user-id='%s'", src->device_user_id), + (NULL)); + return; + +error: + return; +} + static gboolean gst_gentlsrc_start (GstBaseSrc * bsrc) { @@ -1232,6 +1350,10 @@ gst_gentlsrc_start (GstBaseSrc * bsrc) goto error; } + if (src->device_user_id && src->device_user_id[0] != 0) { + get_gentlsrc_select_user_id (src); + } + if (!gst_gentlsrc_open_interface (src)) { g_mutex_unlock (&klass->tl_mutex); goto error; @@ -1584,10 +1706,7 @@ error: src->hDEV = NULL; } - if (src->hIF) { - GTL_IFClose (src->hIF); - src->hIF = NULL; - } + gst_gentlsrc_close_interface (src); gst_gentlsrc_cleanup_tl (src); diff --git a/sys/gentl/gstgentlsrc.h b/sys/gentl/gstgentlsrc.h index 8e6934e..93019a5 100644 --- a/sys/gentl/gstgentlsrc.h +++ b/sys/gentl/gstgentlsrc.h @@ -98,6 +98,7 @@ struct _GstGenTlSrc gchar *interface_id; guint device_index; gchar *device_id; + gchar *device_user_id; guint stream_index; gchar *stream_id; guint num_capture_buffers; From fec3ce5308864d9b9aa579595e212ee8dbbaee52 Mon Sep 17 00:00:00 2001 From: "Joshua M. Doe" Date: Tue, 1 Feb 2022 13:09:43 -0500 Subject: [PATCH 16/20] kayasrc: sync clock every second and use better clock g_get_real_time() on Windows sometimes gives millisecond resolution. Also grabbing framegrabber timestamp takes a non-insignificant amount of time, so do it every second. --- sys/kaya/gstkayasrc.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/sys/kaya/gstkayasrc.c b/sys/kaya/gstkayasrc.c index 94fa043..f7f044a 100644 --- a/sys/kaya/gstkayasrc.c +++ b/sys/kaya/gstkayasrc.c @@ -41,6 +41,7 @@ #include #include +#include "get_unix_ns.h" #include "gstkayasrc.h" #include "genicampixelformat.h" @@ -223,6 +224,7 @@ gst_kayasrc_cleanup (GstKayaSrc * src) src->stop_requested = FALSE; src->acquisition_started = FALSE; src->kaya_base = GST_CLOCK_TIME_NONE; + src->unix_base = 0; if (src->caps) { gst_caps_unref (src->caps); @@ -799,11 +801,13 @@ gst_kayasrc_stream_buffer_callback (STREAM_BUFFER_HANDLE buffer_handle, GST_BUFFER_OFFSET (buf) = src->frame_count; src->frame_count++; - //if (src->kaya_base == GST_CLOCK_TIME_NONE) { - // assume delay between these two calls is negligible + guint64 cur_time = get_unix_ns(); + if (cur_time - src->unix_base > GST_SECOND) { + // assume delay between these two calls is negligible (one measurement showed <100ns) src->kaya_base = KYFG_GetGrabberValueInt (src->cam_handle, "Timestamp"); - src->unix_base = g_get_real_time () * 1000; - //} + src->unix_base = get_unix_ns (); + } + #if GST_CHECK_VERSION(1,14,0) { GstClockTime unix_ts = src->unix_base + (timestamp - src->kaya_base); From 619ce5f132155b881e5ee57e2add94eff489cc39 Mon Sep 17 00:00:00 2001 From: "Joshua M. Doe" Date: Mon, 14 Feb 2022 10:48:49 -0500 Subject: [PATCH 17/20] niimaqdxsrc: add some non standard pixel format names --- sys/niimaqdx/gstniimaqdx.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sys/niimaqdx/gstniimaqdx.c b/sys/niimaqdx/gstniimaqdx.c index 8246931..22fe486 100644 --- a/sys/niimaqdx/gstniimaqdx.c +++ b/sys/niimaqdx/gstniimaqdx.c @@ -153,17 +153,29 @@ static GstStaticCaps unix_reference = GST_STATIC_CAPS ("timestamp/x-unix"); "framerate = " GST_VIDEO_FPS_RANGE /* TODO: handle the format mappings more intelligently */ +/* All pixel format names below have no spaces, as when comparing spaces + will be removed */ ImaqDxCapsInfo imaq_dx_caps_infos[] = { {"Mono8", 0, GST_VIDEO_CAPS_MAKE ("GRAY8"), 8, 8, 4} , + {"8BitMonochrome", 0, GST_VIDEO_CAPS_MAKE("GRAY8"), 8, 8, 4} + , {"Mono10", G_LITTLE_ENDIAN, GST_VIDEO_CAPS_MAKE ("GRAY16_LE"), 10, 16, 4} , + {"10BitMonochrome", G_LITTLE_ENDIAN, GST_VIDEO_CAPS_MAKE("GRAY16_LE"), 10, 16, 4} + , {"Mono10", G_BIG_ENDIAN, GST_VIDEO_CAPS_MAKE ("GRAY16_BE"), 10, 16, 4} , + {"10BitMonochrome", G_BIG_ENDIAN, GST_VIDEO_CAPS_MAKE("GRAY16_BE"), 10, 16, 4} + , {"Mono12", G_LITTLE_ENDIAN, GST_VIDEO_CAPS_MAKE ("GRAY16_LE"), 12, 16, 4} , + {"12BitMonochrome", G_LITTLE_ENDIAN, GST_VIDEO_CAPS_MAKE("GRAY16_LE"), 12, 16, 4} + , {"Mono12", G_BIG_ENDIAN, GST_VIDEO_CAPS_MAKE ("GRAY16_BE"), 12, 16, 4} , + {"12BitMonochrome", G_BIG_ENDIAN, GST_VIDEO_CAPS_MAKE("GRAY16_BE"), 12, 16, 4} + , {"Mono14", G_LITTLE_ENDIAN, GST_VIDEO_CAPS_MAKE ("GRAY16_LE"), 14, 16, 4} , {"Mono14", G_BIG_ENDIAN, GST_VIDEO_CAPS_MAKE ("GRAY16_BE"), 14, 16, 4} From 4836d595cef0b1ae48837e4f26d75bbd8fa32fb5 Mon Sep 17 00:00:00 2001 From: "Joshua M. Doe" Date: Fri, 25 Feb 2022 10:07:03 -0500 Subject: [PATCH 18/20] idsueyesrc: properly close camera handle if there's an error during opening and configuring --- sys/idsueye/gstidsueyesrc.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/sys/idsueye/gstidsueyesrc.c b/sys/idsueye/gstidsueyesrc.c index f8716f0..c9d1ba1 100644 --- a/sys/idsueye/gstidsueyesrc.c +++ b/sys/idsueye/gstidsueyesrc.c @@ -504,7 +504,7 @@ gst_idsueyesrc_start (GstBaseSrc * bsrc) if (!g_file_test (src->config_file, G_FILE_TEST_EXISTS)) { GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, ("Camera file does not exist: %s", src->config_file), (NULL)); - return FALSE; + goto error; } /* function requires Unicode */ @@ -533,7 +533,7 @@ gst_idsueyesrc_start (GstBaseSrc * bsrc) } GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, ("Failed to load parameter file: %s", src->config_file), (NULL)); - return FALSE; + goto error; } } else { ret = @@ -542,37 +542,42 @@ gst_idsueyesrc_start (GstBaseSrc * bsrc) if (ret != IS_SUCCESS) { GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, ("Failed to load parameters from EEPROM"), (NULL)); - return FALSE; + goto error; } } gst_idsueyesrc_set_caps_from_camera (src); if (!src->caps) { - return FALSE; + goto error; } if (!gst_idsueyesrc_alloc_memory (src)) { /* element error already sent */ - return FALSE; + goto error; } ret = is_SetDisplayMode (src->hCam, IS_SET_DM_DIB); if (ret != IS_SUCCESS) { GST_ELEMENT_ERROR (src, STREAM, WRONG_TYPE, ("Failed to set display mode"), (NULL)); - return FALSE; + goto error; } ret = is_InitImageQueue (src->hCam, 0); if (ret != IS_SUCCESS) { GST_ELEMENT_ERROR (src, STREAM, WRONG_TYPE, ("Failed to init image queue"), (NULL)); - return FALSE; + goto error; } gst_idsueyesrc_set_framerate_exposure (src); return TRUE; + +error: + ret = is_ExitCamera (src->hCam); + + return FALSE; } static gboolean From 2beabedaa269ce90214695016590539a697527a7 Mon Sep 17 00:00:00 2001 From: "Joshua M. Doe" Date: Fri, 25 Feb 2022 10:16:25 -0500 Subject: [PATCH 19/20] idsueyesrc: fix CMake build with default path Before, Pleora would only be found if Pleora_DIR was specified --- cmake/modules/FindPleora.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/modules/FindPleora.cmake b/cmake/modules/FindPleora.cmake index cdc2887..d37969b 100644 --- a/cmake/modules/FindPleora.cmake +++ b/cmake/modules/FindPleora.cmake @@ -24,8 +24,8 @@ endif () set (_Pleora_PATHS PATHS "${Pleora_DIR}" - "C:/Program Files/Pleora Technologies Inc/eBUS SDK/Includes" - "C:/Program Files (x86)/Pleora Technologies Inc/eBUS SDK/Includes") + "C:/Program Files/Pleora Technologies Inc/eBUS SDK" + "C:/Program Files (x86)/Pleora Technologies Inc/eBUS SDK") find_path (Pleora_INCLUDE_DIR PvBase.h PATHS ${_Pleora_PATHS} From 8a5478b344c0284684cc1e566332519695aedb40 Mon Sep 17 00:00:00 2001 From: "Joshua M. Doe" Date: Fri, 25 Feb 2022 10:17:16 -0500 Subject: [PATCH 20/20] niimaqdxsrc: show more verbose errors to applications --- sys/niimaqdx/gstniimaqdx.c | 45 ++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/sys/niimaqdx/gstniimaqdx.c b/sys/niimaqdx/gstniimaqdx.c index 22fe486..a36fbe1 100644 --- a/sys/niimaqdx/gstniimaqdx.c +++ b/sys/niimaqdx/gstniimaqdx.c @@ -93,6 +93,19 @@ static gboolean gst_niimaqdxsrc_close_interface (GstNiImaqDxSrc * src); static void gst_niimaqdxsrc_reset (GstNiImaqDxSrc * src); static void gst_niimaqdxsrc_set_dx_attributes (GstNiImaqDxSrc * src); +const char * +gst_niimaqdxsrc_get_imaq_error_str (IMAQdxError code) +{ + static char imaqdx_error_string[IMAQDX_MAX_API_STRING_LENGTH]; + if (code) { + IMAQdxGetErrorString (code, imaqdx_error_string, + IMAQDX_MAX_API_STRING_LENGTH); + return imaqdx_error_string; + } else { + return "No IMAQdx error"; + } +} + IMAQdxError gst_niimaqdxsrc_report_imaq_error (IMAQdxError code) { @@ -158,23 +171,25 @@ static GstStaticCaps unix_reference = GST_STATIC_CAPS ("timestamp/x-unix"); ImaqDxCapsInfo imaq_dx_caps_infos[] = { {"Mono8", 0, GST_VIDEO_CAPS_MAKE ("GRAY8"), 8, 8, 4} , - {"8BitMonochrome", 0, GST_VIDEO_CAPS_MAKE("GRAY8"), 8, 8, 4} + {"8BitMonochrome", 0, GST_VIDEO_CAPS_MAKE ("GRAY8"), 8, 8, 4} , {"Mono10", G_LITTLE_ENDIAN, GST_VIDEO_CAPS_MAKE ("GRAY16_LE"), 10, 16, 4} , - {"10BitMonochrome", G_LITTLE_ENDIAN, GST_VIDEO_CAPS_MAKE("GRAY16_LE"), 10, 16, 4} + {"10BitMonochrome", G_LITTLE_ENDIAN, GST_VIDEO_CAPS_MAKE ("GRAY16_LE"), 10, + 16, 4} , {"Mono10", G_BIG_ENDIAN, GST_VIDEO_CAPS_MAKE ("GRAY16_BE"), 10, 16, 4} , - {"10BitMonochrome", G_BIG_ENDIAN, GST_VIDEO_CAPS_MAKE("GRAY16_BE"), 10, 16, 4} + {"10BitMonochrome", G_BIG_ENDIAN, GST_VIDEO_CAPS_MAKE ("GRAY16_BE"), 10, 16, 4} , {"Mono12", G_LITTLE_ENDIAN, GST_VIDEO_CAPS_MAKE ("GRAY16_LE"), 12, 16, 4} , - {"12BitMonochrome", G_LITTLE_ENDIAN, GST_VIDEO_CAPS_MAKE("GRAY16_LE"), 12, 16, 4} + {"12BitMonochrome", G_LITTLE_ENDIAN, GST_VIDEO_CAPS_MAKE ("GRAY16_LE"), 12, + 16, 4} , {"Mono12", G_BIG_ENDIAN, GST_VIDEO_CAPS_MAKE ("GRAY16_BE"), 12, 16, 4} , - {"12BitMonochrome", G_BIG_ENDIAN, GST_VIDEO_CAPS_MAKE("GRAY16_BE"), 12, 16, 4} + {"12BitMonochrome", G_BIG_ENDIAN, GST_VIDEO_CAPS_MAKE ("GRAY16_BE"), 12, 16, 4} , {"Mono14", G_LITTLE_ENDIAN, GST_VIDEO_CAPS_MAKE ("GRAY16_LE"), 14, 16, 4} , @@ -699,7 +714,7 @@ gst_niimaqdxsrc_fill (GstPushSrc * psrc, GstBuffer * buf) if (!gst_niimaqdxsrc_start_acquisition (src)) { GST_ELEMENT_ERROR (src, RESOURCE, FAILED, - ("Unable to start acquisition."), (NULL)); + ("Unable to start acquisition"), (NULL)); return GST_FLOW_ERROR; } @@ -740,7 +755,8 @@ gst_niimaqdxsrc_fill (GstPushSrc * psrc, GstBuffer * buf) if (rval) { gst_niimaqdxsrc_report_imaq_error (rval); GST_ELEMENT_ERROR (src, RESOURCE, FAILED, - ("failed to copy buffer %d", src->cumbufnum), (NULL)); + ("failed to copy buffer %d: %s", src->cumbufnum, + gst_niimaqdxsrc_get_imaq_error_str (rval)), (NULL)); return GST_FLOW_ERROR; } @@ -950,7 +966,8 @@ gst_niimaqdxsrc_get_cam_caps (GstNiImaqDxSrc * src) if (rval) { GST_ELEMENT_ERROR (src, STREAM, FAILED, - ("attempt to read attributes failed"), + ("attempt to read attributes failed: %s", + gst_niimaqdxsrc_get_imaq_error_str (rval)), ("attempt to read attributes failed")); goto error; } @@ -1083,7 +1100,8 @@ gst_niimaqdxsrc_start (GstBaseSrc * bsrc) if (rval != IMAQdxErrorSuccess) { gst_niimaqdxsrc_report_imaq_error (rval); GST_ELEMENT_ERROR (src, RESOURCE, FAILED, - ("Failed to open IMAQdx interface"), + ("Failed to open IMAQdx interface %s: %s", src->device_name, + gst_niimaqdxsrc_get_imaq_error_str (rval)), ("Failed to open camera interface %s", src->device_name)); goto error; } @@ -1097,7 +1115,8 @@ gst_niimaqdxsrc_start (GstBaseSrc * bsrc) if (rval) { gst_niimaqdxsrc_report_imaq_error (rval); GST_ELEMENT_ERROR (src, RESOURCE, FAILED, - ("Failed to create ring buffer"), + ("Failed to create ring buffer: %s", + gst_niimaqdxsrc_get_imaq_error_str (rval)), ("Failed to create ring buffer with %d buffers", src->ringbuffer_count)); goto error; @@ -1113,7 +1132,8 @@ gst_niimaqdxsrc_start (GstBaseSrc * bsrc) if (rval) { gst_niimaqdxsrc_report_imaq_error (rval); GST_ELEMENT_ERROR (src, RESOURCE, FAILED, - ("Failed to register callback(s)"), (NULL)); + ("Failed to register callback(s): %s", + gst_niimaqdxsrc_get_imaq_error_str (rval)), (NULL)); goto error; } } @@ -1150,7 +1170,8 @@ gst_niimaqdxsrc_stop (GstBaseSrc * bsrc) if (rval != IMAQdxErrorSuccess) { gst_niimaqdxsrc_report_imaq_error (rval); GST_ELEMENT_ERROR (src, RESOURCE, FAILED, - ("Unable to stop acquisition"), (NULL)); + ("Unable to stop acquisition: %s", + gst_niimaqdxsrc_get_imaq_error_str (rval)), (NULL)); result = FALSE; } src->session_started = FALSE;