Commit 4b16b16a authored by Reynaldo H. Verdejo Pinochet's avatar Reynaldo H. Verdejo Pinochet Committed by Nicolas Dufresne

v4l2: use opened device caps instead of physical device ones

The same physical device can export multiple devices. In
this case, the capabilities field now contains a union of
all caps available from all exported V4L2 devices alongside
a V4L2_CAP_DEVICE_CAPS flag that should be used to decide
what capabilities to consider. In our case, we need the
ones from the exported device we are using.

https://bugzilla.gnome.org/show_bug.cgi?id=768195
parent f0ba7a5c
...@@ -119,6 +119,7 @@ gst_v4l2_probe_and_register (GstPlugin * plugin) ...@@ -119,6 +119,7 @@ gst_v4l2_probe_and_register (GstPlugin * plugin)
gint video_fd = -1; gint video_fd = -1;
struct v4l2_capability vcap; struct v4l2_capability vcap;
gboolean ret = TRUE; gboolean ret = TRUE;
guint32 device_caps;
it = gst_v4l2_iterator_new (); it = gst_v4l2_iterator_new ();
...@@ -143,12 +144,16 @@ gst_v4l2_probe_and_register (GstPlugin * plugin) ...@@ -143,12 +144,16 @@ gst_v4l2_probe_and_register (GstPlugin * plugin)
continue; continue;
} }
if (!((vcap.capabilities & (V4L2_CAP_VIDEO_M2M | if (vcap.capabilities & V4L2_CAP_DEVICE_CAPS)
V4L2_CAP_VIDEO_M2M_MPLANE)) || device_caps = vcap.device_caps;
else
device_caps = vcap.capabilitites;
if (!((device_caps & (V4L2_CAP_VIDEO_M2M | V4L2_CAP_VIDEO_M2M_MPLANE)) ||
/* But legacy driver may expose both CAPTURE and OUTPUT */ /* But legacy driver may expose both CAPTURE and OUTPUT */
((vcap.capabilities & ((device_caps &
(V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_CAPTURE_MPLANE)) && (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_CAPTURE_MPLANE)) &&
(vcap.capabilities & (device_caps &
(V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE))))) (V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE)))))
continue; continue;
......
...@@ -716,7 +716,7 @@ gst_v4l2_buffer_pool_start (GstBufferPool * bpool) ...@@ -716,7 +716,7 @@ gst_v4l2_buffer_pool_start (GstBufferPool * bpool)
* poll before that will always fail. Doing an empty read, forces the * poll before that will always fail. Doing an empty read, forces the
* queue to be initialized now. We only do this if we have a streaming * queue to be initialized now. We only do this if we have a streaming
* driver. */ * driver. */
if (obj->vcap.capabilities & V4L2_CAP_STREAMING) if (obj->device_caps & V4L2_CAP_STREAMING)
v4l2_read (obj->video_fd, NULL, 0); v4l2_read (obj->video_fd, NULL, 0);
#endif #endif
break; break;
......
...@@ -136,10 +136,10 @@ gst_v4l2_device_provider_probe_device (GstV4l2DeviceProvider * provider, ...@@ -136,10 +136,10 @@ gst_v4l2_device_provider_probe_device (GstV4l2DeviceProvider * provider,
gst_structure_set (props, "v4l2.device.device_caps", G_TYPE_UINT, gst_structure_set (props, "v4l2.device.device_caps", G_TYPE_UINT,
v4l2obj->vcap.device_caps, NULL); v4l2obj->vcap.device_caps, NULL);
if (v4l2obj->vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE) if (v4l2obj->device_caps & V4L2_CAP_VIDEO_CAPTURE)
type = GST_V4L2_DEVICE_TYPE_SOURCE; type = GST_V4L2_DEVICE_TYPE_SOURCE;
if (v4l2obj->vcap.capabilities & V4L2_CAP_VIDEO_OUTPUT) { if (v4l2obj->device_caps & V4L2_CAP_VIDEO_OUTPUT) {
/* Morph it in case our initial guess was wrong */ /* Morph it in case our initial guess was wrong */
v4l2obj->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; v4l2obj->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
......
...@@ -700,17 +700,17 @@ gst_v4l2_object_get_property_helper (GstV4l2Object * v4l2object, ...@@ -700,17 +700,17 @@ gst_v4l2_object_get_property_helper (GstV4l2Object * v4l2object,
guint flags = 0; guint flags = 0;
if (GST_V4L2_IS_OPEN (v4l2object)) { if (GST_V4L2_IS_OPEN (v4l2object)) {
flags |= v4l2object->vcap.capabilities & flags |= v4l2object->device_caps &
(V4L2_CAP_VIDEO_CAPTURE | (V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT |
V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_VIDEO_OVERLAY |
V4L2_CAP_VBI_CAPTURE | V4L2_CAP_VBI_CAPTURE |
V4L2_CAP_VBI_OUTPUT | V4L2_CAP_TUNER | V4L2_CAP_AUDIO); V4L2_CAP_VBI_OUTPUT | V4L2_CAP_TUNER | V4L2_CAP_AUDIO);
if (v4l2object->vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE) if (v4l2object->device_caps & V4L2_CAP_VIDEO_CAPTURE_MPLANE)
flags |= V4L2_CAP_VIDEO_CAPTURE; flags |= V4L2_CAP_VIDEO_CAPTURE;
if (v4l2object->vcap.capabilities & V4L2_CAP_VIDEO_OUTPUT_MPLANE) if (v4l2object->device_caps & V4L2_CAP_VIDEO_OUTPUT_MPLANE)
flags |= V4L2_CAP_VIDEO_OUTPUT; flags |= V4L2_CAP_VIDEO_OUTPUT;
} }
g_value_set_flags (value, flags); g_value_set_flags (value, flags);
...@@ -873,6 +873,9 @@ gst_v4l2_object_close (GstV4l2Object * v4l2object) ...@@ -873,6 +873,9 @@ gst_v4l2_object_close (GstV4l2Object * v4l2object)
gst_caps_replace (&v4l2object->probed_caps, NULL); gst_caps_replace (&v4l2object->probed_caps, NULL);
/* reset our copy of the device caps */
v4l2object->device_caps = 0;
if (v4l2object->formats) { if (v4l2object->formats) {
gst_v4l2_object_clear_format_list (v4l2object); gst_v4l2_object_clear_format_list (v4l2object);
} }
...@@ -2824,13 +2827,13 @@ gst_v4l2_object_setup_pool (GstV4l2Object * v4l2object, GstCaps * caps) ...@@ -2824,13 +2827,13 @@ gst_v4l2_object_setup_pool (GstV4l2Object * v4l2object, GstCaps * caps)
/* find transport */ /* find transport */
mode = v4l2object->req_mode; mode = v4l2object->req_mode;
if (v4l2object->vcap.capabilities & V4L2_CAP_READWRITE) { if (v4l2object->device_caps & V4L2_CAP_READWRITE) {
if (v4l2object->req_mode == GST_V4L2_IO_AUTO) if (v4l2object->req_mode == GST_V4L2_IO_AUTO)
mode = GST_V4L2_IO_RW; mode = GST_V4L2_IO_RW;
} else if (v4l2object->req_mode == GST_V4L2_IO_RW) } else if (v4l2object->req_mode == GST_V4L2_IO_RW)
goto method_not_supported; goto method_not_supported;
if (v4l2object->vcap.capabilities & V4L2_CAP_STREAMING) { if (v4l2object->device_caps & V4L2_CAP_STREAMING) {
if (v4l2object->req_mode == GST_V4L2_IO_AUTO) if (v4l2object->req_mode == GST_V4L2_IO_AUTO)
mode = GST_V4L2_IO_MMAP; mode = GST_V4L2_IO_MMAP;
} else if (v4l2object->req_mode == GST_V4L2_IO_MMAP) } else if (v4l2object->req_mode == GST_V4L2_IO_MMAP)
......
...@@ -133,6 +133,8 @@ struct _GstV4l2Object { ...@@ -133,6 +133,8 @@ struct _GstV4l2Object {
/* the video device's capabilities */ /* the video device's capabilities */
struct v4l2_capability vcap; struct v4l2_capability vcap;
/* opened device specific capabilities */
guint32 device_caps;
/* the video device's window properties */ /* the video device's window properties */
struct v4l2_window vwin; struct v4l2_window vwin;
......
...@@ -90,7 +90,12 @@ gst_v4l2radio_fill_channel_list (GstV4l2Radio * radio) ...@@ -90,7 +90,12 @@ gst_v4l2radio_fill_channel_list (GstV4l2Radio * radio)
if (res < 0) if (res < 0)
goto caps_failed; goto caps_failed;
if (!(vc.capabilities & V4L2_CAP_TUNER)) if (vc.capabilities & V4L2_CAP_DEVICE_CAPS)
v4l2object->device_caps = vc.device_caps;
else
v4l2object->device_caps = vc.capabilities;
if (!(v4l2object->device_caps & V4L2_CAP_TUNER))
goto not_a_tuner; goto not_a_tuner;
/* getting audio input */ /* getting audio input */
......
...@@ -250,10 +250,10 @@ gst_v4l2sink_sync_overlay_fields (GstV4l2Sink * v4l2sink) ...@@ -250,10 +250,10 @@ gst_v4l2sink_sync_overlay_fields (GstV4l2Sink * v4l2sink)
struct v4l2_format format; struct v4l2_format format;
memset (&format, 0x00, sizeof (struct v4l2_format)); memset (&format, 0x00, sizeof (struct v4l2_format));
if ( v4l2sink->v4l2object->vcap.capabilities & V4L2_CAP_VIDEO_OUTPUT_OVERLAY ) if (v4l2sink->v4l2object->device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)
format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY; format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY;
else else
format.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; format.type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
if (v4l2_ioctl (fd, VIDIOC_G_FMT, &format) < 0) { if (v4l2_ioctl (fd, VIDIOC_G_FMT, &format) < 0) {
GST_WARNING_OBJECT (v4l2sink, "VIDIOC_G_FMT failed"); GST_WARNING_OBJECT (v4l2sink, "VIDIOC_G_FMT failed");
......
...@@ -74,11 +74,16 @@ gst_v4l2_get_capabilities (GstV4l2Object * v4l2object) ...@@ -74,11 +74,16 @@ gst_v4l2_get_capabilities (GstV4l2Object * v4l2object)
if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_QUERYCAP, &v4l2object->vcap) < 0) if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_QUERYCAP, &v4l2object->vcap) < 0)
goto cap_failed; goto cap_failed;
if (v4l2object->vcap.capabilities & V4L2_CAP_DEVICE_CAPS)
v4l2object->device_caps = v4l2object->vcap.device_caps;
else
v4l2object->device_caps = v4l2object->vcap.capabilities;
GST_LOG_OBJECT (e, "driver: '%s'", v4l2object->vcap.driver); GST_LOG_OBJECT (e, "driver: '%s'", v4l2object->vcap.driver);
GST_LOG_OBJECT (e, "card: '%s'", v4l2object->vcap.card); GST_LOG_OBJECT (e, "card: '%s'", v4l2object->vcap.card);
GST_LOG_OBJECT (e, "bus_info: '%s'", v4l2object->vcap.bus_info); GST_LOG_OBJECT (e, "bus_info: '%s'", v4l2object->vcap.bus_info);
GST_LOG_OBJECT (e, "version: %08x", v4l2object->vcap.version); GST_LOG_OBJECT (e, "version: %08x", v4l2object->vcap.version);
GST_LOG_OBJECT (e, "capabilites: %08x", v4l2object->vcap.capabilities); GST_LOG_OBJECT (e, "capabilites: %08x", v4l2object->device_caps);
return TRUE; return TRUE;
...@@ -487,13 +492,13 @@ gst_v4l2_adjust_buf_type (GstV4l2Object * v4l2object) ...@@ -487,13 +492,13 @@ gst_v4l2_adjust_buf_type (GstV4l2Object * v4l2object)
#define CHECK_CAPS (V4L2_CAP_VIDEO_OUTPUT_MPLANE | V4L2_CAP_VIDEO_M2M_MPLANE) #define CHECK_CAPS (V4L2_CAP_VIDEO_OUTPUT_MPLANE | V4L2_CAP_VIDEO_M2M_MPLANE)
switch (v4l2object->type) { switch (v4l2object->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT: case V4L2_BUF_TYPE_VIDEO_OUTPUT:
if (v4l2object->vcap.capabilities & CHECK_CAPS) { if (v4l2object->device_caps & CHECK_CAPS) {
GST_DEBUG ("adjust type to multi-planar output"); GST_DEBUG ("adjust type to multi-planar output");
v4l2object->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; v4l2object->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
} }
break; break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_CAPTURE:
if (v4l2object->vcap.capabilities & CHECK_CAPS) { if (v4l2object->device_caps & CHECK_CAPS) {
GST_DEBUG ("adjust type to multi-planar capture"); GST_DEBUG ("adjust type to multi-planar capture");
v4l2object->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; v4l2object->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
} }
...@@ -556,23 +561,23 @@ gst_v4l2_open (GstV4l2Object * v4l2object) ...@@ -556,23 +561,23 @@ gst_v4l2_open (GstV4l2Object * v4l2object)
/* do we need to be a capture device? */ /* do we need to be a capture device? */
if (GST_IS_V4L2SRC (v4l2object->element) && if (GST_IS_V4L2SRC (v4l2object->element) &&
!(v4l2object->vcap.capabilities & (V4L2_CAP_VIDEO_CAPTURE | !(v4l2object->device_caps & (V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_VIDEO_CAPTURE_MPLANE))) V4L2_CAP_VIDEO_CAPTURE_MPLANE)))
goto not_capture; goto not_capture;
if (GST_IS_V4L2SINK (v4l2object->element) && if (GST_IS_V4L2SINK (v4l2object->element) &&
!(v4l2object->vcap.capabilities & (V4L2_CAP_VIDEO_OUTPUT | !(v4l2object->device_caps & (V4L2_CAP_VIDEO_OUTPUT |
V4L2_CAP_VIDEO_OUTPUT_MPLANE))) V4L2_CAP_VIDEO_OUTPUT_MPLANE)))
goto not_output; goto not_output;
if (GST_IS_V4L2_VIDEO_DEC (v4l2object->element) && if (GST_IS_V4L2_VIDEO_DEC (v4l2object->element) &&
/* Today's M2M device only expose M2M */ /* Today's M2M device only expose M2M */
!((v4l2object->vcap.capabilities & (V4L2_CAP_VIDEO_M2M | !((v4l2object->device_caps & (V4L2_CAP_VIDEO_M2M |
V4L2_CAP_VIDEO_M2M_MPLANE)) || V4L2_CAP_VIDEO_M2M_MPLANE)) ||
/* But legacy driver may expose both CAPTURE and OUTPUT */ /* But legacy driver may expose both CAPTURE and OUTPUT */
((v4l2object->vcap.capabilities & ((v4l2object->device_caps &
(V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_CAPTURE_MPLANE)) && (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_CAPTURE_MPLANE)) &&
(v4l2object->vcap.capabilities & (v4l2object->device_caps &
(V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE))))) (V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE)))))
goto not_m2m; goto not_m2m;
...@@ -625,7 +630,7 @@ not_capture: ...@@ -625,7 +630,7 @@ not_capture:
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND, GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
(_("Device '%s' is not a capture device."), (_("Device '%s' is not a capture device."),
v4l2object->videodev), v4l2object->videodev),
("Capabilities: 0x%x", v4l2object->vcap.capabilities)); ("Capabilities: 0x%x", v4l2object->device_caps));
goto error; goto error;
} }
not_output: not_output:
...@@ -633,7 +638,7 @@ not_output: ...@@ -633,7 +638,7 @@ not_output:
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND, GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
(_("Device '%s' is not a output device."), (_("Device '%s' is not a output device."),
v4l2object->videodev), v4l2object->videodev),
("Capabilities: 0x%x", v4l2object->vcap.capabilities)); ("Capabilities: 0x%x", v4l2object->device_caps));
goto error; goto error;
} }
not_m2m: not_m2m:
...@@ -641,7 +646,7 @@ not_m2m: ...@@ -641,7 +646,7 @@ not_m2m:
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND, GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
(_("Device '%s' is not a M2M device."), (_("Device '%s' is not a M2M device."),
v4l2object->videodev), v4l2object->videodev),
("Capabilities: 0x%x", v4l2object->vcap.capabilities)); ("Capabilities: 0x%x", v4l2object->device_caps));
goto error; goto error;
} }
error: error:
...@@ -1034,7 +1039,7 @@ gst_v4l2_get_input (GstV4l2Object * v4l2object, gint * input) ...@@ -1034,7 +1039,7 @@ gst_v4l2_get_input (GstV4l2Object * v4l2object, gint * input)
/* ERRORS */ /* ERRORS */
input_failed: input_failed:
if (v4l2object->vcap.capabilities & V4L2_CAP_TUNER) { if (v4l2object->device_caps & V4L2_CAP_TUNER) {
/* only give a warning message if driver actually claims to have tuner /* only give a warning message if driver actually claims to have tuner
* support * support
*/ */
...@@ -1059,7 +1064,7 @@ gst_v4l2_set_input (GstV4l2Object * v4l2object, gint input) ...@@ -1059,7 +1064,7 @@ gst_v4l2_set_input (GstV4l2Object * v4l2object, gint input)
/* ERRORS */ /* ERRORS */
input_failed: input_failed:
if (v4l2object->vcap.capabilities & V4L2_CAP_TUNER) { if (v4l2object->device_caps & V4L2_CAP_TUNER) {
/* only give a warning message if driver actually claims to have tuner /* only give a warning message if driver actually claims to have tuner
* support * support
*/ */
...@@ -1091,7 +1096,7 @@ gst_v4l2_get_output (GstV4l2Object * v4l2object, gint * output) ...@@ -1091,7 +1096,7 @@ gst_v4l2_get_output (GstV4l2Object * v4l2object, gint * output)
/* ERRORS */ /* ERRORS */
output_failed: output_failed:
if (v4l2object->vcap.capabilities & V4L2_CAP_TUNER) { if (v4l2object->device_caps & V4L2_CAP_TUNER) {
/* only give a warning message if driver actually claims to have tuner /* only give a warning message if driver actually claims to have tuner
* support * support
*/ */
...@@ -1116,7 +1121,7 @@ gst_v4l2_set_output (GstV4l2Object * v4l2object, gint output) ...@@ -1116,7 +1121,7 @@ gst_v4l2_set_output (GstV4l2Object * v4l2object, gint output)
/* ERRORS */ /* ERRORS */
output_failed: output_failed:
if (v4l2object->vcap.capabilities & V4L2_CAP_TUNER) { if (v4l2object->device_caps & V4L2_CAP_TUNER) {
/* only give a warning message if driver actually claims to have tuner /* only give a warning message if driver actually claims to have tuner
* support * support
*/ */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment