gst-plugin-linescan/sys/pleora/gstpleorasrc.cpp
Joshua M. Doe 19ce118c96 pleorasrc: add config-file and config-file-connect properties
If config-file is set to the filepath of a XML file, such as is
generated by eBUS Player, it will be used to restore configuration
to the device and stream. By default, the device and stream will be
connected using the information from the config-file. Set
config-file-connect=false to connect to the camera using other element
properties, and then apply the configuration changes from the
config-file.
2019-11-07 09:17:49 -05:00

1502 lines
46 KiB
C++

/* GStreamer
* Copyright (C) 2011 FIXME <fixme@example.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
* Boston, MA 02110-1335, USA.
*/
/**
* SECTION:element-gstpleorasrc
*
* The pleorasrc element is a source for Pleora eBUS
*
* <refsect2>
* <title>Example launch line</title>
* |[
* gst-launch -v pleorasrc ! videoconvert ! autovideosink
* ]|
* Shows video from the default Pleora device
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/gst.h>
#include <gst/base/gstpushsrc.h>
#include <gst/video/video.h>
#include "gstpleorasrc.h"
#include <PvConfigurationReader.h>
#include <PvDeviceGEV.h>
#include <PvDeviceU3V.h>
#include <PvStreamGEV.h>
#include <PvStreamU3V.h>
#include <PvSystem.h>
#include <PvVersion.h>
GST_DEBUG_CATEGORY_STATIC (gst_pleorasrc_debug);
#define GST_CAT_DEFAULT gst_pleorasrc_debug
/* prototypes */
static void gst_pleorasrc_set_property (GObject * object,
guint property_id, const GValue * value, GParamSpec * pspec);
static void gst_pleorasrc_get_property (GObject * object,
guint property_id, GValue * value, GParamSpec * pspec);
static void gst_pleorasrc_dispose (GObject * object);
static void gst_pleorasrc_finalize (GObject * object);
static gboolean gst_pleorasrc_start (GstBaseSrc * src);
static gboolean gst_pleorasrc_stop (GstBaseSrc * src);
static GstCaps *gst_pleorasrc_get_caps (GstBaseSrc * src, GstCaps * filter);
static gboolean gst_pleorasrc_set_caps (GstBaseSrc * src, GstCaps * caps);
static gboolean gst_pleorasrc_unlock (GstBaseSrc * src);
static gboolean gst_pleorasrc_unlock_stop (GstBaseSrc * src);
static GstFlowReturn gst_pleorasrc_create (GstPushSrc * src, GstBuffer ** buf);
enum
{
PROP_0,
PROP_DEVICE,
PROP_DEVICE_INDEX,
PROP_NUM_CAPTURE_BUFFERS,
PROP_TIMEOUT,
PROP_DETECTION_TIMEOUT,
PROP_MULTICAST_GROUP,
PROP_PORT,
PROP_RECEIVER_ONLY,
PROP_PACKET_SIZE,
PROP_CONFIG_FILE,
PROP_CONFIG_FILE_CONNECT
};
#define DEFAULT_PROP_DEVICE ""
#define DEFAULT_PROP_DEVICE_INDEX 0
#define DEFAULT_PROP_NUM_CAPTURE_BUFFERS 3
#define DEFAULT_PROP_TIMEOUT 1000
#define DEFAULT_PROP_DETECTION_TIMEOUT 1000
#define DEFAULT_PROP_MULTICAST_GROUP "0.0.0.0"
#define DEFAULT_PROP_PORT 1042
#define DEFAULT_PROP_RECEIVER_ONLY FALSE
#define DEFAULT_PROP_PACKET_SIZE 0
#define DEFAULT_PROP_CONFIG_FILE ""
#define DEFAULT_PROP_CONFIG_FILE_CONNECT TRUE
#define VIDEO_CAPS_MAKE_BAYER8(format) \
"video/x-bayer, " \
"format = (string) " format ", " \
"width = " GST_VIDEO_SIZE_RANGE ", " \
"height = " GST_VIDEO_SIZE_RANGE ", " \
"framerate = " GST_VIDEO_FPS_RANGE
#define VIDEO_CAPS_MAKE_BAYER16(format) \
"video/x-bayer, " \
"format = (string) " format ", " \
"endianness = (int) 1234, " \
"bpp = (int) {16, 14, 12, 10}, " \
"width = " GST_VIDEO_SIZE_RANGE ", " \
"height = " GST_VIDEO_SIZE_RANGE ", " \
"framerate = " GST_VIDEO_FPS_RANGE
/* pad templates */
static GstStaticPadTemplate gst_pleorasrc_src_template =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (VIDEO_CAPS_MAKE_BAYER16
("{ bggr16, grbg16, rggb16, gbrg16 }") ";"
VIDEO_CAPS_MAKE_BAYER8 ("{ bggr, grbg, rggb, gbrg }") ";"
GST_VIDEO_CAPS_MAKE ("{ GRAY16_LE, GRAY16_BE, GRAY8, UYVY, YUY2, RGB }")
)
);
/* class initialization */
G_DEFINE_TYPE (GstPleoraSrc, gst_pleorasrc, GST_TYPE_PUSH_SRC);
static void
gst_pleorasrc_class_init (GstPleoraSrcClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
GstBaseSrcClass *gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
GstPushSrcClass *gstpushsrc_class = GST_PUSH_SRC_CLASS (klass);
gobject_class->set_property = gst_pleorasrc_set_property;
gobject_class->get_property = gst_pleorasrc_get_property;
gobject_class->dispose = gst_pleorasrc_dispose;
gobject_class->finalize = gst_pleorasrc_finalize;
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&gst_pleorasrc_src_template));
gst_element_class_set_static_metadata (gstelement_class,
"Pleora Video Source", "Source/Video",
"Pleora eBUS video source", "Joshua M. Doe <oss@nvl.army.mil>");
gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_pleorasrc_start);
gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_pleorasrc_stop);
gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_pleorasrc_get_caps);
gstbasesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_pleorasrc_set_caps);
gstbasesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_pleorasrc_unlock);
gstbasesrc_class->unlock_stop = GST_DEBUG_FUNCPTR (gst_pleorasrc_unlock_stop);
gstpushsrc_class->create = GST_DEBUG_FUNCPTR (gst_pleorasrc_create);
/* Install GObject properties */
g_object_class_install_property (gobject_class, PROP_DEVICE,
g_param_spec_string ("device", "Device ID",
"Device ID. For GEV use MAC, IP, or user id. For U3V, use GUID or user id.",
DEFAULT_PROP_DEVICE,
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY)));
g_object_class_install_property (gobject_class, PROP_DEVICE_INDEX,
g_param_spec_int ("device-index", "Device index",
"Index of device, use -1 to enumerate all and select last", -1,
G_MAXINT, DEFAULT_PROP_DEVICE_INDEX,
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
g_object_class_install_property (gobject_class, PROP_NUM_CAPTURE_BUFFERS,
g_param_spec_uint ("num-capture-buffers", "Number of capture buffers",
"Number of capture buffers", 1, G_MAXUINT,
DEFAULT_PROP_NUM_CAPTURE_BUFFERS,
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TIMEOUT,
g_param_spec_int ("timeout", "Timeout (ms)",
"Timeout in ms (0 to use default)", 0, G_MAXINT, DEFAULT_PROP_TIMEOUT,
(GParamFlags) (G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE)));
g_object_class_install_property (G_OBJECT_CLASS (klass),
PROP_DETECTION_TIMEOUT, g_param_spec_int ("detection-timeout",
"Detection Timeout (ms)", "Timeout in ms to detect GigE cameras", 100,
60000, DEFAULT_PROP_DETECTION_TIMEOUT,
(GParamFlags) (G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE)));
g_object_class_install_property (gobject_class, PROP_MULTICAST_GROUP,
g_param_spec_string ("multicast-group", "Multicast group IP address",
"The address of the multicast group to join (default is unicast)",
DEFAULT_PROP_MULTICAST_GROUP,
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY)));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PORT,
g_param_spec_int ("port", "Multicast port",
"The port of the multicast group.", 0, 65535, DEFAULT_PROP_PORT,
(GParamFlags) (G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE)));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_RECEIVER_ONLY,
g_param_spec_boolean ("receiver-only", "Receiver only",
"Only open video stream, don't open as controller",
DEFAULT_PROP_RECEIVER_ONLY,
(GParamFlags) (G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE)));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PACKET_SIZE,
g_param_spec_int ("packet-size", "Packet size",
"Packet size (0 to auto negotiate)", 0, 65535,
DEFAULT_PROP_PACKET_SIZE,
(GParamFlags) (G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE)));
g_object_class_install_property (gobject_class, PROP_CONFIG_FILE,
g_param_spec_string ("config-file", "Config file",
"Filepath of the configuration file (*.pvcfg)",
DEFAULT_PROP_CONFIG_FILE,
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY)));
g_object_class_install_property (G_OBJECT_CLASS (klass),
PROP_CONFIG_FILE_CONNECT, g_param_spec_boolean ("config-file-connect",
"Connect using config file",
"Connects to and configures camera from config-file, if false "
"connects using properties and then restores configuration",
DEFAULT_PROP_CONFIG_FILE_CONNECT,
(GParamFlags) (G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE)));
}
static void
gst_pleorasrc_reset (GstPleoraSrc * src)
{
src->device = NULL;
src->stream = NULL;
src->pipeline = NULL;
src->last_frame_count = 0;
src->total_dropped_frames = 0;
if (src->caps) {
gst_caps_unref (src->caps);
src->caps = NULL;
}
}
static void
gst_pleorasrc_init (GstPleoraSrc * src)
{
/* set source as live (no preroll) */
gst_base_src_set_live (GST_BASE_SRC (src), TRUE);
/* override default of BYTES to operate in time mode */
gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME);
/* initialize member variables */
src->device_id = g_strdup (DEFAULT_PROP_DEVICE);
src->device_index = DEFAULT_PROP_DEVICE_INDEX;
src->num_capture_buffers = DEFAULT_PROP_NUM_CAPTURE_BUFFERS;
src->timeout = DEFAULT_PROP_TIMEOUT;
src->detection_timeout = DEFAULT_PROP_DETECTION_TIMEOUT;
src->multicast_group = g_strdup (DEFAULT_PROP_MULTICAST_GROUP);
src->port = DEFAULT_PROP_PORT;
src->receiver_only = DEFAULT_PROP_RECEIVER_ONLY;
src->config_file = g_strdup (DEFAULT_PROP_CONFIG_FILE);
src->config_file_connect = DEFAULT_PROP_CONFIG_FILE_CONNECT;
src->stop_requested = FALSE;
src->caps = NULL;
gst_pleorasrc_reset (src);
}
void
gst_pleorasrc_set_property (GObject * object, guint property_id,
const GValue * value, GParamSpec * pspec)
{
GstPleoraSrc *src;
src = GST_PLEORA_SRC (object);
switch (property_id) {
case PROP_DEVICE:
g_free (src->device_id);
src->device_id = g_strdup (g_value_get_string (value));
break;
case PROP_DEVICE_INDEX:
src->device_index = g_value_get_int (value);
break;
case PROP_NUM_CAPTURE_BUFFERS:
src->num_capture_buffers = g_value_get_uint (value);
break;
case PROP_TIMEOUT:
src->timeout = g_value_get_int (value);
break;
case PROP_DETECTION_TIMEOUT:
src->detection_timeout = g_value_get_int (value);
break;
case PROP_MULTICAST_GROUP:
g_free (src->multicast_group);
src->multicast_group = g_strdup (g_value_get_string (value));
break;
case PROP_PORT:
src->port = g_value_get_int (value);
break;
case PROP_RECEIVER_ONLY:
src->receiver_only = g_value_get_boolean (value);
break;
case PROP_PACKET_SIZE:
src->packet_size = g_value_get_int (value);
break;
case PROP_CONFIG_FILE:
g_free (src->config_file);
src->config_file = g_strdup (g_value_get_string (value));
break;
case PROP_CONFIG_FILE_CONNECT:
src->config_file_connect = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
void
gst_pleorasrc_get_property (GObject * object, guint property_id,
GValue * value, GParamSpec * pspec)
{
GstPleoraSrc *src;
g_return_if_fail (GST_IS_PLEORA_SRC (object));
src = GST_PLEORA_SRC (object);
switch (property_id) {
case PROP_DEVICE:
g_value_set_string (value, src->device_id);
break;
case PROP_DEVICE_INDEX:
g_value_set_int (value, src->device_index);
break;
case PROP_NUM_CAPTURE_BUFFERS:
g_value_set_uint (value, src->num_capture_buffers);
break;
case PROP_TIMEOUT:
g_value_set_int (value, src->timeout);
break;
case PROP_DETECTION_TIMEOUT:
g_value_set_int (value, src->detection_timeout);
break;
case PROP_MULTICAST_GROUP:
g_value_set_string (value, src->multicast_group);
break;
case PROP_PORT:
g_value_set_int (value, src->port);
break;
case PROP_RECEIVER_ONLY:
g_value_set_boolean (value, src->receiver_only);
break;
case PROP_PACKET_SIZE:
g_value_set_int (value, src->packet_size);
break;
case PROP_CONFIG_FILE:
g_value_set_string (value, src->config_file);
break;
case PROP_CONFIG_FILE_CONNECT:
g_value_set_boolean (value, src->config_file_connect);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
void
gst_pleorasrc_dispose (GObject * object)
{
GstPleoraSrc *src;
g_return_if_fail (GST_IS_PLEORA_SRC (object));
src = GST_PLEORA_SRC (object);
/* clean up as possible. may be called multiple times */
G_OBJECT_CLASS (gst_pleorasrc_parent_class)->dispose (object);
}
void
gst_pleorasrc_finalize (GObject * object)
{
GstPleoraSrc *src;
g_return_if_fail (GST_IS_PLEORA_SRC (object));
src = GST_PLEORA_SRC (object);
/* clean up object here */
if (src->device) {
g_free (src->device);
src->device = NULL;
}
if (src->caps) {
gst_caps_unref (src->caps);
src->caps = NULL;
}
G_OBJECT_CLASS (gst_pleorasrc_parent_class)->finalize (object);
}
static const gchar *
usb_speed_str (PvUSBSpeed speed)
{
static const gchar *array[] = {
"Unknown", "Low", "Full", "High", "Super"
};
if (speed >= sizeof (array) / sizeof (const gchar *) || speed < 0) {
speed = PvUSBSpeedUnknown;
}
return array[speed];
}
static const void
gst_pleorasrc_print_device_info (GstPleoraSrc * src,
const PvDeviceInfo * device_info)
{
GST_DEBUG_OBJECT (src, "Found device '%s'",
device_info->GetDisplayID ().GetAscii ());
const PvDeviceInfoGEV *device_info_GEV =
dynamic_cast < const PvDeviceInfoGEV * >(device_info);
const PvDeviceInfoU3V *device_info_U3V =
dynamic_cast < const PvDeviceInfoU3V * >(device_info);
const PvDeviceInfoUSB *device_info_USB =
dynamic_cast < const PvDeviceInfoUSB * >(device_info);
const PvDeviceInfoPleoraProtocol *device_info_pleora =
dynamic_cast < const PvDeviceInfoPleoraProtocol * >(device_info);
const PvNetworkAdapter *iface_nic =
dynamic_cast < const PvNetworkAdapter * >(device_info->GetInterface ());
const PvUSBHostController *iface_usb =
dynamic_cast <
const PvUSBHostController * >(device_info->GetInterface ());
if (iface_nic != NULL) {
#if VERSION_MAJOR == 4
#define PLEORA_GET_PARAM
#else
#define PLEORA_GET_PARAM 0
#endif
GST_DEBUG_OBJECT (src,
"Device found on network interface '%s', MAC: %s, IP: %s, Subnet: %s",
iface_nic->GetDescription ().GetAscii (),
iface_nic->GetMACAddress ().GetAscii (),
iface_nic->GetIPAddress (PLEORA_GET_PARAM).GetAscii (),
iface_nic->GetSubnetMask (PLEORA_GET_PARAM).GetAscii ());
} else if (iface_usb != NULL) {
GST_DEBUG_OBJECT (src,
"Device found on USB interface, VEN_%04X&DEV_%04X&SUBSYS_%08X&REV_%02X, '%s', %s Speed",
iface_usb->GetVendorID (), iface_usb->GetDeviceID (),
iface_usb->GetSubsystemID (), iface_usb->GetRevision (),
iface_usb->GetName ().GetAscii (),
usb_speed_str (iface_usb->GetSpeed ()));
}
if (device_info_GEV != NULL) {
GST_DEBUG_OBJECT (src, "GEV device: MAC: %s, IP: %s, S/N: %s",
device_info_GEV->GetMACAddress ().GetAscii (),
device_info_GEV->GetIPAddress ().GetAscii (),
device_info_GEV->GetSerialNumber ().GetAscii ());
} else if (device_info_U3V != NULL) {
GST_DEBUG_OBJECT (src, "U3V device: GUID: %s, S/N: %s",
device_info_U3V->GetDeviceGUID ().GetAscii (),
device_info_U3V->GetSerialNumber ().GetAscii (),
device_info_U3V->GetInterface ());
} else if (device_info_USB != NULL) {
GST_DEBUG_OBJECT (src, "Unidentified USB device");
} else if (device_info_pleora != NULL) {
GST_DEBUG_OBJECT (src, "Pleora device: MAC: %s, IP: %s, S/N: %s",
device_info_pleora->GetMACAddress ().GetAscii (),
device_info_pleora->GetIPAddress ().GetAscii (),
device_info_pleora->GetSerialNumber ().GetAscii ());
}
}
static const PvDeviceInfo *
gst_pleorasrc_get_device_info (GstPleoraSrc * src, PvSystem & lSystem)
{
PvResult pvRes;
const PvDeviceInfo *device_info = NULL;
// time allowed to detect GEV cameras
lSystem.SetDetectionTimeout (src->detection_timeout);
if (g_strcmp0 (src->device_id, "") != 0) {
GST_DEBUG_OBJECT (src, "Finding device based on ID: %s", src->device_id);
pvRes = lSystem.FindDevice (src->device_id, &device_info);
if (!pvRes.IsOK ()) {
GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
("Failed to find device ID '%s': %s", src->device_id,
pvRes.GetDescription ().GetAscii ()), (NULL));
return NULL;
}
} else if (src->device_index >= 0) {
GST_DEBUG_OBJECT (src, "Finding device based on index: %d",
src->device_index);
/* Find will block for detection_timeout */
pvRes = lSystem.Find ();
if (!pvRes.IsOK ()) {
GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
("Error finding devices: %s", pvRes.GetDescription ().GetAscii ()),
(NULL));
return NULL;
}
if (lSystem.GetDeviceCount () < 1) {
GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
("No Pleora-compatible devices found"), (NULL));
return NULL;
}
if (src->device_index >= lSystem.GetDeviceCount ()) {
GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
("Device index specified (%d) does not exist, out of range [0, %d)",
src->device_index, lSystem.GetDeviceCount ()), (NULL));
return NULL;
}
device_info = lSystem.GetDeviceInfo (src->device_index);
if (device_info == NULL) {
GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
("Failed to find device index %d", src->device_index), (NULL));
return NULL;
}
} else {
guint32 device_count;
GST_DEBUG_OBJECT (src, "Enumerating devices and choosing last one");
pvRes = lSystem.Find ();
if (!pvRes.IsOK ()) {
GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
("Error finding devices: %s", pvRes.GetDescription ().GetAscii ()),
(NULL));
return NULL;
}
device_count = lSystem.GetDeviceCount ();
if (device_count < 1) {
GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
("No Pleora-compatible devices found"), (NULL));
return NULL;
}
GST_DEBUG_OBJECT (src, "Found a total of %d device(s)", device_count);
for (uint32_t x = 0; x < device_count; x++) {
device_info = lSystem.GetDeviceInfo (x);
gst_pleorasrc_print_device_info (src, device_info);
}
#if 0
// iterate through all interfaces on system
uint32_t lInterfaceCount = lSystem.GetInterfaceCount ();
for (uint32_t x = 0; x < lInterfaceCount; x++) {
const PvInterface *lInterface = lSystem.GetInterface (x);
GST_DEBUG_OBJECT (src, "Found interface %d: '%s', '%s'", x,
lInterface->GetName ().GetAscii (),
lInterface->GetDisplayID ().GetAscii ());
const PvNetworkAdapter *lNIC =
dynamic_cast < const PvNetworkAdapter * >(lInterface);
if (lNIC != NULL) {
GST_DEBUG_OBJECT (src, "MAC: %s, IP: %s, Subnet: %s",
lNIC->GetMACAddress ().GetAscii (),
lNIC->GetIPAddress ().GetAscii (),
lNIC->GetSubnetMask ().GetAscii ());
}
const PvUSBHostController *lUSB =
dynamic_cast < const PvUSBHostController * >(lInterface);
if (lUSB != NULL) {
GST_DEBUG_OBJECT (src, "USB '%s'", lUSB->GetName ().GetAscii ());
}
// iterate through all devices on interface
uint32_t lDeviceCount = lInterface->GetDeviceCount ();
if (lDeviceCount == 0) {
GST_DEBUG_OBJECT (src, "No devices found on this interface");
}
for (uint32_t y = 0; y < lDeviceCount; y++) {
const PvDeviceInfo *devinfo = lInterface->GetDeviceInfo (y);
gst_pleorasrc_print_device_info (src, devinfo);
// select last device
device_info = devinfo;
}
}
#endif
}
return device_info;
}
static gboolean
gst_pleorasrc_restore_device_from_config (GstPleoraSrc * src)
{
PvConfigurationReader lConfigReader;
PvResult pvRes;
GST_DEBUG_OBJECT (src, "Loading config file (%s)", src->config_file);
pvRes = lConfigReader.Load (src->config_file);
if (!pvRes.IsOK ()) {
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS,
("Failed to load config file (%s): %s",
src->config_file, pvRes.GetDescription ().GetAscii ()), (NULL));
return FALSE;
}
if (src->device == NULL) {
PvDeviceGEV *lDeviceGEV = new PvDeviceGEV ();
PvDeviceU3V *lDeviceU3V = new PvDeviceU3V ();
GST_DEBUG_OBJECT (src,
"Restoring device connection and settings from config file");
pvRes = lConfigReader.Restore (0, lDeviceGEV);
if (pvRes.IsOK ()) {
src->device = lDeviceGEV;
delete lDeviceU3V;
} else {
pvRes = lConfigReader.Restore (0, lDeviceU3V);
if (pvRes.IsOK ()) {
src->device = lDeviceU3V;
delete lDeviceGEV;
} else {
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS,
("Failed to restore device from config file (%s): %s",
src->config_file, pvRes.GetDescription ().GetAscii ()), (NULL));
return FALSE;
}
}
} else {
GST_DEBUG_OBJECT (src, "Restoring device settings from config file");
pvRes = lConfigReader.Restore (0, src->device);
if (!pvRes.IsOK ()) {
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS,
("Failed to restore device from config file (%s): %s",
src->config_file, pvRes.GetDescription ().GetAscii ()), (NULL));
return FALSE;
}
}
return TRUE;
}
static gboolean
gst_pleorasrc_restore_stream_from_config (GstPleoraSrc * src)
{
PvConfigurationReader lConfigReader;
PvResult pvRes;
GST_DEBUG_OBJECT (src, "Loading config file (%s)", src->config_file);
pvRes = lConfigReader.Load (src->config_file);
if (!pvRes.IsOK ()) {
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS,
("Failed to load config file (%s): %s",
src->config_file, pvRes.GetDescription ().GetAscii ()), (NULL));
return FALSE;
}
if (src->stream == NULL) {
PvStreamGEV *lStreamGEV = new PvStreamGEV ();
PvStreamU3V *lStreamU3V = new PvStreamU3V ();
GST_DEBUG_OBJECT (src,
"Restoring stream connection and settings from config file");
pvRes = lConfigReader.Restore (0, lStreamGEV);
if (pvRes.IsOK ()) {
src->stream = lStreamGEV;
delete lStreamU3V;
} else {
pvRes = lConfigReader.Restore (0, lStreamU3V);
if (pvRes.IsOK ()) {
src->stream = lStreamU3V;
delete lStreamGEV;
} else {
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS,
("Failed to restore stream from config file (%s): %s",
src->config_file, pvRes.GetDescription ().GetAscii ()), (NULL));
return FALSE;
}
}
} else {
GST_DEBUG_OBJECT (src, "Restoring stream settings from config file");
pvRes = lConfigReader.Restore (0, src->stream);
if (!pvRes.IsOK ()) {
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS,
("Failed to restore stream from config file (%s): %s",
src->config_file, pvRes.GetDescription ().GetAscii ()), (NULL));
return FALSE;
}
}
return TRUE;
}
static gboolean
gst_pleorasrc_setup_stream (GstPleoraSrc * src)
{
PvResult pvRes;
const PvDeviceInfo *device_info;
PvSystem lSystem;
if (g_strcmp0 (src->config_file, DEFAULT_PROP_CONFIG_FILE) != 0 &&
src->config_file_connect) {
if (!gst_pleorasrc_restore_device_from_config (src)) {
/* error already sent */
return FALSE;
}
if (!gst_pleorasrc_restore_stream_from_config (src)) {
/* error already sent */
return FALSE;
}
} else {
/* PvSystem creates device info, so we must persist it across this call */
device_info = gst_pleorasrc_get_device_info (src, lSystem);
if (device_info == NULL) {
/* error already sent */
return FALSE;
}
GST_DEBUG_OBJECT (src, "Info for device that will be opened:");
gst_pleorasrc_print_device_info (src, device_info);
/* open device (for GEV, opening device means we're a controller */
if (!src->receiver_only) {
GST_DEBUG_OBJECT (src, "Trying to connect to device '%s' as controller",
device_info->GetDisplayID ().GetAscii ());
src->device = PvDevice::CreateAndConnect (device_info, &pvRes);
if (src->device == NULL) {
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
("Unable to connect to device as controller: %s",
pvRes.GetDescription ().GetAscii ()), (NULL));
return FALSE;
}
GST_DEBUG_OBJECT (src, "Connected to device as controller");
}
/* open stream */
if (device_info->GetType () == PvDeviceInfoTypeGEV ||
device_info->GetType () == PvDeviceInfoTypePleoraProtocol) {
PvStreamGEV *stream = new PvStreamGEV;
if (g_strcmp0 (src->multicast_group, DEFAULT_PROP_MULTICAST_GROUP) != 0) {
GST_DEBUG_OBJECT (src, "Opening device in multicast mode, %s:%d",
src->multicast_group, src->port);
pvRes =
stream->Open (device_info->GetConnectionID (), src->multicast_group,
src->port);
} else {
GST_DEBUG_OBJECT (src, "Opening device in unicast mode");
pvRes = stream->Open (device_info->GetConnectionID ());
}
src->stream = stream;
} else {
src->stream =
PvStream::CreateAndOpen (device_info->GetConnectionID (), &pvRes);
}
if (src->stream == NULL || !pvRes.IsOK ()) {
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, ("Failed to open stream: %s",
pvRes.GetDescription ().GetAscii ()), (NULL));
goto stream_failed;
}
GST_DEBUG_OBJECT (src, "Stream created for device");
/* if acting as a GigE controller, configure stream */
PvDeviceGEV *lDeviceGEV = dynamic_cast < PvDeviceGEV * >(src->device);
if (!src->receiver_only && lDeviceGEV != NULL) {
#if VERSION_MAJOR == 4
PvStreamGEV *lStreamGEV = static_cast < PvStreamGEV * >(src->stream);
#else
const PvStreamGEV *lStreamGEV =
static_cast < PvStreamGEV * >(src->stream);
#endif
/* negotiate or set packet size */
if (src->packet_size == 0) {
/* Negotiate packet size, use safe default if it fails */
pvRes = lDeviceGEV->NegotiatePacketSize (0, 1476);
if (!pvRes.IsOK ()) {
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS,
("Failed to negotiate packet size: %s",
pvRes.GetDescription ().GetAscii ()), (NULL));
goto stream_config_failed;
}
} else {
pvRes = lDeviceGEV->SetPacketSize (src->packet_size);
if (!pvRes.IsOK ()) {
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS,
("Failed to set packet size to %d: %s", src->packet_size,
pvRes.GetDescription ().GetAscii ()), (NULL));
goto stream_config_failed;
}
}
/* Configure device streaming destination */
pvRes =
lDeviceGEV->SetStreamDestination (lStreamGEV->GetLocalIPAddress (),
lStreamGEV->GetLocalPort ());
if (!pvRes.IsOK ()) {
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS,
("Failed to set stream destination: %s",
pvRes.GetDescription ().GetAscii ()), (NULL));
goto stream_config_failed;
}
}
}
/* load config file if specified */
if (g_strcmp0 (src->config_file, DEFAULT_PROP_CONFIG_FILE) != 0 &&
!src->config_file_connect) {
if (!gst_pleorasrc_restore_device_from_config (src)) {
goto stream_config_failed;
}
if (!gst_pleorasrc_restore_stream_from_config (src)) {
goto stream_config_failed;
}
}
src->pipeline = new PvPipeline (src->stream);
if (src->pipeline == NULL) {
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
("Unable to create pipeline from stream"), (NULL));
goto stream_config_failed;
}
pvRes = src->pipeline->SetBufferCount (src->num_capture_buffers);
if (!pvRes.IsOK ()) {
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS,
("Unable to set buffer count: %s", pvRes.GetDescription ().GetAscii ()),
(NULL));
goto pipeline_config_failed;
}
return TRUE;
pipeline_config_failed:
if (src->pipeline) {
delete src->pipeline;
src->pipeline = NULL;
}
stream_config_failed:
if (src->stream) {
src->stream->Close ();
PvStream::Free (src->stream);
src->stream = NULL;
}
stream_failed:
if (src->device) {
src->device->Disconnect ();
PvDevice::Free (src->device);
src->device = NULL;
}
return FALSE;
}
// borrowed from Aravis, arvmisc.c
#define MAKE_FOURCC(a,b,c,d) ((guint32)((a)|(b)<<8|(c)<<16|(d)<<24))
typedef struct
{
PvPixelType pixel_type;
const char *gst_caps_string;
const char *name;
const char *format;
int bpp;
int depth;
guint32 fourcc;
} GstPleoraCapsInfos;
GstPleoraCapsInfos gst_caps_infos[] = {
{
PvPixelMono8,
"video/x-raw, format=(string)GRAY8",
"video/x-raw", "GRAY8",
8, 8, 0},
{
PvPixelMono10,
"video/x-raw, format=(string)GRAY16_LE, bpp=(int)10",
"video/x-raw", "GRAY16_LE",
10, 16, 0},
{
PvPixelMono12,
"video/x-raw, format=(string)GRAY16_LE, bpp=(int)12",
"video/x-raw", "GRAY16_LE",
12, 16, 0},
{
PvPixelMono14,
"video/x-raw, format=(string)GRAY16_LE, bpp=(int)14",
"video/x-raw", "GRAY16_LE",
14, 16, 0},
{
PvPixelMono16,
"video/x-raw, format=(string)GRAY16_LE",
"video/x-raw", "GRAY16_LE",
16, 16, 0},
{
PvPixelBayerGR8,
"video/x-bayer, format=(string)grbg",
"video/x-bayer", "grbg",
8, 8, MAKE_FOURCC ('g', 'r', 'b', 'g')
},
{
PvPixelBayerRG8,
"video/x-bayer, format=(string)rggb",
"video/x-bayer", "rggb",
8, 8, MAKE_FOURCC ('r', 'g', 'g', 'b')
},
{
PvPixelBayerGB8,
"video/x-bayer, format=(string)gbrg",
"video/x-bayer", "gbrg",
8, 8, MAKE_FOURCC ('g', 'b', 'r', 'g')
},
{
PvPixelBayerBG8,
"video/x-bayer, format=(string)bggr",
"video/x-bayer", "bggr",
8, 8, MAKE_FOURCC ('b', 'g', 'g', 'r')
},
/* The caps for non 8-bit bayer formats has not been agreed upon yet.
* This feature is discussed in bug https://bugzilla.gnome.org/show_bug.cgi?id=693666 .*/
{
PvPixelBayerGR10,
"video/x-bayer, format=(string)grbg16, bpp=(int)10",
"video/x-bayer", "grbg",
10, 16, 0},
{
PvPixelBayerRG10,
"video/x-bayer, format=(string)rggb16, bpp=(int)10",
"video/x-bayer", "rggb",
10, 16, 0},
{
PvPixelBayerGB10,
"video/x-bayer, format=(string)gbrg16, bpp=(int)10",
"video/x-bayer", "gbrg",
10, 16, 0},
{
PvPixelBayerBG10,
"video/x-bayer, format=(string)bggr16, bpp=(int)10",
"video/x-bayer", "bggr",
10, 16, 0},
{
PvPixelBayerGR12,
"video/x-bayer, format=(string)grbg16, bpp=(int)12",
"video/x-bayer", "grbg",
12, 16, 0},
{
PvPixelBayerRG12,
"video/x-bayer, format=(string)rggb16, bpp=(int)12",
"video/x-bayer", "rggb",
12, 16, 0},
{
PvPixelBayerGB12,
"video/x-bayer, format=(string)gbrg16, bpp=(int)12",
"video/x-bayer", "gbrg",
12, 16, 0},
{
PvPixelBayerBG12,
"video/x-bayer, format=(string)bggr16, bpp=(int)12",
"video/x-bayer", "bggr",
12, 16, 0},
{
PvPixelBayerGR16,
"video/x-bayer, format=(string)grbg16, bpp=(int)16",
"video/x-bayer", "grbg",
16, 16, 0},
{
PvPixelBayerRG16,
"video/x-bayer, format=(string)rggb16, bpp=(int)16",
"video/x-bayer", "rggb",
16, 16, 0},
{
PvPixelBayerGB16,
"video/x-bayer, format=(string)gbrg16, bpp=(int)16",
"video/x-bayer", "gbrg",
16, 16, 0},
{
PvPixelBayerBG16,
"video/x-bayer, format=(string)bggr16, bpp=(int)16",
"video/x-bayer", "bggr",
16, 16, 0},
{
PvPixelYUV422_8_UYVY,
"video/x-raw, format=(string)UYVY",
"video/x-raw", "UYVY",
0, 0, MAKE_FOURCC ('U', 'Y', 'V', 'Y')
},
{
PvPixelYUV411_8_UYYVYY,
"video/x-raw, format=(string)IYU1",
"video/x-raw", "IYU1",
0, 0, MAKE_FOURCC ('I', 'Y', 'U', '1')
},
{
PvPixelYUV8_UYV,
"video/x-raw, format=(string)IYU2",
"video/x-raw", "IYU2",
0, 0, MAKE_FOURCC ('I', 'Y', 'U', '2')
},
{
PvPixelYUV422_8,
"video/x-raw, format=(string)YUY2",
"video/x-raw", "YUY2",
0, 0, MAKE_FOURCC ('Y', 'U', 'Y', '2')
},
{
PvPixelRGB8,
"video/x-raw, format=(string)RGB",
"video/x-raw", "RGB",
24, 24, 0},
{
PvPixelRGBa8,
"video/x-raw, format=(string)RGBx",
"video/x-raw", "RGBx",
32, 32, 0},
};
/**
* arv_pixel_format_to_gst_caps_string:
* @pixel_format: a pixel format
* Return value: a gstreamer caps string describing the given @pixel_format.
*/
const char *
gst_pleorasrc_pixel_type_to_gst_caps_string (PvPixelType pixel_type)
{
int i;
for (i = 0; i < G_N_ELEMENTS (gst_caps_infos); i++)
if (gst_caps_infos[i].pixel_type == pixel_type)
break;
if (i == G_N_ELEMENTS (gst_caps_infos)) {
GST_WARNING ("Pixel type not currently supported: %d", pixel_type);
return NULL;
}
GST_LOG ("Matched pixel type %d to caps %s",
pixel_type, gst_caps_infos[i].gst_caps_string);
return gst_caps_infos[i].gst_caps_string;
}
PvPixelType
gst_pleorasrc_pixel_type_from_gst_caps (const char *name,
const char *format, int bpp, int depth)
{
unsigned int i;
g_return_val_if_fail (name != NULL, PvPixelUndefined);
for (i = 0; i < G_N_ELEMENTS (gst_caps_infos); i++) {
if (strcmp (name, gst_caps_infos[i].name) != 0 ||
(depth > 0 && depth != gst_caps_infos[i].depth) ||
(bpp > 0 && bpp != gst_caps_infos[i].bpp))
continue;
if (strcmp (name, "video/x-raw") == 0 &&
strcmp (format, gst_caps_infos[i].format) == 0)
return gst_caps_infos[i].pixel_type;
if (strcmp (name, "video/x-bayer") == 0 &&
strcmp (format, gst_caps_infos[i].format) == 0)
return gst_caps_infos[i].pixel_type;
}
return PvPixelUndefined;
}
static gboolean
gst_pleorasrc_start (GstBaseSrc * bsrc)
{
GstPleoraSrc *src = GST_PLEORA_SRC (bsrc);
PvResult pvRes;
GST_DEBUG_OBJECT (src, "start");
if (!gst_pleorasrc_setup_stream (src)) {
/* error already sent */
goto error;
}
/* Note: the pipeline must be initialized before we start acquisition */
GST_DEBUG_OBJECT (src, "Starting pipeline");
pvRes = src->pipeline->Start ();
if (!pvRes.IsOK ()) {
GST_ELEMENT_ERROR (src, RESOURCE, FAILED, ("Failed to start pipeline: %s",
pvRes.GetDescription ().GetAscii ()), (NULL));
goto error;
}
/* command stream to start */
if (!src->receiver_only) {
PvGenParameterArray *lDeviceParams = src->device->GetParameters ();
PvGenCommand *start_cmd =
dynamic_cast <
PvGenCommand * >(lDeviceParams->Get ("AcquisitionStart"));
GST_DEBUG_OBJECT (src,
"Opened as controller, so send AcquisitionStart command");
if (start_cmd == NULL) {
GST_ELEMENT_ERROR (src, RESOURCE, FAILED,
("Failed to get device AcquisitionStart parameter"), (NULL));
goto error;
}
pvRes = src->device->StreamEnable ();
if (!pvRes.IsOK ()) {
GST_ELEMENT_ERROR (src, RESOURCE, FAILED, ("Failed to enable stream: %s",
pvRes.GetDescription ().GetAscii ()), (NULL));
goto error;
}
pvRes = start_cmd->Execute ();
if (!pvRes.IsOK ()) {
GST_ELEMENT_ERROR (src, RESOURCE, FAILED,
("Failed to start acquisition: %s",
pvRes.GetDescription ().GetAscii ()), (NULL));
goto error;
}
}
return TRUE;
error:
if (src->pipeline) {
delete src->pipeline;
src->pipeline = NULL;
}
if (src->stream) {
src->stream->Close ();
PvStream::Free (src->stream);
src->stream = NULL;
}
if (src->device) {
src->device->Disconnect ();
PvDevice::Free (src->device);
src->device = NULL;
}
return FALSE;
}
static gboolean
gst_pleorasrc_stop (GstBaseSrc * bsrc)
{
GstPleoraSrc *src = GST_PLEORA_SRC (bsrc);
GST_DEBUG_OBJECT (src, "stop");
if (!src->receiver_only) {
PvGenParameterArray *lDeviceParams = src->device->GetParameters ();
PvGenCommand *lStop =
dynamic_cast < PvGenCommand * >(lDeviceParams->Get ("AcquisitionStop"));
lStop->Execute ();
src->device->StreamDisable ();
}
src->pipeline->Stop ();
if (src->pipeline) {
delete src->pipeline;
src->pipeline = NULL;
}
if (src->stream) {
src->stream->Close ();
PvStream::Free (src->stream);
src->stream = NULL;
}
if (src->device) {
src->device->Disconnect ();
PvDevice::Free (src->device);
src->device = NULL;
}
gst_pleorasrc_reset (src);
return TRUE;
}
static GstCaps *
gst_pleorasrc_get_caps (GstBaseSrc * bsrc, GstCaps * filter)
{
GstPleoraSrc *src = GST_PLEORA_SRC (bsrc);
GstCaps *caps;
if (src->caps == NULL) {
caps = gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD (src));
} else {
caps = gst_caps_copy (src->caps);
}
GST_DEBUG_OBJECT (src, "The caps before filtering are %" GST_PTR_FORMAT,
caps);
if (filter && caps) {
GstCaps *tmp = gst_caps_intersect (caps, filter);
gst_caps_unref (caps);
caps = tmp;
}
GST_DEBUG_OBJECT (src, "The caps after filtering are %" GST_PTR_FORMAT, caps);
return caps;
}
static gboolean
gst_pleorasrc_set_caps (GstBaseSrc * bsrc, GstCaps * caps)
{
GstPleoraSrc *src = GST_PLEORA_SRC (bsrc);
GstVideoInfo vinfo;
GstStructure *s = gst_caps_get_structure (caps, 0);
GST_DEBUG_OBJECT (src, "The caps being set are %" GST_PTR_FORMAT, caps);
gst_video_info_from_caps (&vinfo, caps);
if (GST_VIDEO_INFO_FORMAT (&vinfo) != GST_VIDEO_FORMAT_UNKNOWN) {
src->height = GST_VIDEO_INFO_HEIGHT (&vinfo);
src->gst_stride = GST_VIDEO_INFO_COMP_STRIDE (&vinfo, 0);
} else {
goto unsupported_caps;
}
return TRUE;
unsupported_caps:
GST_ELEMENT_ERROR (src, RESOURCE, FAILED,
("Unsupported caps: %" GST_PTR_FORMAT, caps), (NULL));
return FALSE;
}
static gboolean
gst_pleorasrc_unlock (GstBaseSrc * bsrc)
{
GstPleoraSrc *src = GST_PLEORA_SRC (bsrc);
GST_LOG_OBJECT (src, "unlock");
src->stop_requested = TRUE;
return TRUE;
}
static gboolean
gst_pleorasrc_unlock_stop (GstBaseSrc * bsrc)
{
GstPleoraSrc *src = GST_PLEORA_SRC (bsrc);
GST_LOG_OBJECT (src, "unlock_stop");
src->stop_requested = FALSE;
return TRUE;
}
//static GstBuffer *
//gst_pleorasrc_create_buffer_from_pvimage (GstPleoraSrc * src,
// PvImage * pvimage)
//{
// GstMapInfo minfo;
// GstBuffer *buf;
//
// /* TODO: use allocator or use from pool */
// buf = gst_buffer_new_and_alloc (src->height * src->gst_stride);
//
// /* Copy image to buffer from surface */
// gst_buffer_map (buf, &minfo, GST_MAP_WRITE);
// GST_LOG_OBJECT (src,
// "GstBuffer size=%d, gst_stride=%d, buffer_num=%d, frame_count=%d, num_frames_on_queue=%d",
// minfo.size, src->gst_stride, circ_handle->BufferNumber,
// circ_handle->FrameCount, circ_handle->NumItemsOnQueue);
// GST_LOG_OBJECT (src, "Buffer timestamp %02d:%02d:%02d.%06d",
// circ_handle->HiResTimeStamp.hour, circ_handle->HiResTimeStamp.min,
// circ_handle->HiResTimeStamp.sec, circ_handle->HiResTimeStamp.usec);
//
// /* TODO: use orc_memcpy */
// if (src->gst_stride == src->bf_stride) {
// memcpy (minfo.data, ((guint8 *) circ_handle->pBufData), minfo.size);
// } else {
// int i;
// GST_LOG_OBJECT (src, "Image strides not identical, copy will be slower.");
// for (i = 0; i < src->height; i++) {
// memcpy (minfo.data + i * src->gst_stride,
// ((guint8 *) circ_handle->pBufData) +
// i * src->bf_stride, src->bf_stride);
// }
// }
// gst_buffer_unmap (buf, &minfo);
//
// return buf;
//}
typedef struct
{
GstPleoraSrc *src;
PvBuffer *buffer;
} VideoFrame;
static void
pvbuffer_release (void *data)
{
VideoFrame *frame = (VideoFrame *) data;
if (frame->src->pipeline) {
// TODO: should use a mutex in case _stop is being called at the same time
frame->src->pipeline->ReleaseBuffer (frame->buffer);
}
}
static GstFlowReturn
gst_pleorasrc_create (GstPushSrc * psrc, GstBuffer ** buf)
{
GstPleoraSrc *src = GST_PLEORA_SRC (psrc);
PvResult pvRes, opRes;
GstClock *clock;
GstClockTime clock_time;
PvBuffer *pvbuffer;
PvImage *pvimage;
GST_LOG_OBJECT (src, "create");
while (TRUE) {
pvRes = src->pipeline->RetrieveNextBuffer (&pvbuffer, src->timeout, &opRes);
if (!pvRes.IsOK ()) {
GST_ELEMENT_ERROR (src, RESOURCE, FAILED,
("Failed to retrieve buffer in timeout (%d ms): 0x%04x, '%s'",
src->timeout, pvRes.GetCode (),
pvRes.GetDescription ().GetAscii ()), (NULL));
return GST_FLOW_ERROR;
}
// continue if we get a bad frame
if (!opRes.IsOK ()) {
GST_WARNING_OBJECT (src, "Failed to get buffer: 0x%04x, '%s'",
opRes.GetCode (), opRes.GetDescription ().GetAscii ());
src->pipeline->ReleaseBuffer (pvbuffer);
continue;
}
if (pvbuffer->GetPayloadType () != PvPayloadTypeImage) {
/* TODO: are non-image buffers normal? */
GST_ERROR_OBJECT (src, "Got buffer with non-image data");
GST_ELEMENT_ERROR (src, RESOURCE, FAILED,
("Got buffer with non-image data"), (NULL));
return GST_FLOW_ERROR;
}
pvimage = pvbuffer->GetImage ();
break;
}
const char *caps_string =
gst_pleorasrc_pixel_type_to_gst_caps_string (pvimage->GetPixelType ());
/* TODO: cache previous caps_string */
if (caps_string != NULL) {
GstStructure *structure;
GstCaps *caps;
caps = gst_caps_new_empty ();
structure = gst_structure_from_string (caps_string, NULL);
gst_structure_set (structure,
"width", G_TYPE_INT, pvimage->GetWidth (),
"height", G_TYPE_INT, pvimage->GetHeight (),
"framerate", GST_TYPE_FRACTION, 30, 1, NULL);
gst_caps_append_structure (caps, structure);
if (src->caps) {
gst_caps_unref (src->caps);
}
src->caps = caps;
gst_base_src_set_caps (GST_BASE_SRC (src), src->caps);
guint32 pixel_bpp = PvGetPixelBitCount (pvimage->GetPixelType ());
src->pleora_stride = (pvimage->GetWidth () * pixel_bpp) / 8;
} else {
GST_ELEMENT_ERROR (src, RESOURCE, FAILED, ("Pixel type %d not supported",
pvimage->GetPixelType ()), (NULL));
return GST_FLOW_ERROR;
}
gpointer data = pvimage->GetDataPointer ();
if (src->pleora_stride == src->gst_stride) {
VideoFrame *vf = g_new0 (VideoFrame, 1);
vf->src = src;
vf->buffer = pvbuffer;
gsize data_size = pvimage->GetImageSize ();
*buf =
gst_buffer_new_wrapped_full ((GstMemoryFlags) GST_MEMORY_FLAG_READONLY,
(gpointer) data, data_size, 0, data_size, vf,
(GDestroyNotify) pvbuffer_release);
} else {
GstMapInfo minfo;
GST_LOG_OBJECT (src,
"Row stride not aligned, copying %d -> %d",
src->pleora_stride, src->gst_stride);
*buf = gst_buffer_new_and_alloc (src->height * src->gst_stride);
guint8 *s = (guint8 *) data;
guint8 *d;
gst_buffer_map (*buf, &minfo, GST_MAP_WRITE);
d = minfo.data;
g_assert (minfo.size >= src->pleora_stride * src->height);
for (int i = 0; i < src->height; i++)
memcpy (d + i * src->gst_stride, s + i * src->pleora_stride,
src->pleora_stride);
gst_buffer_unmap (*buf, &minfo);
src->pipeline->ReleaseBuffer (pvbuffer);
}
clock = gst_element_get_clock (GST_ELEMENT (src));
clock_time = gst_clock_get_time (clock);
gst_object_unref (clock);
/* check for dropped frames and disrupted signal */
//dropped_frames = (circ_handle.FrameCount - src->last_frame_count) - 1;
//if (dropped_frames > 0) {
// src->total_dropped_frames += dropped_frames;
// GST_WARNING_OBJECT (src, "Dropped %d frames (%d total)", dropped_frames,
// src->total_dropped_frames);
//} else if (dropped_frames < 0) {
// GST_WARNING_OBJECT (src, "Frame count non-monotonic, signal disrupted?");
//}
//src->last_frame_count = circ_handle.FrameCount;
/* create GstBuffer then release circ buffer back to acquisition */
//*buf = gst_pleorasrc_create_buffer_from_circ_handle (src, &circ_handle);
//ret =
// BiCirStatusSet (src->board, &src->buffer_array, circ_handle, BIAVAILABLE);
//if (ret != BI_OK) {
// GST_ELEMENT_ERROR (src, RESOURCE, FAILED,
// ("Failed to release buffer: %s", gst_pleorasrc_get_error_string (src,
// ret)), (NULL));
// return GST_FLOW_ERROR;
//}
/* TODO: understand why timestamps for circ_handle are sometimes 0 */
//GST_BUFFER_TIMESTAMP (*buf) =
// GST_CLOCK_DIFF (gst_element_get_base_time (GST_ELEMENT (src)),
// src->acq_start_time + circ_handle.HiResTimeStamp.totalSec * GST_SECOND);
GST_BUFFER_TIMESTAMP (*buf) =
GST_CLOCK_DIFF (gst_element_get_base_time (GST_ELEMENT (src)),
clock_time);
//GST_BUFFER_OFFSET (*buf) = circ_handle.FrameCount - 1;
if (src->stop_requested) {
if (*buf != NULL) {
gst_buffer_unref (*buf);
*buf = NULL;
}
return GST_FLOW_FLUSHING;
}
return GST_FLOW_OK;
}
static gboolean
plugin_init (GstPlugin * plugin)
{
GST_DEBUG_CATEGORY_INIT (gst_pleorasrc_debug, "pleorasrc", 0,
"debug category for pleorasrc element");
gst_element_register (plugin, "pleorasrc", GST_RANK_NONE,
gst_pleorasrc_get_type ());
return TRUE;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
pleora,
"Pleora eBUS video source",
plugin_init, GST_PACKAGE_VERSION, GST_PACKAGE_LICENSE, GST_PACKAGE_NAME,
GST_PACKAGE_ORIGIN)