diff --git a/uvcSupport/libuvc/device.c b/uvcSupport/libuvc/device.c
index 3d49b68..ad446b2 100644
--- a/uvcSupport/libuvc/device.c
+++ b/uvcSupport/libuvc/device.c
@@ -42,10 +42,10 @@
int uvc_already_open(uvc_context_t *ctx, struct libusb_device *usb_dev);
void uvc_free_devh(uvc_device_handle_t *devh);
-uvc_error_t uvc_get_device_info(uvc_device_t *dev, uvc_device_info_t **info);
+uvc_error_t uvc_get_device_info(uvc_device_handle_t *devh, uvc_device_info_t **info);
void uvc_free_device_info(uvc_device_info_t *info);
-uvc_error_t uvc_scan_control(uvc_device_t *dev, uvc_device_info_t *info);
+uvc_error_t uvc_scan_control(uvc_device_handle_t *devh, uvc_device_info_t *info);
uvc_error_t uvc_parse_vc(uvc_device_t *dev,
uvc_device_info_t *info,
const unsigned char *block, size_t block_size);
@@ -263,6 +263,49 @@ uint8_t uvc_get_device_address(uvc_device_t *dev) {
return libusb_get_device_address(dev->usb_dev);
}
+static uvc_error_t uvc_open_internal(uvc_device_t *dev, struct libusb_device_handle *usb_devh, uvc_device_handle_t **devh);
+
+#if LIBUSB_API_VERSION >= 0x01000107
+/** @brief Wrap a platform-specific system device handle and obtain a UVC device handle.
+ * The handle allows you to use libusb to perform I/O on the device in question.
+ *
+ * On Linux, the system device handle must be a valid file descriptor opened on the device node.
+ *
+ * The system device handle must remain open until uvc_close() is called. The system device handle will not be closed by uvc_close().
+ * @ingroup device
+ *
+ * @param sys_dev the platform-specific system device handle
+ * @param context UVC context to prepare the device
+ * @param[out] devh Handle on opened device
+ * @return Error opening device or SUCCESS
+ */
+uvc_error_t uvc_wrap(
+ int sys_dev,
+ uvc_context_t *context,
+ uvc_device_handle_t **devh) {
+ uvc_error_t ret;
+ struct libusb_device_handle *usb_devh;
+
+ UVC_ENTER();
+
+ uvc_device_t *dev = NULL;
+ int err = libusb_wrap_sys_device(context->usb_ctx, sys_dev, &usb_devh);
+ UVC_DEBUG("libusb_wrap_sys_device() = %d", err);
+ if (err != LIBUSB_SUCCESS) {
+ UVC_EXIT(err);
+ return err;
+ }
+
+ dev = calloc(1, sizeof(uvc_device_t));
+ dev->ctx = context;
+ dev->usb_dev = libusb_get_device(usb_devh);
+
+ ret = uvc_open_internal(dev, usb_devh, devh);
+ UVC_EXIT(ret);
+ return ret;
+}
+#endif
+
/** @brief Open a UVC device
* @ingroup device
*
@@ -275,8 +318,6 @@ uvc_error_t uvc_open(
uvc_device_handle_t **devh) {
uvc_error_t ret;
struct libusb_device_handle *usb_devh;
- uvc_device_handle_t *internal_devh;
- struct libusb_device_descriptor desc;
UVC_ENTER();
@@ -288,13 +329,28 @@ uvc_error_t uvc_open(
return ret;
}
+ ret = uvc_open_internal(dev, usb_devh, devh);
+ UVC_EXIT(ret);
+ return ret;
+}
+
+static uvc_error_t uvc_open_internal(
+ uvc_device_t *dev,
+ struct libusb_device_handle *usb_devh,
+ uvc_device_handle_t **devh) {
+ uvc_error_t ret;
+ uvc_device_handle_t *internal_devh;
+ struct libusb_device_descriptor desc;
+
+ UVC_ENTER();
+
uvc_ref_device(dev);
internal_devh = calloc(1, sizeof(*internal_devh));
internal_devh->dev = dev;
internal_devh->usb_devh = usb_devh;
- ret = uvc_get_device_info(dev, &(internal_devh->info));
+ ret = uvc_get_device_info(internal_devh, &(internal_devh->info));
if (ret != UVC_SUCCESS)
goto fail;
@@ -366,7 +422,7 @@ uvc_error_t uvc_open(
* @param dev Device to parse descriptor for
* @param info Where to store a pointer to the new info struct
*/
-uvc_error_t uvc_get_device_info(uvc_device_t *dev,
+uvc_error_t uvc_get_device_info(uvc_device_handle_t *devh,
uvc_device_info_t **info) {
uvc_error_t ret;
uvc_device_info_t *internal_info;
@@ -379,7 +435,7 @@ uvc_error_t uvc_get_device_info(uvc_device_t *dev,
return UVC_ERROR_NO_MEM;
}
- if (libusb_get_config_descriptor(dev->usb_dev,
+ if (libusb_get_config_descriptor(devh->dev->usb_dev,
0,
&(internal_info->config)) != 0) {
free(internal_info);
@@ -387,7 +443,7 @@ uvc_error_t uvc_get_device_info(uvc_device_t *dev,
return UVC_ERROR_IO;
}
- ret = uvc_scan_control(dev, internal_info);
+ ret = uvc_scan_control(devh, internal_info);
if (ret != UVC_SUCCESS) {
uvc_free_device_info(internal_info);
UVC_EXIT(ret);
@@ -474,6 +530,53 @@ void uvc_free_device_info(uvc_device_info_t *info) {
UVC_EXIT_VOID();
}
+static uvc_error_t get_device_descriptor(
+ uvc_device_handle_t *devh,
+ uvc_device_descriptor_t **desc) {
+ uvc_device_descriptor_t *desc_internal;
+ struct libusb_device_descriptor usb_desc;
+ struct libusb_device_handle *usb_devh = devh->usb_devh;
+ uvc_error_t ret;
+
+ UVC_ENTER();
+
+ ret = libusb_get_device_descriptor(devh->dev->usb_dev, &usb_desc);
+
+ if (ret != UVC_SUCCESS) {
+ UVC_EXIT(ret);
+ return ret;
+ }
+
+ desc_internal = calloc(1, sizeof(*desc_internal));
+ desc_internal->idVendor = usb_desc.idVendor;
+ desc_internal->idProduct = usb_desc.idProduct;
+
+ unsigned char buf[64];
+
+ int bytes = libusb_get_string_descriptor_ascii(
+ usb_devh, usb_desc.iSerialNumber, buf, sizeof(buf));
+
+ if (bytes > 0)
+ desc_internal->serialNumber = strdup((const char*) buf);
+
+ bytes = libusb_get_string_descriptor_ascii(
+ usb_devh, usb_desc.iManufacturer, buf, sizeof(buf));
+
+ if (bytes > 0)
+ desc_internal->manufacturer = strdup((const char*) buf);
+
+ bytes = libusb_get_string_descriptor_ascii(
+ usb_devh, usb_desc.iProduct, buf, sizeof(buf));
+
+ if (bytes > 0)
+ desc_internal->product = strdup((const char*) buf);
+
+ *desc = desc_internal;
+
+ UVC_EXIT(ret);
+ return ret;
+}
+
/**
* @brief Get a descriptor that contains the general information about
* a device
@@ -943,7 +1046,7 @@ uvc_error_t uvc_release_if(uvc_device_handle_t *devh, int idx) {
* Find a device's VideoControl interface and process its descriptor
* @ingroup device
*/
-uvc_error_t uvc_scan_control(uvc_device_t *dev, uvc_device_info_t *info) {
+uvc_error_t uvc_scan_control(uvc_device_handle_t *devh, uvc_device_info_t *info) {
const struct libusb_interface_descriptor *if_desc;
uvc_error_t parse_ret, ret;
int interface_idx;
@@ -957,12 +1060,13 @@ uvc_error_t uvc_scan_control(uvc_device_t *dev, uvc_device_info_t *info) {
uvc_device_descriptor_t* dev_desc;
int haveTISCamera = 0;
- uvc_get_device_descriptor ( dev, &dev_desc );
- if ( 0x199e == dev_desc->idVendor && ( 0x8101 == dev_desc->idProduct ||
- 0x8102 == dev_desc->idProduct )) {
- haveTISCamera = 1;
+ if ( get_device_descriptor ( devh, &dev_desc ) == UVC_SUCCESS ) {
+ if ( 0x199e == dev_desc->idVendor && ( 0x8101 == dev_desc->idProduct ||
+ 0x8102 == dev_desc->idProduct )) {
+ haveTISCamera = 1;
+ }
+ uvc_free_device_descriptor ( dev_desc );
}
- uvc_free_device_descriptor ( dev_desc );
for (interface_idx = 0; interface_idx < info->config->bNumInterfaces; ++interface_idx) {
if_desc = &info->config->interface[interface_idx].altsetting[0];
@@ -991,7 +1095,7 @@ uvc_error_t uvc_scan_control(uvc_device_t *dev, uvc_device_info_t *info) {
while (buffer_left >= 3) { // parseX needs to see buf[0,2] = length,type
block_size = buffer[0];
- parse_ret = uvc_parse_vc(dev, info, buffer, block_size);
+ parse_ret = uvc_parse_vc(devh->dev, info, buffer, block_size);
if (parse_ret != UVC_SUCCESS) {
ret = parse_ret;
@@ -1029,8 +1133,10 @@ uvc_error_t uvc_parse_vc_header(uvc_device_t *dev,
switch (info->ctrl_if.bcdUVC) {
case 0x0100:
info->ctrl_if.dwClockFrequency = DW_TO_INT(block + 7);
+ break;
case 0x010a:
info->ctrl_if.dwClockFrequency = DW_TO_INT(block + 7);
+ break;
case 0x0110:
break;
default:
diff --git a/uvcSupport/libuvc/frame-mjpeg.c b/uvcSupport/libuvc/frame-mjpeg.c
index 8d7c545..71cd108 100644
--- a/uvcSupport/libuvc/frame-mjpeg.c
+++ b/uvcSupport/libuvc/frame-mjpeg.c
@@ -122,32 +122,10 @@ static void insert_huff_tables(j_decompress_ptr dinfo) {
COPY_HUFF_TABLE(dinfo, ac_huff_tbl_ptrs[1], ac_chromi);
}
-/** @brief Convert an MJPEG frame to RGB
- * @ingroup frame
- *
- * @param in MJPEG frame
- * @param out RGB frame
- */
-uvc_error_t uvc_mjpeg2rgb(uvc_frame_t *in, uvc_frame_t *out) {
+static uvc_error_t uvc_mjpeg_convert(uvc_frame_t *in, uvc_frame_t *out) {
struct jpeg_decompress_struct dinfo;
struct error_mgr jerr;
size_t lines_read;
-
- if (in->frame_format != UVC_FRAME_FORMAT_MJPEG)
- return UVC_ERROR_INVALID_PARAM;
-
- if (uvc_ensure_frame_size(out, in->width * in->height * 3) < 0)
- return UVC_ERROR_NO_MEM;
-
- out->width = in->width;
- out->height = in->height;
- out->frame_format = UVC_FRAME_FORMAT_RGB;
- out->step = in->width * 3;
- out->sequence = in->sequence;
- out->capture_time = in->capture_time;
- out->capture_time_finished = in->capture_time_finished;
- out->source = in->source;
-
dinfo.err = jpeg_std_error(&jerr.super);
jerr.super.error_exit = _error_exit;
@@ -164,7 +142,13 @@ uvc_error_t uvc_mjpeg2rgb(uvc_frame_t *in, uvc_frame_t *out) {
insert_huff_tables(&dinfo);
}
- dinfo.out_color_space = JCS_RGB;
+ if (out->frame_format == UVC_FRAME_FORMAT_RGB)
+ dinfo.out_color_space = JCS_RGB;
+ else if (out->frame_format == UVC_FRAME_FORMAT_GRAY8)
+ dinfo.out_color_space = JCS_GRAYSCALE;
+ else
+ goto fail;
+
dinfo.dct_method = JDCT_IFAST;
jpeg_start_decompress(&dinfo);
@@ -186,3 +170,53 @@ uvc_error_t uvc_mjpeg2rgb(uvc_frame_t *in, uvc_frame_t *out) {
jpeg_destroy_decompress(&dinfo);
return UVC_ERROR_OTHER;
}
+
+/** @brief Convert an MJPEG frame to RGB
+ * @ingroup frame
+ *
+ * @param in MJPEG frame
+ * @param out RGB frame
+ */
+uvc_error_t uvc_mjpeg2rgb(uvc_frame_t *in, uvc_frame_t *out) {
+ if (in->frame_format != UVC_FRAME_FORMAT_MJPEG)
+ return UVC_ERROR_INVALID_PARAM;
+
+ if (uvc_ensure_frame_size(out, in->width * in->height * 3) < 0)
+ return UVC_ERROR_NO_MEM;
+
+ out->width = in->width;
+ out->height = in->height;
+ out->frame_format = UVC_FRAME_FORMAT_RGB;
+ out->step = in->width * 3;
+ out->sequence = in->sequence;
+ out->capture_time = in->capture_time;
+ out->capture_time_finished = in->capture_time_finished;
+ out->source = in->source;
+
+ return uvc_mjpeg_convert(in, out);
+}
+
+/** @brief Convert an MJPEG frame to GRAY8
+ * @ingroup frame
+ *
+ * @param in MJPEG frame
+ * @param out GRAY8 frame
+ */
+uvc_error_t uvc_mjpeg2gray(uvc_frame_t *in, uvc_frame_t *out) {
+ if (in->frame_format != UVC_FRAME_FORMAT_MJPEG)
+ return UVC_ERROR_INVALID_PARAM;
+
+ if (uvc_ensure_frame_size(out, in->width * in->height) < 0)
+ return UVC_ERROR_NO_MEM;
+
+ out->width = in->width;
+ out->height = in->height;
+ out->frame_format = UVC_FRAME_FORMAT_GRAY8;
+ out->step = in->width;
+ out->sequence = in->sequence;
+ out->capture_time = in->capture_time;
+ out->capture_time_finished = in->capture_time_finished;
+ out->source = in->source;
+
+ return uvc_mjpeg_convert(in, out);
+}
diff --git a/uvcSupport/libuvc/frame.c b/uvcSupport/libuvc/frame.c
index 4eb42ac..1d1dd41 100644
--- a/uvcSupport/libuvc/frame.c
+++ b/uvcSupport/libuvc/frame.c
@@ -440,6 +440,10 @@ uvc_error_t uvc_uyvy2bgr(uvc_frame_t *in, uvc_frame_t *out) {
*/
uvc_error_t uvc_any2rgb(uvc_frame_t *in, uvc_frame_t *out) {
switch (in->frame_format) {
+#ifdef LIBUVC_HAS_JPEG
+ case UVC_FRAME_FORMAT_MJPEG:
+ return uvc_mjpeg2rgb(in, out);
+#endif
case UVC_FRAME_FORMAT_YUYV:
return uvc_yuyv2rgb(in, out);
case UVC_FRAME_FORMAT_UYVY:
diff --git a/uvcSupport/libuvc/init.c b/uvcSupport/libuvc/init.c
index 041fe58..4802835 100644
--- a/uvcSupport/libuvc/init.c
+++ b/uvcSupport/libuvc/init.c
@@ -51,11 +51,11 @@ for USB Video Class (UVC) devices, such as consumer webcams.
\li Support for "extended" (vendor-defined) settings
\section misc Misc.
-\p The source code can be found at https://github.com/ktossell/libuvc. To build
-the library, install libusb 1.0+ and run:
+\p The source code can be found at https://github.com/libuvc/libuvc/. To build
+the library, install libusb 1.0+ and run:
\code
-$ git clone https://github.com/ktossell/libuvc.git
+$ git clone https://github.com/libuvc/libuvc.git
$ cd libuvc
$ mkdir build
$ cd build
diff --git a/uvcSupport/libuvc/libuvc/libuvc.h b/uvcSupport/libuvc/libuvc/libuvc.h
index a64ed3b..d387150 100644
--- a/uvcSupport/libuvc/libuvc/libuvc.h
+++ b/uvcSupport/libuvc/libuvc/libuvc.h
@@ -72,6 +72,7 @@ enum uvc_frame_format {
UVC_FRAME_FORMAT_BGR,
/** Motion-JPEG (or JPEG) encoded images */
UVC_FRAME_FORMAT_MJPEG,
+ UVC_FRAME_FORMAT_H264,
/** Greyscale images */
UVC_FRAME_FORMAT_GRAY8,
UVC_FRAME_FORMAT_GRAY16,
@@ -84,6 +85,8 @@ enum uvc_frame_format {
UVC_FRAME_FORMAT_SBGGR8,
/** YUV420: NV12 */
UVC_FRAME_FORMAT_NV12,
+ /** YUV: P010 */
+ UVC_FRAME_FORMAT_P010,
/** Number of formats understood */
UVC_FRAME_FORMAT_COUNT,
};
@@ -553,6 +556,13 @@ uvc_error_t uvc_find_devices(
uvc_device_t ***devs,
int vid, int pid, const char *sn);
+#if LIBUSB_API_VERSION >= 0x01000107
+uvc_error_t uvc_wrap(
+ int sys_dev,
+ uvc_context_t *context,
+ uvc_device_handle_t **devh);
+#endif
+
uvc_error_t uvc_open(
uvc_device_t *dev,
uvc_device_handle_t **devh);
@@ -791,6 +801,7 @@ uvc_error_t uvc_yuyv2uv(uvc_frame_t *in, uvc_frame_t *out);
#ifdef LIBUVC_HAS_JPEG
uvc_error_t uvc_mjpeg2rgb(uvc_frame_t *in, uvc_frame_t *out);
+uvc_error_t uvc_mjpeg2gray(uvc_frame_t *in, uvc_frame_t *out);
#endif
#ifdef __cplusplus
diff --git a/uvcSupport/libuvc/libuvc/libuvc_config.h b/uvcSupport/libuvc/libuvc/libuvc_config.h
index 5fb212a..45ac230 100644
--- a/uvcSupport/libuvc/libuvc/libuvc_config.h
+++ b/uvcSupport/libuvc/libuvc/libuvc_config.h
@@ -3,8 +3,8 @@
#define LIBUVC_VERSION_MAJOR 0
#define LIBUVC_VERSION_MINOR 0
-#define LIBUVC_VERSION_PATCH 6
-#define LIBUVC_VERSION_STR "0.0.6"
+#define LIBUVC_VERSION_PATCH 7
+#define LIBUVC_VERSION_STR "0.0.7"
#define LIBUVC_VERSION_INT \
((@libuvc_VERSION_MAJOR@ << 16) | \
(@libuvc_VERSION_MINOR@ << 8) | \
diff --git a/uvcSupport/libuvc/libuvc/libuvc_internal.h b/uvcSupport/libuvc/libuvc/libuvc_internal.h
index d26ccdb..0d1c22d 100644
--- a/uvcSupport/libuvc/libuvc/libuvc_internal.h
+++ b/uvcSupport/libuvc/libuvc/libuvc_internal.h
@@ -50,10 +50,18 @@
#ifdef UVC_DEBUGGING
#include
+#ifdef __ANDROID__
+#include
+#define UVC_DEBUG(format, ...) __android_log_print(ANDROID_LOG_DEBUG, "libuvc", "[%s:%d/%s] " format "\n", basename(__FILE__), __LINE__, __FUNCTION__, ##__VA_ARGS__)
+#define UVC_ENTER() __android_log_print(ANDROID_LOG_DEBUG, "libuvc", "[%s:%d] begin %s\n", basename(__FILE__), __LINE__, __FUNCTION__)
+#define UVC_EXIT(code) __android_log_print(ANDROID_LOG_DEBUG, "libuvc", "[%s:%d] end %s (%d)\n", basename(__FILE__), __LINE__, __FUNCTION__, code)
+#define UVC_EXIT_VOID() __android_log_print(ANDROID_LOG_DEBUG, "libuvc", "[%s:%d] end %s\n", basename(__FILE__), __LINE__, __FUNCTION__)
+#else
#define UVC_DEBUG(format, ...) fprintf(stderr, "[%s:%d/%s] " format "\n", basename(__FILE__), __LINE__, __FUNCTION__, ##__VA_ARGS__)
#define UVC_ENTER() fprintf(stderr, "[%s:%d] begin %s\n", basename(__FILE__), __LINE__, __FUNCTION__)
#define UVC_EXIT(code) fprintf(stderr, "[%s:%d] end %s (%d)\n", basename(__FILE__), __LINE__, __FUNCTION__, code)
#define UVC_EXIT_VOID() fprintf(stderr, "[%s:%d] end %s\n", basename(__FILE__), __LINE__, __FUNCTION__)
+#endif
#else
#define UVC_DEBUG(format, ...)
#define UVC_ENTER()
@@ -212,12 +220,17 @@ typedef struct uvc_device_info {
avoids problems with scheduling delays on slow boards causing missed
transfers. A better approach may be to make the transfer thread FIFO
scheduled (if we have root).
- We could/should change this to allow reduce it to, say, 5 by default
- and then allow the user to change the number of buffers as required.
+ Default number of transfer buffers can be overwritten by defining
+ this macro.
*/
+#ifndef LIBUVC_NUM_TRANSFER_BUFS
+#if defined(__APPLE__) && defined(__MACH__)
+#define LIBUVC_NUM_TRANSFER_BUFS 20
+#else
#define LIBUVC_NUM_TRANSFER_BUFS 100
+#endif
+#endif
-#define LIBUVC_XFER_BUF_SIZE ( 16 * 1024 * 1024 )
#define LIBUVC_XFER_META_BUF_SIZE ( 4 * 1024 )
struct uvc_stream_handle {
diff --git a/uvcSupport/libuvc/stream.c b/uvcSupport/libuvc/stream.c
index c409fba..89dac69 100644
--- a/uvcSupport/libuvc/stream.c
+++ b/uvcSupport/libuvc/stream.c
@@ -103,9 +103,10 @@ struct format_table_entry *_get_format_entry(enum uvc_frame_format format) {
ABS_FMT(UVC_FRAME_FORMAT_ANY, 2,
{UVC_FRAME_FORMAT_UNCOMPRESSED, UVC_FRAME_FORMAT_COMPRESSED})
- ABS_FMT(UVC_FRAME_FORMAT_UNCOMPRESSED, 5,
+ ABS_FMT(UVC_FRAME_FORMAT_UNCOMPRESSED, 8,
{UVC_FRAME_FORMAT_YUYV, UVC_FRAME_FORMAT_UYVY, UVC_FRAME_FORMAT_GRAY8,
- UVC_FRAME_FORMAT_GRAY16, UVC_FRAME_FORMAT_NV12})
+ UVC_FRAME_FORMAT_GRAY16, UVC_FRAME_FORMAT_NV12, UVC_FRAME_FORMAT_P010,
+ UVC_FRAME_FORMAT_BGR, UVC_FRAME_FORMAT_RGB})
FMT(UVC_FRAME_FORMAT_YUYV,
{'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
FMT(UVC_FRAME_FORMAT_UYVY,
@@ -116,6 +117,12 @@ struct format_table_entry *_get_format_entry(enum uvc_frame_format format) {
{'Y', '1', '6', ' ', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
FMT(UVC_FRAME_FORMAT_NV12,
{'N', 'V', '1', '2', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
+ FMT(UVC_FRAME_FORMAT_P010,
+ {'P', '0', '1', '0', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
+ FMT(UVC_FRAME_FORMAT_BGR,
+ {0x7d, 0xeb, 0x36, 0xe4, 0x4f, 0x52, 0xce, 0x11, 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70})
+ FMT(UVC_FRAME_FORMAT_RGB,
+ {0x7e, 0xeb, 0x36, 0xe4, 0x4f, 0x52, 0xce, 0x11, 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70})
FMT(UVC_FRAME_FORMAT_BY8,
{'B', 'Y', '8', ' ', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
FMT(UVC_FRAME_FORMAT_BA81,
@@ -128,10 +135,12 @@ struct format_table_entry *_get_format_entry(enum uvc_frame_format format) {
{'R', 'G', 'G', 'B', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
FMT(UVC_FRAME_FORMAT_SBGGR8,
{'B', 'G', 'G', 'R', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
- ABS_FMT(UVC_FRAME_FORMAT_COMPRESSED, 1,
- {UVC_FRAME_FORMAT_MJPEG})
+ ABS_FMT(UVC_FRAME_FORMAT_COMPRESSED, 2,
+ {UVC_FRAME_FORMAT_MJPEG, UVC_FRAME_FORMAT_H264})
FMT(UVC_FRAME_FORMAT_MJPEG,
{'M', 'J', 'P', 'G'})
+ FMT(UVC_FRAME_FORMAT_H264,
+ {'H', '2', '6', '4', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
default:
return NULL;
@@ -583,6 +592,14 @@ uvc_error_t uvc_get_still_ctrl_format_size(
return uvc_probe_still_ctrl(devh, still_ctrl);
}
+static int _uvc_stream_params_negotiated(
+ uvc_stream_ctrl_t *required,
+ uvc_stream_ctrl_t *actual) {
+ return required->bFormatIndex == actual->bFormatIndex &&
+ required->bFrameIndex == actual->bFrameIndex &&
+ required->dwMaxPayloadTransferSize >= actual->dwMaxPayloadTransferSize;
+}
+
/** @internal
* Negotiate streaming parameters with the device
*
@@ -592,16 +609,16 @@ uvc_error_t uvc_get_still_ctrl_format_size(
uvc_error_t uvc_probe_stream_ctrl(
uvc_device_handle_t *devh,
uvc_stream_ctrl_t *ctrl) {
-
- uvc_query_stream_ctrl(
- devh, ctrl, 1, UVC_SET_CUR
- );
+ uvc_stream_ctrl_t required_ctrl = *ctrl;
- uvc_query_stream_ctrl(
- devh, ctrl, 1, UVC_GET_CUR
- );
+ uvc_query_stream_ctrl( devh, ctrl, 1, UVC_SET_CUR );
+ uvc_query_stream_ctrl( devh, ctrl, 1, UVC_GET_CUR );
+
+ if(!_uvc_stream_params_negotiated(&required_ctrl, ctrl)) {
+ UVC_DEBUG("Unable to negotiate streaming format");
+ return UVC_ERROR_INVALID_MODE;
+ }
- /** @todo make sure that worked */
return UVC_SUCCESS;
}
@@ -755,19 +772,22 @@ void _uvc_process_payload(uvc_stream_handle_t *strmh, uint8_t *payload, size_t p
variable_offset += 6;
}
- if (header_len > variable_offset)
- {
+ if (header_len > variable_offset) {
// Metadata is attached to header
- memcpy(strmh->meta_outbuf + strmh->meta_got_bytes, payload + variable_offset, header_len - variable_offset);
- strmh->meta_got_bytes += header_len - variable_offset;
+ size_t meta_len = header_len - variable_offset;
+ if (strmh->meta_got_bytes + meta_len > LIBUVC_XFER_META_BUF_SIZE)
+ meta_len = LIBUVC_XFER_META_BUF_SIZE - strmh->meta_got_bytes; /* Avoid overflow. */
+ memcpy(strmh->meta_outbuf + strmh->meta_got_bytes, payload + variable_offset, meta_len);
+ strmh->meta_got_bytes += meta_len;
}
}
if (data_len > 0) {
+ if (strmh->got_bytes + data_len > strmh->cur_ctrl.dwMaxVideoFrameSize)
+ data_len = strmh->cur_ctrl.dwMaxVideoFrameSize - strmh->got_bytes; /* Avoid overflow. */
memcpy(strmh->outbuf + strmh->got_bytes, payload + header_len, data_len);
strmh->got_bytes += data_len;
-
- if (header_info & (1 << 1)) {
+ if (header_info & (1 << 1) || strmh->got_bytes == strmh->cur_ctrl.dwMaxVideoFrameSize) {
/* The EOF bit is set, so publish the complete frame */
_uvc_swap_buffers(strmh);
}
@@ -1020,9 +1040,9 @@ uvc_error_t uvc_stream_open_ctrl(uvc_device_handle_t *devh, uvc_stream_handle_t
// Set up the streaming status and data space
strmh->running = 0;
- /** @todo take only what we need */
- strmh->outbuf = malloc( LIBUVC_XFER_BUF_SIZE );
- strmh->holdbuf = malloc( LIBUVC_XFER_BUF_SIZE );
+
+ strmh->outbuf = malloc( ctrl->dwMaxVideoFrameSize );
+ strmh->holdbuf = malloc( ctrl->dwMaxVideoFrameSize );
strmh->meta_outbuf = malloc( LIBUVC_XFER_META_BUF_SIZE );
strmh->meta_holdbuf = malloc( LIBUVC_XFER_META_BUF_SIZE );
@@ -1232,7 +1252,7 @@ uvc_error_t uvc_stream_start(
}
}
- if ( ret != UVC_SUCCESS && transfer_id > 0 ) {
+ if ( ret != UVC_SUCCESS && transfer_id >= 0 ) {
for ( ; transfer_id < LIBUVC_NUM_TRANSFER_BUFS; transfer_id++) {
free ( strmh->transfers[transfer_id]->buffer );
libusb_free_transfer ( strmh->transfers[transfer_id]);
@@ -1323,15 +1343,24 @@ void _uvc_populate_frame(uvc_stream_handle_t *strmh) {
frame->height = frame_desc->wHeight;
switch (frame->frame_format) {
+ case UVC_FRAME_FORMAT_BGR:
+ frame->step = frame->width * 3;
+ break;
case UVC_FRAME_FORMAT_YUYV:
frame->step = frame->width * 2;
break;
case UVC_FRAME_FORMAT_NV12:
frame->step = frame->width;
break;
+ case UVC_FRAME_FORMAT_P010:
+ frame->step = frame->width * 2;
+ break;
case UVC_FRAME_FORMAT_MJPEG:
frame->step = 0;
break;
+ case UVC_FRAME_FORMAT_H264:
+ frame->step = 0;
+ break;
default:
frame->step = 0;
break;
@@ -1371,7 +1400,6 @@ uvc_error_t uvc_stream_get_frame(uvc_stream_handle_t *strmh,
time_t add_secs;
time_t add_nsecs;
struct timespec ts;
- struct timeval tv;
if (!strmh->running)
return UVC_ERROR_INVALID_PARAM;
@@ -1397,6 +1425,7 @@ uvc_error_t uvc_stream_get_frame(uvc_stream_handle_t *strmh,
#if _POSIX_TIMERS > 0
clock_gettime(CLOCK_REALTIME, &ts);
#else
+ struct timeval tv;
gettimeofday(&tv, NULL);
ts.tv_sec = tv.tv_sec;
ts.tv_nsec = tv.tv_usec * 1000;
@@ -1415,13 +1444,10 @@ uvc_error_t uvc_stream_get_frame(uvc_stream_handle_t *strmh,
int err = pthread_cond_timedwait(&strmh->cb_cond, &strmh->cb_mutex, &ts);
//TODO: How should we handle EINVAL?
- switch(err){
- case EINVAL:
- *frame = NULL;
- return UVC_ERROR_OTHER;
- case ETIMEDOUT:
- *frame = NULL;
- return UVC_ERROR_TIMEOUT;
+ if (err) {
+ *frame = NULL;
+ pthread_mutex_unlock(&strmh->cb_mutex);
+ return err == ETIMEDOUT ? UVC_ERROR_TIMEOUT : UVC_ERROR_OTHER;
}
}
@@ -1473,15 +1499,12 @@ uvc_error_t uvc_stream_stop(uvc_stream_handle_t *strmh) {
pthread_mutex_lock(&strmh->cb_mutex);
+ /* Attempt to cancel any running transfers, we can't free them just yet because they aren't
+ * necessarily completed but they will be free'd in _uvc_stream_callback().
+ */
for(i=0; i < LIBUVC_NUM_TRANSFER_BUFS; i++) {
- if(strmh->transfers[i] != NULL) {
- int res = libusb_cancel_transfer(strmh->transfers[i]);
- if(res < 0 && res != LIBUSB_ERROR_NOT_FOUND ) {
- free(strmh->transfers[i]->buffer);
- libusb_free_transfer(strmh->transfers[i]);
- strmh->transfers[i] = NULL;
- }
- }
+ if(strmh->transfers[i] != NULL)
+ libusb_cancel_transfer(strmh->transfers[i]);
}
/* Wait for transfers to complete/cancel */