static gboolean
gst_v4l2_object_get_nearest_size (GstV4l2Object * v4l2object,
- guint32 pixelformat, gint * width, gint * height, gboolean * interlaced);
+ guint32 pixelformat, gint * width, gint * height);
static void
gst_v4l2_object_add_aspect_ratio (GstV4l2Object * v4l2object, GstStructure * s)
return FALSE;
}
+static gboolean
+gst_v4l2_object_get_interlace_mode (enum v4l2_field field,
+ GstVideoInterlaceMode * interlace_mode)
+{
+ /* NB: If you add new return values, please fix mode_strings in
+ * gst_v4l2_object_add_interlace_mode */
+ switch (field) {
+ case V4L2_FIELD_ANY:
+ GST_ERROR
+ ("Driver bug detected - check driver with v4l2-compliance from http://git.linuxtv.org/v4l-utils.git\n");
+ /* fallthrough */
+ case V4L2_FIELD_NONE:
+ *interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
+ return TRUE;
+ case V4L2_FIELD_INTERLACED:
+ case V4L2_FIELD_INTERLACED_TB:
+ case V4L2_FIELD_INTERLACED_BT:
+ *interlace_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
+ return TRUE;
+ default:
+ GST_ERROR ("Unknown enum v4l2_field %d", field);
+ return FALSE;
+ }
+}
+
+static int
+gst_v4l2_object_try_fmt (GstV4l2Object * v4l2object,
+ struct v4l2_format *try_fmt)
+{
+ int fd = v4l2object->video_fd;
+ struct v4l2_format fmt;
+ int r;
+
+ memcpy (&fmt, try_fmt, sizeof (fmt));
+ r = v4l2_ioctl (fd, VIDIOC_TRY_FMT, &fmt);
+
+ if (r < 0 && errno == ENOTTY) {
+ /* The driver might not implement TRY_FMT, in which case we will try
+ S_FMT to probe */
+ if (GST_V4L2_IS_ACTIVE (v4l2object))
+ goto error;
+
+ memcpy (&fmt, try_fmt, sizeof (fmt));
+ r = v4l2_ioctl (fd, VIDIOC_S_FMT, &fmt);
+ }
+ memcpy (try_fmt, &fmt, sizeof (fmt));
+ return r;
+
+error:
+ memcpy (try_fmt, &fmt, sizeof (fmt));
+ GST_WARNING_OBJECT (v4l2object->element,
+ "Unable to try format: %s", g_strerror (errno));
+ return r;
+}
+
+
+static void
+gst_v4l2_object_add_interlace_mode (GstV4l2Object * v4l2object,
+ GstStructure * s, guint32 width, guint32 height, guint32 pixelformat)
+{
+ struct v4l2_format fmt;
+ GValue interlace_formats = { 0, };
+ GstVideoInterlaceMode interlace_mode;
+
+ const gchar *mode_strings[] = { "progressive",
+ "interleaved",
+ "mixed"
+ };
+
+ if (!g_str_equal (gst_structure_get_name (s), "video/x-raw"))
+ return;
+
+ if (v4l2object->never_interlaced) {
+ gst_structure_set (s, "interlace-mode", G_TYPE_STRING, "progressive", NULL);
+ return;
+ }
+
+ g_value_init (&interlace_formats, GST_TYPE_LIST);
+
+ /* Try twice - once for NONE, once for INTERLACED. */
+ memset (&fmt, 0, sizeof (fmt));
+ fmt.type = v4l2object->type;
+ fmt.fmt.pix.width = width;
+ fmt.fmt.pix.height = height;
+ fmt.fmt.pix.pixelformat = pixelformat;
+ fmt.fmt.pix.field = V4L2_FIELD_NONE;
+
+ if (gst_v4l2_object_try_fmt (v4l2object, &fmt) == 0 &&
+ gst_v4l2_object_get_interlace_mode (fmt.fmt.pix.field, &interlace_mode)) {
+ GValue interlace_enum = { 0, };
+ g_value_init (&interlace_enum, G_TYPE_STRING);
+ g_value_set_string (&interlace_enum, mode_strings[interlace_mode]);
+ gst_value_list_append_value (&interlace_formats, &interlace_enum);
+ }
+
+ memset (&fmt, 0, sizeof (fmt));
+ fmt.type = v4l2object->type;
+ fmt.fmt.pix.width = width;
+ fmt.fmt.pix.height = height;
+ fmt.fmt.pix.pixelformat = pixelformat;
+ fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
+
+ if (gst_v4l2_object_try_fmt (v4l2object, &fmt) == 0 &&
+ gst_v4l2_object_get_interlace_mode (fmt.fmt.pix.field, &interlace_mode)) {
+ GValue interlace_enum = { 0, };
+ g_value_init (&interlace_enum, G_TYPE_STRING);
+ g_value_set_string (&interlace_enum, mode_strings[interlace_mode]);
+ gst_value_list_append_value (&interlace_formats, &interlace_enum);
+ }
+
+ gst_v4l2src_value_simplify (&interlace_formats);
+ gst_structure_set_value (s, "interlace-mode", &interlace_formats);
+ return;
+}
+
/* The frame interval enumeration code first appeared in Linux 2.6.19. */
static GstStructure *
gst_v4l2_object_probe_caps_for_format_and_size (GstV4l2Object * v4l2object,
guint32 num, denom;
GstStructure *s;
GValue rates = { 0, };
- gboolean interlaced;
- gint int_width = width;
- gint int_height = height;
-
- if (v4l2object->never_interlaced) {
- interlaced = FALSE;
- } else {
- /* Interlaced detection using VIDIOC_TRY/S_FMT */
- if (!gst_v4l2_object_get_nearest_size (v4l2object, pixelformat,
- &int_width, &int_height, &interlaced))
- return NULL;
- }
memset (&ival, 0, sizeof (struct v4l2_frmivalenum));
ival.index = 0;
gst_structure_set (s, "width", G_TYPE_INT, (gint) width,
"height", G_TYPE_INT, (gint) height, NULL);
gst_v4l2_object_add_aspect_ratio (v4l2object, s);
- if (g_str_equal (gst_structure_get_name (s), "video/x-raw"))
- gst_structure_set (s, "interlace-mode", G_TYPE_STRING,
- (interlaced ? "mixed" : "progressive"), NULL);
+ gst_v4l2_object_add_interlace_mode (v4l2object, s, width, height,
+ pixelformat);
if (G_IS_VALUE (&rates)) {
gst_v4l2src_value_simplify (&rates);
default_frame_sizes:
{
gint min_w, max_w, min_h, max_h, fix_num = 0, fix_denom = 0;
- gboolean interlaced;
/* This code is for Linux < 2.6.19 */
min_w = min_h = 1;
max_w = max_h = GST_V4L2_MAX_SIZE;
if (!gst_v4l2_object_get_nearest_size (v4l2object, pixelformat, &min_w,
- &min_h, &interlaced)) {
+ &min_h)) {
GST_WARNING_OBJECT (v4l2object->element,
"Could not probe minimum capture size for pixelformat %"
GST_FOURCC_FORMAT, GST_FOURCC_ARGS (pixelformat));
}
if (!gst_v4l2_object_get_nearest_size (v4l2object, pixelformat, &max_w,
- &max_h, &interlaced)) {
+ &max_h)) {
GST_WARNING_OBJECT (v4l2object->element,
"Could not probe maximum capture size for pixelformat %"
GST_FOURCC_FORMAT, GST_FOURCC_ARGS (pixelformat));
else
gst_structure_set (tmp, "height", GST_TYPE_INT_RANGE, min_h, max_h, NULL);
- if (g_str_equal (gst_structure_get_name (tmp), "video/x-raw"))
- gst_structure_set (tmp, "interlace-mode", G_TYPE_STRING,
- (interlaced ? "mixed" : "progressive"), NULL);
+ /* We could consider setting interlace mode from min and max. */
+ gst_v4l2_object_add_interlace_mode (v4l2object, tmp, max_w, max_h,
+ pixelformat);
gst_v4l2_object_add_aspect_ratio (v4l2object, tmp);
gst_v4l2_object_update_and_append (v4l2object, pixelformat, ret, tmp);
}
static gboolean
-gst_v4l2_object_get_interlace (int field, gboolean * interlaced)
-{
- switch (field) {
- case V4L2_FIELD_ANY:
- case V4L2_FIELD_NONE:
- *interlaced = FALSE;
- return TRUE;
- case V4L2_FIELD_INTERLACED:
- case V4L2_FIELD_INTERLACED_TB:
- case V4L2_FIELD_INTERLACED_BT:
- *interlaced = TRUE;
- return TRUE;
- default:
- return FALSE;
- }
-}
-
-static gboolean
gst_v4l2_object_get_nearest_size (GstV4l2Object * v4l2object,
- guint32 pixelformat, gint * width, gint * height, gboolean * interlaced)
+ guint32 pixelformat, gint * width, gint * height)
{
struct v4l2_format fmt;
- int fd;
- int r;
gboolean ret = FALSE;
+ GstVideoInterlaceMode interlace_mode;
g_return_val_if_fail (width != NULL, FALSE);
g_return_val_if_fail (height != NULL, FALSE);
"getting nearest size to %dx%d with format %" GST_FOURCC_FORMAT,
*width, *height, GST_FOURCC_ARGS (pixelformat));
- fd = v4l2object->video_fd;
-
memset (&fmt, 0, sizeof (struct v4l2_format));
/* get size delimiters */
fmt.fmt.pix.width = *width;
fmt.fmt.pix.height = *height;
fmt.fmt.pix.pixelformat = pixelformat;
- fmt.fmt.pix.field = V4L2_FIELD_NONE;
-
- r = v4l2_ioctl (fd, VIDIOC_TRY_FMT, &fmt);
- if ((r < 0 && errno == EINVAL) ||
- !gst_v4l2_object_get_interlace (fmt.fmt.pix.field, interlaced)) {
- /* try again with interlaced video */
- memset (&fmt, 0, sizeof (fmt));
- fmt.type = v4l2object->type;
- fmt.fmt.pix.width = *width;
- fmt.fmt.pix.height = *height;
- fmt.fmt.pix.pixelformat = pixelformat;
- fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
- r = v4l2_ioctl (fd, VIDIOC_TRY_FMT, &fmt);
- }
-
- if (r < 0) {
- /* The driver might not implement TRY_FMT, in which case we will try
- S_FMT to probe */
- if (errno != ENOTTY)
- goto error;
+ fmt.fmt.pix.field = V4L2_FIELD_ANY;
- /* Only try S_FMT if we're not actively capturing yet, which we shouldn't
- be, because we're still probing */
- if (GST_V4L2_IS_ACTIVE (v4l2object))
- goto error;
-
- GST_LOG_OBJECT (v4l2object->element,
- "Failed to probe size limit with VIDIOC_TRY_FMT, trying VIDIOC_S_FMT");
-
- memset (&fmt, 0, sizeof (fmt));
- fmt.type = v4l2object->type;
- fmt.fmt.pix.width = *width;
- fmt.fmt.pix.height = *height;
- fmt.fmt.pix.pixelformat = pixelformat;
- fmt.fmt.pix.field = V4L2_FIELD_NONE;
-
- r = v4l2_ioctl (fd, VIDIOC_S_FMT, &fmt);
- if ((r < 0 && errno == EINVAL) ||
- !gst_v4l2_object_get_interlace (fmt.fmt.pix.field, interlaced)) {
- /* try again with interlaced video */
- memset (&fmt, 0, sizeof (fmt));
- fmt.type = v4l2object->type;
- fmt.fmt.pix.width = *width;
- fmt.fmt.pix.height = *height;
- fmt.fmt.pix.pixelformat = pixelformat;
- fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
- r = v4l2_ioctl (fd, VIDIOC_S_FMT, &fmt);
- }
-
- if (r < 0)
- goto error;
- }
+ if (gst_v4l2_object_try_fmt (v4l2object, &fmt) < 0)
+ goto error;
GST_LOG_OBJECT (v4l2object->element,
"got nearest size %dx%d", fmt.fmt.pix.width, fmt.fmt.pix.height);
*width = fmt.fmt.pix.width;
*height = fmt.fmt.pix.height;
- if (!gst_v4l2_object_get_interlace (fmt.fmt.pix.field, interlaced)) {
+ if (!gst_v4l2_object_get_interlace_mode (fmt.fmt.pix.field, &interlace_mode)) {
GST_WARNING_OBJECT (v4l2object->element,
"Unsupported field type for %" GST_FOURCC_FORMAT "@%ux%u: %u",
GST_FOURCC_ARGS (pixelformat), *width, *height, fmt.fmt.pix.field);