pylonsrc: use caps negotiation for selecting PixelFormat instead of property

Renamed 'imageformat' property to 'pixel-format', and set default to 'auto',
which will query the camera for supported PixelFormats, then allow
GStreamer to negotiate the format with downstream elements.
This commit is contained in:
Joshua M. Doe 2020-04-08 06:58:07 -04:00
parent 9bf84eb7e8
commit 2a07d3df60
2 changed files with 122 additions and 182 deletions

View File

@ -41,6 +41,8 @@
#include <malloc.h> //malloc
#include <string.h> //memcpy, strcmp
#include "common/genicampixelformat.h"
#ifdef HAVE_ORC
#include <orc/orc.h>
#else
@ -117,7 +119,7 @@ enum
PROP_RESET,
PROP_TESTIMAGE,
PROP_CONTINUOUSMODE,
PROP_IMAGEFORMAT,
PROP_PIXEL_FORMAT,
PROP_USERID,
PROP_BASLERDEMOSAICING,
PROP_DEMOSAICINGNOISEREDUCTION,
@ -146,6 +148,8 @@ enum
PROP_TRANSFORMATION22
};
#define DEFAULT_PROP_PIXEL_FORMAT "auto"
/* pad templates */
static GstStaticPadTemplate gst_pylonsrc_src_template =
GST_STATIC_PAD_TEMPLATE ("src",
@ -355,10 +359,10 @@ gst_pylonsrc_class_init (GstPylonSrcClass * klass)
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.",
TRUE, (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
g_object_class_install_property (gobject_class, PROP_IMAGEFORMAT,
g_param_spec_string ("imageformat", "Image format",
"(Mono8/Bayer8/Bayer10/Bayer10p/RGB8/BGR8/YCbCr422_8). Determines the pixel format in which to send frames. Note that downstream elements might not support some of these.",
"Bayer8",
g_object_class_install_property (gobject_class, PROP_PIXEL_FORMAT,
g_param_spec_string ("pixel-format", "Pixel format",
"Force the pixel format (e.g., Mono8). Default to 'auto', which will use GStreamer negotiation.",
DEFAULT_PROP_PIXEL_FORMAT,
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
g_object_class_install_property (gobject_class, PROP_USERID,
g_param_spec_string ("userid", "Custom Device User ID",
@ -501,6 +505,8 @@ gst_pylonsrc_init (GstPylonSrc * src)
GST_DEBUG_OBJECT (src, "Initialising defaults");
src->deviceConnected = FALSE;
src->acquisition_configured = FALSE;
src->caps = NULL;
// Default parameter values
src->continuousMode = TRUE;
@ -526,7 +532,7 @@ gst_pylonsrc_init (GstPylonSrc * src)
src->autowhitebalance = "off\0";
src->autogain = "off\0";
src->reset = "off\0";
src->imageFormat = "bayer8\0";
src->pixel_format = g_strdup (DEFAULT_PROP_PIXEL_FORMAT);
src->userid = "\0";
src->autoprofile = "default\0";
src->transformationselector = "default\0";
@ -619,8 +625,9 @@ gst_pylonsrc_set_property (GObject * object, guint property_id,
case PROP_AUTOWHITEBALANCE:
src->autowhitebalance = g_value_dup_string (value + '\0');
break;
case PROP_IMAGEFORMAT:
src->imageFormat = g_value_dup_string (value + '\0');
case PROP_PIXEL_FORMAT:
g_free (src->pixel_format);
src->pixel_format = g_value_dup_string (value);
break;
case PROP_AUTOGAIN:
src->autogain = g_value_dup_string (value + '\0');
@ -823,8 +830,8 @@ gst_pylonsrc_get_property (GObject * object, guint property_id,
case PROP_AUTOWHITEBALANCE:
g_value_set_string (value, src->autowhitebalance);
break;
case PROP_IMAGEFORMAT:
g_value_set_string (value, src->imageFormat);
case PROP_PIXEL_FORMAT:
g_value_set_string (value, src->pixel_format);
break;
case PROP_USERID:
g_value_set_string (value, src->userid);
@ -986,56 +993,13 @@ static GstCaps *
gst_pylonsrc_get_caps (GstBaseSrc * bsrc, GstCaps * filter)
{
GstPylonSrc *src = GST_PYLONSRC (bsrc);
GstCaps *caps;
GST_DEBUG_OBJECT (src, "Received a request for caps.");
if (!src->deviceConnected) {
GST_DEBUG_OBJECT (src, "Could not send caps - no camera connected.");
return gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD (bsrc));
} else {
// Set caps
char *type = "";
char *format = "";
if (strncmp ("bayer", src->imageFormat, 5) == 0) {
type = "video/x-bayer\0";
format = "rggb\0";
if (src->flipx && !src->flipy) {
format = "grbg\0";
} else if (!src->flipx && src->flipy) {
format = "gbrg\0";
} else if (src->flipx && src->flipy) {
format = "bggr\0";
}
} else {
type = "video/x-raw\0";
if (strcmp (src->imageFormat, "rgb8") == 0) {
format = "RGB\0";
} else if (strcmp (src->imageFormat, "bgr8") == 0) {
format = "BGR\0";
} else if (strcmp (src->imageFormat, "ycbcr422_8") == 0) {
format = "YUY2\0";
} else if (strcmp (src->imageFormat, "mono8") == 0) {
format = "GRAY8\0";
} else if (strcmp (src->imageFormat, "yuv422packed") == 0) {
format = "UYVY\0";
} else if (strcmp (src->imageFormat, "yuv422_yuyv_packed") == 0) {
format = "YUY2\0";
}
}
caps = gst_caps_new_simple (type,
"format", G_TYPE_STRING, format,
"width", G_TYPE_INT, src->width,
"height", G_TYPE_INT, src->height,
"framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
GST_DEBUG_OBJECT (src,
"The following caps were sent: %s, %s, %dx%d, variable fps.", type,
format, src->width, src->height);
return caps;
return src->caps;
}
}
@ -1043,24 +1007,31 @@ static gboolean
gst_pylonsrc_set_caps (GstBaseSrc * bsrc, GstCaps * caps)
{
GstPylonSrc *src = GST_PYLONSRC (bsrc);
GstStructure *s = gst_caps_get_structure (caps, 0);
gint i;
GString *format = g_string_new (NULL);
GST_DEBUG_OBJECT (src, "Setting caps to %" GST_PTR_FORMAT, caps);
if (strncmp ("bayer", src->imageFormat, 5) == 0) {
if (!g_str_equal ("video/x-bayer", gst_structure_get_name (s))) {
g_free (src->pixel_format);
src->pixel_format = NULL;
for (i = 0; i < G_N_ELEMENTS (gst_genicam_pixel_format_infos); i++) {
GstCaps *super_caps;
GstGenicamPixelFormatInfo *info = &gst_genicam_pixel_format_infos[i];
super_caps = gst_caps_from_string (info->gst_caps_string);
g_string_printf (format, "EnumEntry_PixelFormat_%s", info->pixel_format);
if (gst_caps_is_subset (caps, super_caps)
&& PylonDeviceFeatureIsAvailable (src->deviceHandle, format->str)) {
src->pixel_format = g_strdup (info->pixel_format);
GST_DEBUG_OBJECT (src, "Set caps match PixelFormat '%s'",
src->pixel_format);
break;
}
}
g_string_free (format, TRUE);
if (src->pixel_format == NULL)
goto unsupported_caps;
}
} else {
if (!g_str_equal ("video/x-raw", gst_structure_get_name (s))
|| (!g_str_equal ("YUY2", gst_structure_get_string (s, "format"))
&& !g_str_equal ("RGB", gst_structure_get_string (s, "format"))
&& !g_str_equal ("BGR", gst_structure_get_string (s, "format"))
&& !g_str_equal ("GRAY8", gst_structure_get_string (s, "format"))
&& !g_str_equal ("UYVY", gst_structure_get_string (s, "format")))) {
goto unsupported_caps;
}
}
return TRUE;
unsupported_caps:
@ -1490,112 +1461,61 @@ error:
return FALSE;
}
static GstCaps *
gst_pylonsrc_get_supported_caps (GstPylonSrc * src)
{
GstCaps *caps;
int i;
GString *format = g_string_new (NULL);
gboolean auto_format = FALSE;
if (g_ascii_strncasecmp (src->pixel_format, "auto", -1) == 0) {
auto_format = TRUE;
}
caps = gst_caps_new_empty ();
/* check every pixel format GStreamer supports */
for (i = 0; i < G_N_ELEMENTS (gst_genicam_pixel_format_infos); i++) {
const GstGenicamPixelFormatInfo *info = &gst_genicam_pixel_format_infos[i];
if (!auto_format
&& g_ascii_strncasecmp (src->pixel_format, info->pixel_format,
-1) != 0) {
continue;
}
g_string_printf (format, "EnumEntry_PixelFormat_%s", info->pixel_format);
if (PylonDeviceFeatureIsAvailable (src->deviceHandle, format->str)) {
GstCaps *format_caps;
GST_DEBUG_OBJECT (src, "PixelFormat %s supported, adding to caps",
info->pixel_format);
// TODO: query FPS
format_caps =
gst_genicam_pixel_format_caps_from_pixel_format (info->pixel_format,
G_BYTE_ORDER, src->width, src->height, 30, 1, 1, 1);
if (format_caps)
gst_caps_append (caps, format_caps);
}
}
GST_DEBUG_OBJECT (src, "Supported caps are %" GST_PTR_FORMAT, caps);
return caps;
}
static gboolean
gst_pylonsrc_set_pixel_format (GstPylonSrc * src)
{
GENAPIC_RESULT res;
GString *pixelFormat = g_string_new (NULL);
// Set pixel format.
src->imageFormat = g_ascii_strdown (src->imageFormat, -1);
if (strncmp ("bayer", src->imageFormat, 5) == 0) {
GString *format = g_string_new (NULL);
GString *filter = g_string_new (NULL);
if (!src->flipx && !src->flipy) {
g_string_printf (filter, "RG");
} else if (src->flipx && !src->flipy) {
g_string_printf (filter, "GR");
} else if (!src->flipx && src->flipy) {
g_string_printf (filter, "GB");
} else {
g_string_printf (filter, "BG");
}
g_string_printf (pixelFormat, "Bayer%s%s", filter->str,
&src->imageFormat[5]);
g_string_free (filter, TRUE);
g_string_printf (format, "EnumEntry_PixelFormat_%s", pixelFormat->str);
if (!PylonDeviceFeatureIsAvailable (src->deviceHandle, format->str)) {
g_string_free (format, TRUE);
GST_ELEMENT_ERROR (src, RESOURCE, FAILED,
("Failed to initialise the camera"),
("Camera doesn't support Bayer%s.", &src->imageFormat[5]));
goto error;
}
g_string_free (format, TRUE);
} else if (strcmp (src->imageFormat, "rgb8") == 0) {
if (PylonDeviceFeatureIsAvailable (src->deviceHandle,
"EnumEntry_PixelFormat_RGB8")) {
g_string_printf (pixelFormat, "RGB8");
} else {
GST_ELEMENT_ERROR (src, RESOURCE, FAILED,
("Failed to initialise the camera"),
("Camera doesn't support RGB 8"));
goto error;
}
} else if (strcmp (src->imageFormat, "bgr8") == 0) {
if (PylonDeviceFeatureIsAvailable (src->deviceHandle,
"EnumEntry_PixelFormat_BGR8")) {
g_string_printf (pixelFormat, "RGB8");
} else {
GST_ELEMENT_ERROR (src, RESOURCE, FAILED,
("Failed to initialise the camera"),
("Camera doesn't support BGR 8"));
goto error;
}
} else if (strcmp (src->imageFormat, "ycbcr422_8") == 0) {
if (PylonDeviceFeatureIsAvailable (src->deviceHandle,
"EnumEntry_PixelFormat_YCbCr422_8")) {
g_string_printf (pixelFormat, "YCbCr422_8");
} else {
GST_ELEMENT_ERROR (src, RESOURCE, FAILED,
("Failed to initialise the camera"),
("Camera doesn't support YCbCr422 8"));
goto error;
}
} else if (strcmp (src->imageFormat, "mono8") == 0) {
if (PylonDeviceFeatureIsAvailable (src->deviceHandle,
"EnumEntry_PixelFormat_Mono8")) {
g_string_printf (pixelFormat, "Mono8");
} else {
GST_ELEMENT_ERROR (src, RESOURCE, FAILED,
("Failed to initialise the camera"),
("Camera doesn't support Mono 8"));
goto error;
}
} else if (strcmp (src->imageFormat, "yuv422packed") == 0) {
if (PylonDeviceFeatureIsAvailable (src->deviceHandle,
"EnumEntry_PixelFormat_YUV422Packed")) {
g_string_printf (pixelFormat, "YUV422Packed");
} else {
GST_ELEMENT_ERROR (src, RESOURCE, FAILED,
("Failed to initialise the camera"),
("Camera doesn't support YUV422Packed"));
goto error;
}
} else if (strcmp (src->imageFormat, "yuv422_yuyv_packed") == 0) {
if (PylonDeviceFeatureIsAvailable (src->deviceHandle,
"EnumEntry_PixelFormat_YUV422_YUYV_Packed")) {
g_string_printf (pixelFormat, "YUV422_YUYV_Packed");
} else {
GST_ELEMENT_ERROR (src, RESOURCE, FAILED,
("Failed to initialise the camera"),
("Camera doesn't support YUV422_YUYV_Packed"));
goto error;
}
} else {
GST_ERROR_OBJECT (src,
"Invalid parameter value for imageformat. Available values are: bayer8, bayer10, bayer10p, rgb8, bgr8, ycbcr422_8, mono8. Value provided: \"%s\".",
src->imageFormat);
GST_ELEMENT_ERROR (src, RESOURCE, FAILED,
("Failed to initialise the camera"), ("Invalid parameters provided"));
goto error;
}
GST_DEBUG_OBJECT (src, "Using %s image format.", pixelFormat->str);
GST_DEBUG_OBJECT (src, "Using %s PixelFormat.", src->pixel_format);
res =
PylonDeviceFeatureFromString (src->deviceHandle, "PixelFormat",
pixelFormat->str);
src->pixel_format);
PYLONC_CHECK_ERROR (src, res);
// Output the size of a pixel
@ -1611,7 +1531,6 @@ gst_pylonsrc_set_pixel_format (GstPylonSrc * src)
} else {
GST_WARNING_OBJECT (src, "Couldn't read pixel size from the camera");
}
g_string_free (pixelFormat, TRUE);
return TRUE;
@ -2555,7 +2474,7 @@ gst_pylonsrc_set_pgi (GstPylonSrc * src)
if (FEATURE_SUPPORTED ("DemosaicingMode")) {
if (src->demosaicing || src->sharpnessenhancement != 999.0
|| src->noisereduction != 999.0) {
if (strncmp ("bayer", src->imageFormat, 5) != 0) {
if (strncmp ("bayer", src->pixel_format, 5) != 0) {
GST_DEBUG_OBJECT (src, "Enabling Basler's PGI.");
res =
PylonDeviceFeatureFromString (src->deviceHandle, "DemosaicingMode",
@ -2615,24 +2534,13 @@ error:
}
static gboolean
gst_pylonsrc_start (GstBaseSrc * bsrc)
gst_pylonsrc_configure_start_acquisition (GstPylonSrc * src)
{
GstPylonSrc *src = GST_PYLONSRC (bsrc);
GENAPIC_RESULT res;
gint i;
size_t num_streams;
if (PylonInitialize () != 0) {
GST_ELEMENT_ERROR (src, RESOURCE, FAILED,
("Failed to initialise the camera"),
("Pylon library initialization failed"));
goto error;
}
if (!gst_pylonsrc_select_device (src) ||
!gst_pylonsrc_connect_device (src) ||
!gst_pylonsrc_set_resolution (src) ||
!gst_pylonsrc_set_offset (src) ||
if (!gst_pylonsrc_set_offset (src) ||
!gst_pylonsrc_set_reverse (src) ||
!gst_pylonsrc_set_pixel_format (src) ||
!gst_pylonsrc_set_test_image (src) ||
@ -2789,6 +2697,30 @@ gst_pylonsrc_start (GstBaseSrc * bsrc)
GST_DEBUG_OBJECT (src, "Initialised successfully.");
return TRUE;
error:
return FALSE;
}
static gboolean
gst_pylonsrc_start (GstBaseSrc * bsrc)
{
GstPylonSrc *src = GST_PYLONSRC (bsrc);
if (PylonInitialize () != 0) {
GST_ELEMENT_ERROR (src, RESOURCE, FAILED,
("Failed to initialise the camera"),
("Pylon library initialization failed"));
goto error;
}
if (!gst_pylonsrc_select_device (src) ||
!gst_pylonsrc_connect_device (src) || !gst_pylonsrc_set_resolution (src))
goto error;
src->caps = gst_pylonsrc_get_supported_caps (src);
return TRUE;
error:
pylonc_disconnect_camera (src);
return FALSE;
@ -2804,6 +2736,11 @@ gst_pylonsrc_create (GstPushSrc * psrc, GstBuffer ** buf)
_Bool bufferReady;
GstMapInfo mapInfo;
if (!src->acquisition_configured) {
if (!gst_pylonsrc_configure_start_acquisition (src))
goto error;
src->acquisition_configured = TRUE;
}
// Wait for the buffer to be filled (up to 1 s)
res = PylonWaitObjectWait (src->waitObject, 1000, &bufferReady);
PYLONC_CHECK_ERROR (src, res);

View File

@ -41,11 +41,14 @@ struct _GstPylonSrc
{
GstPushSrc base_pylonsrc;
GstCaps *caps;
gint cameraId;
PYLON_DEVICE_HANDLE deviceHandle; // Handle for the camera.
PYLON_STREAMGRABBER_HANDLE streamGrabber; // Handler for camera's streams.
PYLON_WAITOBJECT_HANDLE waitObject; // Handles timing out in the main loop.
gboolean deviceConnected;
gboolean acquisition_configured;
unsigned char *buffers[NUM_CAPTURE_BUFFERS];
PYLON_STREAMBUFFER_HANDLE bufferHandle[NUM_CAPTURE_BUFFERS];
@ -58,7 +61,7 @@ struct _GstPylonSrc
_Bool setFPS, continuousMode, limitBandwidth, demosaicing, centerx, centery, flipx, flipy;
double fps, exposure, gain, blacklevel, gamma, balancered, balanceblue, balancegreen, redhue, redsaturation, yellowhue, yellowsaturation, greenhue, greensaturation, cyanhue, cyansaturation, bluehue, bluesaturation, magentahue, magentasaturation, sharpnessenhancement, noisereduction, autoexposureupperlimit, autoexposurelowerlimit, gainupperlimit, gainlowerlimit, brightnesstarget, transformation00, transformation01, transformation02, transformation10, transformation11, transformation12, transformation20, transformation21, transformation22;
gint height, width, binningh, binningv, maxHeight, maxWidth, maxBandwidth, testImage, offsetx, offsety;
gchar *imageFormat, *sensorMode, *lightsource, *autoexposure, *autowhitebalance, *autogain, *reset, *autoprofile, *transformationselector, *userid;
gchar *pixel_format, *sensorMode, *lightsource, *autoexposure, *autowhitebalance, *autogain, *reset, *autoprofile, *transformationselector, *userid;
};
struct _GstPylonSrcClass