diff options
Diffstat (limited to 'ext/dc1394/gstdc1394.c')
-rw-r--r-- | ext/dc1394/gstdc1394.c | 1246 |
1 files changed, 1246 insertions, 0 deletions
diff --git a/ext/dc1394/gstdc1394.c b/ext/dc1394/gstdc1394.c new file mode 100644 index 000000000..9af620a66 --- /dev/null +++ b/ext/dc1394/gstdc1394.c @@ -0,0 +1,1246 @@ +/* GStreamer + * Copyright (C) <2006> Eric Jonas <jonas@mit.edu> + * Copyright (C) <2006> Antoine Tremblay <hexa00@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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/** + * SECTION:element-dc1394 + * + * <refsect2> + * <title>Example launch line</title> + * <para> + * <programlisting> + * gst-launch -v dc1394 camera-number=0 ! xvimagesink + * </programlisting> + * </para> + * </refsect2> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "gstdc1394.h" +#include <sys/time.h> +#include <time.h> + +GST_DEBUG_CATEGORY (dc1394_debug); +#define GST_CAT_DEFAULT dc1394_debug + +static GstElementDetails dc1394_details = +GST_ELEMENT_DETAILS ("1394 IIDC Video Source", + "Source/Video", + "libdc1394 based source, supports 1394 IIDC cameras", + "Antoine Tremblay <hexa00@gmail.com>"); + +enum +{ + PROP_0, + PROP_TIMESTAMP_OFFSET, + PROP_CAMNUM, + PROP_BUFSIZE + /* FILL ME */ +}; + + +GST_BOILERPLATE (GstDc1394, gst_dc1394, GstPushSrc, GST_TYPE_PUSH_SRC); + +static void gst_dc1394_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_dc1394_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static GstCaps *gst_dc1394_getcaps (GstBaseSrc * bsrc); +static gboolean gst_dc1394_setcaps (GstBaseSrc * bsrc, GstCaps * caps); +static void gst_dc1394_src_fixate (GstPad * pad, GstCaps * caps); + +static void gst_dc1394_get_times (GstBaseSrc * basesrc, + GstBuffer * buffer, GstClockTime * start, GstClockTime * end); + +static GstFlowReturn gst_dc1394_create (GstPushSrc * psrc, GstBuffer ** buffer); + + +static GstStateChangeReturn +gst_dc1394_change_state (GstElement * element, GstStateChange transition); + + +static gboolean gst_dc1394_parse_caps (const GstCaps * caps, + gint * width, + gint * height, + gint * rate_numerator, gint * rate_denominator, gint * vmode, gint * bpp); + + +gint gst_dc1394_caps_set_format_vmode_caps (GstStructure * st, gint mode); +gboolean gst_dc1394_set_caps_color (GstStructure * gs, gint mc); +void gst_dc1394_set_caps_framesize (GstStructure * gs, gint width, gint height); +void gst_dc1394_set_caps_framesize_range (GstStructure * gs, gint minwidth, + gint maxwidth, gint incwidth, + gint minheight, gint maxheight, gint incheight); + +gint gst_dc1394_caps_set_framerate_list (GstStructure * gs, + dc1394framerates_t * framerates); +void gst_dc1394_framerate_const_to_frac (int framerateconst, + GValue * framefrac); + +GstCaps *gst_dc1394_get_all_dc1394_caps (); +GstCaps *gst_dc1394_get_cam_caps (GstDc1394 * src); +gboolean gst_dc1394_open_cam_with_best_caps (GstDc1394 * src); +gint gst_dc1394_framerate_frac_to_const (gint num, gint denom); +void gst_dc1394_framerate_const_to_frac (gint framerateconst, + GValue * framefrac); +gboolean gst_dc1394_change_camera_transmission (GstDc1394 * src, gboolean on); + + +static void +gst_dc1394_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_set_details (element_class, &dc1394_details); + + gst_element_class_add_pad_template (element_class, + gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, + gst_dc1394_get_all_dc1394_caps ())); + +} + +static void +gst_dc1394_class_init (GstDc1394Class * klass) +{ + GObjectClass *gobject_class; + GstBaseSrcClass *gstbasesrc_class; + GstPushSrcClass *gstpushsrc_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass *) klass; + gstbasesrc_class = (GstBaseSrcClass *) klass; + gstpushsrc_class = (GstPushSrcClass *) klass; + gstelement_class = (GstElementClass *) klass; + + gobject_class->set_property = gst_dc1394_set_property; + gobject_class->get_property = gst_dc1394_get_property; + + g_object_class_install_property (G_OBJECT_CLASS (klass), + PROP_TIMESTAMP_OFFSET, g_param_spec_int64 ("timestamp-offset", + "Timestamp offset", + "An offset added to timestamps set on buffers (in ns)", G_MININT64, + G_MAXINT64, 0, G_PARAM_READWRITE)); + + g_object_class_install_property (G_OBJECT_CLASS (klass), + PROP_CAMNUM, g_param_spec_int ("camera-number", + "The number of the camera on the firewire bus", + "The number of the camera on the firewire bus", 0, + G_MAXINT, 0, G_PARAM_READWRITE)); + + g_object_class_install_property (G_OBJECT_CLASS (klass), + PROP_BUFSIZE, g_param_spec_int ("buffer-size", + "The number of frames in the dma ringbuffer", + "The number of frames in the dma ringbuffer", 1, + G_MAXINT, 10, G_PARAM_READWRITE)); + + gstbasesrc_class->get_caps = gst_dc1394_getcaps; + gstbasesrc_class->set_caps = gst_dc1394_setcaps; + + gstbasesrc_class->get_times = gst_dc1394_get_times; + gstpushsrc_class->create = gst_dc1394_create; + + gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_dc1394_change_state); + +} + +static void +gst_dc1394_init (GstDc1394 * src, GstDc1394Class * g_class) +{ + + src->segment_start_frame = -1; + src->segment_end_frame = -1; + src->timestamp_offset = 0; + src->caps = gst_dc1394_get_all_dc1394_caps (); + src->bufsize = 10; + src->camnum = 0; + src->n_frames = 0; + + gst_pad_set_fixatecaps_function (GST_BASE_SRC_PAD (src), + gst_dc1394_src_fixate); + + gst_base_src_set_live (GST_BASE_SRC (src), TRUE); + +} + +static void +gst_dc1394_src_fixate (GstPad * pad, GstCaps * caps) +{ + + GstDc1394 *src = GST_DC1394 (gst_pad_get_parent (pad)); + + GST_LOG_OBJECT (src, " fixating caps to closest to 320x240 , 30 fps"); + GstStructure *structure; + int i = 0; + + for (i = 0; i < gst_caps_get_size (caps); ++i) { + structure = gst_caps_get_structure (caps, i); + + gst_structure_fixate_field_nearest_int (structure, "width", 320); + gst_structure_fixate_field_nearest_int (structure, "height", 240); + gst_structure_fixate_field_nearest_fraction (structure, "framerate", 30, 1); + } + gst_object_unref (GST_OBJECT (src)); +} + +static void +gst_dc1394_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstDc1394 *src = GST_DC1394 (object); + + switch (prop_id) { + case PROP_TIMESTAMP_OFFSET: + src->timestamp_offset = g_value_get_int64 (value); + break; + case PROP_CAMNUM: + src->camnum = g_value_get_int (value); + break; + case PROP_BUFSIZE: + src->bufsize = g_value_get_int (value); + default: + break; + } +} + +static void +gst_dc1394_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + GstDc1394 *src = GST_DC1394 (object); + + switch (prop_id) { + case PROP_TIMESTAMP_OFFSET: + g_value_set_int64 (value, src->timestamp_offset); + break; + case PROP_CAMNUM: + g_value_set_int (value, src->camnum); + break; + case PROP_BUFSIZE: + g_value_set_int (value, src->bufsize); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GstCaps * +gst_dc1394_getcaps (GstBaseSrc * bsrc) +{ + GstDc1394 *gsrc; + + gsrc = GST_DC1394 (bsrc); + + g_return_val_if_fail (gsrc->caps, NULL); + + return gst_caps_copy (gsrc->caps); +} + + +static gboolean +gst_dc1394_setcaps (GstBaseSrc * bsrc, GstCaps * caps) +{ + + gboolean res = TRUE; + GstDc1394 *dc1394; + gint width, height, rate_denominator, rate_numerator; + gint bpp, vmode; + + dc1394 = GST_DC1394 (bsrc); + + if (dc1394->caps) { + gst_caps_unref (dc1394->caps); + } + + dc1394->caps = gst_caps_copy (caps); + + res = gst_dc1394_parse_caps (caps, &width, &height, + &rate_numerator, &rate_denominator, &vmode, &bpp); + + if (res) { + /* looks ok here */ + dc1394->width = width; + dc1394->height = height; + dc1394->vmode = vmode; + dc1394->rate_numerator = rate_numerator; + dc1394->rate_denominator = rate_denominator; + dc1394->bpp = bpp; + } + + return res; +} + +static void +gst_dc1394_get_times (GstBaseSrc * basesrc, GstBuffer * buffer, + GstClockTime * start, GstClockTime * end) +{ + /* for live sources, sync on the timestamp of the buffer */ + if (gst_base_src_is_live (basesrc)) { + GstClockTime timestamp = GST_BUFFER_TIMESTAMP (buffer); + + if (GST_CLOCK_TIME_IS_VALID (timestamp)) { + /* get duration to calculate end time */ + GstClockTime duration = GST_BUFFER_DURATION (buffer); + + if (GST_CLOCK_TIME_IS_VALID (duration)) { + *end = timestamp + duration; + } + *start = timestamp; + } + } else { + *start = -1; + *end = -1; + } +} + +static GstFlowReturn +gst_dc1394_create (GstPushSrc * psrc, GstBuffer ** buffer) +{ + GstDc1394 *src; + GstBuffer *outbuf; + GstCaps *caps; + dc1394video_frame_t *frame[1]; + GstFlowReturn res = GST_FLOW_OK; + + src = GST_DC1394 (psrc); + + dc1394error_t err = dc1394_capture_dequeue (src->camera, + DC1394_CAPTURE_POLICY_WAIT, + frame); + + if (err != DC1394_SUCCESS) { + + GST_ELEMENT_ERROR (src, RESOURCE, FAILED, + ("failed to dequeue frame"), ("failed to dequeue frame")); + goto error; + } + + outbuf = gst_buffer_new_and_alloc (frame[0]->image_bytes); + + memcpy (GST_BUFFER_MALLOCDATA (outbuf), (guchar *) frame[0]->image, + frame[0]->image_bytes * sizeof (guchar)); + + GST_BUFFER_DATA (outbuf) = GST_BUFFER_MALLOCDATA (outbuf); + + caps = gst_pad_get_caps (GST_BASE_SRC_PAD (psrc)); + gst_buffer_set_caps (outbuf, caps); + gst_caps_unref (caps); + + GST_BUFFER_TIMESTAMP (outbuf) = src->timestamp_offset + src->running_time; + if (src->rate_numerator != 0) { + GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale_int (GST_SECOND, + src->rate_denominator, src->rate_numerator); + } + + src->n_frames++; + if (src->rate_numerator != 0) { + src->running_time = gst_util_uint64_scale_int (src->n_frames * GST_SECOND, + src->rate_denominator, src->rate_numerator); + } + + if (dc1394_capture_enqueue (src->camera, frame[0]) != DC1394_SUCCESS) { + GST_ELEMENT_ERROR (src, RESOURCE, FAILED, ("failed to enqueue frame"), + ("failed to enqueue frame")); + goto error; + } + + *buffer = outbuf; + + return res; + +error: + { + return GST_FLOW_ERROR; + } +} + + +static gboolean +gst_dc1394_parse_caps (const GstCaps * caps, + gint * width, + gint * height, + gint * rate_numerator, gint * rate_denominator, gint * vmode, gint * bpp) +{ + const GstStructure *structure; + GstPadLinkReturn ret; + const GValue *framerate; + + if (gst_caps_get_size (caps) < 1) + return FALSE; + + structure = gst_caps_get_structure (caps, 0); + + ret = gst_structure_get_int (structure, "width", width); + ret &= gst_structure_get_int (structure, "height", height); + + framerate = gst_structure_get_value (structure, "framerate"); + + ret &= gst_structure_get_int (structure, "vmode", vmode); + + ret &= gst_structure_get_int (structure, "bpp", bpp); + + + if (framerate) { + *rate_numerator = gst_value_get_fraction_numerator (framerate); + *rate_denominator = gst_value_get_fraction_denominator (framerate); + } else { + ret = FALSE; + } + + return ret; +} + +static GstStateChangeReturn +gst_dc1394_change_state (GstElement * element, GstStateChange transition) +{ + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + GstDc1394 *src = GST_DC1394 (element); + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + GST_LOG_OBJECT (src, "State change null to ready"); + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + GST_LOG_OBJECT (src, "State ready to paused"); + + if (src->caps) { + gst_caps_unref (src->caps); + src->caps = NULL; + } + src->caps = gst_dc1394_get_cam_caps (src); + if (src->caps == NULL) { + GST_LOG_OBJECT (src, + "Error : Set property could not get cam caps ! , reverting to default"); + src->caps = gst_dc1394_get_all_dc1394_caps (); + ret = GST_STATE_CHANGE_FAILURE; + } + + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + GST_LOG_OBJECT (src, "State change paused to playing"); + + if (!gst_dc1394_open_cam_with_best_caps (src)) { + ret = GST_STATE_CHANGE_FAILURE; + } + + if (src->camera && !gst_dc1394_change_camera_transmission (src, TRUE)) { + ret = GST_STATE_CHANGE_FAILURE; + } + + break; + default: + break; + } + if (ret == GST_STATE_CHANGE_FAILURE) + return ret; + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + + switch (transition) { + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + GST_LOG_OBJECT (src, "State change playing to paused"); + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + GST_LOG_OBJECT (src, "State change paused to ready"); + + if (src->camera && !gst_dc1394_change_camera_transmission (src, FALSE)) { + + if (src->camera) { + dc1394_free_camera (src->camera); + } + src->camera = NULL; + + if (src->caps) { + gst_caps_unref (src->caps); + src->caps = NULL; + } + + ret = GST_STATE_CHANGE_FAILURE; + } + + break; + case GST_STATE_CHANGE_READY_TO_NULL: + GST_LOG_OBJECT (src, "State change ready to null"); + if (src->camera) { + dc1394_free_camera (src->camera); + } + src->camera = NULL; + + if (src->caps) { + gst_caps_unref (src->caps); + src->caps = NULL; + } + break; + default: + break; + } + + return ret; +} + + + +gint +gst_dc1394_caps_set_format_vmode_caps (GstStructure * gs, gint mode) +{ + + gint retval = 0; + + switch (mode) { + case DC1394_VIDEO_MODE_160x120_YUV444: + gst_dc1394_set_caps_color (gs, DC1394_COLOR_CODING_YUV444); + gst_dc1394_set_caps_framesize (gs, 160, 120); + break; + case DC1394_VIDEO_MODE_320x240_YUV422: + gst_dc1394_set_caps_color (gs, DC1394_COLOR_CODING_YUV422); + gst_dc1394_set_caps_framesize (gs, 320, 240); + break; + case DC1394_VIDEO_MODE_640x480_YUV411: + gst_dc1394_set_caps_color (gs, DC1394_COLOR_CODING_YUV411); + gst_dc1394_set_caps_framesize (gs, 640, 480); + break; + case DC1394_VIDEO_MODE_640x480_YUV422: + gst_dc1394_set_caps_color (gs, DC1394_COLOR_CODING_YUV422); + gst_dc1394_set_caps_framesize (gs, 640, 480); + break; + case DC1394_VIDEO_MODE_640x480_RGB8: + gst_dc1394_set_caps_color (gs, DC1394_COLOR_CODING_RGB8); + gst_dc1394_set_caps_framesize (gs, 640, 480); + break; + case DC1394_VIDEO_MODE_640x480_MONO8: + gst_dc1394_set_caps_color (gs, DC1394_COLOR_CODING_MONO8); + gst_dc1394_set_caps_framesize (gs, 640, 480); + break; + case DC1394_VIDEO_MODE_640x480_MONO16: + gst_dc1394_set_caps_color (gs, DC1394_COLOR_CODING_MONO16); + gst_dc1394_set_caps_framesize (gs, 640, 480); + break; + case DC1394_VIDEO_MODE_800x600_YUV422: + gst_dc1394_set_caps_color (gs, DC1394_COLOR_CODING_YUV422); + gst_dc1394_set_caps_framesize (gs, 800, 600); + break; + case DC1394_VIDEO_MODE_800x600_RGB8: + gst_dc1394_set_caps_color (gs, DC1394_COLOR_CODING_RGB8); + gst_dc1394_set_caps_framesize (gs, 800, 600); + break; + case DC1394_VIDEO_MODE_800x600_MONO8: + gst_dc1394_set_caps_color (gs, DC1394_COLOR_CODING_MONO8); + gst_dc1394_set_caps_framesize (gs, 800, 600); + break; + case DC1394_VIDEO_MODE_1024x768_YUV422: + gst_dc1394_set_caps_color (gs, DC1394_COLOR_CODING_YUV422); + gst_dc1394_set_caps_framesize (gs, 1024, 768); + break; + case DC1394_VIDEO_MODE_1024x768_RGB8: + gst_dc1394_set_caps_color (gs, DC1394_COLOR_CODING_RGB8); + gst_dc1394_set_caps_framesize (gs, 1024, 768); + break; + case DC1394_VIDEO_MODE_1024x768_MONO8: + gst_dc1394_set_caps_color (gs, DC1394_COLOR_CODING_MONO8); + gst_dc1394_set_caps_framesize (gs, 1024, 768); + break; + case DC1394_VIDEO_MODE_800x600_MONO16: + gst_dc1394_set_caps_color (gs, DC1394_COLOR_CODING_MONO16); + gst_dc1394_set_caps_framesize (gs, 800, 600); + break; + case DC1394_VIDEO_MODE_1024x768_MONO16: + gst_dc1394_set_caps_color (gs, DC1394_COLOR_CODING_MONO16); + gst_dc1394_set_caps_framesize (gs, 1024, 768); + break; + case DC1394_VIDEO_MODE_1280x960_YUV422: + gst_dc1394_set_caps_color (gs, DC1394_COLOR_CODING_YUV422); + gst_dc1394_set_caps_framesize (gs, 1280, 960); + break; + case DC1394_VIDEO_MODE_1280x960_RGB8: + gst_dc1394_set_caps_color (gs, DC1394_COLOR_CODING_RGB8); + gst_dc1394_set_caps_framesize (gs, 1280, 960); + break; + case DC1394_VIDEO_MODE_1280x960_MONO8: + gst_dc1394_set_caps_color (gs, DC1394_COLOR_CODING_MONO8); + gst_dc1394_set_caps_framesize (gs, 1280, 960); + break; + case DC1394_VIDEO_MODE_1600x1200_YUV422: + gst_dc1394_set_caps_color (gs, DC1394_COLOR_CODING_YUV422); + gst_dc1394_set_caps_framesize (gs, 1600, 1200); + break; + case DC1394_VIDEO_MODE_1600x1200_RGB8: + gst_dc1394_set_caps_color (gs, DC1394_COLOR_CODING_RGB8); + gst_dc1394_set_caps_framesize (gs, 1600, 1200); + break; + case DC1394_VIDEO_MODE_1600x1200_MONO8: + gst_dc1394_set_caps_color (gs, DC1394_COLOR_CODING_MONO8); + gst_dc1394_set_caps_framesize (gs, 1600, 1200); + break; + case DC1394_VIDEO_MODE_1280x960_MONO16: + gst_dc1394_set_caps_color (gs, DC1394_COLOR_CODING_MONO16); + gst_dc1394_set_caps_framesize (gs, 1280, 960); + break; + case DC1394_VIDEO_MODE_1600x1200_MONO16: + gst_dc1394_set_caps_color (gs, DC1394_COLOR_CODING_MONO8); + gst_dc1394_set_caps_framesize (gs, 1600, 1200); + break; + + default: + retval = -1; + } + + return retval; + +} + + +gboolean +gst_dc1394_set_caps_color (GstStructure * gs, gint mc) +{ + gboolean ret = TRUE; + gint fourcc; + + switch (mc) { + case DC1394_COLOR_CODING_YUV444: + gst_structure_set_name (gs, "video/x-raw-yuv"); + + fourcc = GST_MAKE_FOURCC ('I', 'Y', 'U', '2'); + gst_structure_set (gs, + "format", GST_TYPE_FOURCC, fourcc, "bpp", G_TYPE_INT, 16, NULL); + break; + + case DC1394_COLOR_CODING_YUV422: + gst_structure_set_name (gs, "video/x-raw-yuv"); + fourcc = GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'); + gst_structure_set (gs, + "format", GST_TYPE_FOURCC, fourcc, "bpp", G_TYPE_INT, 16, NULL); + break; + + case DC1394_COLOR_CODING_YUV411: + gst_structure_set_name (gs, "video/x-raw-yuv"); + fourcc = GST_MAKE_FOURCC ('Y', '4', '1', 'P'); + gst_structure_set (gs, + "format", GST_TYPE_FOURCC, fourcc, "bpp", G_TYPE_INT, 16, NULL); + break; + case DC1394_COLOR_CODING_RGB8: + gst_structure_set_name (gs, "video/x-raw-rgb"); + gst_structure_set (gs, + "bpp", G_TYPE_INT, 24, + "depth", G_TYPE_INT, 24, + "endianness", G_TYPE_INT, G_BIG_ENDIAN, + "red_mask", G_TYPE_INT, 0xFF0000, + "green_mask", G_TYPE_INT, 0x00FF00, + "blue_mask", G_TYPE_INT, 0x0000FF, NULL); + break; + case DC1394_COLOR_CODING_MONO8: + gst_structure_set_name (gs, "video/x-raw-gray"); + gst_structure_set (gs, + "bpp", G_TYPE_INT, 8, "depth", G_TYPE_INT, 8, NULL); + + break; + case DC1394_COLOR_CODING_MONO16: + gst_structure_set_name (gs, "video/x-raw-gray"); + gst_structure_set (gs, + "bpp", G_TYPE_INT, 16, "depth", G_TYPE_INT, 16, NULL); + // there is no fourcc for this format + break; + default: + ret = FALSE; + printf ("We should never get here; invalid color mode!!\n"); + } + return ret; +} + + +void +gst_dc1394_set_caps_framesize (GstStructure * gs, gint width, gint height) +{ + gst_structure_set (gs, + "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL); +} + +void +gst_dc1394_set_caps_framesize_range (GstStructure * gs, + gint minwidth, + gint maxwidth, + gint incwidth, gint minheight, gint maxheight, gint incheight) +{ + /* + Format 7 cameras allow you to change the camera width/height in multiples + of incwidth/incheight up to some max. This sets the necessary + list structure in the gst caps structure + */ + + GValue widthlist = { 0 }; + GValue widthval = { 0 }; + GValue heightlist = { 0 }; + GValue heightval = { 0 }; + gint x = 0; + + g_value_init (&widthlist, GST_TYPE_LIST); + g_value_init (&widthval, G_TYPE_INT); + for (x = minwidth; x <= maxwidth; x += incwidth) { + g_value_set_int (&widthval, x); + gst_value_list_append_value (&widthlist, &widthval); + } + + gst_structure_set_value (gs, "width", &widthlist); + + g_value_init (&heightlist, GST_TYPE_LIST); + g_value_init (&heightval, G_TYPE_INT); + for (x = minheight; x <= maxheight; x += incheight) { + g_value_set_int (&heightval, x); + gst_value_list_append_value (&heightlist, &heightval); + } + + gst_structure_set_value (gs, "height", &heightlist); + +} + + +gint +gst_dc1394_caps_set_framerate_list (GstStructure * gs, + dc1394framerates_t * framerates) +{ + + GValue framefrac = { 0 }; + GValue frameratelist = { 0 }; + gint f; + + g_value_init (&frameratelist, GST_TYPE_LIST); + g_value_init (&framefrac, GST_TYPE_FRACTION); + + // figure out the frame rate + for (f = framerates->num - 1; f >= 0; f--) { + /* reverse order so we place the faster frame rates higher in + the sequence */ + if (framerates->framerates[f]) { + gst_dc1394_framerate_const_to_frac (framerates->framerates[f], + &framefrac); + + gst_value_list_append_value (&frameratelist, &framefrac); + } + } + gst_structure_set_value (gs, "framerate", &frameratelist); + + g_value_unset (&framefrac); + g_value_unset (&frameratelist); + return 0; +} + + + +void +gst_dc1394_framerate_const_to_frac (gint framerateconst, GValue * framefrac) +{ + + // frac must have been already initialized + + switch (framerateconst) { + case DC1394_FRAMERATE_1_875: + gst_value_set_fraction (framefrac, 15, 8); + break; + case DC1394_FRAMERATE_3_75: + gst_value_set_fraction (framefrac, 15, 4); + break; + case DC1394_FRAMERATE_7_5: + gst_value_set_fraction (framefrac, 15, 2); + break; + case DC1394_FRAMERATE_15: + gst_value_set_fraction (framefrac, 15, 1); + break; + case DC1394_FRAMERATE_30: + gst_value_set_fraction (framefrac, 30, 1); + break; + case DC1394_FRAMERATE_60: + gst_value_set_fraction (framefrac, 60, 1); + break; + case DC1394_FRAMERATE_120: + gst_value_set_fraction (framefrac, 120, 1); + break; + case DC1394_FRAMERATE_240: + gst_value_set_fraction (framefrac, 240, 1); + break; + } +} + + + +GstCaps * +gst_dc1394_get_all_dc1394_caps () +{ + /* + generate all possible caps + + */ + + GstCaps *gcaps; + gint i = 0; + + gcaps = gst_caps_new_empty (); + // first, the fixed mode caps + for (i = DC1394_VIDEO_MODE_MIN; i < DC1394_VIDEO_MODE_EXIF; i++) { + GstStructure *gs = gst_structure_empty_new (""); + gint ret = gst_dc1394_caps_set_format_vmode_caps (gs, i); + + gst_structure_set (gs, + "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); + gst_structure_set (gs, "vmode", G_TYPE_INT, i, NULL); + if (ret >= 0) { + gst_caps_append_structure (gcaps, gs); + } + } + + // then Format 7 options + + for (i = DC1394_COLOR_CODING_MIN; i <= DC1394_COLOR_CODING_MAX; i++) { + GstStructure *gs = gst_structure_empty_new (""); + + //int ret = gst_dc1394_caps_set_format_vmode_caps(gs, i); + + gst_structure_set (gs, "vmode", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL); + + gst_structure_set (gs, + "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); + gst_structure_set (gs, + "width", GST_TYPE_INT_RANGE, 1, G_MAXINT, + "height", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL); + + if (gst_dc1394_set_caps_color (gs, i)) { + gst_caps_append_structure (gcaps, gs); + } + } + return gcaps; + +} + +GstCaps * +gst_dc1394_get_cam_caps (GstDc1394 * src) +{ + + dc1394camera_t *camera = NULL; + dc1394camera_t **cameras = NULL; + dc1394error_t camerr; + guint numCameras; + gint i, j; + dc1394video_modes_t modes; + dc1394framerates_t framerates; + GstCaps *gcaps = NULL; + + gcaps = gst_caps_new_empty (); + + camerr = dc1394_find_cameras (&cameras, &numCameras); + + if (camerr != DC1394_SUCCESS) { + if (camerr == DC1394_NO_CAMERA) { + GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, ("There were no cameras"), + ("There were no cameras")); + } else { + GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, + ("Can't find cameras error : %d", camerr), + ("Can't find cameras error : %d", camerr)); + } + goto error; + } + + if (src->camnum > (numCameras - 1)) { + GST_ELEMENT_ERROR (src, RESOURCE, FAILED, ("Invalid camera number"), + ("Invalid camera number %d", src->camnum)); + + for (i = 0; i < numCameras; i++) { + if (i != src->camnum) { + dc1394_free_camera (cameras[i]); + } + } + goto error; + } + + camera = cameras[src->camnum]; + + // free the other cameras + for (i = 0; i < numCameras; i++) { + if (i != src->camnum) { + dc1394_free_camera (cameras[i]); + } + } + + free (cameras); + + camerr = dc1394_video_get_supported_modes (camera, &modes); + if (camerr != DC1394_SUCCESS) { + GST_ELEMENT_ERROR (src, RESOURCE, FAILED, ("Error getting supported modes"), + ("Error getting supported modes")); + goto error; + } + + for (i = modes.num - 1; i >= 0; i--) { + int m = modes.modes[i]; + + if (m < DC1394_VIDEO_MODE_EXIF) { + + GstStructure *gs = gst_structure_empty_new (""); + + gst_structure_set (gs, "vmode", G_TYPE_INT, m, NULL); + + if (gst_dc1394_caps_set_format_vmode_caps (gs, m) < 0) { + GST_ELEMENT_ERROR (src, STREAM, FAILED, + ("attempt to set mode to %d failed", m), + ("attempt to set mode to %d failed", m)); + goto error; + } else { + + camerr = dc1394_video_get_supported_framerates (camera, m, &framerates); + gst_dc1394_caps_set_framerate_list (gs, &framerates); + gst_caps_append_structure (gcaps, gs); + + } + } else { + // FORMAT 7 + + GstStructure *gs = gst_structure_empty_new (""); + + gst_structure_set (gs, "vmode", G_TYPE_INT, m, NULL); + + + // Get the maximum frame size + guint maxx, maxy; + + camerr = dc1394_format7_get_max_image_size (camera, m, &maxx, &maxy); + if (camerr != DC1394_SUCCESS) { + GST_ELEMENT_ERROR (src, RESOURCE, FAILED, + ("Error getting format 7 max image size"), + ("Error getting format 7 max image size")); + goto error; + } + GST_LOG_OBJECT (src, "Format 7 maxx=%d maxy=%d", maxx, maxy); + + guint xunit, yunit; + + camerr = dc1394_format7_get_unit_size (camera, m, &xunit, &yunit); + if (camerr != DC1394_SUCCESS) { + GST_ELEMENT_ERROR (src, RESOURCE, FAILED, + ("Error getting format 7 image unit size"), + ("Error getting format 7 image unit size")); + goto error; + } + GST_LOG_OBJECT (src, "Format 7 unitx=%d unity=%d", xunit, yunit); + + gst_dc1394_set_caps_framesize_range (gs, xunit, maxx, xunit, + yunit, maxy, yunit); + + + // note that format 7 has no concept of a framerate, so we pass the + // full range + gst_structure_set (gs, + "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); + + + // get the available color codings + dc1394color_codings_t colormodes; + + camerr = dc1394_format7_get_color_codings (camera, m, &colormodes); + if (camerr != DC1394_SUCCESS) { + GST_ELEMENT_ERROR (src, RESOURCE, FAILED, + ("Error getting format 7 color modes"), + ("Error getting format 7 color modes")); + goto error; + } + + for (j = 0; j < colormodes.num; j++) { + GstStructure *newgs = gst_structure_copy (gs); + + gst_dc1394_set_caps_color (newgs, colormodes.codings[j]); + GST_LOG_OBJECT (src, "Format 7 colormode set : %d", + colormodes.codings[j]); + // note that since there are multiple color modes, we append + // multiple structures. + gst_caps_append_structure (gcaps, newgs); + } + + } + } + + if (camera) { + dc1394_free_camera (camera); + } + + return gcaps; + +error: + + if (gcaps) { + gst_caps_unref (gcaps); + } + + if (camera) { + dc1394_free_camera (camera); + camera = NULL; + } + + return NULL; +} + +gint +gst_dc1394_framerate_frac_to_const (gint num, gint denom) +{ + // frac must have been already initialized + + int retvalue = -1; + + if (num == 15 && denom == 8) + retvalue = DC1394_FRAMERATE_1_875; + + if (num == 15 && denom == 4) + retvalue = DC1394_FRAMERATE_3_75; + + if (num == 15 && denom == 2) + retvalue = DC1394_FRAMERATE_7_5; + + if (num == 15 && denom == 1) + retvalue = DC1394_FRAMERATE_15; + + + if (num == 30 && denom == 1) + retvalue = DC1394_FRAMERATE_30; + + if (num == 60 && denom == 1) + retvalue = DC1394_FRAMERATE_60; + + return retvalue; +} + + +gboolean +gst_dc1394_open_cam_with_best_caps (GstDc1394 * src) +{ + + dc1394camera_t **cameras = NULL; + guint numCameras; + gint i; + gint err; + + GST_LOG_OBJECT (src, "Opening the camera!!!"); + + + if (dc1394_find_cameras (&cameras, &numCameras) != DC1394_SUCCESS) { + GST_ELEMENT_ERROR (src, RESOURCE, FAILED, ("Can't find cameras"), + ("Can't find cameras")); + goto error; + } + + GST_LOG_OBJECT (src, "Found %d cameras", numCameras); + + if (src->camnum > (numCameras - 1)) { + GST_ELEMENT_ERROR (src, RESOURCE, FAILED, ("Invalid camera number"), + ("Invalid camera number")); + goto error; + } + + GST_LOG_OBJECT (src, "Opening camera : %d", src->camnum); + + src->camera = cameras[src->camnum]; + + // free the other cameras + for (i = 0; i < numCameras; i++) { + if (i != src->camnum) + dc1394_free_camera (cameras[i]); + } + + free (cameras); + + // figure out mode + int framerateconst = gst_dc1394_framerate_frac_to_const (src->rate_numerator, + src->rate_denominator); + + GST_LOG_OBJECT (src, "The dma buffer queue size is %d buffers", + src->bufsize); + + //FIXME HAVE THIS AUTOMATIC OR AS A PARAMETER ? + err = dc1394_video_set_iso_speed (src->camera, DC1394_ISO_SPEED_400); + + if (err != DC1394_SUCCESS) { + GST_ELEMENT_ERROR (src, RESOURCE, FAILED, ("Could not set ISO speed"), + ("Could not set ISO speed")); + goto error; + } + + + + GST_LOG_OBJECT (src, "Setting mode : %d", src->vmode); + err = dc1394_video_set_mode (src->camera, src->vmode); + + if (err != DC1394_SUCCESS) { + GST_ELEMENT_ERROR (src, RESOURCE, FAILED, ("Could not set video mode %d", + src->vmode), ("Could not set video mode %d", src->vmode)); + goto error; + } + + GST_LOG_OBJECT (src, "Setting framerate : %d", framerateconst); + dc1394_video_set_framerate (src->camera, framerateconst); + + if (err != DC1394_SUCCESS) { + GST_ELEMENT_ERROR (src, RESOURCE, FAILED, ("Could not set framerate to %d", + framerateconst), ("Could not set framerate to %d", framerateconst)); + goto error; + } + // set any format-7 parameters if this is a format-7 mode + if (src->vmode >= DC1394_VIDEO_MODE_FORMAT7_MIN && + src->vmode <= DC1394_VIDEO_MODE_FORMAT7_MAX) { + // the big thing we care about right now is frame size + err = dc1394_format7_set_image_size (src->camera, src->vmode, + src->width, src->height); + if (err != DC1394_SUCCESS) { + GST_ELEMENT_ERROR (src, RESOURCE, FAILED, + ("Could not set format 7 image size to %d x %d", src->width, + src->height), ("Could not set format 7 image size to %d x %d", + src->width, src->height)); + + goto error; + } + + } + err = + dc1394_capture_setup (src->camera, src->bufsize, + DC1394_CAPTURE_FLAGS_DEFAULT); + if (err != DC1394_SUCCESS) { + + GST_ELEMENT_ERROR (src, RESOURCE, FAILED, ("Error setting capture mode"), + ("Error setting capture mode")); + + } + if (err != DC1394_SUCCESS) { + + if (err == DC1394_NO_BANDWIDTH) { + GST_LOG_OBJECT (src, + "Capture setup_dma failed , trying to cleanup the iso_channels_and_bandwidth and retrying"); + + // try to cleanup the bandwidth and retry + err = dc1394_cleanup_iso_channels_and_bandwidth (src->camera); + if (err != DC1394_SUCCESS) { + GST_ELEMENT_ERROR (src, RESOURCE, FAILED, + ("Could not cleanup bandwidth"), ("Could not cleanup bandwidth")); + goto error; + } else { + err = + dc1394_capture_setup (src->camera, src->bufsize, + DC1394_CAPTURE_FLAGS_DEFAULT); + if (err != DC1394_SUCCESS) { + GST_ELEMENT_ERROR (src, RESOURCE, FAILED, + ("unable to setup camera error %d", err), + ("unable to setup camera error %d", err)); + goto error; + } + } + } else { + GST_ELEMENT_ERROR (src, RESOURCE, FAILED, + ("unable to setup camera error %d", err), + ("unable to setup camera error %d", err)); + goto error; + + } + } + + + return TRUE; + +error: + + if (src->camera) { + dc1394_free_camera (src->camera); + src->camera = NULL; + } + + return FALSE;; + +} + + +gboolean +gst_dc1394_change_camera_transmission (GstDc1394 * src, gboolean on) +{ + dc1394switch_t status = DC1394_OFF; + dc1394error_t err = DC1394_FAILURE; + gint i = 0; + + g_return_val_if_fail (src->camera, FALSE); + + if (on) { + + status = dc1394_video_set_transmission (src->camera, DC1394_ON); + + i = 0; + while (status == DC1394_OFF && i++ < 5) { + usleep (50000); + if (dc1394_video_get_transmission (src->camera, + &status) != DC1394_SUCCESS) { + if (status == DC1394_OFF) { + GST_LOG_OBJECT (src, "camera is still off , retrying"); + } + } + } + + if (i == 5) { + GST_ELEMENT_ERROR (src, RESOURCE, FAILED, + ("Camera doesn't seem to want to turn on!"), + ("Camera doesn't seem to want to turn on!")); + return FALSE; + } + + GST_LOG_OBJECT (src, "got transmision status ON"); + + } else { + + if (dc1394_video_set_transmission (src->camera, + DC1394_OFF) != DC1394_SUCCESS) { + GST_ELEMENT_ERROR (src, RESOURCE, FAILED, ("Unable to stop transmision"), + ("Unable to stop transmision")); + return FALSE; + } + + GST_LOG_OBJECT (src, "Stopping capture"); + + err = dc1394_capture_stop (src->camera); + if (err > 0) { + GST_ELEMENT_ERROR (src, RESOURCE, FAILED, ("Capture stop error : %d ", + err), ("Capture stop error : %d ", err)); + return FALSE; + } else { + GST_LOG_OBJECT (src, "Capture stoped successfully"); + } + } + + return TRUE; +} + + +static gboolean +plugin_init (GstPlugin * plugin) +{ + + GST_DEBUG_CATEGORY_INIT (dc1394_debug, "dc1394", 0, "DC1394 interface"); + + return gst_element_register (plugin, "dc1394src", GST_RANK_NONE, + GST_TYPE_DC1394); + +} + + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "dc1394", + "1394 IIDC Video Source", + plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) |