uvch264: Factor out checking if v4l2device is uvc compatible

This commit is contained in:
Thibault Saunier 2019-06-03 12:17:22 -04:00 committed by Thibault Saunier
parent 59d8e56e95
commit 2d3de7afa4
4 changed files with 140 additions and 131 deletions

View file

@ -22,8 +22,8 @@
/**
* SECTION:element-uvch264-src
* @title: uvch264-src
* SECTION:element-uvch264src
* @title: uvch264src
*
* A camera bin src element that wraps v4l2src and implements UVC H264
* Extension Units (XU) to control the H264 encoder in the camera
@ -35,39 +35,6 @@
#include "gstuvch264_src.h"
#include <gst/video/video.h>
#include <linux/uvcvideo.h>
#include <linux/usb/video.h>
#include <sys/ioctl.h>
#include <string.h>
#include "gstuvch264_src.h"
#include <gudev/gudev.h>
#include <libusb.h>
#ifndef LIBUSB_CLASS_VIDEO
#define LIBUSB_CLASS_VIDEO 0x0e
#endif
typedef struct
{
int8_t bLength;
int8_t bDescriptorType;
int8_t bDescriptorSubType;
int8_t bUnitID;
uint8_t guidExtensionCode[16];
} __attribute__ ((__packed__)) xu_descriptor;
#define GUID_FORMAT "02X%02X%02X%02X-%02X%02X%02X%02X-"\
"%02X%02X%02X%02X-%02X%02X%02X%02X"
#define GUID_ARGS(guid) guid[0], guid[1], guid[2], guid[3], \
guid[4], guid[5], guid[6], guid[7], \
guid[8], guid[9], guid[10], guid[11], \
guid[12], guid[13], guid[14], guid[15]
#define USB_VIDEO_CONTROL 1
#define USB_VIDEO_CONTROL_INTERFACE 0x24
#define USB_VIDEO_CONTROL_XU_TYPE 0x06
enum
{
PROP_0,
@ -174,6 +141,11 @@ G_DEFINE_TYPE (GstUvcH264Src, gst_uvc_h264_src, GST_TYPE_BASE_CAMERA_SRC);
"alignment = (string) au, " \
"profile = (string) { high, main, baseline, constrained-baseline }"
/**
* GstUvcH264Src!vfsrc:
*
* The video src pad template
*/
static GstStaticPadTemplate vfsrc_template =
GST_STATIC_PAD_TEMPLATE (GST_BASE_CAMERA_SRC_VIEWFINDER_PAD_NAME,
GST_PAD_SRC,
@ -1794,100 +1766,6 @@ gst_uvc_h264_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
return self->srcpad_event_func (pad, parent, event);
}
static guint8
xu_get_id (GstUvcH264Src * self)
{
static const __u8 guid[16] = GUID_UVCX_H264_XU;
GUdevClient *client;
GUdevDevice *udevice;
GUdevDevice *parent;
guint64 busnum;
guint64 devnum;
libusb_device **device_list = NULL;
libusb_device *device = NULL;
ssize_t cnt;
int i, j, k;
if (self->usb_ctx == NULL)
libusb_init (&self->usb_ctx);
client = g_udev_client_new (NULL);
if (client) {
udevice = g_udev_client_query_by_device_file (client, self->device);
if (udevice) {
parent = g_udev_device_get_parent_with_subsystem (udevice, "usb",
"usb_device");
if (parent) {
busnum = g_udev_device_get_sysfs_attr_as_uint64 (parent, "busnum");
devnum = g_udev_device_get_sysfs_attr_as_uint64 (parent, "devnum");
cnt = libusb_get_device_list (self->usb_ctx, &device_list);
for (i = 0; i < cnt; i++) {
if (busnum == libusb_get_bus_number (device_list[i]) &&
devnum == libusb_get_device_address (device_list[i])) {
device = libusb_ref_device (device_list[i]);
break;
}
}
libusb_free_device_list (device_list, 1);
g_object_unref (parent);
}
g_object_unref (udevice);
}
g_object_unref (client);
}
if (device) {
struct libusb_device_descriptor desc;
if (libusb_get_device_descriptor (device, &desc) == 0) {
for (i = 0; i < desc.bNumConfigurations; ++i) {
struct libusb_config_descriptor *config = NULL;
if (libusb_get_config_descriptor (device, i, &config) == 0) {
for (j = 0; j < config->bNumInterfaces; j++) {
for (k = 0; k < config->interface[j].num_altsetting; k++) {
const struct libusb_interface_descriptor *interface;
const guint8 *ptr = NULL;
interface = &config->interface[j].altsetting[k];
if (interface->bInterfaceClass != LIBUSB_CLASS_VIDEO ||
interface->bInterfaceSubClass != USB_VIDEO_CONTROL)
continue;
ptr = interface->extra;
while (ptr - interface->extra +
sizeof (xu_descriptor) < interface->extra_length) {
xu_descriptor *desc = (xu_descriptor *) ptr;
GST_DEBUG_OBJECT (self, "Found VideoControl interface with "
"unit id %d : %" GUID_FORMAT, desc->bUnitID,
GUID_ARGS (desc->guidExtensionCode));
if (desc->bDescriptorType == USB_VIDEO_CONTROL_INTERFACE &&
desc->bDescriptorSubType == USB_VIDEO_CONTROL_XU_TYPE &&
memcmp (desc->guidExtensionCode, guid, 16) == 0) {
guint8 unit_id = desc->bUnitID;
GST_DEBUG_OBJECT (self, "Found H264 XU unit : %d", unit_id);
libusb_free_config_descriptor (config);
libusb_unref_device (device);
return unit_id;
}
ptr += desc->bLength;
}
}
}
libusb_free_config_descriptor (config);
}
}
}
libusb_unref_device (device);
}
return 0;
}
static gboolean
xu_query (GstUvcH264Src * self, guint selector, guint query, guchar * data)
{
@ -2530,7 +2408,8 @@ ensure_v4l2src (GstUvcH264Src * self)
/* Set/Update the fd and unit id after we go to READY */
g_object_get (self->v4l2_src, "device-fd", &self->v4l2_fd, NULL);
self->h264_unit_id = xu_get_id (self);
self->h264_unit_id =
xu_get_id (GST_OBJECT (self), self->device, &self->usb_ctx);
if (self->h264_unit_id == 0) {
GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,

View file

@ -30,7 +30,6 @@
#include <gst/gst.h>
#include <gst/basecamerabinsrc/gstbasecamerasrc.h>
#include <libusb.h>
#include "uvc_h264.h"

View file

@ -120,3 +120,98 @@ uvc_h264_entropy_get_type (void)
}
return type;
}
guint8
xu_get_id (GstObject * self, const gchar * devicename,
libusb_context ** usb_ctx)
{
static const __u8 guid[16] = GUID_UVCX_H264_XU;
GUdevClient *client;
GUdevDevice *udevice;
GUdevDevice *parent;
guint64 busnum;
guint64 devnum;
libusb_device **device_list = NULL;
libusb_device *device = NULL;
ssize_t cnt;
int i, j, k;
if (*usb_ctx == NULL)
libusb_init (usb_ctx);
client = g_udev_client_new (NULL);
if (client) {
udevice = g_udev_client_query_by_device_file (client, devicename);
if (udevice) {
parent = g_udev_device_get_parent_with_subsystem (udevice, "usb",
"usb_device");
if (parent) {
busnum = g_udev_device_get_sysfs_attr_as_uint64 (parent, "busnum");
devnum = g_udev_device_get_sysfs_attr_as_uint64 (parent, "devnum");
cnt = libusb_get_device_list (*usb_ctx, &device_list);
for (i = 0; i < cnt; i++) {
if (busnum == libusb_get_bus_number (device_list[i]) &&
devnum == libusb_get_device_address (device_list[i])) {
device = libusb_ref_device (device_list[i]);
break;
}
}
libusb_free_device_list (device_list, 1);
g_object_unref (parent);
}
g_object_unref (udevice);
}
g_object_unref (client);
}
if (device) {
struct libusb_device_descriptor desc;
if (libusb_get_device_descriptor (device, &desc) == 0) {
for (i = 0; i < desc.bNumConfigurations; ++i) {
struct libusb_config_descriptor *config = NULL;
if (libusb_get_config_descriptor (device, i, &config) == 0) {
for (j = 0; j < config->bNumInterfaces; j++) {
for (k = 0; k < config->interface[j].num_altsetting; k++) {
const struct libusb_interface_descriptor *interface;
const guint8 *ptr = NULL;
interface = &config->interface[j].altsetting[k];
if (interface->bInterfaceClass != LIBUSB_CLASS_VIDEO ||
interface->bInterfaceSubClass != USB_VIDEO_CONTROL)
continue;
ptr = interface->extra;
while (ptr - interface->extra +
sizeof (xu_descriptor) < interface->extra_length) {
xu_descriptor *desc = (xu_descriptor *) ptr;
GST_DEBUG_OBJECT (self, "Found VideoControl interface with "
"unit id %d : %" GUID_FORMAT, desc->bUnitID,
GUID_ARGS (desc->guidExtensionCode));
if (desc->bDescriptorType == USB_VIDEO_CONTROL_INTERFACE &&
desc->bDescriptorSubType == USB_VIDEO_CONTROL_XU_TYPE &&
memcmp (desc->guidExtensionCode, guid, 16) == 0) {
guint8 unit_id = desc->bUnitID;
GST_DEBUG_OBJECT (self, "Found H264 XU unit : %d", unit_id);
libusb_free_config_descriptor (config);
libusb_unref_device (device);
return unit_id;
}
ptr += desc->bLength;
}
}
}
libusb_free_config_descriptor (config);
}
}
}
libusb_unref_device (device);
}
return 0;
}

View file

@ -33,6 +33,25 @@
#include <glib.h>
#include <glib-object.h>
#include <gst/video/video.h>
#include <linux/uvcvideo.h>
#include <linux/usb/video.h>
#include <sys/ioctl.h>
#include <string.h>
#include <gudev/gudev.h>
#include <libusb.h>
#include <gst/gst.h>
#include <libusb.h>
#define USB_VIDEO_CONTROL 1
#define USB_VIDEO_CONTROL_INTERFACE 0x24
#define USB_VIDEO_CONTROL_XU_TYPE 0x06
#ifndef LIBUSB_CLASS_VIDEO
#define LIBUSB_CLASS_VIDEO 0x0e
#endif
/* bmHints defines */
#define UVC_H264_BMHINTS_RESOLUTION (0x0001)
@ -323,6 +342,23 @@ typedef struct _uvcx_qp_steps_layers_t
guint8 bMaxQp;
} __attribute__((packed)) uvcx_qp_steps_layers_t;
typedef struct
{
int8_t bLength;
int8_t bDescriptorType;
int8_t bDescriptorSubType;
int8_t bUnitID;
uint8_t guidExtensionCode[16];
} __attribute__ ((__packed__)) xu_descriptor;
#define GUID_FORMAT "02X%02X%02X%02X-%02X%02X%02X%02X-"\
"%02X%02X%02X%02X-%02X%02X%02X%02X"
#define GUID_ARGS(guid) guid[0], guid[1], guid[2], guid[3], \
guid[4], guid[5], guid[6], guid[7], \
guid[8], guid[9], guid[10], guid[11], \
guid[12], guid[13], guid[14], guid[15]
guint8 xu_get_id (GstObject *self, const gchar *devname, libusb_context **usb_ctx);
#ifdef _WIN32
// GUID of the UVC H.264 extension unit: {A29E7641-DE04-47E3-8B2B-F4341AFF003B}