From a769e5e70a3ed96d2df52a10aa18b42ca15b40a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 13 Oct 2007 12:03:44 +0000 Subject: [PATCH] sys/v4l2/: When probing the formats and sizes a camera supports, make sure the best ones (highest resolution, prefere... Original commit message from CVS: * sys/v4l2/gstv4l2src.c: * sys/v4l2/v4l2src_calls.c: When probing the formats and sizes a camera supports, make sure the best ones (highest resolution, prefered format) end up at the beginning of the probed caps and the less desirable ones at the end. This is important because the order within the caps matters for things like fixation and negotiation, ie. what format is chosen in the end. With recent kernels, the current probing code will end up querying the supported sizes from lowest resolution to highest resolution, adding them to the probed caps in that order, resulting to v4l2src fixating to the lowest possible resolution if downstream does not express a size preference. Also make up a somewhat random ranking of prefered output formats for the same reason. Fixes #485828. --- ChangeLog | 18 +++++++ sys/v4l2/gstv4l2src.c | 17 +++--- sys/v4l2/v4l2src_calls.c | 112 +++++++++++++++++++++++++++++++++++++-- 3 files changed, 134 insertions(+), 13 deletions(-) diff --git a/ChangeLog b/ChangeLog index b2273257d9..121a7fb30c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2007-10-13 Tim-Philipp Müller + + * sys/v4l2/gstv4l2src.c: + * sys/v4l2/v4l2src_calls.c: + When probing the formats and sizes a camera supports, make + sure the best ones (highest resolution, prefered format) + end up at the beginning of the probed caps and the less + desirable ones at the end. This is important because the + order within the caps matters for things like fixation and + negotiation, ie. what format is chosen in the end. + With recent kernels, the current probing code will end up + querying the supported sizes from lowest resolution to + highest resolution, adding them to the probed caps in that + order, resulting to v4l2src fixating to the lowest possible + resolution if downstream does not express a size preference. + Also make up a somewhat random ranking of prefered output + formats for the same reason. Fixes #485828. + 2007-10-11 Tim-Philipp Müller Based on patch by: Jason Kivlighn diff --git a/sys/v4l2/gstv4l2src.c b/sys/v4l2/gstv4l2src.c index 5a892bda84..9fce1846a9 100644 --- a/sys/v4l2/gstv4l2src.c +++ b/sys/v4l2/gstv4l2src.c @@ -240,7 +240,7 @@ static GstCaps *gst_v4l2src_get_caps (GstBaseSrc * src); static gboolean gst_v4l2src_query (GstBaseSrc * bsrc, GstQuery * query); static GstFlowReturn gst_v4l2src_create (GstPushSrc * src, GstBuffer ** out); -static void gst_v4l2src_fixate (GstPad * pad, GstCaps * caps); +static void gst_v4l2src_fixate (GstBaseSrc * basesrc, GstCaps * caps); static void gst_v4l2src_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); @@ -295,6 +295,7 @@ gst_v4l2src_class_init (GstV4l2SrcClass * klass) basesrc_class->start = GST_DEBUG_FUNCPTR (gst_v4l2src_start); basesrc_class->stop = GST_DEBUG_FUNCPTR (gst_v4l2src_stop); basesrc_class->query = GST_DEBUG_FUNCPTR (gst_v4l2src_query); + basesrc_class->fixate = GST_DEBUG_FUNCPTR (gst_v4l2src_fixate); pushsrc_class->create = GST_DEBUG_FUNCPTR (gst_v4l2src_create); } @@ -313,9 +314,6 @@ gst_v4l2src_init (GstV4l2Src * v4l2src, GstV4l2SrcClass * klass) v4l2src->is_capturing = FALSE; - gst_pad_set_fixatecaps_function (GST_BASE_SRC_PAD (v4l2src), - gst_v4l2src_fixate); - gst_base_src_set_format (GST_BASE_SRC (v4l2src), GST_FORMAT_TIME); gst_base_src_set_live (GST_BASE_SRC (v4l2src), TRUE); @@ -388,15 +386,12 @@ gst_v4l2src_get_property (GObject * object, /* this function is a bit of a last resort */ static void -gst_v4l2src_fixate (GstPad * pad, GstCaps * caps) +gst_v4l2src_fixate (GstBaseSrc * basesrc, GstCaps * caps) { GstStructure *structure; gint i; - G_GNUC_UNUSED gchar *caps_str; - caps_str = gst_caps_to_string (caps); - GST_DEBUG_OBJECT (GST_PAD_PARENT (pad), "fixating caps %s", caps_str); - g_free (caps_str); + GST_DEBUG_OBJECT (basesrc, "fixating caps %" GST_PTR_FORMAT, caps); for (i = 0; i < gst_caps_get_size (caps); ++i) { structure = gst_caps_get_structure (caps, i); @@ -405,7 +400,7 @@ gst_v4l2src_fixate (GstPad * pad, GstCaps * caps) /* FIXME such sizes? we usually fixate to something in the 320x200 * range... */ /* We are fixating to greater possble size (limited to GST_V4L2_MAX_SIZE) - and framarate closer to 15/2 that is common in web-cams */ + and framerate closer to 15/2 that is common in web-cams */ gst_structure_fixate_field_nearest_int (structure, "width", GST_V4L2_MAX_SIZE); gst_structure_fixate_field_nearest_int (structure, "height", @@ -697,6 +692,8 @@ gst_v4l2src_get_caps (GstBaseSrc * src) v4l2src->probed_caps = gst_caps_ref (ret); + GST_INFO_OBJECT (v4l2src, "probed caps: %" GST_PTR_FORMAT, ret); + return ret; } diff --git a/sys/v4l2/v4l2src_calls.c b/sys/v4l2/v4l2src_calls.c index 0ed28a8820..21022c8ccb 100644 --- a/sys/v4l2/v4l2src_calls.c +++ b/sys/v4l2/v4l2src_calls.c @@ -373,6 +373,97 @@ gst_v4l2_buffer_pool_destroy (GstV4l2BufferPool * pool) gst_mini_object_unref (GST_MINI_OBJECT (pool)); } +/* complete made up ranking, the values themselves are meaningless */ +#define YUV_BASE_RANK 1000 +#define JPEG_BASE_RANK 500 +#define DV_BASE_RANK 200 +#define RGB_BASE_RANK 100 +#define YUV_ODD_BASE_RANK 50 +#define RGB_ODD_BASE_RANK 25 +#define BAYER_BASE_RANK 15 +#define GREY_BASE_RANK 5 + +static gint +gst_v4l2src_format_get_rank (guint32 fourcc) +{ + switch (fourcc) { + case V4L2_PIX_FMT_MJPEG: + return JPEG_BASE_RANK; + case V4L2_PIX_FMT_JPEG: + return JPEG_BASE_RANK + 1; + + case V4L2_PIX_FMT_RGB332: + case V4L2_PIX_FMT_RGB555: + case V4L2_PIX_FMT_RGB555X: + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_RGB565X: + return RGB_ODD_BASE_RANK; + + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: + return RGB_BASE_RANK - 1; + + case V4L2_PIX_FMT_RGB32: + case V4L2_PIX_FMT_BGR32: + return RGB_BASE_RANK; + + case V4L2_PIX_FMT_GREY: /* 8 Greyscale */ + return GREY_BASE_RANK; + + case V4L2_PIX_FMT_NV12: /* 12 Y/CbCr 4:2:0 */ + case V4L2_PIX_FMT_NV21: /* 12 Y/CrCb 4:2:0 */ + case V4L2_PIX_FMT_YYUV: /* 16 YUV 4:2:2 */ + case V4L2_PIX_FMT_HI240: /* 8 8-bit color */ + return YUV_ODD_BASE_RANK; + + case V4L2_PIX_FMT_YVU410: /* YVU9, 9 bits per pixel */ + return YUV_BASE_RANK + 3; + case V4L2_PIX_FMT_YUV410: /* YUV9, 9 bits per pixel */ + return YUV_BASE_RANK + 2; + case V4L2_PIX_FMT_YUV420: /* I420, 12 bits per pixel */ + return YUV_BASE_RANK + 7; + case V4L2_PIX_FMT_YUYV: /* YUY2, 16 bits per pixel */ + return YUV_BASE_RANK + 10; + case V4L2_PIX_FMT_YVU420: /* YV12, 12 bits per pixel */ + return YUV_BASE_RANK + 6; + case V4L2_PIX_FMT_UYVY: /* UYVY, 16 bits per pixel */ + return YUV_BASE_RANK + 9; + case V4L2_PIX_FMT_Y41P: /* Y41P, 12 bits per pixel */ + return YUV_BASE_RANK + 5; + case V4L2_PIX_FMT_YUV411P: /* Y41B, 12 bits per pixel */ + return YUV_BASE_RANK + 4; + case V4L2_PIX_FMT_YUV422P: /* Y42B, 16 bits per pixel */ + return YUV_BASE_RANK + 8; + + case V4L2_PIX_FMT_DV: + return DV_BASE_RANK; + + case V4L2_PIX_FMT_MPEG: /* MPEG */ + case V4L2_PIX_FMT_WNVA: /* Winnov hw compres */ + return 0; + + case V4L2_PIX_FMT_SBGGR8: + return BAYER_BASE_RANK; + + default: + break; + } + + return 0; +} + +static gint +gst_v4l2src_format_cmp_func (gconstpointer a, gconstpointer b) +{ + guint32 pf1 = ((struct v4l2_fmtdesc *) a)->pixelformat; + guint32 pf2 = ((struct v4l2_fmtdesc *) b)->pixelformat; + + if (pf1 == pf2) + return 0; + + return gst_v4l2src_format_get_rank (pf2) - gst_v4l2src_format_get_rank (pf1); +} + /****************************************************** * gst_v4l2src_fill_format_list(): * create list of supported capture formats @@ -407,9 +498,12 @@ gst_v4l2src_fill_format_list (GstV4l2Src * v4l2src) GST_LOG_OBJECT (v4l2src, "pixelformat: %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (format->pixelformat)); - v4l2src->formats = g_slist_prepend (v4l2src->formats, format); + /* sort formats according to our preference; we do this, because caps + * are probed in the order the formats are in the list, and the order of + * formats in the final probed caps matters for things like fixation */ + v4l2src->formats = g_slist_insert_sorted (v4l2src->formats, format, + (GCompareFunc) gst_v4l2src_format_cmp_func); } - v4l2src->formats = g_slist_reverse (v4l2src->formats); GST_DEBUG_OBJECT (v4l2src, "got %d format(s)", n); @@ -638,6 +732,7 @@ gst_v4l2src_probe_caps_for_format (GstV4l2Src * v4l2src, guint32 pixelformat, { GstCaps *ret; GstStructure *tmp; + GList *results = NULL; #ifdef VIDIOC_ENUM_FRAMESIZES gint fd = v4l2src->v4l2object->video_fd; @@ -661,7 +756,7 @@ gst_v4l2src_probe_caps_for_format (GstV4l2Src * v4l2src, guint32 pixelformat, tmp = gst_v4l2src_probe_caps_for_format_and_size (v4l2src, pixelformat, w, h, template); if (tmp) - gst_caps_append_structure (ret, tmp); + results = g_list_prepend (results, tmp); size.index++; } while (ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &size) >= 0); @@ -697,6 +792,17 @@ gst_v4l2src_probe_caps_for_format (GstV4l2Src * v4l2src, guint32 pixelformat, goto unknown_type; } + /* we use an intermediary list to store the results of the probing because + * we probe from lowest resolution to highest resolution, but want the caps + * to contain the results in reverse order starting with the highest + * resolution, as order in caps matters for things like fixation. However, + * there's no gst_caps_prepend_structure(), so we use the list as helper to + * reverse the order */ + while (results != NULL) { + gst_caps_append_structure (ret, GST_STRUCTURE (results->data)); + results = g_list_delete_link (results, results); + } + return ret; /* ERRORS */