--- /dev/null
+/*
+ * GStreamer OpenNI2 device source element
+ * Copyright (C) 2013 Miguel Casas-Sanchez <miguelecasassanchez@gmail.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 St,
+ * Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-openni2src
+ *
+ * <refsect2>
+ * <title>Examples</title>
+ * <para>
+ * Some recorded .oni files are available at:
+ * <programlisting>
+ * http://people.cs.pitt.edu/~chang/1635/proj11/kinectRecord
+ * </programlisting>
+ *
+ * <programlisting>
+ LD_LIBRARY_PATH=/usr/lib/OpenNI2/Drivers/ gst-launch-1.0 --gst-debug=openni2src:5 openni2src location='Downloads/mr.oni' sourcetype=depth ! videoconvert ! ximagesink
+ * </programlisting>
+ * <programlisting>
+ LD_LIBRARY_PATH=/usr/lib/OpenNI2/Drivers/ gst-launch-1.0 --gst-debug=openni2src:5 openni2src location='Downloads/mr.oni' sourcetype=color ! videoconvert ! ximagesink
+ * </programlisting>
+ * </para>
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstopenni2src.h"
+\
+GST_DEBUG_CATEGORY_STATIC (openni2src_debug);
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-raw, "
+ "format = (string) {RGBA, RGB, GRAY16_LE} "
+ "framerate = (fraction) [0/1, MAX], "
+ "width = (int) [ 1, MAX ], "
+ "height = (int) [ 1, MAX ]")
+ );
+
+static GstElementClass *parent_class = NULL;
+
+enum
+{
+ PROP_0,
+ PROP_LOCATION,
+ PROP_SOURCETYPE
+};
+typedef enum
+{
+ SOURCETYPE_DEPTH,
+ SOURCETYPE_COLOR,
+ SOURCETYPE_BOTH
+} GstOpenni2SourceType;
+#define DEFAULT_SOURCETYPE SOURCETYPE_DEPTH
+
+#define SAMPLE_READ_WAIT_TIMEOUT 2000 /* 2000ms */
+
+#define GST_TYPE_OPENNI2_SRC_SOURCETYPE (gst_openni2_src_sourcetype_get_type ())
+static GType
+gst_openni2_src_sourcetype_get_type (void)
+{
+ static GType etype = 0;
+ if (etype == 0) {
+ static const GEnumValue values[] = {
+ {SOURCETYPE_DEPTH, "Get depth readings", "depth"},
+ {SOURCETYPE_COLOR, "Get color readings", "color"},
+ {SOURCETYPE_BOTH, "Get color and depth (as alpha) readings - EXPERIMENTAL",
+ "both"},
+ {0, NULL, NULL},
+ };
+ etype = g_enum_register_static ("GstOpenni2SrcSourcetype", values);
+ }
+ return etype;
+}
+
+/* GObject methods */
+static void gst_openni2_src_dispose (GObject * object);
+static void gst_openni2_src_finalize (GObject * gobject);
+static void gst_openni2_src_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_openni2_src_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+/* basesrc methods */
+static gboolean gst_openni2_src_start (GstBaseSrc * bsrc);
+static gboolean gst_openni2_src_stop (GstBaseSrc * bsrc);
+static GstCaps *gst_openni2_src_get_caps (GstBaseSrc * src, GstCaps * filter);
+
+/* element methods */
+static GstStateChangeReturn gst_openni2_src_change_state (GstElement * element,
+ GstStateChange transition);
+
+/* pushsrc method */
+static GstFlowReturn gst_openni2src_fill (GstPushSrc * src,
+ GstBuffer * buf);
+
+/* OpenNI2 interaction methods */
+static gboolean openni2_initialise_library ();
+static GstFlowReturn openni2_initialise_devices (GstOpenni2Src * src);
+static GstFlowReturn openni2_read_gstbuffer (GstOpenni2Src * src,
+ GstBuffer * buf);
+static void openni2_finalise (GstOpenni2Src * src);
+
+G_DEFINE_TYPE (GstOpenni2Src, gst_openni2_src, GST_TYPE_PUSH_SRC)
+
+static void
+gst_openni2_src_class_init (GstOpenni2SrcClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstPushSrcClass *pushsrc_class;
+ GstBaseSrcClass *basesrc_class;
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+ gobject_class = (GObjectClass *) klass;
+ basesrc_class = (GstBaseSrcClass *) klass;
+ pushsrc_class = (GstPushSrcClass *) klass;
+ parent_class = (GstElementClass *) g_type_class_peek_parent (klass);
+
+ gobject_class->dispose = gst_openni2_src_dispose;
+ gobject_class->finalize = gst_openni2_src_finalize;
+ gobject_class->set_property = gst_openni2_src_set_property;
+ gobject_class->get_property = gst_openni2_src_get_property;
+ g_object_class_install_property
+ (gobject_class, PROP_LOCATION,
+ g_param_spec_string ("location", "Location",
+ "Source uri, can be a file or a device.", "",
+ (GParamFlags)
+ (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+ g_object_class_install_property (gobject_class, PROP_SOURCETYPE,
+ g_param_spec_enum ("sourcetype",
+ "Device source type",
+ "Type of readings to get from the source",
+ GST_TYPE_OPENNI2_SRC_SOURCETYPE, DEFAULT_SOURCETYPE,
+ (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+
+ basesrc_class->start = GST_DEBUG_FUNCPTR (gst_openni2_src_start);
+ basesrc_class->stop = GST_DEBUG_FUNCPTR (gst_openni2_src_stop);
+ basesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_openni2_src_get_caps);
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&srctemplate));
+
+ gst_element_class_set_static_metadata (element_class, "Openni2 client source",
+ "Source/Device",
+ "Extract readings from an OpenNI supported device (Kinect etc). ",
+ "Miguel Casas-Sanchez <miguelecasassanchez@gmail.com>");
+
+ element_class->change_state = gst_openni2_src_change_state;
+
+ pushsrc_class->fill = GST_DEBUG_FUNCPTR (gst_openni2src_fill);
+
+ GST_DEBUG_CATEGORY_INIT (openni2src_debug, "openni2src", 0,
+ "OpenNI2 Device Source");
+
+ /* OpenNI2 initialisation inside this function */
+ openni2_initialise_library();
+}
+
+static void
+gst_openni2_src_init (GstOpenni2Src * ni2src)
+{
+ gst_base_src_set_format (GST_BASE_SRC (ni2src), GST_FORMAT_BYTES);
+}
+
+static void
+gst_openni2_src_dispose (GObject * object)
+{
+ GstOpenni2Src *ni2src = GST_OPENNI2_SRC (object);
+ if (ni2src->gst_caps)
+ gst_caps_unref (ni2src->gst_caps);
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_openni2_src_finalize (GObject * gobject)
+{
+ GstOpenni2Src *ni2src = GST_OPENNI2_SRC (gobject);
+
+ openni2_finalise (ni2src);
+
+ if (ni2src->uri_name) {
+ g_free (ni2src->uri_name);
+ ni2src->uri_name = NULL;
+ }
+ if (ni2src->gst_caps)
+ gst_caps_unref(ni2src->gst_caps);
+ ni2src->gst_caps = NULL;
+
+ G_OBJECT_CLASS (parent_class)->finalize (gobject);
+}
+
+static void
+gst_openni2_src_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstOpenni2Src *openni2src = GST_OPENNI2_SRC (object);
+
+ GST_OBJECT_LOCK (openni2src);
+ switch (prop_id) {
+ case PROP_LOCATION:
+ if (!g_value_get_string (value)) {
+ GST_WARNING ("location property cannot be NULL");
+ break;
+ }
+
+ if (openni2src->uri_name != NULL) {
+ g_free (openni2src->uri_name);
+ openni2src->uri_name = NULL;
+ }
+ openni2src->uri_name = g_value_dup_string (value);
+ /* Action! */
+ openni2_initialise_devices (openni2src);
+ break;
+ case PROP_SOURCETYPE:
+ openni2src->sourcetype = g_value_get_enum (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+
+ GST_OBJECT_UNLOCK (openni2src);
+}
+
+static void
+gst_openni2_src_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstOpenni2Src *openni2src = GST_OPENNI2_SRC (object);
+
+ GST_OBJECT_LOCK (openni2src);
+ switch (prop_id) {
+ case PROP_LOCATION:
+ g_value_set_string (value, openni2src->uri_name);
+ break;
+ case PROP_SOURCETYPE:
+ g_value_set_enum (value, openni2src->sourcetype);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+ GST_OBJECT_UNLOCK (openni2src);
+}
+
+/* Interesting info from gstv4l2src.c:
+ * "start and stop are not symmetric -- start will open the device, but not
+ * start capture. it's setcaps that will start capture, which is called via
+ * basesrc's negotiate method. stop will both stop capture and close t device."
+ */
+static gboolean
+gst_openni2_src_start (GstBaseSrc * bsrc)
+{
+ GstOpenni2Src *src = GST_OPENNI2_SRC (bsrc);
+ openni::Status rc = openni::STATUS_OK;
+ if (src->depth.isValid ()){
+ rc = src->depth.start();
+ if (rc != openni::STATUS_OK){
+ GST_ERROR_OBJECT( src, "Couldn't start the depth stream\n%s\n",
+ openni::OpenNI::getExtendedError());
+ return FALSE;
+ }
+ }
+ if (src->color.isValid ()){
+ rc = src->color.start();
+ if (rc != openni::STATUS_OK){
+ GST_ERROR_OBJECT( src, "Couldn't start the color stream\n%s\n",
+ openni::OpenNI::getExtendedError());
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+static gboolean
+gst_openni2_src_stop (GstBaseSrc * bsrc)
+{
+ GstOpenni2Src *src = GST_OPENNI2_SRC (bsrc);
+
+ if (src->depth.isValid ())
+ src->depth.stop();
+ if (src->color.isValid ())
+ src->color.stop();
+ return TRUE;
+}
+
+static GstCaps *
+gst_openni2_src_get_caps (GstBaseSrc * src, GstCaps * filter)
+{
+ GstOpenni2Src *ni2src;
+ GstCaps *caps;
+ ni2src = GST_OPENNI2_SRC (src);
+ GST_OBJECT_LOCK (ni2src);
+ if (ni2src->gst_caps) {
+ GST_OBJECT_UNLOCK (ni2src);
+ return (filter)
+ ? gst_caps_intersect_full (filter, ni2src->gst_caps, GST_CAPS_INTERSECT_FIRST)
+ : gst_caps_ref (ni2src->gst_caps);
+ }
+
+ // If we are here, we need to compose the caps and return them.
+ caps = gst_caps_new_empty();
+ if (ni2src->colorpixfmt != openni::PIXEL_FORMAT_RGB888)
+ return caps; /* Uh oh, not RGB :? Not supported. */
+
+ if (ni2src->depth.isValid () && ni2src->color.isValid () &&
+ ni2src->sourcetype == SOURCETYPE_BOTH) {
+ caps = gst_caps_new_simple ("video/x-raw",
+ "format", G_TYPE_STRING, "RGBA",
+ "framerate", GST_TYPE_FRACTION, ni2src->fps, 1,
+ "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1,
+ "width", G_TYPE_INT, ni2src->width,
+ "height", G_TYPE_INT, ni2src->height,
+ NULL);
+ } else if (ni2src->depth.isValid () && ni2src->sourcetype == SOURCETYPE_DEPTH) {
+ caps = gst_caps_new_simple ("video/x-raw",
+ "format", G_TYPE_STRING, "GRAY16_LE",
+ "framerate", GST_TYPE_FRACTION, ni2src->fps, 1,
+ "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1,
+ "width", G_TYPE_INT, ni2src->width,
+ "height", G_TYPE_INT, ni2src->height,
+ NULL);
+ } else if (ni2src->color.isValid () && ni2src->sourcetype == SOURCETYPE_COLOR) {
+ caps = gst_caps_new_simple ("video/x-raw",
+ "format", G_TYPE_STRING, "RGB",
+ "framerate", GST_TYPE_FRACTION, ni2src->fps, 1,
+ "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1,
+ "width", G_TYPE_INT, ni2src->width,
+ "height", G_TYPE_INT, ni2src->height,
+ NULL);
+ }
+ GST_INFO_OBJECT (ni2src, "probed caps: %" GST_PTR_FORMAT, caps);
+ ni2src->gst_caps = gst_caps_ref(caps);
+ GST_OBJECT_UNLOCK (ni2src);
+ return (filter)
+ ? gst_caps_intersect_full (filter, ni2src->gst_caps, GST_CAPS_INTERSECT_FIRST)
+ : gst_caps_ref (ni2src->gst_caps);
+}
+
+static GstStateChangeReturn
+gst_openni2_src_change_state (GstElement * element, GstStateChange transition)
+{
+ GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
+ GstOpenni2Src *src = GST_OPENNI2_SRC (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ break;
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ if (!src->uri_name) {
+ GST_ERROR_OBJECT (src, "Invalid location");
+ return ret;
+ }
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+ if (ret == GST_STATE_CHANGE_FAILURE) {
+ return ret;
+ }
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ gst_openni2_src_stop(GST_BASE_SRC(src));
+ if (src->gst_caps) {
+ gst_caps_unref (src->gst_caps);
+ src->gst_caps = NULL;
+ }
+ break;
+ case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+
+static GstFlowReturn
+gst_openni2src_fill (GstPushSrc * src, GstBuffer * buf)
+{
+ GstOpenni2Src *ni2src = GST_OPENNI2_SRC (src);
+ return openni2_read_gstbuffer (ni2src, buf);
+}
+
+gboolean
+gst_openni2src_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "openni2src", GST_RANK_NONE,
+ GST_TYPE_OPENNI2_SRC);
+}
+
+
+static gboolean
+openni2_initialise_library ()
+{
+ openni::Status rc = openni::STATUS_OK;
+ rc = openni::OpenNI::initialize ();
+ if (rc != openni::STATUS_OK) {
+ GST_ERROR("Initialization failed: %s", openni::OpenNI::getExtendedError ());
+ openni::OpenNI::shutdown ();
+ return GST_FLOW_ERROR;
+ }
+ return (rc == openni::STATUS_OK);
+}
+
+GstFlowReturn
+openni2_initialise_devices (GstOpenni2Src * src)
+{
+ openni::Status rc = openni::STATUS_OK;
+ const char *deviceURI = openni::ANY_DEVICE;
+ if (src->uri_name)
+ deviceURI = src->uri_name;
+
+ /** OpenNI2 open device or file **/
+ rc = src->device.open (deviceURI);
+ if (rc != openni::STATUS_OK) {
+ GST_ERROR_OBJECT (src, "Device (%s) open failed: %s", deviceURI,
+ openni::OpenNI::getExtendedError ());
+ openni::OpenNI::shutdown ();
+ return GST_FLOW_ERROR;
+ }
+
+ /** depth sensor **/
+ rc = src->depth.create (src->device, openni::SENSOR_DEPTH);
+ if (rc == openni::STATUS_OK) {
+ rc = src->depth.start ();
+ if (rc != openni::STATUS_OK) {
+ GST_ERROR_OBJECT (src, "%s", openni::OpenNI::getExtendedError ());
+ src->depth.destroy ();
+ }
+ } else
+ GST_WARNING_OBJECT (src, "Couldn't find depth stream: %s",
+ openni::OpenNI::getExtendedError ());
+
+ /** color sensor **/
+ rc = src->color.create (src->device, openni::SENSOR_COLOR);
+ if (rc == openni::STATUS_OK) {
+ rc = src->color.start ();
+ if (rc != openni::STATUS_OK) {
+ GST_ERROR_OBJECT (src, "Couldn't start color stream: %s ",
+ openni::OpenNI::getExtendedError ());
+ src->color.destroy ();
+ }
+ } else
+ GST_WARNING_OBJECT (src, "Couldn't find color stream: %s",
+ openni::OpenNI::getExtendedError ());
+
+
+ if (!src->depth.isValid () && !src->color.isValid ()) {
+ GST_ERROR_OBJECT (src, "No valid streams. Exiting\n");
+ openni::OpenNI::shutdown ();
+ return GST_FLOW_ERROR;
+ }
+
+ /** Get resolution and make sure is valid **/
+ if (src->depth.isValid () && src->color.isValid ()) {
+ src->depthVideoMode = src->depth.getVideoMode ();
+ src->colorVideoMode = src->color.getVideoMode ();
+
+ int depthWidth = src->depthVideoMode.getResolutionX ();
+ int depthHeight = src->depthVideoMode.getResolutionY ();
+ int colorWidth = src->colorVideoMode.getResolutionX ();
+ int colorHeight = src->colorVideoMode.getResolutionY ();
+
+ if (depthWidth == colorWidth && depthHeight == colorHeight) {
+ src->width = depthWidth;
+ src->height = depthHeight;
+ src->fps = src->depthVideoMode.getFps();
+ src->colorpixfmt = src->colorVideoMode.getPixelFormat();
+ src->depthpixfmt = src->depthVideoMode.getPixelFormat();
+ } else {
+ GST_ERROR_OBJECT (src, "Error - expect color and depth to be"
+ " in same resolution: D: %dx%d vs C: %dx%d",
+ depthWidth, depthHeight, colorWidth, colorHeight);
+ return GST_FLOW_ERROR;
+ }
+ GST_INFO_OBJECT (src, "DEPTH&COLOR resolution: %dx%d",
+ src->width, src->height);
+ } else if (src->depth.isValid ()) {
+ src->depthVideoMode = src->depth.getVideoMode ();
+ src->width = src->depthVideoMode.getResolutionX ();
+ src->height = src->depthVideoMode.getResolutionY ();
+ src->fps = src->depthVideoMode.getFps();
+ src->depthpixfmt = src->depthVideoMode.getPixelFormat();
+ GST_INFO_OBJECT (src, "DEPTH resolution: %dx%d", src->width, src->height);
+ } else if (src->color.isValid ()) {
+ src->colorVideoMode = src->color.getVideoMode ();
+ src->width = src->colorVideoMode.getResolutionX ();
+ src->height = src->colorVideoMode.getResolutionY ();
+ src->fps = src->colorVideoMode.getFps();
+ src->colorpixfmt = src->colorVideoMode.getPixelFormat();
+ GST_INFO_OBJECT (src, "COLOR resolution: %dx%d", src->width, src->height);
+ } else {
+ GST_ERROR_OBJECT (src, "Expected at least one of the streams to be valid.");
+ return GST_FLOW_ERROR;
+ }
+
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+openni2_read_gstbuffer (GstOpenni2Src * src, GstBuffer * buf)
+{
+ openni::Status rc = openni::STATUS_OK;
+ openni::VideoStream * pStream = &(src->depth);
+ int changedStreamDummy;
+
+ /* Block until we get some data */
+ rc = openni::OpenNI::waitForAnyStream (&pStream, 1, &changedStreamDummy,
+ SAMPLE_READ_WAIT_TIMEOUT);
+ if (rc != openni::STATUS_OK) {
+ GST_ERROR_OBJECT (src, "Frame read timeout: %s",
+ openni::OpenNI::getExtendedError ());
+ return GST_FLOW_ERROR;
+ }
+
+ GstMapInfo info;
+ if (src->depth.isValid () && src->color.isValid () &&
+ src->sourcetype == SOURCETYPE_BOTH) {
+ rc = src->depth.readFrame (&src->depthFrame);
+ if (rc != openni::STATUS_OK) {
+ GST_ERROR_OBJECT (src, "Frame read error: %s",
+ openni::OpenNI::getExtendedError ());
+ return GST_FLOW_ERROR;
+ }
+ rc = src->color.readFrame (&src->colorFrame);
+ if (rc != openni::STATUS_OK) {
+ GST_ERROR_OBJECT (src, "Frame read error: %s",
+ openni::OpenNI::getExtendedError ());
+ return GST_FLOW_ERROR;
+ }
+ if ((src->colorFrame.getStrideInBytes() != src->colorFrame.getWidth()) ||
+ (src->depthFrame.getStrideInBytes() != 2*src->depthFrame.getWidth())) {
+ // This case is not handled - yet :B
+ GST_ERROR_OBJECT(src, "Stride does not coincide with width");
+ return GST_FLOW_ERROR;
+ }
+
+ int framesize = src->colorFrame.getDataSize() + src->depthFrame.getDataSize()/2;
+ buf = gst_buffer_new_and_alloc(framesize);
+ /* Copy colour information */
+ gst_buffer_map(buf, &info, (GstMapFlags)(GST_MAP_WRITE));
+ memcpy(info.data, src->colorFrame.getData(), src->colorFrame.getDataSize());
+ guint8* pData = info.data + src->colorFrame.getDataSize();
+ /* Add depth as 8bit alpha channel, depth is 16bit samples. */
+ guint16* pDepth = (guint16*) src->depthFrame.getData();
+ for( int i=0; i < src->depthFrame.getDataSize()/2; ++i)
+ pData[i] = pDepth[i] >> 8;
+ GST_WARNING_OBJECT (src, "sending buffer (%d+%d)B [%08llu]",
+ src->colorFrame.getDataSize(),
+ src->depthFrame.getDataSize (),
+ (long long) src->depthFrame.getTimestamp ());
+ gst_buffer_unmap(buf, &info);
+ } else if (src->depth.isValid () && src->sourcetype == SOURCETYPE_DEPTH) {
+ rc = src->depth.readFrame (&src->depthFrame);
+ if (rc != openni::STATUS_OK) {
+ GST_ERROR_OBJECT (src, "Frame read error: %s",
+ openni::OpenNI::getExtendedError ());
+ return GST_FLOW_ERROR;
+ }
+ if (src->depthFrame.getStrideInBytes() != 2*src->depthFrame.getWidth()) {
+ // This case is not handled - yet :B
+ GST_ERROR_OBJECT(src, "Stride does not coincide with width");
+ return GST_FLOW_ERROR;
+ }
+
+ int framesize = src->depthFrame.getDataSize();
+ buf = gst_buffer_new_and_alloc(framesize);
+ gst_buffer_map(buf, &info, (GstMapFlags)(GST_MAP_WRITE));
+ memcpy(info.data, src->depthFrame.getData(), framesize);
+ GST_BUFFER_PTS(buf) = src->depthFrame.getTimestamp() * 1000;
+ GST_WARNING_OBJECT (src, "sending buffer (%dx%d)=%dB [%08llu]",
+ src->depthFrame.getWidth (),
+ src->depthFrame.getHeight (),
+ src->depthFrame.getDataSize (),
+ (long long) src->depthFrame.getTimestamp ());
+ gst_buffer_unmap(buf, &info);
+ } else if (src->color.isValid () && src->sourcetype == SOURCETYPE_COLOR) {
+ rc = src->color.readFrame (&src->colorFrame);
+ if (rc != openni::STATUS_OK) {
+ GST_ERROR_OBJECT (src, "Frame read error: %s",
+ openni::OpenNI::getExtendedError ());
+ return GST_FLOW_ERROR;
+ }
+ if (src->colorFrame.getStrideInBytes() != src->colorFrame.getWidth()) {
+ // This case is not handled - yet :B
+ GST_ERROR_OBJECT(src, "Stride does not coincide with width");
+ return GST_FLOW_ERROR;
+ }
+ int framesize = src->colorFrame.getDataSize();
+ buf = gst_buffer_new_and_alloc(framesize);
+ gst_buffer_map(buf, &info, (GstMapFlags)(GST_MAP_WRITE));
+ memcpy(info.data, src->depthFrame.getData(), framesize);
+ GST_BUFFER_PTS(buf) = src->colorFrame.getTimestamp() * 1000;
+ GST_WARNING_OBJECT (src, "sending buffer (%dx%d)=%dB [%08llu]",
+ src->colorFrame.getWidth (),
+ src->colorFrame.getHeight (),
+ src->colorFrame.getDataSize (),
+ (long long) src->colorFrame.getTimestamp ());
+ gst_buffer_unmap(buf, &info);
+ }
+ return GST_FLOW_OK;
+}
+
+static void
+openni2_finalise (GstOpenni2Src * src)
+{
+ src->depth.destroy();
+ src->color.destroy();
+ openni::OpenNI::shutdown ();
+}