From b4e5796a04dd2ba7c176024d9bf5d51dd3ee917b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 4 Sep 2007 16:40:05 +0000 Subject: [PATCH] sys/v4l2/gstv4l2src.c: Restructure the setcaps function so that we can also compute the expected GStreamer output siz... Original commit message from CVS: * sys/v4l2/gstv4l2src.c: (gst_v4l2_get_caps_info), (gst_v4l2src_set_caps), (gst_v4l2src_get_mmap): Restructure the setcaps function so that we can also compute the expected GStreamer output size of the video frames. Set frame_byte_size correctly so that read-based devices have a chance of working correctly. When grabbing a frame, discard frames that are not of the expected size. Some cameras don't output the right framesize for the first buffer. Try only a couple of times to get a valid frame, else error out. * sys/v4l2/v4l2_calls.c: (gst_v4l2_get_capabilities), (gst_v4l2_fill_lists), (gst_v4l2_get_input): Add some more debug info when scanning the device. * sys/v4l2/v4l2src_calls.c: (gst_v4l2_buffer_new), (gst_v4l2_buffer_pool_new), (gst_v4l2_buffer_pool_activate), (gst_v4l2src_fill_format_list), (gst_v4l2src_grab_frame), (gst_v4l2src_set_capture), (gst_v4l2src_capture_init): Add some more debug info when dequeing a frame. --- ChangeLog | 22 ++++ sys/v4l2/gstv4l2src.c | 263 ++++++++++++++++++++++++++++++----------------- sys/v4l2/v4l2_calls.c | 58 +++++++---- sys/v4l2/v4l2src_calls.c | 70 ++++++++++--- 4 files changed, 282 insertions(+), 131 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2b9a4ba..9986678 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,25 @@ +2007-09-04 Wim Taymans + + * sys/v4l2/gstv4l2src.c: (gst_v4l2_get_caps_info), + (gst_v4l2src_set_caps), (gst_v4l2src_get_mmap): + Restructure the setcaps function so that we can also compute the + expected GStreamer output size of the video frames. + Set frame_byte_size correctly so that read-based devices have a chance + of working correctly. + When grabbing a frame, discard frames that are not of the expected size. + Some cameras don't output the right framesize for the first buffer. + Try only a couple of times to get a valid frame, else error out. + + * sys/v4l2/v4l2_calls.c: (gst_v4l2_get_capabilities), + (gst_v4l2_fill_lists), (gst_v4l2_get_input): + Add some more debug info when scanning the device. + + * sys/v4l2/v4l2src_calls.c: (gst_v4l2_buffer_new), + (gst_v4l2_buffer_pool_new), (gst_v4l2_buffer_pool_activate), + (gst_v4l2src_fill_format_list), (gst_v4l2src_grab_frame), + (gst_v4l2src_set_capture), (gst_v4l2src_capture_init): + Add some more debug info when dequeing a frame. + 2007-09-04 Stefan Kost * gst/wavparse/gstwavparse.c: diff --git a/sys/v4l2/gstv4l2src.c b/sys/v4l2/gstv4l2src.c index 5cc184a..d0c1ddb 100644 --- a/sys/v4l2/gstv4l2src.c +++ b/sys/v4l2/gstv4l2src.c @@ -595,74 +595,6 @@ gst_v4l2src_v4l2fourcc_to_structure (guint32 fourcc) return structure; } -static guint32 -gst_v4l2_fourcc_from_structure (GstStructure * structure) -{ - guint32 fourcc = 0; - const gchar *mimetype = gst_structure_get_name (structure); - - if (!strcmp (mimetype, "video/x-raw-yuv")) { - gst_structure_get_fourcc (structure, "format", &fourcc); - - switch (fourcc) { - case GST_MAKE_FOURCC ('I', '4', '2', '0'): - case GST_MAKE_FOURCC ('I', 'Y', 'U', 'V'): - fourcc = V4L2_PIX_FMT_YUV420; - break; - case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'): - fourcc = V4L2_PIX_FMT_YUYV; - break; - case GST_MAKE_FOURCC ('Y', '4', '1', 'P'): - fourcc = V4L2_PIX_FMT_Y41P; - break; - case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'): - fourcc = V4L2_PIX_FMT_UYVY; - break; - case GST_MAKE_FOURCC ('Y', 'V', '1', '2'): - fourcc = V4L2_PIX_FMT_YVU420; - break; - case GST_MAKE_FOURCC ('Y', '4', '1', 'B'): - fourcc = V4L2_PIX_FMT_YUV411P; - break; - case GST_MAKE_FOURCC ('Y', '4', '2', 'B'): - fourcc = V4L2_PIX_FMT_YUV422P; - break; - } - } else if (!strcmp (mimetype, "video/x-raw-rgb")) { - gint depth, endianness, r_mask; - - gst_structure_get_int (structure, "depth", &depth); - gst_structure_get_int (structure, "endianness", &endianness); - gst_structure_get_int (structure, "red_mask", &r_mask); - - switch (depth) { - case 8: - fourcc = V4L2_PIX_FMT_RGB332; - break; - case 15: - fourcc = (endianness == G_LITTLE_ENDIAN) ? - V4L2_PIX_FMT_RGB555 : V4L2_PIX_FMT_RGB555X; - break; - case 16: - fourcc = (endianness == G_LITTLE_ENDIAN) ? - V4L2_PIX_FMT_RGB565 : V4L2_PIX_FMT_RGB565X; - break; - case 24: - fourcc = (r_mask == 0xFF) ? V4L2_PIX_FMT_BGR24 : V4L2_PIX_FMT_RGB24; - break; - case 32: - fourcc = (r_mask == 0xFF) ? V4L2_PIX_FMT_BGR32 : V4L2_PIX_FMT_RGB32; - break; - } - } else if (strcmp (mimetype, "video/x-dv") == 0) { - fourcc = V4L2_PIX_FMT_DV; - } else if (strcmp (mimetype, "image/jpeg") == 0) { - fourcc = V4L2_PIX_FMT_JPEG; - } - - return fourcc; -} - static struct v4l2_fmtdesc * gst_v4l2src_get_format_from_fourcc (GstV4l2Src * v4l2src, guint32 fourcc) { @@ -689,14 +621,6 @@ gst_v4l2src_get_format_from_fourcc (GstV4l2Src * v4l2src, guint32 fourcc) return NULL; } -static struct v4l2_fmtdesc * -gst_v4l2_structure_to_v4l2fourcc (GstV4l2Src * v4l2src, - GstStructure * structure) -{ - return gst_v4l2src_get_format_from_fourcc (v4l2src, - gst_v4l2_fourcc_from_structure (structure)); -} - static GstCaps * gst_v4l2src_get_all_caps (void) { @@ -771,15 +695,132 @@ gst_v4l2src_get_caps (GstBaseSrc * src) return ret; } +/* collect data for the given caps + * @caps: given input caps + * @format: location for the v4l format + * @w/@h: location for width and height + * @fps_n/@fps_d: location for framerate + * @size: location for expected size of the frame or 0 if unknown + */ +static gboolean +gst_v4l2_get_caps_info (GstV4l2Src * v4l2src, GstCaps * caps, + struct v4l2_fmtdesc **format, gint * w, gint * h, guint * fps_n, + guint * fps_d, guint * size) +{ + GstStructure *structure; + const GValue *framerate; + guint32 fourcc; + const gchar *mimetype; + guint outsize; + + /* default unknown values */ + fourcc = 0; + outsize = 0; + + structure = gst_caps_get_structure (caps, 0); + + if (!gst_structure_get_int (structure, "width", w)) + return FALSE; + + if (!gst_structure_get_int (structure, "height", h)) + return FALSE; + + framerate = gst_structure_get_value (structure, "framerate"); + if (!framerate) + return FALSE; + + *fps_n = gst_value_get_fraction_numerator (framerate); + *fps_d = gst_value_get_fraction_denominator (framerate); + + mimetype = gst_structure_get_name (structure); + + if (!strcmp (mimetype, "video/x-raw-yuv")) { + gst_structure_get_fourcc (structure, "format", &fourcc); + + switch (fourcc) { + case GST_MAKE_FOURCC ('I', '4', '2', '0'): + case GST_MAKE_FOURCC ('I', 'Y', 'U', 'V'): + fourcc = V4L2_PIX_FMT_YUV420; + outsize = GST_ROUND_UP_4 (*w) * GST_ROUND_UP_2 (*h); + outsize += 2 * ((GST_ROUND_UP_8 (*w) / 2) * (GST_ROUND_UP_2 (*h) / 2)); + break; + case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'): + fourcc = V4L2_PIX_FMT_YUYV; + outsize = (GST_ROUND_UP_2 (*w) * 2) * *h; + break; + case GST_MAKE_FOURCC ('Y', '4', '1', 'P'): + fourcc = V4L2_PIX_FMT_Y41P; + outsize = (GST_ROUND_UP_2 (*w) * 2) * *h; + break; + case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'): + fourcc = V4L2_PIX_FMT_UYVY; + outsize = (GST_ROUND_UP_2 (*w) * 2) * *h; + break; + case GST_MAKE_FOURCC ('Y', 'V', '1', '2'): + fourcc = V4L2_PIX_FMT_YVU420; + outsize = GST_ROUND_UP_4 (*w) * GST_ROUND_UP_2 (*h); + outsize += 2 * ((GST_ROUND_UP_8 (*w) / 2) * (GST_ROUND_UP_2 (*h) / 2)); + break; + case GST_MAKE_FOURCC ('Y', '4', '1', 'B'): + fourcc = V4L2_PIX_FMT_YUV411P; + outsize = GST_ROUND_UP_4 (*w) * *h; + outsize += 2 * ((GST_ROUND_UP_8 (*w) / 4) * *h); + break; + case GST_MAKE_FOURCC ('Y', '4', '2', 'B'): + fourcc = V4L2_PIX_FMT_YUV422P; + outsize = GST_ROUND_UP_4 (*w) * *h; + outsize += 2 * ((GST_ROUND_UP_8 (*w) / 2) * *h); + break; + } + } else if (!strcmp (mimetype, "video/x-raw-rgb")) { + gint depth, endianness, r_mask; + + gst_structure_get_int (structure, "depth", &depth); + gst_structure_get_int (structure, "endianness", &endianness); + gst_structure_get_int (structure, "red_mask", &r_mask); + + switch (depth) { + case 8: + fourcc = V4L2_PIX_FMT_RGB332; + break; + case 15: + fourcc = (endianness == G_LITTLE_ENDIAN) ? + V4L2_PIX_FMT_RGB555 : V4L2_PIX_FMT_RGB555X; + break; + case 16: + fourcc = (endianness == G_LITTLE_ENDIAN) ? + V4L2_PIX_FMT_RGB565 : V4L2_PIX_FMT_RGB565X; + break; + case 24: + fourcc = (r_mask == 0xFF) ? V4L2_PIX_FMT_BGR24 : V4L2_PIX_FMT_RGB24; + break; + case 32: + fourcc = (r_mask == 0xFF) ? V4L2_PIX_FMT_BGR32 : V4L2_PIX_FMT_RGB32; + break; + } + } else if (strcmp (mimetype, "video/x-dv") == 0) { + fourcc = V4L2_PIX_FMT_DV; + } else if (strcmp (mimetype, "image/jpeg") == 0) { + fourcc = V4L2_PIX_FMT_JPEG; + } + + if (fourcc == 0) + return FALSE; + + *format = gst_v4l2src_get_format_from_fourcc (v4l2src, fourcc); + *size = outsize; + + return TRUE; +} + static gboolean gst_v4l2src_set_caps (GstBaseSrc * src, GstCaps * caps) { GstV4l2Src *v4l2src; gint w = 0, h = 0; - GstStructure *structure; struct v4l2_fmtdesc *format; - const GValue *framerate; guint fps_n, fps_d; + guint size; v4l2src = GST_V4L2SRC (src); @@ -796,28 +837,14 @@ gst_v4l2src_set_caps (GstBaseSrc * src, GstCaps * caps) return FALSE; } - structure = gst_caps_get_structure (caps, 0); - /* we want our own v4l2 type of fourcc codes */ - if (!(format = gst_v4l2_structure_to_v4l2fourcc (v4l2src, structure))) { - GST_DEBUG_OBJECT (v4l2src, "can't get capture format from caps %" - GST_PTR_FORMAT, caps); + if (!gst_v4l2_get_caps_info (v4l2src, caps, &format, &w, &h, &fps_n, &fps_d, + &size)) { + GST_DEBUG_OBJECT (v4l2src, + "can't get capture format from caps %" GST_PTR_FORMAT, caps); return FALSE; } - if (!gst_structure_get_int (structure, "width", &w)) - return FALSE; - - if (!gst_structure_get_int (structure, "height", &h)) - return FALSE; - - framerate = gst_structure_get_value (structure, "framerate"); - if (!framerate) - return FALSE; - - fps_n = gst_value_get_fraction_numerator (framerate); - fps_d = gst_value_get_fraction_denominator (framerate); - GST_DEBUG_OBJECT (v4l2src, "trying to set_capture %dx%d at %d/%d fps, " "format %s", w, h, fps_n, fps_d, format->description); @@ -832,6 +859,9 @@ gst_v4l2src_set_caps (GstBaseSrc * src, GstCaps * caps) if (!gst_v4l2src_capture_start (v4l2src)) return FALSE; + /* now store the expected output size */ + v4l2src->frame_byte_size = size; + return TRUE; } @@ -945,7 +975,46 @@ read_error: static GstFlowReturn gst_v4l2src_get_mmap (GstV4l2Src * v4l2src, GstBuffer ** buf) { - return gst_v4l2src_grab_frame (v4l2src, buf); + GstBuffer *temp; + GstFlowReturn ret; + guint size; + guint count; + + count = 0; + +again: + ret = gst_v4l2src_grab_frame (v4l2src, &temp); + if (ret != GST_FLOW_OK) + goto done; + + if (v4l2src->frame_byte_size > 0) { + size = GST_BUFFER_SIZE (temp); + + /* if size does not match what we expected, try again */ + if (size != v4l2src->frame_byte_size) { + GST_ELEMENT_WARNING (v4l2src, RESOURCE, READ, + (_("Got unexpected frame size of %u instead of %u."), + size, v4l2src->frame_byte_size), (NULL)); + gst_buffer_unref (temp); + if (count++ > 50) + goto size_error; + + goto again; + } + } + + *buf = temp; +done: + return ret; + + /* ERRORS */ +size_error: + { + GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, + (_("Error read()ing %d bytes on device '%s'."), + v4l2src->frame_byte_size, v4l2src->v4l2object->videodev), (NULL)); + return GST_FLOW_ERROR; + } } static GstFlowReturn diff --git a/sys/v4l2/v4l2_calls.c b/sys/v4l2/v4l2_calls.c index 0721a2e..6233d010 100644 --- a/sys/v4l2/v4l2_calls.c +++ b/sys/v4l2/v4l2_calls.c @@ -51,7 +51,11 @@ GST_DEBUG_CATEGORY_EXTERN (v4l2_debug); gboolean gst_v4l2_get_capabilities (GstV4l2Object * v4l2object) { - GST_DEBUG_OBJECT (v4l2object->element, "getting capabilities"); + GstElement *e; + + e = v4l2object->element; + + GST_DEBUG_OBJECT (e, "getting capabilities"); if (!GST_V4L2_IS_OPEN (v4l2object)) return FALSE; @@ -59,6 +63,12 @@ gst_v4l2_get_capabilities (GstV4l2Object * v4l2object) if (ioctl (v4l2object->video_fd, VIDIOC_QUERYCAP, &v4l2object->vcap) < 0) goto cap_failed; + GST_LOG_OBJECT (e, "driver: '%s'", v4l2object->vcap.driver); + GST_LOG_OBJECT (e, "card: '%s'", v4l2object->vcap.card); + GST_LOG_OBJECT (e, "bus_info: '%s'", v4l2object->vcap.bus_info); + GST_LOG_OBJECT (e, "version: %08x", v4l2object->vcap.version); + GST_LOG_OBJECT (e, "capabilites: %08x", v4l2object->vcap.capabilities); + return TRUE; /* ERRORS */ @@ -82,11 +92,14 @@ static gboolean gst_v4l2_fill_lists (GstV4l2Object * v4l2object) { gint n; + GstElement *e; + + e = v4l2object->element; - GST_DEBUG_OBJECT (v4l2object->element, "getting enumerations"); + GST_DEBUG_OBJECT (e, "getting enumerations"); GST_V4L2_CHECK_OPEN (v4l2object); - GST_DEBUG_OBJECT (v4l2object->element, " channels"); + GST_DEBUG_OBJECT (e, " channels"); /* and now, the channels */ for (n = 0;; n++) { struct v4l2_input input; @@ -98,7 +111,7 @@ gst_v4l2_fill_lists (GstV4l2Object * v4l2object) if (errno == EINVAL) break; /* end of enumeration */ else { - GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, + GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS, (_("Failed to query attributes of input %d in device %s"), n, v4l2object->videodev), ("Failed to get %d in input enumeration for %s. (%d - %s)", @@ -107,13 +120,19 @@ gst_v4l2_fill_lists (GstV4l2Object * v4l2object) } } - GST_DEBUG_OBJECT (v4l2object->element, " '%s'", input.name); + GST_LOG_OBJECT (e, " index: %d", input.index); + GST_LOG_OBJECT (e, " name: '%s'", input.name); + GST_LOG_OBJECT (e, " type: %08x", input.type); + GST_LOG_OBJECT (e, " audioset: %08x", input.audioset); + GST_LOG_OBJECT (e, " std: %016x", input.std); + GST_LOG_OBJECT (e, " status: %08x", input.status); v4l2channel = g_object_new (GST_TYPE_V4L2_TUNER_CHANNEL, NULL); channel = GST_TUNER_CHANNEL (v4l2channel); channel->label = g_strdup ((const gchar *) input.name); channel->flags = GST_TUNER_CHANNEL_INPUT; v4l2channel->index = n; + if (input.type == V4L2_INPUT_TYPE_TUNER) { struct v4l2_tuner vtun; @@ -122,12 +141,13 @@ gst_v4l2_fill_lists (GstV4l2Object * v4l2object) vtun.index = input.tuner; if (ioctl (v4l2object->video_fd, VIDIOC_G_TUNER, &vtun) < 0) { - GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, + GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS, (_("Failed to get setting of tuner %d on device '%s'."), input.tuner, v4l2object->videodev), GST_ERROR_SYSTEM); g_object_unref (G_OBJECT (channel)); return FALSE; } + channel->freq_multiplicator = 62.5 * ((vtun.capability & V4L2_TUNER_CAP_LOW) ? 1 : 1000); channel->min_frequency = vtun.rangelow * channel->freq_multiplicator; @@ -147,7 +167,7 @@ gst_v4l2_fill_lists (GstV4l2Object * v4l2object) g_list_append (v4l2object->channels, (gpointer) channel); } - GST_DEBUG_OBJECT (v4l2object->element, " norms"); + GST_DEBUG_OBJECT (e, " norms"); /* norms... */ for (n = 0;; n++) { struct v4l2_standard standard; @@ -158,11 +178,12 @@ gst_v4l2_fill_lists (GstV4l2Object * v4l2object) standard.frameperiod.numerator = 1; standard.frameperiod.denominator = 0; standard.index = n; + if (ioctl (v4l2object->video_fd, VIDIOC_ENUMSTD, &standard) < 0) { if (errno == EINVAL) break; /* end of enumeration */ else { - GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, + GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS, (_("Failed to query norm on device '%s'."), v4l2object->videodev), ("Failed to get attributes for norm %d on devide '%s'. (%d - %s)", @@ -171,7 +192,7 @@ gst_v4l2_fill_lists (GstV4l2Object * v4l2object) } } - GST_DEBUG_OBJECT (v4l2object->element, " '%s', fps: %d / %d", + GST_DEBUG_OBJECT (e, " '%s', fps: %d / %d", standard.name, standard.frameperiod.denominator, standard.frameperiod.numerator); @@ -185,7 +206,7 @@ gst_v4l2_fill_lists (GstV4l2Object * v4l2object) v4l2object->norms = g_list_append (v4l2object->norms, (gpointer) norm); } - GST_DEBUG_OBJECT (v4l2object->element, " controls+menus"); + GST_DEBUG_OBJECT (e, " controls+menus"); /* and lastly, controls+menus (if appropriate) */ for (n = V4L2_CID_BASE;; n++) { struct v4l2_queryctrl control; @@ -194,7 +215,7 @@ gst_v4l2_fill_lists (GstV4l2Object * v4l2object) /* when we reached the last official CID, continue with private CIDs */ if (n == V4L2_CID_LASTP1) { - GST_DEBUG_OBJECT (v4l2object->element, "checking private CIDs"); + GST_DEBUG_OBJECT (e, "checking private CIDs"); n = V4L2_CID_PRIVATE_BASE; /* FIXME: We are still not handling private controls. We need a new GstInterface to export those controls */ @@ -210,7 +231,7 @@ gst_v4l2_fill_lists (GstV4l2Object * v4l2object) else break; } else { - GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, + GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS, (_("Failed getting controls attributes on device '%s.'"), v4l2object->videodev), ("Failed querying control %d on device '%s'. (%d - %s)", @@ -253,7 +274,7 @@ gst_v4l2_fill_lists (GstV4l2Object * v4l2object) /* FIXME: We should implement GstMixer interface */ /* fall through */ default: - GST_DEBUG_OBJECT (v4l2object->element, + GST_DEBUG_OBJECT (e, "ControlID %s (%x) unhandled, FIXME", control.name, n); control.id++; break; @@ -261,8 +282,7 @@ gst_v4l2_fill_lists (GstV4l2Object * v4l2object) if (n != control.id) continue; - GST_DEBUG_OBJECT (v4l2object->element, - "Adding ControlID %s (%x)", control.name, n); + GST_DEBUG_OBJECT (e, "Adding ControlID %s (%x)", control.name, n); v4l2channel = g_object_new (GST_TYPE_V4L2_COLOR_BALANCE_CHANNEL, NULL); channel = GST_COLOR_BALANCE_CHANNEL (v4l2channel); channel->label = g_strdup ((const gchar *) control.name); @@ -281,7 +301,7 @@ gst_v4l2_fill_lists (GstV4l2Object * v4l2object) if (errno == EINVAL) break; /* end of enumeration */ else { - GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, + GST_ELEMENT_ERROR (e, RESOURCE, SETTINGS, (_("Failed getting controls attributes on device '%s'."), v4l2object->videodev), ("Failed to get %d in menu enumeration for %s. (%d - %s)", @@ -310,7 +330,7 @@ gst_v4l2_fill_lists (GstV4l2Object * v4l2object) /* FIXME we should find out how to handle V4L2_CTRL_TYPE_BUTTON. BUTTON controls like V4L2_CID_DO_WHITE_BALANCE can just be set (1) or unset (0), but can't be queried */ - GST_DEBUG_OBJECT (v4l2object->element, + GST_DEBUG_OBJECT (e, "Control with non supported type %s (%x), type=%d", control.name, n, control.type); channel->min_value = channel->max_value = 0; @@ -320,7 +340,7 @@ gst_v4l2_fill_lists (GstV4l2Object * v4l2object) v4l2object->colors = g_list_append (v4l2object->colors, (gpointer) channel); } - GST_DEBUG_OBJECT (v4l2object->element, "done"); + GST_DEBUG_OBJECT (e, "done"); return TRUE; } @@ -720,6 +740,8 @@ gst_v4l2_get_input (GstV4l2Object * v4l2object, gint * input) *input = n; + GST_DEBUG_OBJECT (v4l2object->element, "input: %d", n); + return TRUE; /* ERRORS */ diff --git a/sys/v4l2/v4l2src_calls.c b/sys/v4l2/v4l2src_calls.c index 0006f0e..5483e6d 100644 --- a/sys/v4l2/v4l2src_calls.c +++ b/sys/v4l2/v4l2src_calls.c @@ -138,12 +138,16 @@ static GstV4l2Buffer * gst_v4l2_buffer_new (GstV4l2BufferPool * pool, guint index, GstCaps * caps) { GstV4l2Buffer *ret; + guint8 *data; ret = (GstV4l2Buffer *) gst_mini_object_new (GST_TYPE_V4L2_BUFFER); + GST_LOG ("creating buffer %u, %p in pool %p", index, ret, pool); + ret->pool = pool; gst_mini_object_ref (GST_MINI_OBJECT (pool)); memset (&ret->vbuffer, 0x00, sizeof (ret->vbuffer)); + ret->vbuffer.index = index; ret->vbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ret->vbuffer.memory = V4L2_MEMORY_MMAP; @@ -151,18 +155,34 @@ gst_v4l2_buffer_new (GstV4l2BufferPool * pool, guint index, GstCaps * caps) if (ioctl (pool->video_fd, VIDIOC_QUERYBUF, &ret->vbuffer) < 0) goto querybuf_failed; - GST_BUFFER_DATA (ret) = mmap (0, ret->vbuffer.length, + GST_LOG (" index: %u", ret->vbuffer.index); + GST_LOG (" type: %d", ret->vbuffer.type); + GST_LOG (" bytesused: %u", ret->vbuffer.bytesused); + GST_LOG (" flags: %08x", ret->vbuffer.flags); + GST_LOG (" field: %d", ret->vbuffer.field); + GST_LOG (" memory: %d", ret->vbuffer.memory); + if (ret->vbuffer.memory == V4L2_MEMORY_MMAP) + GST_LOG (" MMAP offset: %u", ret->vbuffer.m.offset); + GST_LOG (" length: %u", ret->vbuffer.length); + GST_LOG (" input: %u", ret->vbuffer.input); + + data = mmap (0, ret->vbuffer.length, PROT_READ | PROT_WRITE, MAP_SHARED, pool->video_fd, ret->vbuffer.m.offset); - if (GST_BUFFER_DATA (ret) == MAP_FAILED) + if (data == MAP_FAILED) goto mmap_failed; + GST_BUFFER_DATA (ret) = data; + GST_BUFFER_SIZE (ret) = ret->vbuffer.length; + GST_BUFFER_FLAG_SET (ret, GST_BUFFER_FLAG_READONLY); + gst_buffer_set_caps (GST_BUFFER (ret), caps); return ret; + /* ERRORS */ querybuf_failed: { gint errnosave = errno; @@ -266,6 +286,7 @@ gst_v4l2_buffer_pool_new (GstV4l2Src * v4l2src, gint fd, gint num_buffers, return pool; + /* ERRORS */ dup_failed: { gint errnosave = errno; @@ -296,18 +317,22 @@ gst_v4l2_buffer_pool_activate (GstV4l2BufferPool * pool, GstV4l2Src * v4l2src) g_mutex_lock (pool->lock); for (n = 0; n < pool->buffer_count; n++) { - struct v4l2_buffer *buf = &pool->buffers[n]->vbuffer; + struct v4l2_buffer *buf; + + buf = &pool->buffers[n]->vbuffer; + + GST_LOG ("enqueue pool buffer %d", n); if (ioctl (pool->video_fd, VIDIOC_QBUF, buf) < 0) goto queue_failed; } - pool->running = TRUE; g_mutex_unlock (pool->lock); return TRUE; + /* ERRORS */ queue_failed: { GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, @@ -367,19 +392,27 @@ gst_v4l2src_fill_format_list (GstV4l2Src * v4l2src) format->index = n; format->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_ENUM_FMT, format) < 0) { - if (errno == EINVAL) { + if (errno == EINVAL) break; /* end of enumeration */ - } else + else goto failed; } - GST_DEBUG_OBJECT (v4l2src, "got format %" GST_FOURCC_FORMAT, + + GST_LOG_OBJECT (v4l2src, "index: %u", format->index); + GST_LOG_OBJECT (v4l2src, "type: %d", format->type); + GST_LOG_OBJECT (v4l2src, "flags: %08x", format->flags); + GST_LOG_OBJECT (v4l2src, "description: '%s'", format->description); + GST_LOG_OBJECT (v4l2src, "pixelformat: %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (format->pixelformat)); v4l2src->formats = g_slist_prepend (v4l2src->formats, format); } v4l2src->formats = g_slist_reverse (v4l2src->formats); + GST_DEBUG_OBJECT (v4l2src, "got %d format(s)", n); + return TRUE; /* ERRORS */ @@ -803,8 +836,9 @@ gst_v4l2src_grab_frame (GstV4l2Src * v4l2src, GstBuffer ** buf) *buf = pool_buffer; } - GST_LOG_OBJECT (v4l2src, "grabbed frame %d (ix=%d), pool-ct=%d", - buffer.sequence, buffer.index, v4l2src->pool->num_live_buffers); + GST_LOG_OBJECT (v4l2src, "grabbed frame %d (ix=%d), flags %08x, pool-ct=%d", + buffer.sequence, buffer.index, buffer.flags, + v4l2src->pool->num_live_buffers); return GST_FLOW_OK; @@ -910,11 +944,9 @@ gst_v4l2src_set_capture (GstV4l2Src * v4l2src, guint32 pixelformat, if (stream.parm.capture.timeperframe.numerator != fps_d || stream.parm.capture.timeperframe.denominator != fps_n) goto invalid_framerate; - } } - return TRUE; /* ERRORS */ @@ -986,24 +1018,30 @@ gst_v4l2src_capture_init (GstV4l2Src * v4l2src, GstCaps * caps) GST_V4L2_CHECK_NOT_ACTIVE (v4l2src->v4l2object); if (v4l2src->v4l2object->vcap.capabilities & V4L2_CAP_STREAMING) { - breq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - breq.count = v4l2src->num_buffers; + GST_DEBUG_OBJECT (v4l2src, "STREAMING, requesting %d MMAP CAPTURE buffers", + v4l2src->num_buffers); + + breq.count = v4l2src->num_buffers; + breq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; breq.memory = V4L2_MEMORY_MMAP; + if (ioctl (fd, VIDIOC_REQBUFS, &breq) < 0) goto reqbufs_failed; + GST_LOG_OBJECT (v4l2src, " count: %u", breq.count); + GST_LOG_OBJECT (v4l2src, " type: %d", breq.type); + GST_LOG_OBJECT (v4l2src, " memory: %d", breq.memory); + if (breq.count < GST_V4L2_MIN_BUFFERS) goto no_buffers; if (v4l2src->num_buffers != breq.count) { + GST_WARNING_OBJECT (v4l2src, "using %u buffers instead", breq.count); v4l2src->num_buffers = breq.count; g_object_notify (G_OBJECT (v4l2src), "queue-size"); } - GST_INFO_OBJECT (v4l2src, "Got %d buffers of size %d kB", - breq.count, v4l2src->frame_byte_size / 1024); - /* Map the buffers */ GST_LOG_OBJECT (v4l2src, "initiating buffer pool"); -- 2.7.4