gentlsrc: use GEV buffer timestamps if available for unix reference time

This commit is contained in:
Joshua M. Doe 2021-05-26 09:06:54 -04:00
parent 6c4eedde70
commit 765662aa82
3 changed files with 148 additions and 0 deletions

43
common/get_unix_ns.h Normal file
View File

@ -0,0 +1,43 @@
#ifndef _GET_UNIX_NS_H_
#define _GET_UNIX_NS_H_
#include <gmodule.h>
typedef struct _MYFILETIME
{
guint32 dwLowDateTime;
guint32 dwHighDateTime;
} MYFILETIME;
typedef void (*GetSystemTimeFunc) (MYFILETIME * lpSystemTimeAsFileTime);
static guint64
get_unix_ns ()
{
MYFILETIME ftime;
LARGE_INTEGER ltime;
static GetSystemTimeFunc time_func = NULL;
if (!time_func) {
GModule *module;
module = g_module_open ("Kernel32.dll", G_MODULE_BIND_LAZY);
if (module) {
if (!g_module_symbol (module, "GetSystemTimePreciseAsFileTime",
(gpointer *) & time_func) || time_func == NULL) {
GST_WARNING
("Couldn't find GetSystemTimePreciseAsFileTime, falling back to GetSystemTimeAsFileTime");
if (!g_module_symbol (module, "GetSystemTimeAsFileTime",
(gpointer *) & time_func) || time_func == NULL) {
GST_WARNING
("Couldn't find GetSystemTimeAsFileTime, something is very wrong");
}
}
}
}
//GetSystemTimePreciseAsFileTime(&ftime);
time_func (&ftime);
ltime.HighPart = ftime.dwHighDateTime;
ltime.LowPart = ftime.dwLowDateTime;
ltime.QuadPart -= 11644473600000 * 10000;
return ltime.QuadPart * 100;
}
#endif /* _GET_UNIX_NS_H_ */

View File

@ -34,6 +34,9 @@
#include "config.h" #include "config.h"
#endif #endif
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <gmodule.h> #include <gmodule.h>
#include <gio/gio.h> #include <gio/gio.h>
@ -42,6 +45,7 @@
#include <gst/video/video.h> #include <gst/video/video.h>
#include "genicampixelformat.h" #include "genicampixelformat.h"
#include "get_unix_ns.h"
#include "unzip.h" #include "unzip.h"
@ -64,6 +68,11 @@
#define GENAPI_ACQMODE 0xB000 #define GENAPI_ACQMODE 0xB000
#define GENAPI_ACQSTART 0xB004 #define GENAPI_ACQSTART 0xB004
#define GENAPI_ACQSTOP 0xB008 #define GENAPI_ACQSTOP 0xB008
#define GENAPI_TICK_FREQ_LOW 0x0940
#define GENAPI_TICK_FREQ_HIGH 0x093C
#define GENAPI_TIMESTAMP_CONTROL_LATCH 0x944
#define GENAPI_TIMESTAMP_VALUE_LOW 0x094C
#define GENAPI_TIMESTAMP_VALUE_HIGH 0x0948
#define CTI_PATH "C:\\Program Files\\EVT\\eSDK\\bin\\EmergentGenTL.cti" #define CTI_PATH "C:\\Program Files\\EVT\\eSDK\\bin\\EmergentGenTL.cti"
// Basler // Basler
@ -354,6 +363,9 @@ gst_gentlsrc_class_init (GstGenTlSrcClass * klass)
static void static void
gst_gentlsrc_reset (GstGenTlSrc * src) gst_gentlsrc_reset (GstGenTlSrc * src)
{ {
src->gentl_latched_ticks = 0;
src->unix_latched_time = 0;
src->error_string[0] = 0; src->error_string[0] = 0;
src->last_frame_count = 0; src->last_frame_count = 0;
src->total_dropped_frames = 0; src->total_dropped_frames = 0;
@ -771,6 +783,64 @@ error:
return FALSE; return FALSE;
} }
static guint64
gst_gentlsrc_get_gev_tick_frequency (GstGenTlSrc * src)
{
GC_ERROR ret;
if (!GENAPI_TICK_FREQ_HIGH || !GENAPI_TICK_FREQ_LOW)
return 0;
guint32 freq_low, freq_high;
size_t datasize = 4;
ret = GTL_GCReadPort (src->hDevPort, GENAPI_TICK_FREQ_LOW, &freq_low, &datasize); // GevTimestampTickFrequencyLow
HANDLE_GTL_ERROR ("Failed to get GevTimestampTickFrequencyLow");
ret = GTL_GCReadPort (src->hDevPort, GENAPI_TICK_FREQ_HIGH, &freq_high, &datasize); // GevTimestampTickFrequencyHigh
HANDLE_GTL_ERROR ("Failed to get GevTimestampTickFrequencyHigh");
guint64 tick_frequency =
GUINT64_FROM_BE ((guint64) freq_low << 32 | freq_high);
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)
{
GC_ERROR ret;
size_t datasize = 4;
guint32 val, ts_low, ts_high;
val = GUINT32_TO_BE (2);
datasize = sizeof (val);
ret = GTL_GCWritePort (src->hDevPort, GENAPI_TIMESTAMP_CONTROL_LATCH, &val, &datasize); // GevTimestampControlLatch
HANDLE_GTL_ERROR ("Failed to latch timestamp GevTimestampControlLatch");
ret = GTL_GCReadPort (src->hDevPort, GENAPI_TIMESTAMP_VALUE_LOW, &ts_low, &datasize); // GevTimestampValueLow
HANDLE_GTL_ERROR ("Failed to get GevTimestampValueLow");
ret = GTL_GCReadPort (src->hDevPort, GENAPI_TIMESTAMP_VALUE_HIGH, &ts_high, &datasize); // GevTimestampValueHigh
HANDLE_GTL_ERROR ("Failed to get GevTimestampValueHigh");
guint64 ticks = GUINT64_FROM_BE ((guint64) ts_low << 32 | ts_high);
GST_LOG_OBJECT (src, "Timestamp ticks are %llu", ticks);
return ticks;
error:
return 0;
}
static void
gst_gentlsrc_src_latch_timestamps (GstGenTlSrc * src)
{
src->unix_latched_time = get_unix_ns ();
src->gentl_latched_ticks = gst_gentlsrc_get_gev_timestamp_ticks (src);
}
static gboolean static gboolean
gst_gentlsrc_start (GstBaseSrc * bsrc) gst_gentlsrc_start (GstBaseSrc * bsrc)
{ {
@ -1044,6 +1114,8 @@ gst_gentlsrc_start (GstBaseSrc * bsrc)
} }
} }
src->tick_frequency = gst_gentlsrc_get_gev_tick_frequency (src);
{ {
// TODO: use GenTl node map for this // TODO: use GenTl node map for this
guint32 val = 0; guint32 val = 0;
@ -1298,6 +1370,8 @@ gst_gentlsrc_unlock_stop (GstBaseSrc * bsrc)
return TRUE; return TRUE;
} }
static GstStaticCaps unix_reference = GST_STATIC_CAPS ("timestamp/x-unix");
static GstBuffer * static GstBuffer *
gst_gentlsrc_get_buffer (GstGenTlSrc * src) gst_gentlsrc_get_buffer (GstGenTlSrc * src)
{ {
@ -1311,6 +1385,8 @@ gst_gentlsrc_get_buffer (GstGenTlSrc * src)
bool8_t buffer_is_incomplete, is_acquiring; bool8_t buffer_is_incomplete, is_acquiring;
guint8 *data_ptr; guint8 *data_ptr;
GstMapInfo minfo; GstMapInfo minfo;
GstClockTime unix_ts;
uint64_t buf_timestamp_ticks;
datasize = sizeof (new_buffer_data); datasize = sizeof (new_buffer_data);
ret = ret =
@ -1329,6 +1405,13 @@ gst_gentlsrc_get_buffer (GstGenTlSrc * src)
goto error; goto error;
} }
datasize = sizeof (buf_timestamp_ticks);
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);
datasize = sizeof (frame_id); datasize = sizeof (frame_id);
ret = ret =
GTL_DSGetBufferInfo (src->hDS, new_buffer_data.BufferHandle, GTL_DSGetBufferInfo (src->hDS, new_buffer_data.BufferHandle,
@ -1372,6 +1455,24 @@ gst_gentlsrc_get_buffer (GstGenTlSrc * src)
GTL_DSQueueBuffer (src->hDS, new_buffer_data.BufferHandle); GTL_DSQueueBuffer (src->hDS, new_buffer_data.BufferHandle);
HANDLE_GTL_ERROR ("Failed to queue buffer"); HANDLE_GTL_ERROR ("Failed to queue buffer");
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) {
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;
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);
}
return buf; return buf;
error: error:

View File

@ -65,6 +65,10 @@ struct _GstGenTlSrc
guint32 last_frame_count; guint32 last_frame_count;
guint32 total_dropped_frames; guint32 total_dropped_frames;
guint64 tick_frequency;
guint64 unix_latched_time;
guint64 gentl_latched_ticks;
GstCaps *caps; GstCaps *caps;
gint height; gint height;
gint gst_stride; gint gst_stride;