Merge branch 'joshdoe:master' into master
This commit is contained in:
commit
cc1efa8ec2
@ -117,6 +117,11 @@ macro_log_feature(SAPERA_FOUND "Teledyne DALSA Sapera" "Required to build Teledy
|
|||||||
find_package(XCLIB)
|
find_package(XCLIB)
|
||||||
macro_log_feature(XCLIB_FOUND "EPIX PIXCI" "Required to build EPIX PIXCI source element" "http://www.epixinc.com/" FALSE)
|
macro_log_feature(XCLIB_FOUND "EPIX PIXCI" "Required to build EPIX PIXCI source element" "http://www.epixinc.com/" FALSE)
|
||||||
|
|
||||||
|
if (WIN32)
|
||||||
|
# Windows distributions of GStreamer include ZLIB
|
||||||
|
set(ZLIB_ROOT ${GSTREAMER_ROOT})
|
||||||
|
endif ()
|
||||||
|
find_package(ZLIB)
|
||||||
|
|
||||||
# Setup common environment
|
# Setup common environment
|
||||||
include_directories(
|
include_directories(
|
||||||
|
|||||||
@ -16,7 +16,7 @@ if (NOT Pleora_DIR)
|
|||||||
set (Pleora_DIR $ENV{PUREGEV_ROOT} CACHE PATH "Directory containing Pleora SDK includes and libraries")
|
set (Pleora_DIR $ENV{PUREGEV_ROOT} CACHE PATH "Directory containing Pleora SDK includes and libraries")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
if (CMAKE_SIZEOF_VOID_P MATCHES "8")
|
if (WIN32 AND CMAKE_SIZEOF_VOID_P MATCHES "8")
|
||||||
set(_LIB_SUFFIX "64")
|
set(_LIB_SUFFIX "64")
|
||||||
else ()
|
else ()
|
||||||
set(_LIB_SUFFIX "")
|
set(_LIB_SUFFIX "")
|
||||||
@ -29,16 +29,21 @@ set(_Pleora_PATHS PATHS
|
|||||||
|
|
||||||
find_path (Pleora_INCLUDE_DIR PvBase.h
|
find_path (Pleora_INCLUDE_DIR PvBase.h
|
||||||
PATHS ${_Pleora_PATHS}
|
PATHS ${_Pleora_PATHS}
|
||||||
PATH_SUFFIXES Includes)
|
PATH_SUFFIXES Includes include)
|
||||||
|
message (STATUS "Found Pleora include dir in ${Pleora_INCLUDE_DIR}")
|
||||||
|
|
||||||
find_path (Pleora_LIBRARY_DIR PvBase${_LIB_SUFFIX}.lib
|
find_path (Pleora_LIBRARY_DIR NAMES libPvBase.so "PvBase${_LIB_NAME}"
|
||||||
PATHS ${_Pleora_PATHS}
|
PATHS ${_Pleora_PATHS}
|
||||||
PATH_SUFFIXES Libraries)
|
PATH_SUFFIXES Libraries lib)
|
||||||
|
|
||||||
find_library (Pleora_LIBRARY_BASE PvBase${_LIB_SUFFIX} ${Pleora_LIBRARY_DIR})
|
message (STATUS "Found Pleora library in ${Pleora_LIBRARY_DIR}")
|
||||||
find_library (Pleora_LIBRARY_DEVICE PvDevice${_LIB_SUFFIX} ${Pleora_LIBRARY_DIR})
|
|
||||||
|
|
||||||
set (Pleora_LIBRARIES ${Pleora_LIBRARY_BASE} ${Pleora_LIBRARY_DEVICE})
|
find_library (Pleora_LIBRARY_BASE "PvBase${_LIB_SUFFIX}" ${Pleora_LIBRARY_DIR})
|
||||||
|
find_library (Pleora_LIBRARY_DEVICE "PvDevice${_LIB_SUFFIX}" ${Pleora_LIBRARY_DIR})
|
||||||
|
find_library (Pleora_LIBRARY_PERSISTENCE "PvPersistence${_LIB_SUFFIX}" ${Pleora_LIBRARY_DIR})
|
||||||
|
find_library (Pleora_LIBRARY_VIRTUAL_DEVICE "PvVirtualDevice${_LIB_SUFFIX}" ${Pleora_LIBRARY_DIR})
|
||||||
|
|
||||||
|
set (Pleora_LIBRARIES ${Pleora_LIBRARY_BASE} ${Pleora_LIBRARY_DEVICE} ${Pleora_LIBRARY_PERSISTENCE} ${Pleora_LIBRARY_VIRTUAL_DEVICE})
|
||||||
|
|
||||||
if (Pleora_INCLUDE_DIR)
|
if (Pleora_INCLUDE_DIR)
|
||||||
file(STRINGS "${Pleora_INCLUDE_DIR}/PvVersion.h" _pleora_VERSION_CONTENTS REGEX "#define NVERSION_STRING")
|
file(STRINGS "${Pleora_INCLUDE_DIR}/PvVersion.h" _pleora_VERSION_CONTENTS REGEX "#define NVERSION_STRING")
|
||||||
|
|||||||
@ -29,7 +29,9 @@ find_path (PYLON_INCLUDE_DIR pylonc/PylonC.h
|
|||||||
find_library (_PylonCLib NAMES PylonC_MD_VC120 pylonc
|
find_library (_PylonCLib NAMES PylonC_MD_VC120 pylonc
|
||||||
PATHS
|
PATHS
|
||||||
"${PYLON_DIR}/Development/lib/x64"
|
"${PYLON_DIR}/Development/lib/x64"
|
||||||
"${PYLON_DIR}/lib64")
|
"${PYLON_DIR}/lib64"
|
||||||
|
"${PYLON_DIR}/lib"
|
||||||
|
)
|
||||||
|
|
||||||
set (PYLON_LIBRARIES ${_PylonCLib})
|
set (PYLON_LIBRARIES ${_PylonCLib})
|
||||||
|
|
||||||
|
|||||||
@ -1,17 +0,0 @@
|
|||||||
FILE(TO_CMAKE_PATH "$ENV{ZLIB_DIR}" TRY1_DIR)
|
|
||||||
FILE(TO_CMAKE_PATH "${ZLIB_DIR}" TRY2_DIR)
|
|
||||||
FILE(GLOB ZLIB_DIR ${TRY1_DIR} ${TRY2_DIR})
|
|
||||||
|
|
||||||
FIND_PATH(ZLIB_INCLUDE_DIR zlib.h
|
|
||||||
PATHS ${ZLIB_DIR}/include /usr/local/include /usr/include
|
|
||||||
ENV INCLUDE DOC "Directory containing zlib.h include file")
|
|
||||||
|
|
||||||
FIND_LIBRARY(ZLIB_LIBRARY NAMES z
|
|
||||||
PATHS ${ZLIB_DIR}/bin ${ZLIB_DIR}/win32/bin ${ZLIB_DIR}/lib ${ZLIB_DIR}/win32/lib /usr/local/lib /usr/lib
|
|
||||||
ENV LIB
|
|
||||||
DOC "zlib library to link with"
|
|
||||||
NO_SYSTEM_ENVIRONMENT_PATH)
|
|
||||||
|
|
||||||
IF (ZLIB_INCLUDE_DIR AND ZLIB_LIBRARY)
|
|
||||||
SET(ZLIB_FOUND TRUE)
|
|
||||||
ENDIF (ZLIB_INCLUDE_DIR AND ZLIB_LIBRARY)
|
|
||||||
64
common/get_unix_ns.h
Normal file
64
common/get_unix_ns.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#ifndef _GET_UNIX_NS_H_
|
||||||
|
#define _GET_UNIX_NS_H_
|
||||||
|
|
||||||
|
#include <gmodule.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <Windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
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 /* _WIN32 */
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __unix__
|
||||||
|
static guint64
|
||||||
|
get_unix_ns ()
|
||||||
|
{
|
||||||
|
struct timespec spec;
|
||||||
|
|
||||||
|
clock_gettime (CLOCK_REALTIME, &spec);
|
||||||
|
return (guint64) spec.tv_sec * 1000000000L + (guint64) spec.tv_nsec;
|
||||||
|
}
|
||||||
|
#endif /* __unix__ */
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _GET_UNIX_NS_H_ */
|
||||||
@ -61,6 +61,12 @@ enum
|
|||||||
PROP_HIGHOUT,
|
PROP_HIGHOUT,
|
||||||
PROP_AUTO,
|
PROP_AUTO,
|
||||||
PROP_INTERVAL,
|
PROP_INTERVAL,
|
||||||
|
PROP_LOWER_SATURATION,
|
||||||
|
PROP_UPPER_SATURATION,
|
||||||
|
PROP_ROI_X,
|
||||||
|
PROP_ROI_Y,
|
||||||
|
PROP_ROI_WIDTH,
|
||||||
|
PROP_ROI_HEIGHT,
|
||||||
PROP_LAST
|
PROP_LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -72,6 +78,12 @@ static GParamSpec *properties[PROP_LAST];
|
|||||||
#define DEFAULT_PROP_HIGHOUT 255
|
#define DEFAULT_PROP_HIGHOUT 255
|
||||||
#define DEFAULT_PROP_AUTO 0
|
#define DEFAULT_PROP_AUTO 0
|
||||||
#define DEFAULT_PROP_INTERVAL (GST_SECOND / 2)
|
#define DEFAULT_PROP_INTERVAL (GST_SECOND / 2)
|
||||||
|
#define DEFAULT_PROP_LOW_SAT 0.01
|
||||||
|
#define DEFAULT_PROP_HIGH_SAT 0.01
|
||||||
|
#define DEFAULT_PROP_ROI_X -1
|
||||||
|
#define DEFAULT_PROP_ROI_Y -1
|
||||||
|
#define DEFAULT_PROP_ROI_WIDTH 0
|
||||||
|
#define DEFAULT_PROP_ROI_HEIGHT 0
|
||||||
|
|
||||||
/* the capabilities of the inputs and outputs */
|
/* the capabilities of the inputs and outputs */
|
||||||
static GstStaticPadTemplate gst_videolevels_src_template =
|
static GstStaticPadTemplate gst_videolevels_src_template =
|
||||||
@ -224,6 +236,30 @@ gst_videolevels_class_init (GstVideoLevelsClass * klass)
|
|||||||
g_param_spec_uint64 ("interval", "Interval",
|
g_param_spec_uint64 ("interval", "Interval",
|
||||||
"Interval of time between adjustments (in nanoseconds)", 1,
|
"Interval of time between adjustments (in nanoseconds)", 1,
|
||||||
G_MAXUINT64, DEFAULT_PROP_INTERVAL, G_PARAM_READWRITE));
|
G_MAXUINT64, DEFAULT_PROP_INTERVAL, G_PARAM_READWRITE));
|
||||||
|
g_object_class_install_property (gobject_class, PROP_LOWER_SATURATION,
|
||||||
|
g_param_spec_double ("lower-saturation", "Lower saturation",
|
||||||
|
"The fraction of the histogram to saturate on the low end when auto is enabled",
|
||||||
|
0, 0.99, DEFAULT_PROP_LOW_SAT, G_PARAM_READWRITE));
|
||||||
|
g_object_class_install_property (gobject_class, PROP_UPPER_SATURATION,
|
||||||
|
g_param_spec_double ("upper-saturation", "Upper saturation",
|
||||||
|
"The fraction of the histogram to saturate on the upper end when auto is enabled",
|
||||||
|
0, 0.99, DEFAULT_PROP_HIGH_SAT, G_PARAM_READWRITE));
|
||||||
|
g_object_class_install_property (gobject_class, PROP_ROI_X,
|
||||||
|
g_param_spec_int ("roi-x", "ROI x",
|
||||||
|
"Starting column of the ROI when auto is enabled (-1 centers ROI)",
|
||||||
|
-1, G_MAXINT, DEFAULT_PROP_ROI_X, G_PARAM_READWRITE));
|
||||||
|
g_object_class_install_property (gobject_class, PROP_ROI_Y,
|
||||||
|
g_param_spec_int ("roi-y", "ROI y",
|
||||||
|
"Starting row of the ROI when auto is enabled (-1 centers ROI)",
|
||||||
|
-1, G_MAXINT, DEFAULT_PROP_ROI_Y, G_PARAM_READWRITE));
|
||||||
|
g_object_class_install_property (gobject_class, PROP_ROI_WIDTH,
|
||||||
|
g_param_spec_int ("roi-width", "ROI width",
|
||||||
|
"Width of the ROI when auto is enabled (0 uses 1/2 of the image width)",
|
||||||
|
0, G_MAXINT, DEFAULT_PROP_ROI_WIDTH, G_PARAM_READWRITE));
|
||||||
|
g_object_class_install_property (gobject_class, PROP_ROI_HEIGHT,
|
||||||
|
g_param_spec_int ("roi-height", "ROI height",
|
||||||
|
"Height of the ROI when auto is enabled (0 uses 1/2 of the image height)",
|
||||||
|
0, G_MAXINT, DEFAULT_PROP_ROI_HEIGHT, G_PARAM_READWRITE));
|
||||||
|
|
||||||
gst_element_class_add_pad_template (gstelement_class,
|
gst_element_class_add_pad_template (gstelement_class,
|
||||||
gst_static_pad_template_get (&gst_videolevels_sink_template));
|
gst_static_pad_template_get (&gst_videolevels_sink_template));
|
||||||
@ -305,6 +341,30 @@ gst_videolevels_set_property (GObject * object, guint prop_id,
|
|||||||
videolevels->interval = g_value_get_uint64 (value);
|
videolevels->interval = g_value_get_uint64 (value);
|
||||||
videolevels->last_auto_timestamp = GST_CLOCK_TIME_NONE;
|
videolevels->last_auto_timestamp = GST_CLOCK_TIME_NONE;
|
||||||
break;
|
break;
|
||||||
|
case PROP_LOWER_SATURATION:
|
||||||
|
videolevels->lower_pix_sat = g_value_get_double (value);
|
||||||
|
gst_videolevels_calculate_lut (videolevels);
|
||||||
|
break;
|
||||||
|
case PROP_UPPER_SATURATION:
|
||||||
|
videolevels->upper_pix_sat = g_value_get_double (value);
|
||||||
|
gst_videolevels_calculate_lut (videolevels);
|
||||||
|
break;
|
||||||
|
case PROP_ROI_X:
|
||||||
|
videolevels->roi_x = g_value_get_int (value);
|
||||||
|
videolevels->check_roi = TRUE;
|
||||||
|
break;
|
||||||
|
case PROP_ROI_Y:
|
||||||
|
videolevels->roi_y = g_value_get_int (value);
|
||||||
|
videolevels->check_roi = TRUE;
|
||||||
|
break;
|
||||||
|
case PROP_ROI_WIDTH:
|
||||||
|
videolevels->roi_width = g_value_get_int (value);
|
||||||
|
videolevels->check_roi = TRUE;
|
||||||
|
break;
|
||||||
|
case PROP_ROI_HEIGHT:
|
||||||
|
videolevels->roi_height = g_value_get_int (value);
|
||||||
|
videolevels->check_roi = TRUE;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
@ -325,7 +385,7 @@ gst_videolevels_get_property (GObject * object, guint prop_id, GValue * value,
|
|||||||
{
|
{
|
||||||
GstVideoLevels *videolevels = GST_VIDEOLEVELS (object);
|
GstVideoLevels *videolevels = GST_VIDEOLEVELS (object);
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (videolevels, "getting property %s", pspec->name);
|
GST_LOG_OBJECT (videolevels, "getting property %s", pspec->name);
|
||||||
|
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
case PROP_LOWIN:
|
case PROP_LOWIN:
|
||||||
@ -346,6 +406,24 @@ gst_videolevels_get_property (GObject * object, guint prop_id, GValue * value,
|
|||||||
case PROP_INTERVAL:
|
case PROP_INTERVAL:
|
||||||
g_value_set_uint64 (value, videolevels->interval);
|
g_value_set_uint64 (value, videolevels->interval);
|
||||||
break;
|
break;
|
||||||
|
case PROP_LOWER_SATURATION:
|
||||||
|
g_value_set_double (value, videolevels->lower_pix_sat);
|
||||||
|
break;
|
||||||
|
case PROP_UPPER_SATURATION:
|
||||||
|
g_value_set_double (value, videolevels->upper_pix_sat);
|
||||||
|
break;
|
||||||
|
case PROP_ROI_X:
|
||||||
|
g_value_set_int (value, videolevels->roi_x);
|
||||||
|
break;
|
||||||
|
case PROP_ROI_Y:
|
||||||
|
g_value_set_int (value, videolevels->roi_y);
|
||||||
|
break;
|
||||||
|
case PROP_ROI_WIDTH:
|
||||||
|
g_value_set_int (value, videolevels->roi_width);
|
||||||
|
break;
|
||||||
|
case PROP_ROI_HEIGHT:
|
||||||
|
g_value_set_int (value, videolevels->roi_height);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
@ -571,6 +649,8 @@ gst_videolevels_set_caps (GstBaseTransform * trans, GstCaps * incaps,
|
|||||||
|
|
||||||
levels->nbins = MIN (4096, 1 << levels->bpp_in);
|
levels->nbins = MIN (4096, 1 << levels->bpp_in);
|
||||||
|
|
||||||
|
levels->check_roi = TRUE;
|
||||||
|
|
||||||
res = gst_videolevels_calculate_lut (levels);
|
res = gst_videolevels_calculate_lut (levels);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@ -689,13 +769,18 @@ gst_videolevels_reset (GstVideoLevels * videolevels)
|
|||||||
videolevels->upper_input = DEFAULT_PROP_HIGHIN;
|
videolevels->upper_input = DEFAULT_PROP_HIGHIN;
|
||||||
videolevels->lower_output = DEFAULT_PROP_LOWOUT;
|
videolevels->lower_output = DEFAULT_PROP_LOWOUT;
|
||||||
videolevels->upper_output = DEFAULT_PROP_HIGHOUT;
|
videolevels->upper_output = DEFAULT_PROP_HIGHOUT;
|
||||||
|
videolevels->lower_pix_sat = DEFAULT_PROP_LOW_SAT;
|
||||||
|
videolevels->upper_pix_sat = DEFAULT_PROP_HIGH_SAT;
|
||||||
|
videolevels->roi_x = DEFAULT_PROP_ROI_X;
|
||||||
|
videolevels->roi_y = DEFAULT_PROP_ROI_Y;
|
||||||
|
videolevels->roi_width = DEFAULT_PROP_ROI_WIDTH;
|
||||||
|
videolevels->roi_height = DEFAULT_PROP_ROI_HEIGHT;
|
||||||
|
|
||||||
videolevels->auto_adjust = DEFAULT_PROP_AUTO;
|
videolevels->auto_adjust = DEFAULT_PROP_AUTO;
|
||||||
videolevels->interval = DEFAULT_PROP_INTERVAL;
|
videolevels->interval = DEFAULT_PROP_INTERVAL;
|
||||||
videolevels->last_auto_timestamp = GST_CLOCK_TIME_NONE;
|
|
||||||
|
|
||||||
videolevels->lower_pix_sat = 0.01f;
|
videolevels->check_roi = TRUE;
|
||||||
videolevels->upper_pix_sat = 0.01f;
|
videolevels->last_auto_timestamp = GST_CLOCK_TIME_NONE;
|
||||||
|
|
||||||
/* if GRAY8, this will be set in set_info */
|
/* if GRAY8, this will be set in set_info */
|
||||||
videolevels->nbins = 4096;
|
videolevels->nbins = 4096;
|
||||||
@ -805,23 +890,29 @@ gst_videolevels_calculate_histogram (GstVideoLevels * videolevels,
|
|||||||
GST_LOG_OBJECT (videolevels, "Calculating histogram");
|
GST_LOG_OBJECT (videolevels, "Calculating histogram");
|
||||||
if (videolevels->bpp_in > 8) {
|
if (videolevels->bpp_in > 8) {
|
||||||
if (endianness == G_BYTE_ORDER) {
|
if (endianness == G_BYTE_ORDER) {
|
||||||
for (r = 0; r < videolevels->height; r++) {
|
for (r = videolevels->roi_y;
|
||||||
for (c = 0; c < videolevels->width; c++) {
|
r < videolevels->roi_y + videolevels->roi_height; r++) {
|
||||||
|
for (c = videolevels->roi_x;
|
||||||
|
c < videolevels->roi_x + videolevels->roi_width; c++) {
|
||||||
hist[GINT_CLAMP (data[c + r * stride / 2] * factor, 0, nbins - 1)]++;
|
hist[GINT_CLAMP (data[c + r * stride / 2] * factor, 0, nbins - 1)]++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (r = 0; r < videolevels->height; r++) {
|
for (r = videolevels->roi_y;
|
||||||
for (c = 0; c < videolevels->width; c++) {
|
r < videolevels->roi_y + videolevels->roi_height; r++) {
|
||||||
hist[GINT_CLAMP (GUINT16_FROM_BE (data[c +
|
for (c = videolevels->roi_x;
|
||||||
r * stride / 2]) * factor, 0, nbins - 1)]++;
|
c < videolevels->roi_x + videolevels->roi_width; c++) {
|
||||||
|
hist[GINT_CLAMP (GUINT16_FROM_BE (data[c + r * stride / 2]) * factor,
|
||||||
|
0, nbins - 1)]++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
guint8 *data8 = (guint8 *) data;
|
guint8 *data8 = (guint8 *) data;
|
||||||
for (r = 0; r < videolevels->height; r++) {
|
for (r = videolevels->roi_y;
|
||||||
for (c = 0; c < videolevels->width; c++) {
|
r < videolevels->roi_y + videolevels->roi_height; r++) {
|
||||||
|
for (c = videolevels->roi_x;
|
||||||
|
c < videolevels->roi_x + videolevels->roi_width; c++) {
|
||||||
hist[GINT_CLAMP (data8[c + r * stride / 2] * factor, 0, nbins - 1)]++;
|
hist[GINT_CLAMP (data8[c + r * stride / 2] * factor, 0, nbins - 1)]++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -830,6 +921,38 @@ gst_videolevels_calculate_histogram (GstVideoLevels * videolevels,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
gst_videolevels_check_roi (GstVideoLevels * filt)
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (filt, "ROI before check is (%d, %d, %d, %d)", filt->roi_x,
|
||||||
|
filt->roi_y, filt->roi_width, filt->roi_height);
|
||||||
|
|
||||||
|
/* adjust ROI if defaults are set */
|
||||||
|
if (filt->roi_width <= 0) {
|
||||||
|
filt->roi_width = filt->width / 2;
|
||||||
|
}
|
||||||
|
if (filt->roi_height <= 0) {
|
||||||
|
filt->roi_height = filt->height / 2;
|
||||||
|
}
|
||||||
|
if (filt->roi_x <= -1) {
|
||||||
|
filt->roi_x = (filt->width - filt->roi_width) / 2;
|
||||||
|
}
|
||||||
|
if (filt->roi_y <= -1) {
|
||||||
|
filt->roi_y = (filt->height - filt->roi_height) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ensure ROI is within image */
|
||||||
|
filt->roi_x = GINT_CLAMP (filt->roi_x, 0, filt->width - 1);
|
||||||
|
filt->roi_y = GINT_CLAMP (filt->roi_y, 0, filt->height - 1);
|
||||||
|
filt->roi_width = GINT_CLAMP (filt->roi_width, 1, filt->width - filt->roi_x);
|
||||||
|
filt->roi_height =
|
||||||
|
GINT_CLAMP (filt->roi_height, 1, filt->height - filt->roi_y);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (filt, "ROI after check is (%d, %d, %d, %d)", filt->roi_x,
|
||||||
|
filt->roi_y, filt->roi_width, filt->roi_height);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_videolevels_auto_adjust
|
* gst_videolevels_auto_adjust
|
||||||
* @videolevels: #GstVideoLevels
|
* @videolevels: #GstVideoLevels
|
||||||
@ -840,48 +963,54 @@ gst_videolevels_calculate_histogram (GstVideoLevels * videolevels,
|
|||||||
* Returns: TRUE on success
|
* Returns: TRUE on success
|
||||||
*/
|
*/
|
||||||
gboolean
|
gboolean
|
||||||
gst_videolevels_auto_adjust (GstVideoLevels * videolevels, guint16 * data)
|
gst_videolevels_auto_adjust (GstVideoLevels * filt, guint16 * data)
|
||||||
{
|
{
|
||||||
guint npixsat;
|
guint npixsat;
|
||||||
guint sum;
|
guint sum;
|
||||||
gint i;
|
gint i;
|
||||||
gint size;
|
gint pixel_count;
|
||||||
gint minVal = 0;
|
gint minVal = 0;
|
||||||
gint maxVal = (1 << videolevels->bpp_in) - 1;
|
gint maxVal = (1 << filt->bpp_in) - 1;
|
||||||
float factor = maxVal / (videolevels->nbins - 1.0f);
|
float factor = maxVal / (filt->nbins - 1.0f);
|
||||||
gst_videolevels_calculate_histogram (videolevels, data);
|
|
||||||
|
|
||||||
size = videolevels->width * videolevels->height;
|
if (filt->check_roi) {
|
||||||
|
gst_videolevels_check_roi (filt);
|
||||||
|
filt->check_roi = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_videolevels_calculate_histogram (filt, data);
|
||||||
|
|
||||||
|
pixel_count = filt->roi_width * filt->roi_height;
|
||||||
|
|
||||||
/* pixels to saturate on low end */
|
/* pixels to saturate on low end */
|
||||||
npixsat = (guint) (videolevels->lower_pix_sat * size);
|
npixsat = (guint) (filt->lower_pix_sat * pixel_count);
|
||||||
sum = 0;
|
sum = 0;
|
||||||
for (i = 0; i < videolevels->nbins; i++) {
|
for (i = 0; i < filt->nbins; i++) {
|
||||||
sum += videolevels->histogram[i];
|
sum += filt->histogram[i];
|
||||||
if (sum > npixsat) {
|
if (sum > npixsat) {
|
||||||
videolevels->lower_input = (gint) CLAMP (i * factor, minVal, maxVal);
|
filt->lower_input = (gint) CLAMP (i * factor, minVal, maxVal);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* pixels to saturate on high end */
|
/* pixels to saturate on high end */
|
||||||
npixsat = (guint) (videolevels->upper_pix_sat * size);
|
npixsat = (guint) (filt->upper_pix_sat * pixel_count);
|
||||||
sum = 0;
|
sum = 0;
|
||||||
for (i = videolevels->nbins - 1; i >= 0; i--) {
|
for (i = filt->nbins - 1; i >= 0; i--) {
|
||||||
sum += videolevels->histogram[i];
|
sum += filt->histogram[i];
|
||||||
if (sum > npixsat) {
|
if (sum > npixsat) {
|
||||||
videolevels->upper_input = (gint) CLAMP (i * factor, minVal, maxVal);
|
filt->upper_input = (gint) CLAMP (i * factor, minVal, maxVal);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_videolevels_calculate_lut (videolevels);
|
gst_videolevels_calculate_lut (filt);
|
||||||
|
|
||||||
GST_LOG_OBJECT (videolevels, "Contrast stretch with npixsat=%d, (%d, %d)",
|
GST_LOG_OBJECT (filt, "Contrast stretch with npixsat=%d, (%d, %d)",
|
||||||
npixsat, videolevels->lower_input, videolevels->upper_input);
|
npixsat, filt->lower_input, filt->upper_input);
|
||||||
|
|
||||||
g_object_notify_by_pspec (G_OBJECT (videolevels), properties[PROP_LOWIN]);
|
g_object_notify_by_pspec (G_OBJECT (filt), properties[PROP_LOWIN]);
|
||||||
g_object_notify_by_pspec (G_OBJECT (videolevels), properties[PROP_HIGHIN]);
|
g_object_notify_by_pspec (G_OBJECT (filt), properties[PROP_HIGHIN]);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@ -891,6 +1020,7 @@ gst_videolevels_check_passthrough (GstVideoLevels * levels)
|
|||||||
{
|
{
|
||||||
gboolean passthrough;
|
gboolean passthrough;
|
||||||
if (levels->bpp_in == 8 &&
|
if (levels->bpp_in == 8 &&
|
||||||
|
levels->auto_adjust == GST_VIDEOLEVELS_AUTO_OFF &&
|
||||||
levels->lower_input == levels->lower_output &&
|
levels->lower_input == levels->lower_output &&
|
||||||
levels->upper_input == levels->upper_output) {
|
levels->upper_input == levels->upper_output) {
|
||||||
passthrough = TRUE;
|
passthrough = TRUE;
|
||||||
|
|||||||
@ -83,14 +83,19 @@ struct _GstVideoLevels
|
|||||||
gint upper_input;
|
gint upper_input;
|
||||||
gint lower_output;
|
gint lower_output;
|
||||||
gint upper_output;
|
gint upper_output;
|
||||||
|
gfloat lower_pix_sat;
|
||||||
|
gfloat upper_pix_sat;
|
||||||
|
gint roi_x;
|
||||||
|
gint roi_y;
|
||||||
|
gint roi_width;
|
||||||
|
gint roi_height;
|
||||||
|
|
||||||
/* tables */
|
/* tables */
|
||||||
gpointer lookup_table;
|
gpointer lookup_table;
|
||||||
|
|
||||||
GstVideoLevelsAuto auto_adjust;
|
GstVideoLevelsAuto auto_adjust;
|
||||||
guint64 interval;
|
guint64 interval;
|
||||||
gfloat lower_pix_sat;
|
gboolean check_roi;
|
||||||
gfloat upper_pix_sat;
|
|
||||||
gint nbins;
|
gint nbins;
|
||||||
gint * histogram;
|
gint * histogram;
|
||||||
|
|
||||||
|
|||||||
@ -23,7 +23,7 @@ target_link_libraries (${libname}
|
|||||||
${GSTREAMER_LIBRARY}
|
${GSTREAMER_LIBRARY}
|
||||||
${GSTREAMER_BASE_LIBRARY}
|
${GSTREAMER_BASE_LIBRARY}
|
||||||
${GSTREAMER_VIDEO_LIBRARY}
|
${GSTREAMER_VIDEO_LIBRARY}
|
||||||
${GSTREAMER_INCLUDE_DIR}/../../lib/z.lib
|
${ZLIB_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
|
|||||||
@ -42,6 +42,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"
|
||||||
|
|
||||||
@ -56,24 +57,61 @@
|
|||||||
// "C:\\BitFlow SDK 6.20\\Bin64\\BFGTL.cti";
|
// "C:\\BitFlow SDK 6.20\\Bin64\\BFGTL.cti";
|
||||||
// "C:\\Program Files\\Basler\\pylon 5\\Runtime\\x64\\ProducerGEV.cti";
|
// "C:\\Program Files\\Basler\\pylon 5\\Runtime\\x64\\ProducerGEV.cti";
|
||||||
|
|
||||||
// EVT
|
static void
|
||||||
#define GENAPI_WIDTH 0xA000
|
initialize_evt_addresses (GstGenTlProducer * producer)
|
||||||
#define GENAPI_HEIGHT 0xA004
|
{
|
||||||
#define GENAPI_PIXFMT 0xA008
|
memset (producer, 0, sizeof (producer));
|
||||||
#define GENAPI_PAYLOAD_SIZE 0xD008
|
producer->cti_path =
|
||||||
#define GENAPI_ACQMODE 0xB000
|
g_strdup ("C:\\Program Files\\EVT\\eSDK\\bin\\EmergentGenTL.cti");
|
||||||
#define GENAPI_ACQSTART 0xB004
|
producer->acquisition_mode_value = 0;
|
||||||
#define GENAPI_ACQSTOP 0xB008
|
producer->width = 0xA000;
|
||||||
#define CTI_PATH "C:\\Program Files\\EVT\\eSDK\\bin\\EmergentGenTL.cti"
|
producer->height = 0xA004;
|
||||||
|
producer->pixel_format = 0xA008;
|
||||||
|
producer->payload_size = 0xD008;
|
||||||
|
producer->acquisition_mode = 0xB000;
|
||||||
|
producer->acquisition_start = 0xB004;
|
||||||
|
producer->acquisition_stop = 0xB008;
|
||||||
|
producer->tick_frequency_low = 0x0940;
|
||||||
|
producer->tick_frequency_high = 0x093C;
|
||||||
|
producer->timestamp_control_latch = 0x944;
|
||||||
|
producer->timestamp_low = 0x094C;
|
||||||
|
producer->timestamp_high = 0x0948;
|
||||||
|
}
|
||||||
|
|
||||||
// Basler
|
static void
|
||||||
//#define GENAPI_WIDTH 0x30204
|
initialize_basler_addresses (GstGenTlProducer * producer)
|
||||||
//#define GENAPI_HEIGHT 0x30224
|
{
|
||||||
//#define GENAPI_PAYLOAD_SIZE 0x10088
|
memset (producer, 0, sizeof (producer));
|
||||||
//#define GENAPI_ACQMODE 0x40004
|
producer->cti_path =
|
||||||
//#define GENAPI_ACQSTART 0x40024
|
g_strdup
|
||||||
//#define GENAPI_ACQSTOP 0x40044
|
("C:\\Program Files\\Basler\\pylon 5\\Runtime\\x64\\ProducerGEV.cti");
|
||||||
//#define CTI_PATH "C:\\Program Files\\Basler\\pylon 6\\Runtime\\x64\\ProducerGEV.cti"
|
producer->acquisition_mode_value = 2;
|
||||||
|
producer->width = 0x30204;
|
||||||
|
producer->height = 0x30224;
|
||||||
|
producer->pixel_format = 0x30024;
|
||||||
|
producer->payload_size = 0x10088;
|
||||||
|
producer->acquisition_mode = 0x40004;
|
||||||
|
producer->acquisition_start = 0x40024;
|
||||||
|
producer->acquisition_stop = 0x40044;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GST_TYPE_GENTLSRC_PRODUCER (gst_gentlsrc_producer_get_type())
|
||||||
|
static GType
|
||||||
|
gst_gentlsrc_producer_get_type (void)
|
||||||
|
{
|
||||||
|
static GType gentlsrc_producer_type = 0;
|
||||||
|
static const GEnumValue gentlsrc_producer[] = {
|
||||||
|
{GST_GENTLSRC_PRODUCER_BASLER, "Basler producer", "basler"},
|
||||||
|
{GST_GENTLSRC_PRODUCER_EVT, "EVT producer", "evt"},
|
||||||
|
{0, NULL, NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!gentlsrc_producer_type) {
|
||||||
|
gentlsrc_producer_type =
|
||||||
|
g_enum_register_static ("GstGenTlSrcProducer", gentlsrc_producer);
|
||||||
|
}
|
||||||
|
return gentlsrc_producer_type;
|
||||||
|
}
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_STATIC (gst_gentlsrc_debug);
|
GST_DEBUG_CATEGORY_STATIC (gst_gentlsrc_debug);
|
||||||
#define GST_CAT_DEFAULT gst_gentlsrc_debug
|
#define GST_CAT_DEFAULT gst_gentlsrc_debug
|
||||||
@ -96,10 +134,12 @@ static gboolean gst_gentlsrc_unlock_stop (GstBaseSrc * src);
|
|||||||
static GstFlowReturn gst_gentlsrc_create (GstPushSrc * src, GstBuffer ** buf);
|
static GstFlowReturn gst_gentlsrc_create (GstPushSrc * src, GstBuffer ** buf);
|
||||||
|
|
||||||
static gchar *gst_gentlsrc_get_error_string (GstGenTlSrc * src);
|
static gchar *gst_gentlsrc_get_error_string (GstGenTlSrc * src);
|
||||||
|
static void gst_gentlsrc_cleanup_tl (GstGenTlSrc * src);
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
PROP_0,
|
PROP_0,
|
||||||
|
PROP_PRODUCER,
|
||||||
PROP_INTERFACE_INDEX,
|
PROP_INTERFACE_INDEX,
|
||||||
PROP_INTERFACE_ID,
|
PROP_INTERFACE_ID,
|
||||||
PROP_DEVICE_INDEX,
|
PROP_DEVICE_INDEX,
|
||||||
@ -107,9 +147,11 @@ enum
|
|||||||
PROP_STREAM_INDEX,
|
PROP_STREAM_INDEX,
|
||||||
PROP_STREAM_ID,
|
PROP_STREAM_ID,
|
||||||
PROP_NUM_CAPTURE_BUFFERS,
|
PROP_NUM_CAPTURE_BUFFERS,
|
||||||
PROP_TIMEOUT
|
PROP_TIMEOUT,
|
||||||
|
PROP_ATTRIBUTES
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define DEFAULT_PROP_PRODUCER GST_GENTLSRC_PRODUCER_BASLER
|
||||||
#define DEFAULT_PROP_INTERFACE_INDEX 0
|
#define DEFAULT_PROP_INTERFACE_INDEX 0
|
||||||
#define DEFAULT_PROP_INTERFACE_ID ""
|
#define DEFAULT_PROP_INTERFACE_ID ""
|
||||||
#define DEFAULT_PROP_DEVICE_INDEX 0
|
#define DEFAULT_PROP_DEVICE_INDEX 0
|
||||||
@ -118,6 +160,7 @@ enum
|
|||||||
#define DEFAULT_PROP_STREAM_ID ""
|
#define DEFAULT_PROP_STREAM_ID ""
|
||||||
#define DEFAULT_PROP_NUM_CAPTURE_BUFFERS 3
|
#define DEFAULT_PROP_NUM_CAPTURE_BUFFERS 3
|
||||||
#define DEFAULT_PROP_TIMEOUT 1000
|
#define DEFAULT_PROP_TIMEOUT 1000
|
||||||
|
#define DEFAULT_PROP_ATTRIBUTES ""
|
||||||
|
|
||||||
/* pad templates */
|
/* pad templates */
|
||||||
|
|
||||||
@ -140,6 +183,13 @@ static GstStaticPadTemplate gst_gentlsrc_src_template =
|
|||||||
goto error; \
|
goto error; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define HANDLE_GTL_WARNING(arg) \
|
||||||
|
if (ret != GC_ERR_SUCCESS) { \
|
||||||
|
GST_ELEMENT_WARNING (src, LIBRARY, FAILED, \
|
||||||
|
(arg ": %s", gst_gentlsrc_get_error_string (src)), (NULL)); \
|
||||||
|
goto error; \
|
||||||
|
}
|
||||||
|
|
||||||
PGCGetInfo GTL_GCGetInfo;
|
PGCGetInfo GTL_GCGetInfo;
|
||||||
PGCGetLastError GTL_GCGetLastError;
|
PGCGetLastError GTL_GCGetLastError;
|
||||||
PGCInitLib GTL_GCInitLib;
|
PGCInitLib GTL_GCInitLib;
|
||||||
@ -197,7 +247,7 @@ gboolean
|
|||||||
gst_gentlsrc_bind_functions (GstGenTlSrc * src)
|
gst_gentlsrc_bind_functions (GstGenTlSrc * src)
|
||||||
{
|
{
|
||||||
GModule *module;
|
GModule *module;
|
||||||
const char cti_path[] = CTI_PATH;
|
const char *cti_path = src->producer.cti_path;
|
||||||
gboolean ret = TRUE;
|
gboolean ret = TRUE;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (src, "Trying to bind functions from '%s'", cti_path);
|
GST_DEBUG_OBJECT (src, "Trying to bind functions from '%s'", cti_path);
|
||||||
@ -302,6 +352,12 @@ gst_gentlsrc_class_init (GstGenTlSrcClass * klass)
|
|||||||
gstpushsrc_class->create = GST_DEBUG_FUNCPTR (gst_gentlsrc_create);
|
gstpushsrc_class->create = GST_DEBUG_FUNCPTR (gst_gentlsrc_create);
|
||||||
|
|
||||||
/* Install GObject properties */
|
/* Install GObject properties */
|
||||||
|
g_object_class_install_property (gobject_class, PROP_PRODUCER,
|
||||||
|
g_param_spec_enum ("producer", "Producer", "GenTL producer",
|
||||||
|
GST_TYPE_GENTLSRC_PRODUCER, DEFAULT_PROP_PRODUCER,
|
||||||
|
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE |
|
||||||
|
GST_PARAM_MUTABLE_PLAYING));
|
||||||
|
|
||||||
g_object_class_install_property (gobject_class, PROP_INTERFACE_INDEX,
|
g_object_class_install_property (gobject_class, PROP_INTERFACE_INDEX,
|
||||||
g_param_spec_uint ("interface-index", "Interface index",
|
g_param_spec_uint ("interface-index", "Interface index",
|
||||||
"Interface index number, zero-based, overridden by interface-id",
|
"Interface index number, zero-based, overridden by interface-id",
|
||||||
@ -348,12 +404,22 @@ gst_gentlsrc_class_init (GstGenTlSrcClass * klass)
|
|||||||
"Timeout (ms)",
|
"Timeout (ms)",
|
||||||
"Timeout in ms (0 to use default)", 0, G_MAXINT,
|
"Timeout in ms (0 to use default)", 0, G_MAXINT,
|
||||||
DEFAULT_PROP_TIMEOUT, G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE));
|
DEFAULT_PROP_TIMEOUT, G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE));
|
||||||
|
g_object_class_install_property (G_OBJECT_CLASS (klass),
|
||||||
|
PROP_ATTRIBUTES, g_param_spec_string ("attributes",
|
||||||
|
"Attributes", "Attributes to change, comma separated key=value pairs",
|
||||||
|
DEFAULT_PROP_ATTRIBUTES, G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE));
|
||||||
|
|
||||||
|
klass->hTL = NULL;
|
||||||
|
g_mutex_init (&klass->tl_mutex);
|
||||||
|
klass->tl_refcount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
@ -374,10 +440,12 @@ gst_gentlsrc_init (GstGenTlSrc * src)
|
|||||||
gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME);
|
gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME);
|
||||||
|
|
||||||
/* initialize member variables */
|
/* initialize member variables */
|
||||||
|
src->producer_prop = DEFAULT_PROP_PRODUCER;
|
||||||
src->interface_index = DEFAULT_PROP_INTERFACE_INDEX;
|
src->interface_index = DEFAULT_PROP_INTERFACE_INDEX;
|
||||||
src->interface_id = g_strdup (DEFAULT_PROP_INTERFACE_ID);
|
src->interface_id = g_strdup (DEFAULT_PROP_INTERFACE_ID);
|
||||||
src->num_capture_buffers = DEFAULT_PROP_NUM_CAPTURE_BUFFERS;
|
src->num_capture_buffers = DEFAULT_PROP_NUM_CAPTURE_BUFFERS;
|
||||||
src->timeout = DEFAULT_PROP_TIMEOUT;
|
src->timeout = DEFAULT_PROP_TIMEOUT;
|
||||||
|
src->attributes = g_strdup (DEFAULT_PROP_ATTRIBUTES);
|
||||||
|
|
||||||
src->stop_requested = FALSE;
|
src->stop_requested = FALSE;
|
||||||
src->caps = NULL;
|
src->caps = NULL;
|
||||||
@ -399,6 +467,9 @@ gst_gentlsrc_set_property (GObject * object, guint property_id,
|
|||||||
src = GST_GENTL_SRC (object);
|
src = GST_GENTL_SRC (object);
|
||||||
|
|
||||||
switch (property_id) {
|
switch (property_id) {
|
||||||
|
case PROP_PRODUCER:
|
||||||
|
src->producer_prop = g_value_get_enum (value);
|
||||||
|
break;
|
||||||
case PROP_INTERFACE_INDEX:
|
case PROP_INTERFACE_INDEX:
|
||||||
src->interface_index = g_value_get_uint (value);
|
src->interface_index = g_value_get_uint (value);
|
||||||
break;
|
break;
|
||||||
@ -426,6 +497,11 @@ gst_gentlsrc_set_property (GObject * object, guint property_id,
|
|||||||
case PROP_TIMEOUT:
|
case PROP_TIMEOUT:
|
||||||
src->timeout = g_value_get_int (value);
|
src->timeout = g_value_get_int (value);
|
||||||
break;
|
break;
|
||||||
|
case PROP_ATTRIBUTES:
|
||||||
|
if (src->attributes)
|
||||||
|
g_free (src->attributes);
|
||||||
|
src->attributes = g_strdup (g_value_get_string (value));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
break;
|
break;
|
||||||
@ -442,6 +518,9 @@ gst_gentlsrc_get_property (GObject * object, guint property_id,
|
|||||||
src = GST_GENTL_SRC (object);
|
src = GST_GENTL_SRC (object);
|
||||||
|
|
||||||
switch (property_id) {
|
switch (property_id) {
|
||||||
|
case PROP_PRODUCER:
|
||||||
|
g_value_set_enum (value, src->producer_prop);
|
||||||
|
break;
|
||||||
case PROP_INTERFACE_INDEX:
|
case PROP_INTERFACE_INDEX:
|
||||||
g_value_set_uint (value, src->interface_index);
|
g_value_set_uint (value, src->interface_index);
|
||||||
break;
|
break;
|
||||||
@ -466,6 +545,9 @@ gst_gentlsrc_get_property (GObject * object, guint property_id,
|
|||||||
case PROP_TIMEOUT:
|
case PROP_TIMEOUT:
|
||||||
g_value_set_int (value, src->timeout);
|
g_value_set_int (value, src->timeout);
|
||||||
break;
|
break;
|
||||||
|
case PROP_ATTRIBUTES:
|
||||||
|
g_value_set_string (value, src->attributes);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
break;
|
break;
|
||||||
@ -718,7 +800,9 @@ gst_gentlsrc_get_payload_size (GstGenTlSrc * src)
|
|||||||
guint32 val = 0;
|
guint32 val = 0;
|
||||||
size_t datasize = 4;
|
size_t datasize = 4;
|
||||||
// TODO: use node map
|
// TODO: use node map
|
||||||
ret = GTL_GCReadPort (src->hDevPort, GENAPI_PAYLOAD_SIZE, &val, &datasize);
|
ret =
|
||||||
|
GTL_GCReadPort (src->hDevPort, src->producer.payload_size, &val,
|
||||||
|
&datasize);
|
||||||
HANDLE_GTL_ERROR ("Failed to get payload size");
|
HANDLE_GTL_ERROR ("Failed to get payload size");
|
||||||
payload_size = GUINT32_FROM_BE (val);
|
payload_size = GUINT32_FROM_BE (val);
|
||||||
GST_DEBUG_OBJECT (src, "Payload size defined by node map: %d",
|
GST_DEBUG_OBJECT (src, "Payload size defined by node map: %d",
|
||||||
@ -771,28 +855,142 @@ error:
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static guint64
|
||||||
gst_gentlsrc_start (GstBaseSrc * bsrc)
|
gst_gentlsrc_get_gev_tick_frequency (GstGenTlSrc * src)
|
||||||
{
|
{
|
||||||
GstGenTlSrc *src = GST_GENTL_SRC (bsrc);
|
|
||||||
GC_ERROR ret;
|
GC_ERROR ret;
|
||||||
uint32_t i, num_ifaces, num_devs;
|
|
||||||
guint32 width, height, stride;
|
|
||||||
GstVideoInfo vinfo;
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (src, "start");
|
if (!src->producer.tick_frequency_high || !src->producer.tick_frequency_low)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* bind functions from CTI */
|
guint32 freq_low, freq_high;
|
||||||
/* TODO: Enumerate CTI files in env var GENTL_GENTL64_PATH */
|
size_t datasize = 4;
|
||||||
if (!gst_gentlsrc_bind_functions (src)) {
|
ret = GTL_GCReadPort (src->hDevPort, src->producer.tick_frequency_low, &freq_low, &datasize); // GevTimestampTickFrequencyLow
|
||||||
GST_ELEMENT_ERROR (src, LIBRARY, INIT,
|
HANDLE_GTL_ERROR ("Failed to get GevTimestampTickFrequencyLow");
|
||||||
("GenTL CTI could not be opened: %s", g_module_error ()), (NULL));
|
ret = GTL_GCReadPort (src->hDevPort, src->producer.tick_frequency_high, &freq_high, &datasize); // GevTimestampTickFrequencyHigh
|
||||||
return FALSE;
|
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, src->producer.timestamp_control_latch, &val, &datasize); // GevTimestampControlLatch
|
||||||
|
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);
|
||||||
|
|
||||||
|
return ticks;
|
||||||
|
|
||||||
|
error:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (gev_ts != 0) {
|
||||||
|
src->unix_latched_time = unix_ts;
|
||||||
|
src->gentl_latched_ticks = gev_ts;
|
||||||
|
} else {
|
||||||
|
GST_WARNING_OBJECT (src, "Failed to latch GEV time, using old latch value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_gentlsrc_set_attributes (GstGenTlSrc * src)
|
||||||
|
{
|
||||||
|
gchar **pairs;
|
||||||
|
int i;
|
||||||
|
guint32 val;
|
||||||
|
size_t datasize;
|
||||||
|
GC_ERROR ret;
|
||||||
|
|
||||||
|
if (!src->attributes || src->attributes == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (src, "Trying to set following attributes: '%s'",
|
||||||
|
src->attributes);
|
||||||
|
|
||||||
|
pairs = g_strsplit (src->attributes, ";", 0);
|
||||||
|
|
||||||
|
for (i = 0;; i++) {
|
||||||
|
gchar **pair;
|
||||||
|
|
||||||
|
if (!pairs[i])
|
||||||
|
break;
|
||||||
|
|
||||||
|
pair = g_strsplit (pairs[i], "=", 2);
|
||||||
|
|
||||||
|
if (!pair[0] || !pair[1]) {
|
||||||
|
GST_WARNING_OBJECT (src, "Failed to parse attribute/value: '%s'", pair);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
if (ret != GC_ERR_SUCCESS) {
|
||||||
|
GST_WARNING_OBJECT (src, "Failed to set attribute: %s",
|
||||||
|
gst_gentlsrc_get_error_string (src));
|
||||||
|
}
|
||||||
|
g_strfreev (pair);
|
||||||
|
}
|
||||||
|
g_strfreev (pairs);
|
||||||
|
|
||||||
|
if (src->attributes) {
|
||||||
|
g_free (src->attributes);
|
||||||
|
src->attributes = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_gentlsrc_open_tl (GstGenTlSrc * src)
|
||||||
|
{
|
||||||
|
GstGenTlSrcClass *klass = GST_GENTL_SRC_GET_CLASS (src);
|
||||||
|
GC_ERROR ret;
|
||||||
|
uint32_t i, num_ifaces;
|
||||||
|
|
||||||
|
/* open framegrabber if it isn't already opened */
|
||||||
|
if (klass->tl_refcount > 0) {
|
||||||
|
GST_DEBUG_OBJECT (src,
|
||||||
|
"Framegrabber interface already opened in this process, reusing");
|
||||||
|
src->hTL = klass->hTL;
|
||||||
|
klass->tl_refcount++;
|
||||||
|
} else {
|
||||||
/* initialize library and print info */
|
/* initialize library and print info */
|
||||||
ret = GTL_GCInitLib ();
|
ret = GTL_GCInitLib ();
|
||||||
HANDLE_GTL_ERROR ("GenTL Producer library could not be initialized");
|
//HANDLE_GTL_ERROR ("GenTL Producer library could not be initialized");
|
||||||
|
|
||||||
gst_gentl_print_gentl_impl_info (src);
|
gst_gentl_print_gentl_impl_info (src);
|
||||||
|
|
||||||
@ -818,6 +1016,22 @@ gst_gentlsrc_start (GstBaseSrc * bsrc)
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
klass->hTL = src->hTL;
|
||||||
|
klass->tl_refcount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
error:
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_gentlsrc_open_interface (GstGenTlSrc * src)
|
||||||
|
{
|
||||||
|
GstGenTlSrcClass *klass = GST_GENTL_SRC_GET_CLASS (src);
|
||||||
|
GC_ERROR ret;
|
||||||
|
|
||||||
if (!src->interface_id || src->interface_id[0] == 0) {
|
if (!src->interface_id || src->interface_id[0] == 0) {
|
||||||
size_t id_size;
|
size_t id_size;
|
||||||
GST_DEBUG_OBJECT (src, "Trying to find interface ID at index %d",
|
GST_DEBUG_OBJECT (src, "Trying to find interface ID at index %d",
|
||||||
@ -839,6 +1053,54 @@ gst_gentlsrc_start (GstBaseSrc * bsrc)
|
|||||||
ret = GTL_TLOpenInterface (src->hTL, src->interface_id, &src->hIF);
|
ret = GTL_TLOpenInterface (src->hTL, src->interface_id, &src->hIF);
|
||||||
HANDLE_GTL_ERROR ("Interface module failed to open");
|
HANDLE_GTL_ERROR ("Interface module failed to open");
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
error:
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_gentlsrc_start (GstBaseSrc * bsrc)
|
||||||
|
{
|
||||||
|
GstGenTlSrc *src = GST_GENTL_SRC (bsrc);
|
||||||
|
GstGenTlSrcClass *klass = GST_GENTL_SRC_GET_CLASS (src);
|
||||||
|
GC_ERROR ret;
|
||||||
|
uint32_t i, num_devs;
|
||||||
|
guint32 width, height, stride;
|
||||||
|
GstVideoInfo vinfo;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (src, "start");
|
||||||
|
|
||||||
|
if (src->producer_prop == GST_GENTLSRC_PRODUCER_BASLER) {
|
||||||
|
initialize_basler_addresses (&src->producer);
|
||||||
|
} else if (src->producer_prop == GST_GENTLSRC_PRODUCER_EVT) {
|
||||||
|
initialize_evt_addresses (&src->producer);
|
||||||
|
} else {
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* bind functions from CTI */
|
||||||
|
/* TODO: Enumerate CTI files in env var GENTL_GENTL64_PATH */
|
||||||
|
if (!gst_gentlsrc_bind_functions (src)) {
|
||||||
|
GST_ELEMENT_ERROR (src, LIBRARY, INIT,
|
||||||
|
("GenTL CTI could not be opened: %s", g_module_error ()), (NULL));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_mutex_lock (&klass->tl_mutex);
|
||||||
|
|
||||||
|
if (!gst_gentlsrc_open_tl (src)) {
|
||||||
|
g_mutex_unlock (&klass->tl_mutex);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gst_gentlsrc_open_interface (src)) {
|
||||||
|
g_mutex_unlock (&klass->tl_mutex);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_mutex_unlock (&klass->tl_mutex);
|
||||||
|
|
||||||
ret = GTL_IFUpdateDeviceList (src->hIF, NULL, src->timeout);
|
ret = GTL_IFUpdateDeviceList (src->hIF, NULL, src->timeout);
|
||||||
HANDLE_GTL_ERROR ("Failed to update device list within timeout");
|
HANDLE_GTL_ERROR ("Failed to update device list within timeout");
|
||||||
|
|
||||||
@ -927,7 +1189,7 @@ gst_gentlsrc_start (GstBaseSrc * bsrc)
|
|||||||
GST_ELEMENT_ERROR (src, RESOURCE, TOO_LAZY,
|
GST_ELEMENT_ERROR (src, RESOURCE, TOO_LAZY,
|
||||||
("file url not supported yet"), (NULL));
|
("file url not supported yet"), (NULL));
|
||||||
goto error;
|
goto error;
|
||||||
} else if (g_str_has_prefix (url, "local")) {
|
} else if (g_ascii_strncasecmp (url, "local", 5) == 0) {
|
||||||
GError *err = NULL;
|
GError *err = NULL;
|
||||||
GMatchInfo *matchInfo;
|
GMatchInfo *matchInfo;
|
||||||
GRegex *regex;
|
GRegex *regex;
|
||||||
@ -938,7 +1200,7 @@ gst_gentlsrc_start (GstBaseSrc * bsrc)
|
|||||||
|
|
||||||
regex =
|
regex =
|
||||||
g_regex_new
|
g_regex_new
|
||||||
("local:(?:///)?(?<filename>[^;]+);(?<address>[^;]+);(?<length>[^?]+)(?:[?]SchemaVersion=([^&]+))?",
|
("[lL]ocal:(?:///)?(?<filename>[^;]+);(?<address>[^;]+);(?<length>[^?]+)(?:[?]SchemaVersion=([^&]+))?",
|
||||||
(GRegexCompileFlags) 0, (GRegexMatchFlags) 0, &err);
|
(GRegexCompileFlags) 0, (GRegexMatchFlags) 0, &err);
|
||||||
if (!regex) {
|
if (!regex) {
|
||||||
goto error;
|
goto error;
|
||||||
@ -967,6 +1229,7 @@ gst_gentlsrc_start (GstBaseSrc * bsrc)
|
|||||||
gchar *xml;
|
gchar *xml;
|
||||||
|
|
||||||
zipfilepath = g_build_filename (g_get_tmp_dir (), filename, NULL);
|
zipfilepath = g_build_filename (g_get_tmp_dir (), filename, NULL);
|
||||||
|
GST_DEBUG_OBJECT (src, "Writing XML ZIP file to %s", zipfilepath);
|
||||||
if (!g_file_set_contents (zipfilepath, buf, len, &err)) {
|
if (!g_file_set_contents (zipfilepath, buf, len, &err)) {
|
||||||
GST_ELEMENT_ERROR (src, RESOURCE, TOO_LAZY,
|
GST_ELEMENT_ERROR (src, RESOURCE, TOO_LAZY,
|
||||||
("Failed to write zipped XML to %s", zipfilepath), (NULL));
|
("Failed to write zipped XML to %s", zipfilepath), (NULL));
|
||||||
@ -1012,6 +1275,7 @@ gst_gentlsrc_start (GstBaseSrc * bsrc)
|
|||||||
g_free (zipfilepath);
|
g_free (zipfilepath);
|
||||||
|
|
||||||
zipfilepath = g_build_filename (g_get_tmp_dir (), xmlfilename, NULL);
|
zipfilepath = g_build_filename (g_get_tmp_dir (), xmlfilename, NULL);
|
||||||
|
GST_DEBUG_OBJECT (src, "Writing XML file to %s", zipfilepath);
|
||||||
g_file_set_contents (zipfilepath, xml, fileinfo.uncompressed_size,
|
g_file_set_contents (zipfilepath, xml, fileinfo.uncompressed_size,
|
||||||
&err);
|
&err);
|
||||||
g_free (zipfilepath);
|
g_free (zipfilepath);
|
||||||
@ -1044,24 +1308,40 @@ 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
|
// TODO: use GenTl node map for this
|
||||||
guint32 val = 0;
|
guint32 val = 0;
|
||||||
size_t datasize = 4;
|
size_t datasize = 4;
|
||||||
ret = GTL_GCReadPort (src->hDevPort, GENAPI_WIDTH, &val, &datasize);
|
ret = GTL_GCReadPort (src->hDevPort, src->producer.width, &val, &datasize);
|
||||||
HANDLE_GTL_ERROR ("Failed to get width");
|
HANDLE_GTL_ERROR ("Failed to get width");
|
||||||
width = GUINT32_FROM_BE (val);
|
width = GUINT32_FROM_BE (val);
|
||||||
ret = GTL_GCReadPort (src->hDevPort, GENAPI_HEIGHT, &val, &datasize);
|
ret = GTL_GCReadPort (src->hDevPort, src->producer.height, &val, &datasize);
|
||||||
HANDLE_GTL_ERROR ("Failed to get height");
|
HANDLE_GTL_ERROR ("Failed to get height");
|
||||||
height = GUINT32_FROM_BE (val);
|
height = GUINT32_FROM_BE (val);
|
||||||
GST_DEBUG_OBJECT (src, "Width and height %dx%d", width, height);
|
GST_DEBUG_OBJECT (src, "Width and height %dx%d", width, height);
|
||||||
|
|
||||||
ret = GTL_GCReadPort (src->hDevPort, GENAPI_PIXFMT, &val, &datasize);
|
ret =
|
||||||
|
GTL_GCReadPort (src->hDevPort, src->producer.pixel_format, &val,
|
||||||
|
&datasize);
|
||||||
HANDLE_GTL_ERROR ("Failed to get height");
|
HANDLE_GTL_ERROR ("Failed to get height");
|
||||||
const char *genicam_pixfmt;
|
const char *genicam_pixfmt;
|
||||||
guint32 pixfmt_enum = GUINT32_FROM_BE (val);
|
guint32 pixfmt_enum = GUINT32_FROM_BE (val);
|
||||||
switch (pixfmt_enum) {
|
switch (pixfmt_enum) {
|
||||||
|
case 0x1: // Basler Ace
|
||||||
|
case 0x01080001:
|
||||||
|
genicam_pixfmt = "Mono8";
|
||||||
|
break;
|
||||||
|
case 0x5: // Basler Ace
|
||||||
|
case 0x01100005:
|
||||||
|
genicam_pixfmt = "Mono12";
|
||||||
|
break;
|
||||||
|
case 0x1100010: // Basler Ace
|
||||||
|
genicam_pixfmt = "BayerGR12";
|
||||||
|
break;
|
||||||
case 0x01080009:
|
case 0x01080009:
|
||||||
genicam_pixfmt = "BayerRG8";
|
genicam_pixfmt = "BayerRG8";
|
||||||
break;
|
break;
|
||||||
@ -1132,15 +1412,19 @@ gst_gentlsrc_start (GstBaseSrc * bsrc)
|
|||||||
/* set AcquisitionMode to Continuous */
|
/* set AcquisitionMode to Continuous */
|
||||||
// TODO: "Continuous" value can have different integer values, we need
|
// TODO: "Continuous" value can have different integer values, we need
|
||||||
// to look it up in the node map (EVT is 0, Basler is 2)
|
// to look it up in the node map (EVT is 0, Basler is 2)
|
||||||
val = GUINT32_TO_BE (0);
|
val = GUINT32_TO_BE (src->producer.acquisition_mode_value);
|
||||||
datasize = sizeof (val);
|
datasize = sizeof (val);
|
||||||
ret = GTL_GCWritePort (src->hDevPort, GENAPI_ACQMODE, &val, &datasize);
|
ret =
|
||||||
|
GTL_GCWritePort (src->hDevPort, src->producer.acquisition_mode, &val,
|
||||||
|
&datasize);
|
||||||
HANDLE_GTL_ERROR ("Failed to start device acquisition");
|
HANDLE_GTL_ERROR ("Failed to start device acquisition");
|
||||||
|
|
||||||
/* send AcquisitionStart command */
|
/* send AcquisitionStart command */
|
||||||
val = GUINT32_TO_BE (1);
|
val = GUINT32_TO_BE (1);
|
||||||
datasize = sizeof (val);
|
datasize = sizeof (val);
|
||||||
ret = GTL_GCWritePort (src->hDevPort, GENAPI_ACQSTART, &val, &datasize);
|
ret =
|
||||||
|
GTL_GCWritePort (src->hDevPort, src->producer.acquisition_start, &val,
|
||||||
|
&datasize);
|
||||||
HANDLE_GTL_ERROR ("Failed to start device acquisition");
|
HANDLE_GTL_ERROR ("Failed to start device acquisition");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1169,14 +1453,31 @@ error:
|
|||||||
src->hIF = NULL;
|
src->hIF = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gst_gentlsrc_cleanup_tl (src);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_gentlsrc_cleanup_tl (GstGenTlSrc * src)
|
||||||
|
{
|
||||||
|
GstGenTlSrcClass *klass = GST_GENTL_SRC_GET_CLASS (src);
|
||||||
if (src->hTL) {
|
if (src->hTL) {
|
||||||
|
g_mutex_lock (&klass->tl_mutex);
|
||||||
|
GST_DEBUG_OBJECT (src, "Framegrabber open with refcount=%d",
|
||||||
|
klass->tl_refcount);
|
||||||
|
klass->tl_refcount--;
|
||||||
|
if (klass->tl_refcount == 0) {
|
||||||
|
GST_DEBUG_OBJECT (src, "Framegrabber ref dropped to 0, closing");
|
||||||
GTL_TLClose (src->hTL);
|
GTL_TLClose (src->hTL);
|
||||||
src->hTL = NULL;
|
src->hTL = NULL;
|
||||||
}
|
}
|
||||||
|
g_mutex_unlock (&klass->tl_mutex);
|
||||||
|
src->hTL = NULL;
|
||||||
|
|
||||||
GTL_GCCloseLib ();
|
// don't close library, otherwise we can't reopen in the same process
|
||||||
|
//GTL_GCCloseLib ();
|
||||||
return FALSE;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@ -1191,7 +1492,8 @@ gst_gentlsrc_stop (GstBaseSrc * bsrc)
|
|||||||
guint32 val = GUINT32_TO_BE (1);
|
guint32 val = GUINT32_TO_BE (1);
|
||||||
gsize datasize = sizeof (val);
|
gsize datasize = sizeof (val);
|
||||||
GC_ERROR ret =
|
GC_ERROR ret =
|
||||||
GTL_GCWritePort (src->hDevPort, GENAPI_ACQSTOP, &val, &datasize);
|
GTL_GCWritePort (src->hDevPort, src->producer.acquisition_stop, &val,
|
||||||
|
&datasize);
|
||||||
|
|
||||||
GTL_DSStopAcquisition (src->hDS, ACQ_STOP_FLAGS_DEFAULT);
|
GTL_DSStopAcquisition (src->hDS, ACQ_STOP_FLAGS_DEFAULT);
|
||||||
GTL_DSFlushQueue (src->hDS, ACQ_QUEUE_INPUT_TO_OUTPUT);
|
GTL_DSFlushQueue (src->hDS, ACQ_QUEUE_INPUT_TO_OUTPUT);
|
||||||
@ -1210,12 +1512,7 @@ gst_gentlsrc_stop (GstBaseSrc * bsrc)
|
|||||||
src->hIF = NULL;
|
src->hIF = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (src->hTL) {
|
gst_gentlsrc_cleanup_tl (src);
|
||||||
GTL_TLClose (src->hTL);
|
|
||||||
src->hTL = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
GTL_GCCloseLib ();
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (src, "Closed data stream, device, interface, and library");
|
GST_DEBUG_OBJECT (src, "Closed data stream, device, interface, and library");
|
||||||
|
|
||||||
@ -1298,6 +1595,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,7 +1610,12 @@ 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;
|
||||||
|
|
||||||
|
|
||||||
|
/* sometimes we get non-image payloads, try several times for an image */
|
||||||
|
for (int i = 0; i < 5; ++i) {
|
||||||
datasize = sizeof (new_buffer_data);
|
datasize = sizeof (new_buffer_data);
|
||||||
ret =
|
ret =
|
||||||
GTL_EventGetData (src->hNewBufferEvent, &new_buffer_data, &datasize,
|
GTL_EventGetData (src->hNewBufferEvent, &new_buffer_data, &datasize,
|
||||||
@ -1323,6 +1627,26 @@ gst_gentlsrc_get_buffer (GstGenTlSrc * src)
|
|||||||
GTL_DSGetBufferInfo (src->hDS, new_buffer_data.BufferHandle,
|
GTL_DSGetBufferInfo (src->hDS, new_buffer_data.BufferHandle,
|
||||||
BUFFER_INFO_PAYLOADTYPE, &datatype, &payload_type, &datasize);
|
BUFFER_INFO_PAYLOADTYPE, &datatype, &payload_type, &datasize);
|
||||||
HANDLE_GTL_ERROR ("Failed to get payload type");
|
HANDLE_GTL_ERROR ("Failed to get payload type");
|
||||||
|
if (payload_type != PAYLOAD_TYPE_IMAGE) {
|
||||||
|
GST_WARNING_OBJECT (src, "Non-image payload type, trying again");
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (payload_type != PAYLOAD_TYPE_IMAGE) {
|
||||||
|
GST_ELEMENT_ERROR (src, STREAM, TOO_LAZY,
|
||||||
|
("Unsupported payload type: %d", payload_type), (NULL));
|
||||||
|
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 =
|
||||||
@ -1335,6 +1659,9 @@ gst_gentlsrc_get_buffer (GstGenTlSrc * src)
|
|||||||
GTL_DSGetBufferInfo (src->hDS, new_buffer_data.BufferHandle,
|
GTL_DSGetBufferInfo (src->hDS, new_buffer_data.BufferHandle,
|
||||||
BUFFER_INFO_IS_INCOMPLETE, &datatype, &buffer_is_incomplete, &datasize);
|
BUFFER_INFO_IS_INCOMPLETE, &datatype, &buffer_is_incomplete, &datasize);
|
||||||
HANDLE_GTL_ERROR ("Failed to get complete flag");
|
HANDLE_GTL_ERROR ("Failed to get complete flag");
|
||||||
|
if (buffer_is_incomplete) {
|
||||||
|
GST_WARNING_OBJECT (src, "Buffer is incomplete");
|
||||||
|
}
|
||||||
|
|
||||||
datasize = sizeof (buffer_size);
|
datasize = sizeof (buffer_size);
|
||||||
ret =
|
ret =
|
||||||
@ -1348,11 +1675,6 @@ gst_gentlsrc_get_buffer (GstGenTlSrc * src)
|
|||||||
BUFFER_INFO_BASE, &datatype, &data_ptr, &datasize);
|
BUFFER_INFO_BASE, &datatype, &data_ptr, &datasize);
|
||||||
HANDLE_GTL_ERROR ("Failed to get buffer pointer");
|
HANDLE_GTL_ERROR ("Failed to get buffer pointer");
|
||||||
|
|
||||||
if (payload_type != PAYLOAD_TYPE_IMAGE) {
|
|
||||||
GST_ELEMENT_ERROR (src, STREAM, TOO_LAZY,
|
|
||||||
("Unsupported payload type: %d", payload_type), (NULL));
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
// TODO: what if strides aren't same?
|
// TODO: what if strides aren't same?
|
||||||
|
|
||||||
buf = gst_buffer_new_allocate (NULL, buffer_size, NULL);
|
buf = gst_buffer_new_allocate (NULL, buffer_size, NULL);
|
||||||
@ -1361,7 +1683,7 @@ gst_gentlsrc_get_buffer (GstGenTlSrc * src)
|
|||||||
("Failed to allocate buffer"), (NULL));
|
("Failed to allocate buffer"), (NULL));
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
// TODO: try to eliminate this memcpy by using gst_buffer_new_wrapped_full
|
||||||
gst_buffer_map (buf, &minfo, GST_MAP_WRITE);
|
gst_buffer_map (buf, &minfo, GST_MAP_WRITE);
|
||||||
orc_memcpy (minfo.data, (void *) data_ptr, minfo.size);
|
orc_memcpy (minfo.data, (void *) data_ptr, minfo.size);
|
||||||
gst_buffer_unmap (buf, &minfo);
|
gst_buffer_unmap (buf, &minfo);
|
||||||
@ -1369,6 +1691,26 @@ 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");
|
||||||
|
|
||||||
|
GST_BUFFER_OFFSET (buf) = frame_id;
|
||||||
|
|
||||||
|
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:
|
||||||
@ -1388,6 +1730,8 @@ gst_gentlsrc_create (GstPushSrc * psrc, GstBuffer ** buf)
|
|||||||
|
|
||||||
GST_LOG_OBJECT (src, "create");
|
GST_LOG_OBJECT (src, "create");
|
||||||
|
|
||||||
|
gst_gentlsrc_set_attributes (src);
|
||||||
|
|
||||||
*buf = gst_gentlsrc_get_buffer (src);
|
*buf = gst_gentlsrc_get_buffer (src);
|
||||||
if (!*buf) {
|
if (!*buf) {
|
||||||
return GST_FLOW_ERROR;
|
return GST_FLOW_ERROR;
|
||||||
@ -1426,7 +1770,6 @@ gst_gentlsrc_create (GstPushSrc * psrc, GstBuffer ** buf)
|
|||||||
GST_BUFFER_TIMESTAMP (*buf) =
|
GST_BUFFER_TIMESTAMP (*buf) =
|
||||||
GST_CLOCK_DIFF (gst_element_get_base_time (GST_ELEMENT (src)),
|
GST_CLOCK_DIFF (gst_element_get_base_time (GST_ELEMENT (src)),
|
||||||
clock_time);
|
clock_time);
|
||||||
//GST_BUFFER_OFFSET (*buf) = circ_handle.FrameCount - 1;
|
|
||||||
|
|
||||||
if (src->stop_requested) {
|
if (src->stop_requested) {
|
||||||
if (*buf != NULL) {
|
if (*buf != NULL) {
|
||||||
|
|||||||
@ -34,10 +34,46 @@ G_BEGIN_DECLS
|
|||||||
#define GST_GENTL_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GENTL_SRC,GstGenTlSrcClass))
|
#define GST_GENTL_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GENTL_SRC,GstGenTlSrcClass))
|
||||||
#define GST_IS_GENTL_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GENTL_SRC))
|
#define GST_IS_GENTL_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GENTL_SRC))
|
||||||
#define GST_IS_GENTL_SRC_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GENTL_SRC))
|
#define GST_IS_GENTL_SRC_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GENTL_SRC))
|
||||||
|
#define GST_GENTL_SRC_GET_CLASS(klass) \
|
||||||
|
(G_TYPE_INSTANCE_GET_CLASS ((klass), GST_TYPE_GENTL_SRC, GstGenTlSrcClass))
|
||||||
|
|
||||||
typedef struct _GstGenTlSrc GstGenTlSrc;
|
typedef struct _GstGenTlSrc GstGenTlSrc;
|
||||||
typedef struct _GstGenTlSrcClass GstGenTlSrcClass;
|
typedef struct _GstGenTlSrcClass GstGenTlSrcClass;
|
||||||
|
|
||||||
|
typedef struct _GstGenTlProducer GstGenTlProducer;
|
||||||
|
struct _GstGenTlProducer
|
||||||
|
{
|
||||||
|
gchar* cti_path;
|
||||||
|
guint32 acquisition_mode_value;
|
||||||
|
|
||||||
|
guint64 width;
|
||||||
|
guint64 height;
|
||||||
|
guint64 pixel_format;
|
||||||
|
guint64 payload_size;
|
||||||
|
guint64 acquisition_mode;
|
||||||
|
guint64 acquisition_start;
|
||||||
|
guint64 acquisition_stop;
|
||||||
|
guint64 tick_frequency_low;
|
||||||
|
guint64 tick_frequency_high;
|
||||||
|
guint64 timestamp_control_latch;
|
||||||
|
guint64 timestamp_low;
|
||||||
|
guint64 timestamp_high;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GstGenTlSrcProducer:
|
||||||
|
* @GST_GENTLSRC_PRODUCER_BASLER: Basler producer
|
||||||
|
* @GST_GENTLSRC_PRODUCER_EVT: EVT producer
|
||||||
|
*
|
||||||
|
* Producer to use.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
GST_GENTLSRC_PRODUCER_BASLER,
|
||||||
|
GST_GENTLSRC_PRODUCER_EVT,
|
||||||
|
} GstGenTlSrcProducer;
|
||||||
|
|
||||||
|
|
||||||
struct _GstGenTlSrc
|
struct _GstGenTlSrc
|
||||||
{
|
{
|
||||||
GstPushSrc base_gentlsrc;
|
GstPushSrc base_gentlsrc;
|
||||||
@ -50,8 +86,10 @@ struct _GstGenTlSrc
|
|||||||
PORT_HANDLE hDevPort;
|
PORT_HANDLE hDevPort;
|
||||||
EVENT_HANDLE hNewBufferEvent;
|
EVENT_HANDLE hNewBufferEvent;
|
||||||
char error_string[MAX_ERROR_STRING_LEN];
|
char error_string[MAX_ERROR_STRING_LEN];
|
||||||
|
GstGenTlProducer producer;
|
||||||
|
|
||||||
/* properties */
|
/* properties */
|
||||||
|
GstGenTlSrcProducer producer_prop;
|
||||||
guint interface_index;
|
guint interface_index;
|
||||||
gchar *interface_id;
|
gchar *interface_id;
|
||||||
guint device_index;
|
guint device_index;
|
||||||
@ -60,11 +98,16 @@ struct _GstGenTlSrc
|
|||||||
gchar *stream_id;
|
gchar *stream_id;
|
||||||
guint num_capture_buffers;
|
guint num_capture_buffers;
|
||||||
gint timeout;
|
gint timeout;
|
||||||
|
gchar* attributes;
|
||||||
|
|
||||||
GstClockTime acq_start_time;
|
GstClockTime acq_start_time;
|
||||||
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;
|
||||||
@ -75,6 +118,9 @@ struct _GstGenTlSrc
|
|||||||
struct _GstGenTlSrcClass
|
struct _GstGenTlSrcClass
|
||||||
{
|
{
|
||||||
GstPushSrcClass base_gentlsrc_class;
|
GstPushSrcClass base_gentlsrc_class;
|
||||||
|
TL_HANDLE hTL;
|
||||||
|
GMutex tl_mutex;
|
||||||
|
guint tl_refcount;
|
||||||
};
|
};
|
||||||
|
|
||||||
GType gst_gentlsrc_get_type (void);
|
GType gst_gentlsrc_get_type (void);
|
||||||
|
|||||||
@ -799,11 +799,11 @@ gst_kayasrc_stream_buffer_callback (STREAM_BUFFER_HANDLE buffer_handle,
|
|||||||
GST_BUFFER_OFFSET (buf) = src->frame_count;
|
GST_BUFFER_OFFSET (buf) = src->frame_count;
|
||||||
src->frame_count++;
|
src->frame_count++;
|
||||||
|
|
||||||
if (src->kaya_base == GST_CLOCK_TIME_NONE) {
|
//if (src->kaya_base == GST_CLOCK_TIME_NONE) {
|
||||||
/* assume delay between these two calls is negligible */
|
// assume delay between these two calls is negligible
|
||||||
src->kaya_base = KYFG_GetGrabberValueInt (src->cam_handle, "Timestamp");
|
src->kaya_base = KYFG_GetGrabberValueInt (src->cam_handle, "Timestamp");
|
||||||
src->unix_base = g_get_real_time () * 1000;
|
src->unix_base = g_get_real_time () * 1000;
|
||||||
}
|
//}
|
||||||
#if GST_CHECK_VERSION(1,14,0)
|
#if GST_CHECK_VERSION(1,14,0)
|
||||||
{
|
{
|
||||||
GstClockTime unix_ts = src->unix_base + (timestamp - src->kaya_base);
|
GstClockTime unix_ts = src->unix_base + (timestamp - src->kaya_base);
|
||||||
|
|||||||
@ -2,6 +2,10 @@ if (ENABLE_KLV)
|
|||||||
add_definitions(-DGST_PLUGINS_VISION_ENABLE_KLV)
|
add_definitions(-DGST_PLUGINS_VISION_ENABLE_KLV)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
if (UNIX)
|
||||||
|
add_definitions(-D_UNIX_)
|
||||||
|
endif ()
|
||||||
|
|
||||||
add_definitions(-D_XKEYCHECK_H)
|
add_definitions(-D_XKEYCHECK_H)
|
||||||
|
|
||||||
set (SOURCES
|
set (SOURCES
|
||||||
@ -42,6 +46,7 @@ set (LIBRARIES
|
|||||||
${GSTREAMER_LIBRARY}
|
${GSTREAMER_LIBRARY}
|
||||||
${GSTREAMER_BASE_LIBRARY}
|
${GSTREAMER_BASE_LIBRARY}
|
||||||
${GSTREAMER_VIDEO_LIBRARY}
|
${GSTREAMER_VIDEO_LIBRARY}
|
||||||
|
${Pleora_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
|
||||||
if (ENABLE_KLV)
|
if (ENABLE_KLV)
|
||||||
|
|||||||
@ -255,9 +255,6 @@ gst_pleorasink_init (GstPleoraSink * sink)
|
|||||||
sink->source = new GstStreamingChannelSource ();
|
sink->source = new GstStreamingChannelSource ();
|
||||||
sink->source->SetSink (sink);
|
sink->source->SetSink (sink);
|
||||||
sink->device = new PvSoftDeviceGEV ();
|
sink->device = new PvSoftDeviceGEV ();
|
||||||
|
|
||||||
g_mutex_init (&sink->mutex);
|
|
||||||
g_cond_init (&sink->cond);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -396,9 +393,6 @@ gst_pleorasink_dispose (GObject * object)
|
|||||||
sink->source = NULL;
|
sink->source = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_mutex_clear (&sink->mutex);
|
|
||||||
g_cond_clear (&sink->cond);
|
|
||||||
|
|
||||||
g_free (sink->address);
|
g_free (sink->address);
|
||||||
|
|
||||||
G_OBJECT_CLASS (gst_pleorasink_parent_class)->dispose (object);
|
G_OBJECT_CLASS (gst_pleorasink_parent_class)->dispose (object);
|
||||||
@ -695,7 +689,6 @@ GstFlowReturn
|
|||||||
gst_pleorasink_render (GstBaseSink * basesink, GstBuffer * buffer)
|
gst_pleorasink_render (GstBaseSink * basesink, GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
GstPleoraSink *sink = GST_PLEORASINK (basesink);
|
GstPleoraSink *sink = GST_PLEORASINK (basesink);
|
||||||
GST_LOG_OBJECT (sink, "Rendering buffer");
|
|
||||||
|
|
||||||
if (sink->stop_requested) {
|
if (sink->stop_requested) {
|
||||||
GST_DEBUG_OBJECT (sink, "stop requested, flushing");
|
GST_DEBUG_OBJECT (sink, "stop requested, flushing");
|
||||||
@ -713,10 +706,7 @@ gst_pleorasink_unlock (GstBaseSink * basesink)
|
|||||||
{
|
{
|
||||||
GstPleoraSink *sink = GST_PLEORASINK (basesink);
|
GstPleoraSink *sink = GST_PLEORASINK (basesink);
|
||||||
|
|
||||||
g_mutex_lock (&sink->mutex);
|
|
||||||
sink->stop_requested = TRUE;
|
sink->stop_requested = TRUE;
|
||||||
g_cond_signal (&sink->cond);
|
|
||||||
g_mutex_unlock (&sink->mutex);
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,8 +62,6 @@ struct _GstPleoraSink
|
|||||||
gboolean camera_connected;
|
gboolean camera_connected;
|
||||||
GstVideoInfo vinfo;
|
GstVideoInfo vinfo;
|
||||||
|
|
||||||
GMutex mutex;
|
|
||||||
GCond cond;
|
|
||||||
gboolean acquisition_started;
|
gboolean acquisition_started;
|
||||||
gboolean stop_requested;
|
gboolean stop_requested;
|
||||||
|
|
||||||
|
|||||||
@ -29,10 +29,24 @@ GST_DEBUG_CATEGORY_EXTERN (pleorasink_debug);
|
|||||||
#define KLV_CHUNKID 0xFEDC
|
#define KLV_CHUNKID 0xFEDC
|
||||||
|
|
||||||
GstStreamingChannelSource::GstStreamingChannelSource ()
|
GstStreamingChannelSource::GstStreamingChannelSource ()
|
||||||
: mAcquisitionBuffer (NULL), mBufferCount (0), mBufferValid (FALSE),
|
: mBufferCount (0),
|
||||||
mChunkModeActive(TRUE), mChunkKlvEnabled(TRUE), mKlvChunkSize(0)
|
mChunkModeActive(TRUE), mChunkKlvEnabled(TRUE), mKlvChunkSize(0),
|
||||||
|
mStreamingStarted(false)
|
||||||
{
|
{
|
||||||
|
mInputQueue = g_async_queue_new ();
|
||||||
|
mOutputQueue = g_async_queue_new ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GstStreamingChannelSource::OnStreamingStart()
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT(mSink, "Controller has requested streaming start");
|
||||||
|
mStreamingStarted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GstStreamingChannelSource::OnStreamingStop()
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT(mSink, "Controller has requested streaming stop");
|
||||||
|
mStreamingStarted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -128,8 +142,12 @@ gboolean GstStreamingChannelSource::GetKlvEnabled()
|
|||||||
PvBuffer * GstStreamingChannelSource::AllocBuffer ()
|
PvBuffer * GstStreamingChannelSource::AllocBuffer ()
|
||||||
{
|
{
|
||||||
if (mBufferCount < mSink->num_internal_buffers) {
|
if (mBufferCount < mSink->num_internal_buffers) {
|
||||||
|
GST_LOG_OBJECT(mSink, "Allocating buffer #%d", mBufferCount);
|
||||||
|
PvBuffer *buf = new PvBuffer;
|
||||||
|
buf->SetID(mBufferCount);
|
||||||
mBufferCount++;
|
mBufferCount++;
|
||||||
return new PvBuffer;
|
|
||||||
|
return buf;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -142,39 +160,21 @@ void GstStreamingChannelSource::FreeBuffer (PvBuffer * aBuffer)
|
|||||||
|
|
||||||
PvResult GstStreamingChannelSource::QueueBuffer (PvBuffer * aBuffer)
|
PvResult GstStreamingChannelSource::QueueBuffer (PvBuffer * aBuffer)
|
||||||
{
|
{
|
||||||
g_mutex_lock (&mSink->mutex);
|
GST_LOG_OBJECT(mSink, "Pushing buffer #%d to input queue", aBuffer->GetID());
|
||||||
if (mAcquisitionBuffer == NULL) {
|
g_async_queue_push(mInputQueue, aBuffer);
|
||||||
// No buffer queued, accept it
|
|
||||||
mAcquisitionBuffer = aBuffer;
|
|
||||||
mBufferValid = FALSE;
|
|
||||||
g_mutex_unlock (&mSink->mutex);
|
|
||||||
return PvResult::Code::OK;
|
return PvResult::Code::OK;
|
||||||
}
|
}
|
||||||
g_mutex_unlock (&mSink->mutex);
|
|
||||||
return PvResult::Code::BUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
PvResult GstStreamingChannelSource::RetrieveBuffer(PvBuffer** aBuffer)
|
PvResult GstStreamingChannelSource::RetrieveBuffer(PvBuffer** aBuffer)
|
||||||
{
|
{
|
||||||
gint64 end_time;
|
guint64 timeout_ms = 50;
|
||||||
|
*aBuffer = (PvBuffer*)(g_async_queue_timeout_pop(mOutputQueue, timeout_ms * 1000));
|
||||||
g_mutex_lock (&mSink->mutex);
|
if (!*aBuffer) {
|
||||||
// WAIT for buffer
|
GST_WARNING_OBJECT(mSink, "No buffers available in output queue after %llu ms, possibly slow video framerate", timeout_ms);
|
||||||
end_time = g_get_monotonic_time () + 50 * G_TIME_SPAN_MILLISECOND;
|
|
||||||
while ((mAcquisitionBuffer == NULL || !mBufferValid)
|
|
||||||
&& !mSink->stop_requested) {
|
|
||||||
if (!g_cond_wait_until (&mSink->cond, &mSink->mutex, end_time)) {
|
|
||||||
// No buffer queued for acquisition
|
|
||||||
g_mutex_unlock (&mSink->mutex);
|
|
||||||
return PvResult::Code::NO_AVAILABLE_DATA;
|
return PvResult::Code::NO_AVAILABLE_DATA;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// Remove buffer from 1-deep pipeline
|
|
||||||
*aBuffer = mAcquisitionBuffer;
|
|
||||||
mAcquisitionBuffer = NULL;
|
|
||||||
mBufferValid = FALSE;
|
|
||||||
g_mutex_unlock (&mSink->mutex);
|
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (mSink, "Returning buffer #%llu from output queue to GEV streaming thread", (*aBuffer)->GetID());
|
||||||
return PvResult::Code::OK;
|
return PvResult::Code::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,22 +237,21 @@ GstStreamingChannelSource::SetBuffer (GstBuffer * buf)
|
|||||||
{
|
{
|
||||||
GByteArray * klv_byte_array = NULL;
|
GByteArray * klv_byte_array = NULL;
|
||||||
|
|
||||||
GST_LOG_OBJECT (mSink, "SetBuffer");
|
PvBuffer* pvBuffer;
|
||||||
|
|
||||||
g_mutex_lock (&mSink->mutex);
|
guint64 timeout_ms = 50;
|
||||||
|
pvBuffer = (PvBuffer*)(g_async_queue_timeout_pop (mInputQueue, timeout_ms * 1000));
|
||||||
if (mAcquisitionBuffer == NULL) {
|
if (!pvBuffer) {
|
||||||
GST_WARNING_OBJECT (mSink, "No PvBuffer available to fill, dropping frame");
|
if (mStreamingStarted) {
|
||||||
g_mutex_unlock (&mSink->mutex);
|
GST_WARNING_OBJECT(mSink, "No free buffers, dropping frame. No consumers connected, or insufficient network bandwidth. Try increasing num-internal-buffers and/or packet-size.");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
GST_LOG_OBJECT(mSink, "Dropping frame as no controller has requested streaming to start");
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mBufferValid) {
|
GST_LOG_OBJECT(mSink, "Got buffer #%llu from input queue to fill with video data", pvBuffer->GetID());
|
||||||
GST_WARNING_OBJECT (mSink,
|
|
||||||
"Buffer already filled, dropping incoming frame");
|
|
||||||
g_mutex_unlock (&mSink->mutex);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mChunkKlvEnabled) {
|
if (mChunkKlvEnabled) {
|
||||||
klv_byte_array = GetKlvByteArray (buf);
|
klv_byte_array = GetKlvByteArray (buf);
|
||||||
@ -263,31 +262,31 @@ GstStreamingChannelSource::SetBuffer (GstBuffer * buf)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ResizeBufferIfNeeded (mAcquisitionBuffer);
|
ResizeBufferIfNeeded (pvBuffer);
|
||||||
|
|
||||||
/* TODO: avoid memcpy (when strides align) by attaching to PvBuffer */
|
/* TODO: avoid memcpy (when strides align) by attaching to PvBuffer */
|
||||||
GstMapInfo minfo;
|
GstMapInfo minfo;
|
||||||
gst_buffer_map (buf, &minfo, GST_MAP_READ);
|
gst_buffer_map (buf, &minfo, GST_MAP_READ);
|
||||||
|
|
||||||
|
|
||||||
guint8 *dst = mAcquisitionBuffer->GetDataPointer ();
|
guint8 *dst = pvBuffer->GetDataPointer ();
|
||||||
if (!dst) {
|
if (!dst) {
|
||||||
GST_ERROR_OBJECT (mSink, "Have buffer to fill, but data pointer is invalid");
|
GST_ERROR_OBJECT (mSink, "Have buffer to fill, but data pointer is invalid");
|
||||||
g_mutex_unlock (&mSink->mutex);
|
//g_mutex_unlock (&mSink->mutex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
g_assert (mAcquisitionBuffer->GetSize () >= minfo.size);
|
g_assert (pvBuffer->GetSize () >= minfo.size);
|
||||||
/* TODO: fix stride if needed */
|
/* TODO: fix stride if needed */
|
||||||
memcpy (dst, minfo.data, minfo.size);
|
memcpy (dst, minfo.data, minfo.size);
|
||||||
|
|
||||||
gst_buffer_unmap (buf, &minfo);
|
gst_buffer_unmap (buf, &minfo);
|
||||||
|
|
||||||
mAcquisitionBuffer->ResetChunks();
|
pvBuffer->ResetChunks();
|
||||||
mAcquisitionBuffer->SetChunkLayoutID(CHUNKLAYOUTID);
|
pvBuffer->SetChunkLayoutID(CHUNKLAYOUTID);
|
||||||
|
|
||||||
if (mChunkKlvEnabled && klv_byte_array && klv_byte_array->len > 0) {
|
if (mChunkKlvEnabled && klv_byte_array && klv_byte_array->len > 0) {
|
||||||
PvResult pvRes;
|
PvResult pvRes;
|
||||||
pvRes = mAcquisitionBuffer->AddChunk (KLV_CHUNKID, (uint8_t*)klv_byte_array->data, klv_byte_array->len);
|
pvRes = pvBuffer->AddChunk (KLV_CHUNKID, (uint8_t*)klv_byte_array->data, klv_byte_array->len);
|
||||||
if (pvRes.IsOK ()) {
|
if (pvRes.IsOK ()) {
|
||||||
GST_LOG_OBJECT (mSink, "Added KLV as chunk data (len=%d)", klv_byte_array->len);
|
GST_LOG_OBJECT (mSink, "Added KLV as chunk data (len=%d)", klv_byte_array->len);
|
||||||
} else {
|
} else {
|
||||||
@ -301,10 +300,8 @@ GstStreamingChannelSource::SetBuffer (GstBuffer * buf)
|
|||||||
g_byte_array_unref (klv_byte_array);
|
g_byte_array_unref (klv_byte_array);
|
||||||
}
|
}
|
||||||
|
|
||||||
mBufferValid = TRUE;
|
GST_LOG_OBJECT(mSink, "Pushing buffer #%d to output queue", pvBuffer->GetID());
|
||||||
g_cond_signal (&mSink->cond);
|
g_async_queue_push(mOutputQueue, pvBuffer);
|
||||||
|
|
||||||
g_mutex_unlock (&mSink->mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GByteArray * GstStreamingChannelSource::GetKlvByteArray (GstBuffer * buf)
|
GByteArray * GstStreamingChannelSource::GetKlvByteArray (GstBuffer * buf)
|
||||||
|
|||||||
@ -26,6 +26,9 @@ class GstStreamingChannelSource:public PvStreamingChannelSourceDefault
|
|||||||
public:
|
public:
|
||||||
GstStreamingChannelSource ();
|
GstStreamingChannelSource ();
|
||||||
|
|
||||||
|
void OnStreamingStart();
|
||||||
|
void OnStreamingStop();
|
||||||
|
|
||||||
void SetSink (GstPleoraSink * sink);
|
void SetSink (GstPleoraSink * sink);
|
||||||
void SetCaps (GstCaps * caps);
|
void SetCaps (GstCaps * caps);
|
||||||
void ResizeBufferIfNeeded (PvBuffer * aBuffer);
|
void ResizeBufferIfNeeded (PvBuffer * aBuffer);
|
||||||
@ -55,8 +58,8 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
GstPleoraSink * mSink;
|
GstPleoraSink * mSink;
|
||||||
PvBuffer *mAcquisitionBuffer;
|
GAsyncQueue* mInputQueue;
|
||||||
gboolean mBufferValid;
|
GAsyncQueue* mOutputQueue;
|
||||||
gint mBufferCount;
|
gint mBufferCount;
|
||||||
|
|
||||||
gint mWidth;
|
gint mWidth;
|
||||||
@ -67,4 +70,6 @@ private:
|
|||||||
bool mChunkKlvEnabled;
|
bool mChunkKlvEnabled;
|
||||||
|
|
||||||
gint mKlvChunkSize;
|
gint mKlvChunkSize;
|
||||||
|
|
||||||
|
bool mStreamingStarted;
|
||||||
};
|
};
|
||||||
Loading…
x
Reference in New Issue
Block a user