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.
This commit is contained in:
Tim-Philipp Müller 2007-10-13 12:03:44 +00:00
parent 4faf179db8
commit a769e5e70a
3 changed files with 134 additions and 13 deletions

View file

@ -1,3 +1,21 @@
2007-10-13 Tim-Philipp Müller <tim at centricular dot net>
* 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 <tim at centricular dot net> 2007-10-11 Tim-Philipp Müller <tim at centricular dot net>
Based on patch by: Jason Kivlighn <jkivlighn gmail com> Based on patch by: Jason Kivlighn <jkivlighn gmail com>

View file

@ -240,7 +240,7 @@ static GstCaps *gst_v4l2src_get_caps (GstBaseSrc * src);
static gboolean gst_v4l2src_query (GstBaseSrc * bsrc, GstQuery * query); static gboolean gst_v4l2src_query (GstBaseSrc * bsrc, GstQuery * query);
static GstFlowReturn gst_v4l2src_create (GstPushSrc * src, GstBuffer ** out); 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, static void gst_v4l2src_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec); 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->start = GST_DEBUG_FUNCPTR (gst_v4l2src_start);
basesrc_class->stop = GST_DEBUG_FUNCPTR (gst_v4l2src_stop); basesrc_class->stop = GST_DEBUG_FUNCPTR (gst_v4l2src_stop);
basesrc_class->query = GST_DEBUG_FUNCPTR (gst_v4l2src_query); 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); pushsrc_class->create = GST_DEBUG_FUNCPTR (gst_v4l2src_create);
} }
@ -313,9 +314,6 @@ gst_v4l2src_init (GstV4l2Src * v4l2src, GstV4l2SrcClass * klass)
v4l2src->is_capturing = FALSE; 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_format (GST_BASE_SRC (v4l2src), GST_FORMAT_TIME);
gst_base_src_set_live (GST_BASE_SRC (v4l2src), TRUE); 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 */ /* this function is a bit of a last resort */
static void static void
gst_v4l2src_fixate (GstPad * pad, GstCaps * caps) gst_v4l2src_fixate (GstBaseSrc * basesrc, GstCaps * caps)
{ {
GstStructure *structure; GstStructure *structure;
gint i; gint i;
G_GNUC_UNUSED gchar *caps_str;
caps_str = gst_caps_to_string (caps); GST_DEBUG_OBJECT (basesrc, "fixating caps %" GST_PTR_FORMAT, caps);
GST_DEBUG_OBJECT (GST_PAD_PARENT (pad), "fixating caps %s", caps_str);
g_free (caps_str);
for (i = 0; i < gst_caps_get_size (caps); ++i) { for (i = 0; i < gst_caps_get_size (caps); ++i) {
structure = gst_caps_get_structure (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 /* FIXME such sizes? we usually fixate to something in the 320x200
* range... */ * range... */
/* We are fixating to greater possble size (limited to GST_V4L2_MAX_SIZE) /* 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_structure_fixate_field_nearest_int (structure, "width",
GST_V4L2_MAX_SIZE); GST_V4L2_MAX_SIZE);
gst_structure_fixate_field_nearest_int (structure, "height", 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); v4l2src->probed_caps = gst_caps_ref (ret);
GST_INFO_OBJECT (v4l2src, "probed caps: %" GST_PTR_FORMAT, ret);
return ret; return ret;
} }

View file

@ -373,6 +373,97 @@ gst_v4l2_buffer_pool_destroy (GstV4l2BufferPool * pool)
gst_mini_object_unref (GST_MINI_OBJECT (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(): * gst_v4l2src_fill_format_list():
* create list of supported capture formats * 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_LOG_OBJECT (v4l2src, "pixelformat: %" GST_FOURCC_FORMAT,
GST_FOURCC_ARGS (format->pixelformat)); 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); 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; GstCaps *ret;
GstStructure *tmp; GstStructure *tmp;
GList *results = NULL;
#ifdef VIDIOC_ENUM_FRAMESIZES #ifdef VIDIOC_ENUM_FRAMESIZES
gint fd = v4l2src->v4l2object->video_fd; 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, tmp = gst_v4l2src_probe_caps_for_format_and_size (v4l2src, pixelformat,
w, h, template); w, h, template);
if (tmp) if (tmp)
gst_caps_append_structure (ret, tmp); results = g_list_prepend (results, tmp);
size.index++; size.index++;
} while (ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &size) >= 0); } 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; 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; return ret;
/* ERRORS */ /* ERRORS */