├── .gitignore ├── .travis.yml ├── .vscode └── settings.json ├── CMakeLists.txt ├── Config.cmake.in ├── INSTALL_WINDOWS.md ├── LICENSE.txt ├── README.md ├── cameras ├── isight_imac.txt ├── isight_macbook.txt ├── logitech_hd_pro_920.txt ├── ms_lifecam_show.txt ├── quickcampro9000.txt ├── quickcampro9000_builtin_ctrls.txt └── quickcampro9000_extra_ctrls.txt ├── changelog.txt ├── doxygen.conf ├── include ├── libuvc │ ├── libuvc.h │ └── libuvc_internal.h └── utlist.h ├── src ├── ctrl-gen.c ├── ctrl-gen.py ├── ctrl.c ├── device.c ├── diag.c ├── example.c ├── frame-mjpeg.c ├── frame.c ├── init.c ├── misc.c ├── stream.c ├── test.c ├── time_linux.h ├── time_mac.h └── time_windows.h ├── standard-units.yaml └── tests ├── CMakeLists.txt └── test-enumerating-devices.c /.gitignore: -------------------------------------------------------------------------------- 1 | # Build directory (recommended location) 2 | build/ 3 | # Created by https://www.toptal.com/developers/gitignore/api/VisualStudioCode,C 4 | # Edit at https://www.toptal.com/developers/gitignore?templates=VisualStudioCode,C 5 | 6 | ### C ### 7 | # Prerequisites 8 | *.d 9 | 10 | # Object files 11 | *.o 12 | *.ko 13 | *.obj 14 | *.elf 15 | 16 | # Linker output 17 | *.ilk 18 | *.map 19 | *.exp 20 | 21 | # Precompiled Headers 22 | *.gch 23 | *.pch 24 | 25 | # Libraries 26 | *.lib 27 | *.a 28 | *.la 29 | *.lo 30 | 31 | # Shared objects (inc. Windows DLLs) 32 | *.dll 33 | *.so 34 | *.so.* 35 | *.dylib 36 | 37 | # Executables 38 | *.exe 39 | *.out 40 | *.app 41 | *.i*86 42 | *.x86_64 43 | *.hex 44 | 45 | # Debug files 46 | *.dSYM/ 47 | *.su 48 | *.idb 49 | *.pdb 50 | 51 | # Kernel Module Compile Results 52 | *.mod* 53 | *.cmd 54 | .tmp_versions/ 55 | modules.order 56 | Module.symvers 57 | Mkfile.old 58 | dkms.conf 59 | 60 | ### VisualStudioCode ### 61 | .vscode/* 62 | !.vscode/settings.json 63 | !.vscode/tasks.json 64 | !.vscode/launch.json 65 | !.vscode/extensions.json 66 | !.vscode/*.code-snippets 67 | 68 | # Local History for Visual Studio Code 69 | .history/ 70 | 71 | # Built Visual Studio Code Extensions 72 | *.vsix 73 | 74 | ### VisualStudioCode Patch ### 75 | # Ignore all local history of files 76 | .history 77 | .ionide 78 | 79 | # Support for Project snippet scope 80 | .vscode/*.code-snippets 81 | 82 | # Ignore code-workspaces 83 | *.code-workspace 84 | 85 | # End of https://www.toptal.com/developers/gitignore/api/VisualStudioCode,C 86 | n -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: cpp 3 | compiler: 4 | - gcc 5 | - clang 6 | addons: 7 | apt: 8 | packages: 9 | - libusb-1.0-0-dev 10 | - libjpeg-dev 11 | before_script: 12 | - mkdir build 13 | - cd build 14 | - cmake .. 15 | script: 16 | - make 17 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cmake.configureOnOpen": true, 3 | "editor.formatOnSave": true 4 | } -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.23) 2 | cmake_policy(SET CMP0042 NEW) 3 | project(libuvc 4 | VERSION 0.1.0 5 | LANGUAGES C 6 | DESCRIPTION "A cross-platform library for USB video devices" 7 | HOMEPAGE_URL "https://github.com/pupil-labs/libuvc" 8 | ) 9 | cmake_policy(SET CMP0054 NEW) 10 | 11 | if(NOT CMAKE_BUILD_TYPE) 12 | message(STATUS "No build type selected, default to Release") 13 | set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE) 14 | endif() 15 | 16 | if(WIN32) 17 | set(LIBUSB_WIN_INCLUDE_DIR "NOTSET" CACHE PATH "Path to the libusb include dir") 18 | set(LIBUSB_WIN_IMPORT_LIB_PATH "NOTSET" CACHE FILEPATH "Path to the libusb import library") 19 | 20 | # FindThreads will not find pthread.h with MSVC so we use pthreads-win 21 | set(PTHREADS_WIN_INCLUDE_DIR "NOTSET" CACHE PATH "Path to the pthreads-win include dir") 22 | set(PTHREADS_WIN_IMPORT_LIB_PATH "NOTSET" CACHE FILEPATH "Path to the pthreads-win import library") 23 | 24 | list(APPEND required_variables 25 | PTHREADS_WIN_INCLUDE_DIR 26 | PTHREADS_WIN_IMPORT_LIB_PATH 27 | LIBUSB_WIN_INCLUDE_DIR 28 | LIBUSB_WIN_IMPORT_LIB_PATH 29 | ) 30 | message(STATUS "Validating config:") 31 | 32 | foreach(VAR IN LISTS required_variables) 33 | if(${VAR} STREQUAL "NOTSET") 34 | message(FATAL_ERROR "Required variable ${VAR} is not set!") 35 | endif() 36 | endforeach() 37 | 38 | foreach(VAR IN LISTS required_variables) 39 | message(STATUS " ${VAR}: ${${VAR}}") 40 | endforeach() 41 | 42 | # winmm is necessary for __imp_timeGetTime 43 | add_definitions("-D_TIMESPEC_DEFINED") 44 | else() 45 | find_package(PkgConfig) 46 | pkg_check_modules(LIBUSB REQUIRED libusb-1.0) 47 | message(STATUS " " ${LIBUSB_LIBRARY_DIRS}) 48 | SET(CMAKE_C_FLAGS_DEBUG "-g -DUVC_DEBUGGING") 49 | endif() 50 | 51 | include(GNUInstallDirs) 52 | 53 | # "Installation directory for CMake files") 54 | add_library(uvc SHARED) 55 | add_library(PLLibUVC::uvc ALIAS uvc) 56 | 57 | target_sources(uvc PUBLIC 58 | $ 59 | $ 60 | $ 61 | $ 62 | $ 63 | $ 64 | $ 65 | $ 66 | ) 67 | 68 | target_include_directories( 69 | uvc 70 | PUBLIC 71 | $ 72 | $ 73 | 74 | # Unix vars 75 | ${LIBUSB_INCLUDE_DIRS} 76 | ${PTHREAD_INCLUDE_DIRS} 77 | 78 | # Windows vars 79 | ${PTHREADS_WIN_INCLUDE_DIR} 80 | ${LIBUSB_WIN_INCLUDE_DIR} 81 | ) 82 | 83 | target_sources(uvc 84 | PUBLIC 85 | FILE_SET HEADERS 86 | BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include 87 | FILES 88 | ${CMAKE_CURRENT_SOURCE_DIR}/include/libuvc/libuvc.h 89 | ) 90 | 91 | target_link_directories( 92 | uvc 93 | PUBLIC 94 | ${LIBUSB_LIBRARY_DIRS} 95 | ${PTHREAD_LIBRARY_DIRS} 96 | ) 97 | 98 | set_target_properties( 99 | uvc PROPERTIES 100 | WINDOWS_EXPORT_ALL_SYMBOLS TRUE 101 | VERSION ${libuvc_VERSION} 102 | SOVERSION ${libuvc_VERSION} 103 | ) 104 | 105 | if(UNIX AND NOT APPLE) 106 | message(STATUS "Adding extra -pthread c flag") 107 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread") 108 | endif() 109 | 110 | target_link_libraries( 111 | uvc 112 | PUBLIC 113 | 114 | # Unix vars 115 | ${LIBUSB_LIBRARIES} 116 | ${PTHREAD_LIBRARIES} 117 | 118 | # Windows vars 119 | ${PTHREADS_WIN_IMPORT_LIB_PATH} 120 | ${LIBUSB_WIN_IMPORT_LIB_PATH} 121 | ) 122 | 123 | install(TARGETS uvc 124 | EXPORT libuvcTargets 125 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 126 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 127 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 128 | PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} 129 | FILE_SET HEADERS 130 | ) 131 | 132 | # export(PACKAGE libuvc) 133 | install(EXPORT libuvcTargets 134 | FILE libuvcTargets.cmake 135 | NAMESPACE PLLibUVC:: 136 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libuvc 137 | ) 138 | 139 | install(FILES 140 | ${CMAKE_CURRENT_BINARY_DIR}/libuvcConfig.cmake 141 | ${CMAKE_CURRENT_BINARY_DIR}/libuvcConfigVersion.cmake 142 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libuvc 143 | ) 144 | 145 | export(EXPORT libuvcTargets 146 | FILE ${CMAKE_CURRENT_BINARY_DIR}/libuvcTargets.cmake 147 | NAMESPACE PLLibUVC:: 148 | ) 149 | 150 | include(CMakePackageConfigHelpers) 151 | 152 | set(LIBRARY_DIRS ${CMAKE_INSTALL_LIBDIR}) 153 | 154 | # generate the config file that is includes the exports 155 | configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in 156 | "${CMAKE_CURRENT_BINARY_DIR}/libuvcConfig.cmake" 157 | INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libuvc 158 | PATH_VARS LIBRARY_DIRS 159 | ) 160 | 161 | write_basic_package_version_file( 162 | libuvcConfigVersion.cmake 163 | VERSION ${libuvc_VERSION} 164 | COMPATIBILITY SameMajorVersion 165 | ) 166 | 167 | enable_testing() 168 | add_subdirectory(tests) 169 | -------------------------------------------------------------------------------- /Config.cmake.in: -------------------------------------------------------------------------------- 1 | 2 | @PACKAGE_INIT@ 3 | include("${CMAKE_CURRENT_LIST_DIR}/libuvcTargets.cmake") 4 | set_and_check(libuvc_LIBRARY_DIRS "@PACKAGE_LIBRARY_DIRS@") 5 | check_required_components(libuvc) -------------------------------------------------------------------------------- /INSTALL_WINDOWS.md: -------------------------------------------------------------------------------- 1 | ## Prerequisites 2 | 3 | 4 | 1. [Libusb with isochronous support] (https://github.com/pupil-labs/libusb) 5 | 2. Cmake (https://cmake.org/files/v3.7/cmake-3.7.0-rc2-win64-x64.msi) 6 | 7 | ## Installation 8 | 9 | 1. Download and extract posix threads for Windows from http://kent.dl.sourceforge.net/project/pthreads4w/pthreads-w32-2-9-1-release.zip 10 | Add the dll\x64 directory to the system path 11 | 2. Run cmake. Set the top level libuvc directory as the source path. Set a 12 | directory of your choice as the binares location 13 | 3. Click configure. Select "Visual studio 14 2015 Win64" as code generator. Fill in the 14 | locations for LIBUSB (set include to /libusb and lib to /x64/Release/dll/libusb-1.0.lib ) 15 | and PTHREAD (include to /include, lib to 16 | /lib/x64/pthreadVC2.lib). LIBJPEG is optional. If you are using pyuvc, it provides decoding via turbojpeg. 17 | 4. Click configure again. Click generate. 18 | 5. Open \libuvc.sln Using Visual Studio. Make sure x64 platform is 19 | selected. Select Release configuration. Build the "ALL_BUILD" project 20 | 6. Add the \Release to system path 21 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Software License Agreement (BSD License) 2 | 3 | Copyright (C) 2010-2015 Ken Tossell 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions 8 | are met: 9 | 10 | * Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above 13 | copyright notice, this list of conditions and the following 14 | disclaimer in the documentation and/or other materials provided 15 | with the distribution. 16 | * Neither the name of the author nor other contributors may be 17 | used to endorse or promote products derived from this software 18 | without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 30 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 | POSSIBILITY OF SUCH DAMAGE. 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | `libuvc` is a cross-platform library for USB video devices, built atop `libusb`. 2 | It enables fine-grained control over USB video devices exporting the standard USB Video Class 3 | (UVC) interface, enabling developers to write drivers for previously unsupported devices, 4 | or just access UVC devices in a generic fashion. 5 | 6 | ## Getting and Building libuvc 7 | 8 | Prerequisites: You will need `libusb` and [CMake](http://www.cmake.org/) installed. 9 | 10 | To build, you can just run these shell commands: 11 | 12 | git clone https://github.com/pupil-labs/libuvc 13 | cd libuvc 14 | mkdir build 15 | cd build 16 | cmake .. 17 | make && sudo make install 18 | 19 | and you're set! If you want to change the build configuration, you can edit `CMakeCache.txt` 20 | in the build directory, or use a CMake GUI to make the desired changes. 21 | 22 | ## Developing with libuvc 23 | 24 | The documentation for `libuvc` can currently be found at https://int80k.com/libuvc/doc/. 25 | 26 | Happy hacking! 27 | -------------------------------------------------------------------------------- /cameras/isight_imac.txt: -------------------------------------------------------------------------------- 1 | 2 | Bus 001 Device 007: ID 05ac:8501 Apple, Inc. Built-in iSight [Micron] 3 | Device Descriptor: 4 | bLength 18 5 | bDescriptorType 1 6 | bcdUSB 2.00 7 | bDeviceClass 239 Miscellaneous Device 8 | bDeviceSubClass 2 ? 9 | bDeviceProtocol 1 Interface Association 10 | bMaxPacketSize0 64 11 | idVendor 0x05ac Apple, Inc. 12 | idProduct 0x8501 Built-in iSight [Micron] 13 | bcdDevice 1.89 14 | iManufacturer 1 Micron 15 | iProduct 2 Built-in iSight 16 | iSerial 0 17 | bNumConfigurations 1 18 | Configuration Descriptor: 19 | bLength 9 20 | bDescriptorType 2 21 | wTotalLength 267 22 | bNumInterfaces 2 23 | bConfigurationValue 1 24 | iConfiguration 0 25 | bmAttributes 0x80 26 | (Bus Powered) 27 | MaxPower 100mA 28 | Interface Association: 29 | bLength 8 30 | bDescriptorType 11 31 | bFirstInterface 0 32 | bInterfaceCount 2 33 | bFunctionClass 14 Video 34 | bFunctionSubClass 3 Video Interface Collection 35 | bFunctionProtocol 0 36 | iFunction 0 37 | Interface Descriptor: 38 | bLength 9 39 | bDescriptorType 4 40 | bInterfaceNumber 0 41 | bAlternateSetting 0 42 | bNumEndpoints 1 43 | bInterfaceClass 14 Video 44 | bInterfaceSubClass 1 Video Control 45 | bInterfaceProtocol 0 46 | iInterface 0 47 | VideoControl Interface Descriptor: 48 | bLength 13 49 | bDescriptorType 36 50 | bDescriptorSubtype 1 (HEADER) 51 | bcdUVC 1.00 52 | wTotalLength 49 53 | dwClockFrequency 13.500000MHz 54 | bInCollection 1 55 | baInterfaceNr( 0) 1 56 | VideoControl Interface Descriptor: 57 | bLength 16 58 | bDescriptorType 36 59 | bDescriptorSubtype 2 (INPUT_TERMINAL) 60 | bTerminalID 1 61 | wTerminalType 0x0201 Camera Sensor 62 | bAssocTerminal 0 63 | iTerminal 0 64 | wObjectiveFocalLengthMin 0 65 | wObjectiveFocalLengthMax 0 66 | wOcularFocalLength 0 67 | bControlSize 1 68 | bmControls 0x00000000 69 | VideoControl Interface Descriptor: 70 | bLength 11 71 | bDescriptorType 36 72 | bDescriptorSubtype 5 (PROCESSING_UNIT) 73 | Warning: Descriptor too short 74 | bUnitID 2 75 | bSourceID 1 76 | wMaxMultiplier 0 77 | bControlSize 2 78 | bmControls 0x00000039 79 | Brightness 80 | Saturation 81 | Sharpness 82 | Gamma 83 | iProcessing 0 84 | bmVideoStandards 0x 9 85 | None 86 | SECAM - 625/50 87 | VideoControl Interface Descriptor: 88 | bLength 9 89 | bDescriptorType 36 90 | bDescriptorSubtype 3 (OUTPUT_TERMINAL) 91 | bTerminalID 3 92 | wTerminalType 0x0101 USB Streaming 93 | bAssocTerminal 0 94 | bSourceID 2 95 | iTerminal 0 96 | Endpoint Descriptor: 97 | bLength 7 98 | bDescriptorType 5 99 | bEndpointAddress 0x81 EP 1 IN 100 | bmAttributes 3 101 | Transfer Type Interrupt 102 | Synch Type None 103 | Usage Type Data 104 | wMaxPacketSize 0x0008 1x 8 bytes 105 | bInterval 10 106 | Interface Descriptor: 107 | bLength 9 108 | bDescriptorType 4 109 | bInterfaceNumber 1 110 | bAlternateSetting 0 111 | bNumEndpoints 0 112 | bInterfaceClass 14 Video 113 | bInterfaceSubClass 2 Video Streaming 114 | bInterfaceProtocol 0 115 | iInterface 0 116 | VideoStreaming Interface Descriptor: 117 | bLength 14 118 | bDescriptorType 36 119 | bDescriptorSubtype 1 (INPUT_HEADER) 120 | bNumFormats 1 121 | wTotalLength 155 122 | bEndPointAddress 130 123 | bmInfo 0 124 | bTerminalLink 3 125 | bStillCaptureMethod 0 126 | bTriggerSupport 0 127 | bTriggerUsage 0 128 | bControlSize 1 129 | bmaControls( 0) 27 130 | VideoStreaming Interface Descriptor: 131 | bLength 27 132 | bDescriptorType 36 133 | bDescriptorSubtype 4 (FORMAT_UNCOMPRESSED) 134 | bFormatIndex 1 135 | bNumFrameDescriptors 3 136 | guidFormat {55595659-0000-1000-8000-00aa00389b71} 137 | bBitsPerPixel 16 138 | bDefaultFrameIndex 1 139 | bAspectRatioX 0 140 | bAspectRatioY 0 141 | bmInterlaceFlags 0x00 142 | Interlaced stream or variable: No 143 | Fields per frame: 1 fields 144 | Field 1 first: No 145 | Field pattern: Field 1 only 146 | bCopyProtect 0 147 | VideoStreaming Interface Descriptor: 148 | bLength 38 149 | bDescriptorType 36 150 | bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) 151 | bFrameIndex 1 152 | bmCapabilities 0x00 153 | Still image unsupported 154 | wWidth 640 155 | wHeight 480 156 | dwMinBitRate 383976960 157 | dwMaxBitRate 383976960 158 | dwMaxVideoFrameBufferSize 614400 159 | dwDefaultFrameInterval 333333 160 | bFrameIntervalType 0 161 | dwMinFrameInterval 333333 162 | dwMaxFrameInterval 333333 163 | dwFrameIntervalStep 0 164 | VideoStreaming Interface Descriptor: 165 | bLength 38 166 | bDescriptorType 36 167 | bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) 168 | bFrameIndex 2 169 | bmCapabilities 0x00 170 | Still image unsupported 171 | wWidth 352 172 | wHeight 288 173 | dwMinBitRate 383976960 174 | dwMaxBitRate 383976960 175 | dwMaxVideoFrameBufferSize 202752 176 | dwDefaultFrameInterval 333333 177 | bFrameIntervalType 0 178 | dwMinFrameInterval 333333 179 | dwMaxFrameInterval 333333 180 | dwFrameIntervalStep 0 181 | VideoStreaming Interface Descriptor: 182 | bLength 38 183 | bDescriptorType 36 184 | bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) 185 | bFrameIndex 3 186 | bmCapabilities 0x00 187 | Still image unsupported 188 | wWidth 320 189 | wHeight 240 190 | dwMinBitRate 383976960 191 | dwMaxBitRate 383976960 192 | dwMaxVideoFrameBufferSize 153600 193 | dwDefaultFrameInterval 333333 194 | bFrameIntervalType 0 195 | dwMinFrameInterval 333333 196 | dwMaxFrameInterval 333333 197 | dwFrameIntervalStep 0 198 | Interface Descriptor: 199 | bLength 9 200 | bDescriptorType 4 201 | bInterfaceNumber 1 202 | bAlternateSetting 1 203 | bNumEndpoints 1 204 | bInterfaceClass 14 Video 205 | bInterfaceSubClass 2 Video Streaming 206 | bInterfaceProtocol 0 207 | iInterface 0 208 | Endpoint Descriptor: 209 | bLength 7 210 | bDescriptorType 5 211 | bEndpointAddress 0x82 EP 2 IN 212 | bmAttributes 5 213 | Transfer Type Isochronous 214 | Synch Type Asynchronous 215 | Usage Type Data 216 | wMaxPacketSize 0x1400 3x 1024 bytes 217 | bInterval 1 218 | Device Qualifier (for other device speed): 219 | bLength 10 220 | bDescriptorType 6 221 | bcdUSB 2.00 222 | bDeviceClass 14 Video 223 | bDeviceSubClass 2 Video Streaming 224 | bDeviceProtocol 0 225 | bMaxPacketSize0 8 226 | bNumConfigurations 1 227 | Device Status: 0x0000 228 | (Bus Powered) 229 | -------------------------------------------------------------------------------- /cameras/isight_macbook.txt: -------------------------------------------------------------------------------- 1 | 2 | Bus 001 Device 010: ID 05ac:8501 Apple, Inc. Built-in iSight [Micron] 3 | Device Descriptor: 4 | bLength 18 5 | bDescriptorType 1 6 | bcdUSB 2.00 7 | bDeviceClass 239 Miscellaneous Device 8 | bDeviceSubClass 2 ? 9 | bDeviceProtocol 1 Interface Association 10 | bMaxPacketSize0 64 11 | idVendor 0x05ac Apple, Inc. 12 | idProduct 0x8501 Built-in iSight [Micron] 13 | bcdDevice 1.89 14 | iManufacturer 1 Micron 15 | iProduct 2 Built-in iSight 16 | iSerial 0 17 | bNumConfigurations 1 18 | Configuration Descriptor: 19 | bLength 9 20 | bDescriptorType 2 21 | wTotalLength 267 22 | bNumInterfaces 2 23 | bConfigurationValue 1 24 | iConfiguration 0 25 | bmAttributes 0x80 26 | (Bus Powered) 27 | MaxPower 100mA 28 | Interface Association: 29 | bLength 8 30 | bDescriptorType 11 31 | bFirstInterface 0 32 | bInterfaceCount 2 33 | bFunctionClass 14 Video 34 | bFunctionSubClass 3 Video Interface Collection 35 | bFunctionProtocol 0 36 | iFunction 0 37 | Interface Descriptor: 38 | bLength 9 39 | bDescriptorType 4 40 | bInterfaceNumber 0 41 | bAlternateSetting 0 42 | bNumEndpoints 1 43 | bInterfaceClass 14 Video 44 | bInterfaceSubClass 1 Video Control 45 | bInterfaceProtocol 0 46 | iInterface 0 47 | VideoControl Interface Descriptor: 48 | bLength 13 49 | bDescriptorType 36 50 | bDescriptorSubtype 1 (HEADER) 51 | bcdUVC 1.00 52 | wTotalLength 49 53 | dwClockFrequency 13.500000MHz 54 | bInCollection 1 55 | baInterfaceNr( 0) 1 56 | VideoControl Interface Descriptor: 57 | bLength 16 58 | bDescriptorType 36 59 | bDescriptorSubtype 2 (INPUT_TERMINAL) 60 | bTerminalID 1 61 | wTerminalType 0x0201 Camera Sensor 62 | bAssocTerminal 0 63 | iTerminal 0 64 | wObjectiveFocalLengthMin 0 65 | wObjectiveFocalLengthMax 0 66 | wOcularFocalLength 0 67 | bControlSize 1 68 | bmControls 0x00000000 69 | VideoControl Interface Descriptor: 70 | bLength 11 71 | bDescriptorType 36 72 | bDescriptorSubtype 5 (PROCESSING_UNIT) 73 | Warning: Descriptor too short 74 | bUnitID 2 75 | bSourceID 1 76 | wMaxMultiplier 0 77 | bControlSize 2 78 | bmControls 0x00000039 79 | Brightness 80 | Saturation 81 | Sharpness 82 | Gamma 83 | iProcessing 0 84 | bmVideoStandards 0x 9 85 | None 86 | SECAM - 625/50 87 | VideoControl Interface Descriptor: 88 | bLength 9 89 | bDescriptorType 36 90 | bDescriptorSubtype 3 (OUTPUT_TERMINAL) 91 | bTerminalID 3 92 | wTerminalType 0x0101 USB Streaming 93 | bAssocTerminal 0 94 | bSourceID 2 95 | iTerminal 0 96 | Endpoint Descriptor: 97 | bLength 7 98 | bDescriptorType 5 99 | bEndpointAddress 0x81 EP 1 IN 100 | bmAttributes 3 101 | Transfer Type Interrupt 102 | Synch Type None 103 | Usage Type Data 104 | wMaxPacketSize 0x0008 1x 8 bytes 105 | bInterval 10 106 | Interface Descriptor: 107 | bLength 9 108 | bDescriptorType 4 109 | bInterfaceNumber 1 110 | bAlternateSetting 0 111 | bNumEndpoints 0 112 | bInterfaceClass 14 Video 113 | bInterfaceSubClass 2 Video Streaming 114 | bInterfaceProtocol 0 115 | iInterface 0 116 | VideoStreaming Interface Descriptor: 117 | bLength 14 118 | bDescriptorType 36 119 | bDescriptorSubtype 1 (INPUT_HEADER) 120 | bNumFormats 1 121 | wTotalLength 155 122 | bEndPointAddress 130 123 | bmInfo 0 124 | bTerminalLink 3 125 | bStillCaptureMethod 0 126 | bTriggerSupport 0 127 | bTriggerUsage 0 128 | bControlSize 1 129 | bmaControls( 0) 27 130 | VideoStreaming Interface Descriptor: 131 | bLength 27 132 | bDescriptorType 36 133 | bDescriptorSubtype 4 (FORMAT_UNCOMPRESSED) 134 | bFormatIndex 1 135 | bNumFrameDescriptors 3 136 | guidFormat {55595659-0000-1000-8000-00aa00389b71} 137 | bBitsPerPixel 16 138 | bDefaultFrameIndex 1 139 | bAspectRatioX 0 140 | bAspectRatioY 0 141 | bmInterlaceFlags 0x00 142 | Interlaced stream or variable: No 143 | Fields per frame: 1 fields 144 | Field 1 first: No 145 | Field pattern: Field 1 only 146 | bCopyProtect 0 147 | VideoStreaming Interface Descriptor: 148 | bLength 38 149 | bDescriptorType 36 150 | bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) 151 | bFrameIndex 1 152 | bmCapabilities 0x00 153 | Still image unsupported 154 | wWidth 640 155 | wHeight 480 156 | dwMinBitRate 383976960 157 | dwMaxBitRate 383976960 158 | dwMaxVideoFrameBufferSize 614400 159 | dwDefaultFrameInterval 333333 160 | bFrameIntervalType 0 161 | dwMinFrameInterval 333333 162 | dwMaxFrameInterval 333333 163 | dwFrameIntervalStep 0 164 | VideoStreaming Interface Descriptor: 165 | bLength 38 166 | bDescriptorType 36 167 | bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) 168 | bFrameIndex 2 169 | bmCapabilities 0x00 170 | Still image unsupported 171 | wWidth 352 172 | wHeight 288 173 | dwMinBitRate 383976960 174 | dwMaxBitRate 383976960 175 | dwMaxVideoFrameBufferSize 202752 176 | dwDefaultFrameInterval 333333 177 | bFrameIntervalType 0 178 | dwMinFrameInterval 333333 179 | dwMaxFrameInterval 333333 180 | dwFrameIntervalStep 0 181 | VideoStreaming Interface Descriptor: 182 | bLength 38 183 | bDescriptorType 36 184 | bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) 185 | bFrameIndex 3 186 | bmCapabilities 0x00 187 | Still image unsupported 188 | wWidth 320 189 | wHeight 240 190 | dwMinBitRate 383976960 191 | dwMaxBitRate 383976960 192 | dwMaxVideoFrameBufferSize 153600 193 | dwDefaultFrameInterval 333333 194 | bFrameIntervalType 0 195 | dwMinFrameInterval 333333 196 | dwMaxFrameInterval 333333 197 | dwFrameIntervalStep 0 198 | Interface Descriptor: 199 | bLength 9 200 | bDescriptorType 4 201 | bInterfaceNumber 1 202 | bAlternateSetting 1 203 | bNumEndpoints 1 204 | bInterfaceClass 14 Video 205 | bInterfaceSubClass 2 Video Streaming 206 | bInterfaceProtocol 0 207 | iInterface 0 208 | Endpoint Descriptor: 209 | bLength 7 210 | bDescriptorType 5 211 | bEndpointAddress 0x82 EP 2 IN 212 | bmAttributes 5 213 | Transfer Type Isochronous 214 | Synch Type Asynchronous 215 | Usage Type Data 216 | wMaxPacketSize 0x1400 3x 1024 bytes 217 | bInterval 1 218 | Device Qualifier (for other device speed): 219 | bLength 10 220 | bDescriptorType 6 221 | bcdUSB 2.00 222 | bDeviceClass 14 Video 223 | bDeviceSubClass 2 Video Streaming 224 | bDeviceProtocol 0 225 | bMaxPacketSize0 8 226 | bNumConfigurations 1 227 | Device Status: 0x0000 228 | (Bus Powered) 229 | -------------------------------------------------------------------------------- /cameras/ms_lifecam_show.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pupil-labs/libuvc/b7181e9625fb19eae80b54818537d2fd0a9090d3/cameras/ms_lifecam_show.txt -------------------------------------------------------------------------------- /cameras/quickcampro9000_builtin_ctrls.txt: -------------------------------------------------------------------------------- 1 | Listing available controls for device video0: 2 | Exposure, Auto Priority 3 | Exposure (Absolute) 4 | Exposure, Auto 5 | Backlight Compensation 6 | Sharpness 7 | White Balance Temperature 8 | Power Line Frequency 9 | Gain 10 | White Balance Temperature, Auto 11 | Saturation 12 | Contrast 13 | Brightness 14 | -------------------------------------------------------------------------------- /cameras/quickcampro9000_extra_ctrls.txt: -------------------------------------------------------------------------------- 1 | Listing available controls for device video0: 2 | Raw bits per pixel 3 | Disable video processing 4 | LED1 Frequency 5 | LED1 Mode 6 | Focus 7 | Exposure, Auto Priority 8 | Exposure (Absolute) 9 | Exposure, Auto 10 | Backlight Compensation 11 | Sharpness 12 | White Balance Temperature 13 | Power Line Frequency 14 | Gain 15 | White Balance Temperature, Auto 16 | Saturation 17 | Contrast 18 | Brightness 19 | -------------------------------------------------------------------------------- /changelog.txt: -------------------------------------------------------------------------------- 1 | Changes in 0.1.0 (2023-01-19) 2 | ---------------- 3 | 4 | - Cleaned up CMAKE build pipeline 5 | - Added support for GRAY8 video streams 6 | - Fix bugs 7 | 8 | Changes in 0.0.5 (2014-07-19) 9 | ---------------- 10 | 11 | New features: 12 | - Added support for all of the camera terminal and processing unit controls, including the controls 13 | that appeared in UVC 1.1 and 1.5. 14 | - Added LIBUVC_VERSION_GTE(major, minor, patch) macro. 15 | 16 | Bug fixes: 17 | - Switching to explicit kernel driver detachment since auto_detach isn't available in libusb < 1.0.16. 18 | - The cmake module now looks for libuvc.dylib instead of libuvc.so on OS X. 19 | 20 | 21 | Changes in 0.0.4 (2014-06-26) 22 | ---------------- 23 | 24 | New features: 25 | - Support devices with multiple streaming interfaces and multiple concurrent streams. 26 | A new uvc_stream* API is added, along with a uvc_stream_handle type to encapsulate the 27 | state of a single UVC stream. Multiple streams can run alongside each other, provided 28 | your USB connection has enough bandwidth. Streams can be individually stopped and 29 | resumed; the old uvc_start/stop_streaming API is still provided as a convenient way 30 | to interact with the usual one-stream devices. 31 | - Added support for MJPEG streams. 32 | - Added functions for checking/setting autofocus mode. 33 | - Added an interface to set/get arbitrary controls on units and terminals. 34 | - Made the input, output, processing and extension units public. 35 | - Implemented uvc_get_device and uvc_get_libusb_handle. 36 | - Add a library-owned flag to uvc_frame_t so that users may allocate their own frame buffers. 37 | 38 | Bug fixes: 39 | - Send frames as soon as they're received, not when the following frame arrives 40 | - Fixed call to NULL when no status callback is provided. 41 | - Fixed crash that occurred during shutdown if the USB device was disconnected during streaming. 42 | 43 | Miscellaneous improvements: 44 | - Hid the transfer method (isochronous vs bulk) from the user. This was never really 45 | selectable; the camera's streaming interface supports either bulk or isochronous 46 | transfers, so now libuvc will figure out which one is appropriate. The `isochronous` 47 | parameter has been converted to a `flags` parameter, which is currently unused but 48 | could be used to convey up to 7 bits of stream mode information in the future. 49 | - Improved the method for claiming the camera's interfaces. 50 | - Renamed UVC_COLOR_FORMAT_* to UVC_FRAME_FORMAT_*. The old #defines are still available. 51 | - Simplified format definition and lookup. 52 | - Improved transfer status (error) handling. 53 | -------------------------------------------------------------------------------- /include/libuvc/libuvc.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBUVC_H 2 | #define LIBUVC_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include // FILE 9 | #include 10 | #ifndef WIN32 11 | #include 12 | #else 13 | #include 14 | #endif 15 | 16 | struct libusb_context; 17 | struct libusb_device_handle; 18 | 19 | 20 | /** UVC error types, based on libusb errors 21 | * @ingroup diag 22 | */ 23 | typedef enum uvc_error { 24 | /** Success (no error) */ 25 | UVC_SUCCESS = 0, 26 | /** Input/output error */ 27 | UVC_ERROR_IO = -1, 28 | /** Invalid parameter */ 29 | UVC_ERROR_INVALID_PARAM = -2, 30 | /** Access denied */ 31 | UVC_ERROR_ACCESS = -3, 32 | /** No such device */ 33 | UVC_ERROR_NO_DEVICE = -4, 34 | /** Entity not found */ 35 | UVC_ERROR_NOT_FOUND = -5, 36 | /** Resource busy */ 37 | UVC_ERROR_BUSY = -6, 38 | /** Operation timed out */ 39 | UVC_ERROR_TIMEOUT = -7, 40 | /** Overflow */ 41 | UVC_ERROR_OVERFLOW = -8, 42 | /** Pipe error */ 43 | UVC_ERROR_PIPE = -9, 44 | /** System call interrupted */ 45 | UVC_ERROR_INTERRUPTED = -10, 46 | /** Insufficient memory */ 47 | UVC_ERROR_NO_MEM = -11, 48 | /** Operation not supported */ 49 | UVC_ERROR_NOT_SUPPORTED = -12, 50 | /** Device is not UVC-compliant */ 51 | UVC_ERROR_INVALID_DEVICE = -50, 52 | /** Mode not supported */ 53 | UVC_ERROR_INVALID_MODE = -51, 54 | /** Resource has a callback (can't use polling and async) */ 55 | UVC_ERROR_CALLBACK_EXISTS = -52, 56 | /** Undefined error */ 57 | UVC_ERROR_OTHER = -99 58 | } uvc_error_t; 59 | 60 | /** Color coding of stream, transport-independent 61 | * @ingroup streaming 62 | */ 63 | enum uvc_frame_format { 64 | UVC_FRAME_FORMAT_UNKNOWN = 0, 65 | /** Any supported format */ 66 | UVC_FRAME_FORMAT_ANY = 0, 67 | UVC_FRAME_FORMAT_UNCOMPRESSED, 68 | UVC_FRAME_FORMAT_COMPRESSED, 69 | /** YUYV/YUV2/YUV422: YUV encoding with one luminance value per pixel and 70 | * one UV (chrominance) pair for every two pixels. 71 | */ 72 | UVC_FRAME_FORMAT_YUYV, 73 | UVC_FRAME_FORMAT_UYVY, 74 | /** 24-bit RGB */ 75 | UVC_FRAME_FORMAT_RGB, 76 | UVC_FRAME_FORMAT_BGR, 77 | /** Motion-JPEG (or JPEG) encoded images */ 78 | UVC_FRAME_FORMAT_MJPEG, 79 | UVC_FRAME_FORMAT_H264, 80 | /** Greyscale images */ 81 | UVC_FRAME_FORMAT_GRAY8, 82 | UVC_FRAME_FORMAT_GRAY16, 83 | /* Raw colour mosaic images */ 84 | UVC_FRAME_FORMAT_BY8, 85 | UVC_FRAME_FORMAT_BA81, 86 | UVC_FRAME_FORMAT_SGRBG8, 87 | UVC_FRAME_FORMAT_SGBRG8, 88 | UVC_FRAME_FORMAT_SRGGB8, 89 | UVC_FRAME_FORMAT_SBGGR8, 90 | /** YUV420: NV12 */ 91 | UVC_FRAME_FORMAT_NV12, 92 | /** YUV: P010 */ 93 | UVC_FRAME_FORMAT_P010, 94 | /** Number of formats understood */ 95 | UVC_FRAME_FORMAT_COUNT, 96 | }; 97 | 98 | /* UVC_COLOR_FORMAT_* have been replaced with UVC_FRAME_FORMAT_*. Please use 99 | * UVC_FRAME_FORMAT_* instead of using these. */ 100 | #define UVC_COLOR_FORMAT_UNKNOWN UVC_FRAME_FORMAT_UNKNOWN 101 | #define UVC_COLOR_FORMAT_UNCOMPRESSED UVC_FRAME_FORMAT_UNCOMPRESSED 102 | #define UVC_COLOR_FORMAT_COMPRESSED UVC_FRAME_FORMAT_COMPRESSED 103 | #define UVC_COLOR_FORMAT_YUYV UVC_FRAME_FORMAT_YUYV 104 | #define UVC_COLOR_FORMAT_UYVY UVC_FRAME_FORMAT_UYVY 105 | #define UVC_COLOR_FORMAT_RGB UVC_FRAME_FORMAT_RGB 106 | #define UVC_COLOR_FORMAT_BGR UVC_FRAME_FORMAT_BGR 107 | #define UVC_COLOR_FORMAT_MJPEG UVC_FRAME_FORMAT_MJPEG 108 | #define UVC_COLOR_FORMAT_GRAY8 UVC_FRAME_FORMAT_GRAY8 109 | #define UVC_COLOR_FORMAT_GRAY16 UVC_FRAME_FORMAT_GRAY16 110 | 111 | /** VideoStreaming interface descriptor subtype (A.6) */ 112 | enum uvc_vs_desc_subtype { 113 | UVC_VS_UNDEFINED = 0x00, 114 | UVC_VS_INPUT_HEADER = 0x01, 115 | UVC_VS_OUTPUT_HEADER = 0x02, 116 | UVC_VS_STILL_IMAGE_FRAME = 0x03, 117 | UVC_VS_FORMAT_UNCOMPRESSED = 0x04, 118 | UVC_VS_FRAME_UNCOMPRESSED = 0x05, 119 | UVC_VS_FORMAT_MJPEG = 0x06, 120 | UVC_VS_FRAME_MJPEG = 0x07, 121 | UVC_VS_FORMAT_MPEG2TS = 0x0a, 122 | UVC_VS_FORMAT_DV = 0x0c, 123 | UVC_VS_COLORFORMAT = 0x0d, 124 | UVC_VS_FORMAT_FRAME_BASED = 0x10, 125 | UVC_VS_FRAME_FRAME_BASED = 0x11, 126 | UVC_VS_FORMAT_STREAM_BASED = 0x12 127 | }; 128 | 129 | struct uvc_format_desc; 130 | struct uvc_frame_desc; 131 | 132 | /** Frame descriptor 133 | * 134 | * A "frame" is a configuration of a streaming format 135 | * for a particular image size at one of possibly several 136 | * available frame rates. 137 | */ 138 | typedef struct uvc_frame_desc { 139 | struct uvc_format_desc *parent; 140 | struct uvc_frame_desc *prev, *next; 141 | /** Type of frame, such as JPEG frame or uncompressed frme */ 142 | enum uvc_vs_desc_subtype bDescriptorSubtype; 143 | /** Index of the frame within the list of specs available for this format */ 144 | uint8_t bFrameIndex; 145 | uint8_t bmCapabilities; 146 | /** Image width */ 147 | uint16_t wWidth; 148 | /** Image height */ 149 | uint16_t wHeight; 150 | /** Bitrate of corresponding stream at minimal frame rate */ 151 | uint32_t dwMinBitRate; 152 | /** Bitrate of corresponding stream at maximal frame rate */ 153 | uint32_t dwMaxBitRate; 154 | /** Maximum number of bytes for a video frame */ 155 | uint32_t dwMaxVideoFrameBufferSize; 156 | /** Default frame interval (in 100ns units) */ 157 | uint32_t dwDefaultFrameInterval; 158 | /** Minimum frame interval for continuous mode (100ns units) */ 159 | uint32_t dwMinFrameInterval; 160 | /** Maximum frame interval for continuous mode (100ns units) */ 161 | uint32_t dwMaxFrameInterval; 162 | /** Granularity of frame interval range for continuous mode (100ns) */ 163 | uint32_t dwFrameIntervalStep; 164 | /** Frame intervals */ 165 | uint8_t bFrameIntervalType; 166 | /** number of bytes per line */ 167 | uint32_t dwBytesPerLine; 168 | /** Available frame rates, zero-terminated (in 100ns units) */ 169 | uint32_t *intervals; 170 | } uvc_frame_desc_t; 171 | 172 | /** Format descriptor 173 | * 174 | * A "format" determines a stream's image type (e.g., raw YUYV or JPEG) 175 | * and includes many "frame" configurations. 176 | */ 177 | typedef struct uvc_format_desc { 178 | struct uvc_streaming_interface *parent; 179 | struct uvc_format_desc *prev, *next; 180 | /** Type of image stream, such as JPEG or uncompressed. */ 181 | enum uvc_vs_desc_subtype bDescriptorSubtype; 182 | /** Identifier of this format within the VS interface's format list */ 183 | uint8_t bFormatIndex; 184 | uint8_t bNumFrameDescriptors; 185 | /** Format specifier */ 186 | union { 187 | uint8_t guidFormat[16]; 188 | uint8_t fourccFormat[4]; 189 | }; 190 | /** Format-specific data */ 191 | union { 192 | /** BPP for uncompressed stream */ 193 | uint8_t bBitsPerPixel; 194 | /** Flags for JPEG stream */ 195 | uint8_t bmFlags; 196 | }; 197 | /** Default {uvc_frame_desc} to choose given this format */ 198 | uint8_t bDefaultFrameIndex; 199 | uint8_t bAspectRatioX; 200 | uint8_t bAspectRatioY; 201 | uint8_t bmInterlaceFlags; 202 | uint8_t bCopyProtect; 203 | uint8_t bVariableSize; 204 | /** Available frame specifications for this format */ 205 | struct uvc_frame_desc *frame_descs; 206 | } uvc_format_desc_t; 207 | 208 | /** UVC request code (A.8) */ 209 | enum uvc_req_code { 210 | UVC_RC_UNDEFINED = 0x00, 211 | UVC_SET_CUR = 0x01, 212 | UVC_GET_CUR = 0x81, 213 | UVC_GET_MIN = 0x82, 214 | UVC_GET_MAX = 0x83, 215 | UVC_GET_RES = 0x84, 216 | UVC_GET_LEN = 0x85, 217 | UVC_GET_INFO = 0x86, 218 | UVC_GET_DEF = 0x87 219 | }; 220 | 221 | enum uvc_device_power_mode { 222 | UVC_VC_VIDEO_POWER_MODE_FULL = 0x000b, 223 | UVC_VC_VIDEO_POWER_MODE_DEVICE_DEPENDENT = 0x001b, 224 | }; 225 | 226 | /** Camera terminal control selector (A.9.4) */ 227 | enum uvc_ct_ctrl_selector { 228 | UVC_CT_CONTROL_UNDEFINED = 0x00, 229 | UVC_CT_SCANNING_MODE_CONTROL = 0x01, 230 | UVC_CT_AE_MODE_CONTROL = 0x02, 231 | UVC_CT_AE_PRIORITY_CONTROL = 0x03, 232 | UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL = 0x04, 233 | UVC_CT_EXPOSURE_TIME_RELATIVE_CONTROL = 0x05, 234 | UVC_CT_FOCUS_ABSOLUTE_CONTROL = 0x06, 235 | UVC_CT_FOCUS_RELATIVE_CONTROL = 0x07, 236 | UVC_CT_FOCUS_AUTO_CONTROL = 0x08, 237 | UVC_CT_IRIS_ABSOLUTE_CONTROL = 0x09, 238 | UVC_CT_IRIS_RELATIVE_CONTROL = 0x0a, 239 | UVC_CT_ZOOM_ABSOLUTE_CONTROL = 0x0b, 240 | UVC_CT_ZOOM_RELATIVE_CONTROL = 0x0c, 241 | UVC_CT_PANTILT_ABSOLUTE_CONTROL = 0x0d, 242 | UVC_CT_PANTILT_RELATIVE_CONTROL = 0x0e, 243 | UVC_CT_ROLL_ABSOLUTE_CONTROL = 0x0f, 244 | UVC_CT_ROLL_RELATIVE_CONTROL = 0x10, 245 | UVC_CT_PRIVACY_CONTROL = 0x11, 246 | UVC_CT_FOCUS_SIMPLE_CONTROL = 0x12, 247 | UVC_CT_DIGITAL_WINDOW_CONTROL = 0x13, 248 | UVC_CT_REGION_OF_INTEREST_CONTROL = 0x14 249 | }; 250 | 251 | /** Processing unit control selector (A.9.5) */ 252 | enum uvc_pu_ctrl_selector { 253 | UVC_PU_CONTROL_UNDEFINED = 0x00, 254 | UVC_PU_BACKLIGHT_COMPENSATION_CONTROL = 0x01, 255 | UVC_PU_BRIGHTNESS_CONTROL = 0x02, 256 | UVC_PU_CONTRAST_CONTROL = 0x03, 257 | UVC_PU_GAIN_CONTROL = 0x04, 258 | UVC_PU_POWER_LINE_FREQUENCY_CONTROL = 0x05, 259 | UVC_PU_HUE_CONTROL = 0x06, 260 | UVC_PU_SATURATION_CONTROL = 0x07, 261 | UVC_PU_SHARPNESS_CONTROL = 0x08, 262 | UVC_PU_GAMMA_CONTROL = 0x09, 263 | UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL = 0x0a, 264 | UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL = 0x0b, 265 | UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL = 0x0c, 266 | UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL = 0x0d, 267 | UVC_PU_DIGITAL_MULTIPLIER_CONTROL = 0x0e, 268 | UVC_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL = 0x0f, 269 | UVC_PU_HUE_AUTO_CONTROL = 0x10, 270 | UVC_PU_ANALOG_VIDEO_STANDARD_CONTROL = 0x11, 271 | UVC_PU_ANALOG_LOCK_STATUS_CONTROL = 0x12, 272 | UVC_PU_CONTRAST_AUTO_CONTROL = 0x13 273 | }; 274 | 275 | /** USB terminal type (B.1) */ 276 | enum uvc_term_type { 277 | UVC_TT_VENDOR_SPECIFIC = 0x0100, 278 | UVC_TT_STREAMING = 0x0101 279 | }; 280 | 281 | /** Input terminal type (B.2) */ 282 | enum uvc_it_type { 283 | UVC_ITT_VENDOR_SPECIFIC = 0x0200, 284 | UVC_ITT_CAMERA = 0x0201, 285 | UVC_ITT_MEDIA_TRANSPORT_INPUT = 0x0202 286 | }; 287 | 288 | /** Output terminal type (B.3) */ 289 | enum uvc_ot_type { 290 | UVC_OTT_VENDOR_SPECIFIC = 0x0300, 291 | UVC_OTT_DISPLAY = 0x0301, 292 | UVC_OTT_MEDIA_TRANSPORT_OUTPUT = 0x0302 293 | }; 294 | 295 | /** External terminal type (B.4) */ 296 | enum uvc_et_type { 297 | UVC_EXTERNAL_VENDOR_SPECIFIC = 0x0400, 298 | UVC_COMPOSITE_CONNECTOR = 0x0401, 299 | UVC_SVIDEO_CONNECTOR = 0x0402, 300 | UVC_COMPONENT_CONNECTOR = 0x0403 301 | }; 302 | 303 | /** Context, equivalent to libusb's contexts. 304 | * 305 | * May either own a libusb context or use one that's already made. 306 | * 307 | * Always create these with uvc_get_context. 308 | */ 309 | struct uvc_context; 310 | typedef struct uvc_context uvc_context_t; 311 | 312 | /** UVC device. 313 | * 314 | * Get this from uvc_get_device_list() or uvc_find_device(). 315 | */ 316 | struct uvc_device; 317 | typedef struct uvc_device uvc_device_t; 318 | 319 | /** Handle on an open UVC device. 320 | * 321 | * Get one of these from uvc_open(). Once you uvc_close() 322 | * it, it's no longer valid. 323 | */ 324 | struct uvc_device_handle; 325 | typedef struct uvc_device_handle uvc_device_handle_t; 326 | 327 | /** Handle on an open UVC stream. 328 | * 329 | * Get one of these from uvc_stream_open*(). 330 | * Once you uvc_stream_close() it, it will no longer be valid. 331 | */ 332 | struct uvc_stream_handle; 333 | typedef struct uvc_stream_handle uvc_stream_handle_t; 334 | 335 | /** Representation of the interface that brings data into the UVC device */ 336 | typedef struct uvc_input_terminal { 337 | struct uvc_input_terminal *prev, *next; 338 | /** Index of the terminal within the device */ 339 | uint8_t bTerminalID; 340 | /** Type of terminal (e.g., camera) */ 341 | enum uvc_it_type wTerminalType; 342 | uint16_t wObjectiveFocalLengthMin; 343 | uint16_t wObjectiveFocalLengthMax; 344 | uint16_t wOcularFocalLength; 345 | /** Camera controls (meaning of bits given in {uvc_ct_ctrl_selector}) */ 346 | uint64_t bmControls; 347 | } uvc_input_terminal_t; 348 | 349 | typedef struct uvc_output_terminal { 350 | struct uvc_output_terminal *prev, *next; 351 | /** @todo */ 352 | } uvc_output_terminal_t; 353 | 354 | /** Represents post-capture processing functions */ 355 | typedef struct uvc_processing_unit { 356 | struct uvc_processing_unit *prev, *next; 357 | /** Index of the processing unit within the device */ 358 | uint8_t bUnitID; 359 | /** Index of the terminal from which the device accepts images */ 360 | uint8_t bSourceID; 361 | /** Processing controls (meaning of bits given in {uvc_pu_ctrl_selector}) */ 362 | uint64_t bmControls; 363 | } uvc_processing_unit_t; 364 | 365 | /** Represents selector unit to connect other units */ 366 | typedef struct uvc_selector_unit { 367 | struct uvc_selector_unit *prev, *next; 368 | /** Index of the selector unit within the device */ 369 | uint8_t bUnitID; 370 | } uvc_selector_unit_t; 371 | 372 | /** Custom processing or camera-control functions */ 373 | typedef struct uvc_extension_unit { 374 | struct uvc_extension_unit *prev, *next; 375 | /** Index of the extension unit within the device */ 376 | uint8_t bUnitID; 377 | /** GUID identifying the extension unit */ 378 | uint8_t guidExtensionCode[16]; 379 | /** Bitmap of available controls (manufacturer-dependent) */ 380 | uint64_t bmControls; 381 | } uvc_extension_unit_t; 382 | 383 | enum uvc_status_class { 384 | UVC_STATUS_CLASS_CONTROL = 0x10, 385 | UVC_STATUS_CLASS_CONTROL_CAMERA = 0x11, 386 | UVC_STATUS_CLASS_CONTROL_PROCESSING = 0x12, 387 | }; 388 | 389 | enum uvc_status_attribute { 390 | UVC_STATUS_ATTRIBUTE_VALUE_CHANGE = 0x00, 391 | UVC_STATUS_ATTRIBUTE_INFO_CHANGE = 0x01, 392 | UVC_STATUS_ATTRIBUTE_FAILURE_CHANGE = 0x02, 393 | UVC_STATUS_ATTRIBUTE_UNKNOWN = 0xff 394 | }; 395 | 396 | /** A callback function to accept status updates 397 | * @ingroup device 398 | */ 399 | typedef void(uvc_status_callback_t)(enum uvc_status_class status_class, 400 | int event, 401 | int selector, 402 | enum uvc_status_attribute status_attribute, 403 | void *data, size_t data_len, 404 | void *user_ptr); 405 | 406 | /** A callback function to accept button events 407 | * @ingroup device 408 | */ 409 | typedef void(uvc_button_callback_t)(int button, 410 | int state, 411 | void *user_ptr); 412 | 413 | /** Structure representing a UVC device descriptor. 414 | * 415 | * (This isn't a standard structure.) 416 | */ 417 | typedef struct uvc_device_descriptor { 418 | /** Vendor ID */ 419 | uint16_t idVendor; 420 | /** Product ID */ 421 | uint16_t idProduct; 422 | /** UVC compliance level, e.g. 0x0100 (1.0), 0x0110 */ 423 | uint16_t bcdUVC; 424 | /** Serial number (null if unavailable) */ 425 | const char *serialNumber; 426 | /** Device-reported manufacturer name (or null) */ 427 | const char *manufacturer; 428 | /** Device-reporter product name (or null) */ 429 | const char *product; 430 | } uvc_device_descriptor_t; 431 | 432 | /** An image frame received from the UVC device 433 | * @ingroup streaming 434 | */ 435 | typedef struct uvc_frame { 436 | /** Image data for this frame */ 437 | void *data; 438 | /** Size of image data buffer */ 439 | size_t data_bytes; 440 | /** Width of image in pixels */ 441 | uint32_t width; 442 | /** Height of image in pixels */ 443 | uint32_t height; 444 | /** Pixel data format */ 445 | enum uvc_frame_format frame_format; 446 | /** Number of bytes per horizontal line (undefined for compressed format) */ 447 | size_t step; 448 | /** Frame number (may skip, but is strictly monotonically increasing) */ 449 | uint32_t sequence; 450 | /** Estimate of system time when the device started capturing the image */ 451 | struct timeval capture_time; 452 | /** Handle on the device that produced the image. 453 | * @warning You must not call any uvc_* functions during a callback. */ 454 | uvc_device_handle_t *source; 455 | /** Is the data buffer owned by the library? 456 | * If 1, the data buffer can be arbitrarily reallocated by frame conversion 457 | * functions. 458 | * If 0, the data buffer will not be reallocated or freed by the library. 459 | * Set this field to zero if you are supplying the buffer. 460 | */ 461 | uint8_t library_owns_data; 462 | } uvc_frame_t; 463 | 464 | /** A callback function to handle incoming assembled UVC frames 465 | * @ingroup streaming 466 | */ 467 | typedef void(uvc_frame_callback_t)(struct uvc_frame *frame, void *user_ptr); 468 | 469 | /** Streaming mode, includes all information needed to select stream 470 | * @ingroup streaming 471 | */ 472 | typedef struct uvc_stream_ctrl { 473 | uint16_t bmHint; 474 | uint8_t bFormatIndex; 475 | uint8_t bFrameIndex; 476 | uint32_t dwFrameInterval; 477 | uint16_t wKeyFrameRate; 478 | uint16_t wPFrameRate; 479 | uint16_t wCompQuality; 480 | uint16_t wCompWindowSize; 481 | uint16_t wDelay; 482 | uint32_t dwMaxVideoFrameSize; 483 | uint32_t dwMaxPayloadTransferSize; 484 | uint32_t dwClockFrequency; 485 | uint8_t bmFramingInfo; 486 | uint8_t bPreferredVersion; 487 | uint8_t bMinVersion; 488 | uint8_t bMaxVersion; 489 | uint8_t bInterfaceNumber; 490 | } uvc_stream_ctrl_t; 491 | 492 | uvc_error_t uvc_init(uvc_context_t **ctx, struct libusb_context *usb_ctx); 493 | void uvc_exit(uvc_context_t *ctx); 494 | 495 | uvc_error_t uvc_get_device_list( 496 | uvc_context_t *ctx, 497 | uvc_device_t ***list); 498 | void uvc_free_device_list(uvc_device_t **list, uint8_t unref_devices); 499 | 500 | uvc_error_t uvc_get_device_descriptor( 501 | uvc_device_t *dev, 502 | uvc_device_descriptor_t **desc); 503 | void uvc_free_device_descriptor( 504 | uvc_device_descriptor_t *desc); 505 | 506 | uint8_t uvc_get_bus_number(uvc_device_t *dev); 507 | uint8_t uvc_get_device_address(uvc_device_t *dev); 508 | 509 | uvc_error_t uvc_find_device( 510 | uvc_context_t *ctx, 511 | uvc_device_t **dev, 512 | int vid, int pid, const char *sn); 513 | 514 | uvc_error_t uvc_find_devices( 515 | uvc_context_t *ctx, 516 | uvc_device_t ***devs, 517 | int vid, int pid, const char *sn); 518 | 519 | uvc_error_t uvc_open( 520 | uvc_device_t *dev, 521 | uvc_device_handle_t **devh, 522 | int should_detach_kernel_driver); 523 | void uvc_close(uvc_device_handle_t *devh); 524 | 525 | uvc_device_t *uvc_get_device(uvc_device_handle_t *devh); 526 | struct libusb_device_handle *uvc_get_libusb_handle(uvc_device_handle_t *devh); 527 | 528 | void uvc_ref_device(uvc_device_t *dev); 529 | void uvc_unref_device(uvc_device_t *dev); 530 | 531 | void uvc_set_status_callback(uvc_device_handle_t *devh, 532 | uvc_status_callback_t cb, 533 | void *user_ptr); 534 | 535 | void uvc_set_button_callback(uvc_device_handle_t *devh, 536 | uvc_button_callback_t cb, 537 | void *user_ptr); 538 | 539 | const uvc_input_terminal_t *uvc_get_camera_terminal(uvc_device_handle_t *devh); 540 | const uvc_input_terminal_t *uvc_get_input_terminals(uvc_device_handle_t *devh); 541 | const uvc_output_terminal_t *uvc_get_output_terminals(uvc_device_handle_t *devh); 542 | const uvc_selector_unit_t *uvc_get_selector_units(uvc_device_handle_t *devh); 543 | const uvc_processing_unit_t *uvc_get_processing_units(uvc_device_handle_t *devh); 544 | const uvc_extension_unit_t *uvc_get_extension_units(uvc_device_handle_t *devh); 545 | 546 | enum uvc_frame_format uvc_frame_format_for_guid(uint8_t guid[16]); 547 | uvc_error_t uvc_get_stream_ctrl_format_size( 548 | uvc_device_handle_t *devh, 549 | uvc_stream_ctrl_t *ctrl, 550 | enum uvc_frame_format format, 551 | int width, int height, 552 | int fps, int should_detach_kernel_driver 553 | ); 554 | 555 | const uvc_format_desc_t *uvc_get_format_descs(uvc_device_handle_t* ); 556 | 557 | uvc_error_t uvc_probe_stream_ctrl( 558 | uvc_device_handle_t *devh, 559 | uvc_stream_ctrl_t *ctrl, 560 | int should_detach_kernel_driver); 561 | 562 | uvc_error_t uvc_start_streaming( 563 | uvc_device_handle_t *devh, 564 | uvc_stream_ctrl_t *ctrl, 565 | uvc_frame_callback_t *cb, 566 | void *user_ptr, 567 | uint8_t flags, 568 | int should_detach_kernel_driver); 569 | 570 | uvc_error_t uvc_start_iso_streaming( 571 | uvc_device_handle_t *devh, 572 | uvc_stream_ctrl_t *ctrl, 573 | uvc_frame_callback_t *cb, 574 | void *user_ptr, 575 | int should_detach_kernel_driver); 576 | 577 | void uvc_stop_streaming(uvc_device_handle_t *devh); 578 | 579 | uvc_error_t uvc_stream_open_ctrl(uvc_device_handle_t *devh, uvc_stream_handle_t **strmh, uvc_stream_ctrl_t *ctrl, int should_detach_kernel_driver); 580 | uvc_error_t uvc_stream_ctrl(uvc_stream_handle_t *strmh, uvc_stream_ctrl_t *ctrl); 581 | uvc_error_t uvc_stream_start(uvc_stream_handle_t *strmh, 582 | uvc_frame_callback_t *cb, 583 | void *user_ptr, 584 | float bandwidth_factor, 585 | uint8_t flags); 586 | uvc_error_t uvc_stream_start_iso(uvc_stream_handle_t *strmh, 587 | uvc_frame_callback_t *cb, 588 | void *user_ptr); 589 | uvc_error_t uvc_stream_get_frame( 590 | uvc_stream_handle_t *strmh, 591 | uvc_frame_t **frame, 592 | int32_t timeout_us 593 | ); 594 | uvc_error_t uvc_stream_stop(uvc_stream_handle_t *strmh); 595 | void uvc_stream_close(uvc_stream_handle_t *strmh); 596 | 597 | int uvc_get_ctrl_len(uvc_device_handle_t *devh, uint8_t unit, uint8_t ctrl); 598 | int uvc_get_ctrl(uvc_device_handle_t *devh, uint8_t unit, uint8_t ctrl, void *data, int len, enum uvc_req_code req_code); 599 | int uvc_set_ctrl(uvc_device_handle_t *devh, uint8_t unit, uint8_t ctrl, void *data, int len); 600 | 601 | uvc_error_t uvc_get_power_mode(uvc_device_handle_t *devh, enum uvc_device_power_mode *mode, enum uvc_req_code req_code); 602 | uvc_error_t uvc_set_power_mode(uvc_device_handle_t *devh, enum uvc_device_power_mode mode); 603 | 604 | /* AUTO-GENERATED control accessors! Update them with the output of `ctrl-gen.py decl`. */ 605 | uvc_error_t uvc_get_scanning_mode(uvc_device_handle_t *devh, uint8_t* mode, enum uvc_req_code req_code); 606 | uvc_error_t uvc_set_scanning_mode(uvc_device_handle_t *devh, uint8_t mode); 607 | 608 | uvc_error_t uvc_get_ae_mode(uvc_device_handle_t *devh, uint8_t* mode, enum uvc_req_code req_code); 609 | uvc_error_t uvc_set_ae_mode(uvc_device_handle_t *devh, uint8_t mode); 610 | 611 | uvc_error_t uvc_get_ae_priority(uvc_device_handle_t *devh, uint8_t* priority, enum uvc_req_code req_code); 612 | uvc_error_t uvc_set_ae_priority(uvc_device_handle_t *devh, uint8_t priority); 613 | 614 | uvc_error_t uvc_get_exposure_abs(uvc_device_handle_t *devh, uint32_t* time, enum uvc_req_code req_code); 615 | uvc_error_t uvc_set_exposure_abs(uvc_device_handle_t *devh, uint32_t time); 616 | 617 | uvc_error_t uvc_get_exposure_rel(uvc_device_handle_t *devh, int8_t* step, enum uvc_req_code req_code); 618 | uvc_error_t uvc_set_exposure_rel(uvc_device_handle_t *devh, int8_t step); 619 | 620 | uvc_error_t uvc_get_focus_abs(uvc_device_handle_t *devh, uint16_t* focus, enum uvc_req_code req_code); 621 | uvc_error_t uvc_set_focus_abs(uvc_device_handle_t *devh, uint16_t focus); 622 | 623 | uvc_error_t uvc_get_focus_rel(uvc_device_handle_t *devh, int8_t* focus_rel, uint8_t* speed, enum uvc_req_code req_code); 624 | uvc_error_t uvc_set_focus_rel(uvc_device_handle_t *devh, int8_t focus_rel, uint8_t speed); 625 | 626 | uvc_error_t uvc_get_focus_simple_range(uvc_device_handle_t *devh, uint8_t* focus, enum uvc_req_code req_code); 627 | uvc_error_t uvc_set_focus_simple_range(uvc_device_handle_t *devh, uint8_t focus); 628 | 629 | uvc_error_t uvc_get_focus_auto(uvc_device_handle_t *devh, uint8_t* state, enum uvc_req_code req_code); 630 | uvc_error_t uvc_set_focus_auto(uvc_device_handle_t *devh, uint8_t state); 631 | 632 | uvc_error_t uvc_get_iris_abs(uvc_device_handle_t *devh, uint16_t* iris, enum uvc_req_code req_code); 633 | uvc_error_t uvc_set_iris_abs(uvc_device_handle_t *devh, uint16_t iris); 634 | 635 | uvc_error_t uvc_get_iris_rel(uvc_device_handle_t *devh, uint8_t* iris_rel, enum uvc_req_code req_code); 636 | uvc_error_t uvc_set_iris_rel(uvc_device_handle_t *devh, uint8_t iris_rel); 637 | 638 | uvc_error_t uvc_get_zoom_abs(uvc_device_handle_t *devh, uint16_t* focal_length, enum uvc_req_code req_code); 639 | uvc_error_t uvc_set_zoom_abs(uvc_device_handle_t *devh, uint16_t focal_length); 640 | 641 | uvc_error_t uvc_get_zoom_rel(uvc_device_handle_t *devh, int8_t* zoom_rel, uint8_t* digital_zoom, uint8_t* speed, enum uvc_req_code req_code); 642 | uvc_error_t uvc_set_zoom_rel(uvc_device_handle_t *devh, int8_t zoom_rel, uint8_t digital_zoom, uint8_t speed); 643 | 644 | uvc_error_t uvc_get_pantilt_abs(uvc_device_handle_t *devh, int32_t* pan, int32_t* tilt, enum uvc_req_code req_code); 645 | uvc_error_t uvc_set_pantilt_abs(uvc_device_handle_t *devh, int32_t pan, int32_t tilt); 646 | 647 | uvc_error_t uvc_get_pantilt_rel(uvc_device_handle_t *devh, int8_t* pan_rel, uint8_t* pan_speed, int8_t* tilt_rel, uint8_t* tilt_speed, enum uvc_req_code req_code); 648 | uvc_error_t uvc_set_pantilt_rel(uvc_device_handle_t *devh, int8_t pan_rel, uint8_t pan_speed, int8_t tilt_rel, uint8_t tilt_speed); 649 | 650 | uvc_error_t uvc_get_roll_abs(uvc_device_handle_t *devh, int16_t* roll, enum uvc_req_code req_code); 651 | uvc_error_t uvc_set_roll_abs(uvc_device_handle_t *devh, int16_t roll); 652 | 653 | uvc_error_t uvc_get_roll_rel(uvc_device_handle_t *devh, int8_t* roll_rel, uint8_t* speed, enum uvc_req_code req_code); 654 | uvc_error_t uvc_set_roll_rel(uvc_device_handle_t *devh, int8_t roll_rel, uint8_t speed); 655 | 656 | uvc_error_t uvc_get_privacy(uvc_device_handle_t *devh, uint8_t* privacy, enum uvc_req_code req_code); 657 | uvc_error_t uvc_set_privacy(uvc_device_handle_t *devh, uint8_t privacy); 658 | 659 | uvc_error_t uvc_get_digital_window(uvc_device_handle_t *devh, uint16_t* window_top, uint16_t* window_left, uint16_t* window_bottom, uint16_t* window_right, uint16_t* num_steps, uint16_t* num_steps_units, enum uvc_req_code req_code); 660 | uvc_error_t uvc_set_digital_window(uvc_device_handle_t *devh, uint16_t window_top, uint16_t window_left, uint16_t window_bottom, uint16_t window_right, uint16_t num_steps, uint16_t num_steps_units); 661 | 662 | uvc_error_t uvc_get_digital_roi(uvc_device_handle_t *devh, uint16_t* roi_top, uint16_t* roi_left, uint16_t* roi_bottom, uint16_t* roi_right, uint16_t* auto_controls, enum uvc_req_code req_code); 663 | uvc_error_t uvc_set_digital_roi(uvc_device_handle_t *devh, uint16_t roi_top, uint16_t roi_left, uint16_t roi_bottom, uint16_t roi_right, uint16_t auto_controls); 664 | 665 | uvc_error_t uvc_get_backlight_compensation(uvc_device_handle_t *devh, uint16_t* backlight_compensation, enum uvc_req_code req_code); 666 | uvc_error_t uvc_set_backlight_compensation(uvc_device_handle_t *devh, uint16_t backlight_compensation); 667 | 668 | uvc_error_t uvc_get_brightness(uvc_device_handle_t *devh, int16_t* brightness, enum uvc_req_code req_code); 669 | uvc_error_t uvc_set_brightness(uvc_device_handle_t *devh, int16_t brightness); 670 | 671 | uvc_error_t uvc_get_contrast(uvc_device_handle_t *devh, uint16_t* contrast, enum uvc_req_code req_code); 672 | uvc_error_t uvc_set_contrast(uvc_device_handle_t *devh, uint16_t contrast); 673 | 674 | uvc_error_t uvc_get_contrast_auto(uvc_device_handle_t *devh, uint8_t* contrast_auto, enum uvc_req_code req_code); 675 | uvc_error_t uvc_set_contrast_auto(uvc_device_handle_t *devh, uint8_t contrast_auto); 676 | 677 | uvc_error_t uvc_get_gain(uvc_device_handle_t *devh, uint16_t* gain, enum uvc_req_code req_code); 678 | uvc_error_t uvc_set_gain(uvc_device_handle_t *devh, uint16_t gain); 679 | 680 | uvc_error_t uvc_get_power_line_frequency(uvc_device_handle_t *devh, uint8_t* power_line_frequency, enum uvc_req_code req_code); 681 | uvc_error_t uvc_set_power_line_frequency(uvc_device_handle_t *devh, uint8_t power_line_frequency); 682 | 683 | uvc_error_t uvc_get_hue(uvc_device_handle_t *devh, int16_t* hue, enum uvc_req_code req_code); 684 | uvc_error_t uvc_set_hue(uvc_device_handle_t *devh, int16_t hue); 685 | 686 | uvc_error_t uvc_get_hue_auto(uvc_device_handle_t *devh, uint8_t* hue_auto, enum uvc_req_code req_code); 687 | uvc_error_t uvc_set_hue_auto(uvc_device_handle_t *devh, uint8_t hue_auto); 688 | 689 | uvc_error_t uvc_get_saturation(uvc_device_handle_t *devh, uint16_t* saturation, enum uvc_req_code req_code); 690 | uvc_error_t uvc_set_saturation(uvc_device_handle_t *devh, uint16_t saturation); 691 | 692 | uvc_error_t uvc_get_sharpness(uvc_device_handle_t *devh, uint16_t* sharpness, enum uvc_req_code req_code); 693 | uvc_error_t uvc_set_sharpness(uvc_device_handle_t *devh, uint16_t sharpness); 694 | 695 | uvc_error_t uvc_get_gamma(uvc_device_handle_t *devh, uint16_t* gamma, enum uvc_req_code req_code); 696 | uvc_error_t uvc_set_gamma(uvc_device_handle_t *devh, uint16_t gamma); 697 | 698 | uvc_error_t uvc_get_white_balance_temperature(uvc_device_handle_t *devh, uint16_t* temperature, enum uvc_req_code req_code); 699 | uvc_error_t uvc_set_white_balance_temperature(uvc_device_handle_t *devh, uint16_t temperature); 700 | 701 | uvc_error_t uvc_get_white_balance_temperature_auto(uvc_device_handle_t *devh, uint8_t* temperature_auto, enum uvc_req_code req_code); 702 | uvc_error_t uvc_set_white_balance_temperature_auto(uvc_device_handle_t *devh, uint8_t temperature_auto); 703 | 704 | uvc_error_t uvc_get_white_balance_component(uvc_device_handle_t *devh, uint16_t* blue, uint16_t* red, enum uvc_req_code req_code); 705 | uvc_error_t uvc_set_white_balance_component(uvc_device_handle_t *devh, uint16_t blue, uint16_t red); 706 | 707 | uvc_error_t uvc_get_white_balance_component_auto(uvc_device_handle_t *devh, uint8_t* white_balance_component_auto, enum uvc_req_code req_code); 708 | uvc_error_t uvc_set_white_balance_component_auto(uvc_device_handle_t *devh, uint8_t white_balance_component_auto); 709 | 710 | uvc_error_t uvc_get_digital_multiplier(uvc_device_handle_t *devh, uint16_t* multiplier_step, enum uvc_req_code req_code); 711 | uvc_error_t uvc_set_digital_multiplier(uvc_device_handle_t *devh, uint16_t multiplier_step); 712 | 713 | uvc_error_t uvc_get_digital_multiplier_limit(uvc_device_handle_t *devh, uint16_t* multiplier_step, enum uvc_req_code req_code); 714 | uvc_error_t uvc_set_digital_multiplier_limit(uvc_device_handle_t *devh, uint16_t multiplier_step); 715 | 716 | uvc_error_t uvc_get_analog_video_standard(uvc_device_handle_t *devh, uint8_t* video_standard, enum uvc_req_code req_code); 717 | uvc_error_t uvc_set_analog_video_standard(uvc_device_handle_t *devh, uint8_t video_standard); 718 | 719 | uvc_error_t uvc_get_analog_video_lock_status(uvc_device_handle_t *devh, uint8_t* status, enum uvc_req_code req_code); 720 | uvc_error_t uvc_set_analog_video_lock_status(uvc_device_handle_t *devh, uint8_t status); 721 | 722 | uvc_error_t uvc_get_input_select(uvc_device_handle_t *devh, uint8_t* selector, enum uvc_req_code req_code); 723 | uvc_error_t uvc_set_input_select(uvc_device_handle_t *devh, uint8_t selector); 724 | /* end AUTO-GENERATED control accessors */ 725 | 726 | void uvc_perror(uvc_error_t err, const char *msg); 727 | const char* uvc_strerror(uvc_error_t err); 728 | void uvc_print_diag(uvc_device_handle_t *devh, FILE *stream); 729 | void uvc_print_stream_ctrl(uvc_stream_ctrl_t *ctrl, FILE *stream); 730 | 731 | uvc_frame_t *uvc_allocate_frame(size_t data_bytes); 732 | void uvc_free_frame(uvc_frame_t *frame); 733 | 734 | uvc_error_t uvc_duplicate_frame(uvc_frame_t *in, uvc_frame_t *out); 735 | 736 | uvc_error_t uvc_yuyv2rgb(uvc_frame_t *in, uvc_frame_t *out); 737 | uvc_error_t uvc_uyvy2rgb(uvc_frame_t *in, uvc_frame_t *out); 738 | uvc_error_t uvc_any2rgb(uvc_frame_t *in, uvc_frame_t *out); 739 | 740 | uvc_error_t uvc_yuyv2bgr(uvc_frame_t *in, uvc_frame_t *out); 741 | uvc_error_t uvc_uyvy2bgr(uvc_frame_t *in, uvc_frame_t *out); 742 | uvc_error_t uvc_any2bgr(uvc_frame_t *in, uvc_frame_t *out); 743 | 744 | uvc_error_t uvc_yuyv2y(uvc_frame_t *in, uvc_frame_t *out); 745 | uvc_error_t uvc_yuyv2uv(uvc_frame_t *in, uvc_frame_t *out); 746 | 747 | #ifdef LIBUVC_HAS_JPEG 748 | uvc_error_t uvc_mjpeg2rgb(uvc_frame_t *in, uvc_frame_t *out); 749 | #endif 750 | 751 | #ifdef __cplusplus 752 | } 753 | #endif 754 | 755 | #endif // !def(LIBUVC_H) 756 | 757 | -------------------------------------------------------------------------------- /include/libuvc/libuvc_internal.h: -------------------------------------------------------------------------------- 1 | /** @file libuvc_internal.h 2 | * @brief Implementation-specific UVC constants and structures. 3 | * @cond include_hidden 4 | */ 5 | #ifndef LIBUVC_INTERNAL_H 6 | #define LIBUVC_INTERNAL_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "utlist.h" 16 | 17 | #define DEBUG_PTS_LEN (60 * 200) 18 | /** Converts an unaligned four-byte little-endian integer into an int32 */ 19 | #define DW_TO_INT(p) ((p)[0] | ((p)[1] << 8) | ((p)[2] << 16) | ((p)[3] << 24)) 20 | /** Converts an unaligned two-byte little-endian integer into an int16 */ 21 | #define SW_TO_SHORT(p) ((p)[0] | ((p)[1] << 8)) 22 | /** Converts an int16 into an unaligned two-byte little-endian integer */ 23 | #define SHORT_TO_SW(s, p) \ 24 | (p)[0] = (s); \ 25 | (p)[1] = (s) >> 8; 26 | /** Converts an int32 into an unaligned four-byte little-endian integer */ 27 | #define INT_TO_DW(i, p) \ 28 | (p)[0] = (i); \ 29 | (p)[1] = (i) >> 8; \ 30 | (p)[2] = (i) >> 16; \ 31 | (p)[3] = (i) >> 24; 32 | 33 | /** Selects the nth item in a doubly linked list. n=-1 selects the last item. */ 34 | #define DL_NTH(head, out, n) \ 35 | do { \ 36 | int dl_nth_i = 0; \ 37 | LDECLTYPE(head) dl_nth_p = (head); \ 38 | if ((n) < 0) { \ 39 | while (dl_nth_p && dl_nth_i > (n)) { \ 40 | dl_nth_p = dl_nth_p->prev; \ 41 | dl_nth_i--; \ 42 | } \ 43 | } else { \ 44 | while (dl_nth_p && dl_nth_i < (n)) { \ 45 | dl_nth_p = dl_nth_p->next; \ 46 | dl_nth_i++; \ 47 | } \ 48 | } \ 49 | (out) = dl_nth_p; \ 50 | } while (0); 51 | 52 | #ifdef UVC_DEBUGGING 53 | #include 54 | #define UVC_DEBUG(format, ...) fprintf(stderr, "[%s:%d/%s] " format "\n", basename(__FILE__), __LINE__, __FUNCTION__, ##__VA_ARGS__) 55 | #define UVC_ENTER() fprintf(stderr, "[%s:%d] begin %s\n", basename(__FILE__), __LINE__, __FUNCTION__) 56 | #define UVC_EXIT(code) fprintf(stderr, "[%s:%d] end %s (%d)\n", basename(__FILE__), __LINE__, __FUNCTION__, code) 57 | #define UVC_EXIT_VOID() fprintf(stderr, "[%s:%d] end %s\n", basename(__FILE__), __LINE__, __FUNCTION__) 58 | #else 59 | #define UVC_DEBUG(format, ...) 60 | #define UVC_ENTER() 61 | #define UVC_EXIT_VOID() 62 | #define UVC_EXIT(code) 63 | #endif 64 | 65 | /* http://stackoverflow.com/questions/19452971/array-size-macro-that-rejects-pointers */ 66 | #define IS_INDEXABLE(arg) (sizeof(arg[0])) 67 | #define IS_ARRAY(arg) (IS_INDEXABLE(arg) && (((void *) &arg) == ((void *) arg))) 68 | #define ARRAYSIZE(arr) (sizeof(arr) / (IS_ARRAY(arr) ? sizeof(arr[0]) : 0)) 69 | 70 | /** Video interface subclass code (A.2) */ 71 | enum uvc_int_subclass_code { 72 | UVC_SC_UNDEFINED = 0x00, 73 | UVC_SC_VIDEOCONTROL = 0x01, 74 | UVC_SC_VIDEOSTREAMING = 0x02, 75 | UVC_SC_VIDEO_INTERFACE_COLLECTION = 0x03 76 | }; 77 | 78 | /** Video interface protocol code (A.3) */ 79 | enum uvc_int_proto_code { 80 | UVC_PC_PROTOCOL_UNDEFINED = 0x00 81 | }; 82 | 83 | /** VideoControl interface descriptor subtype (A.5) */ 84 | enum uvc_vc_desc_subtype { 85 | UVC_VC_DESCRIPTOR_UNDEFINED = 0x00, 86 | UVC_VC_HEADER = 0x01, 87 | UVC_VC_INPUT_TERMINAL = 0x02, 88 | UVC_VC_OUTPUT_TERMINAL = 0x03, 89 | UVC_VC_SELECTOR_UNIT = 0x04, 90 | UVC_VC_PROCESSING_UNIT = 0x05, 91 | UVC_VC_EXTENSION_UNIT = 0x06 92 | }; 93 | 94 | /** UVC endpoint descriptor subtype (A.7) */ 95 | enum uvc_ep_desc_subtype { 96 | UVC_EP_UNDEFINED = 0x00, 97 | UVC_EP_GENERAL = 0x01, 98 | UVC_EP_ENDPOINT = 0x02, 99 | UVC_EP_INTERRUPT = 0x03 100 | }; 101 | 102 | /** VideoControl interface control selector (A.9.1) */ 103 | enum uvc_vc_ctrl_selector { 104 | UVC_VC_CONTROL_UNDEFINED = 0x00, 105 | UVC_VC_VIDEO_POWER_MODE_CONTROL = 0x01, 106 | UVC_VC_REQUEST_ERROR_CODE_CONTROL = 0x02 107 | }; 108 | 109 | /** Terminal control selector (A.9.2) */ 110 | enum uvc_term_ctrl_selector { 111 | UVC_TE_CONTROL_UNDEFINED = 0x00 112 | }; 113 | 114 | /** Selector unit control selector (A.9.3) */ 115 | enum uvc_su_ctrl_selector { 116 | UVC_SU_CONTROL_UNDEFINED = 0x00, 117 | UVC_SU_INPUT_SELECT_CONTROL = 0x01 118 | }; 119 | 120 | /** Extension unit control selector (A.9.6) */ 121 | enum uvc_xu_ctrl_selector { 122 | UVC_XU_CONTROL_UNDEFINED = 0x00 123 | }; 124 | 125 | /** VideoStreaming interface control selector (A.9.7) */ 126 | enum uvc_vs_ctrl_selector { 127 | UVC_VS_CONTROL_UNDEFINED = 0x00, 128 | UVC_VS_PROBE_CONTROL = 0x01, 129 | UVC_VS_COMMIT_CONTROL = 0x02, 130 | UVC_VS_STILL_PROBE_CONTROL = 0x03, 131 | UVC_VS_STILL_COMMIT_CONTROL = 0x04, 132 | UVC_VS_STILL_IMAGE_TRIGGER_CONTROL = 0x05, 133 | UVC_VS_STREAM_ERROR_CODE_CONTROL = 0x06, 134 | UVC_VS_GENERATE_KEY_FRAME_CONTROL = 0x07, 135 | UVC_VS_UPDATE_FRAME_SEGMENT_CONTROL = 0x08, 136 | UVC_VS_SYNC_DELAY_CONTROL = 0x09 137 | }; 138 | 139 | /** Status packet type (2.4.2.2) */ 140 | enum uvc_status_type { 141 | UVC_STATUS_TYPE_CONTROL = 1, 142 | UVC_STATUS_TYPE_STREAMING = 2 143 | }; 144 | 145 | /** Payload header flags (2.4.3.3) */ 146 | #define UVC_STREAM_EOH (1 << 7) 147 | #define UVC_STREAM_ERR (1 << 6) 148 | #define UVC_STREAM_STI (1 << 5) 149 | #define UVC_STREAM_RES (1 << 4) 150 | #define UVC_STREAM_SCR (1 << 3) 151 | #define UVC_STREAM_PTS (1 << 2) 152 | #define UVC_STREAM_EOF (1 << 1) 153 | #define UVC_STREAM_FID (1 << 0) 154 | 155 | /** Control capabilities (4.1.2) */ 156 | #define UVC_CONTROL_CAP_GET (1 << 0) 157 | #define UVC_CONTROL_CAP_SET (1 << 1) 158 | #define UVC_CONTROL_CAP_DISABLED (1 << 2) 159 | #define UVC_CONTROL_CAP_AUTOUPDATE (1 << 3) 160 | #define UVC_CONTROL_CAP_ASYNCHRONOUS (1 << 4) 161 | 162 | struct uvc_streaming_interface; 163 | struct uvc_device_info; 164 | 165 | /** VideoStream interface */ 166 | typedef struct uvc_streaming_interface { 167 | struct uvc_device_info *parent; 168 | struct uvc_streaming_interface *prev, *next; 169 | /** Interface number */ 170 | uint8_t bInterfaceNumber; 171 | /** Video formats that this interface provides */ 172 | struct uvc_format_desc *format_descs; 173 | /** USB endpoint to use when communicating with this interface */ 174 | uint8_t bEndpointAddress; 175 | uint8_t bTerminalLink; 176 | } uvc_streaming_interface_t; 177 | 178 | /** VideoControl interface */ 179 | typedef struct uvc_control_interface { 180 | struct uvc_device_info *parent; 181 | struct uvc_input_terminal *input_term_descs; 182 | // struct uvc_output_terminal *output_term_descs; 183 | struct uvc_selector_unit *selector_unit_descs; 184 | struct uvc_processing_unit *processing_unit_descs; 185 | struct uvc_extension_unit *extension_unit_descs; 186 | uint16_t bcdUVC; 187 | uint32_t dwClockFrequency; 188 | uint8_t bEndpointAddress; 189 | /** Interface number */ 190 | uint8_t bInterfaceNumber; 191 | } uvc_control_interface_t; 192 | 193 | struct uvc_stream_ctrl; 194 | 195 | struct uvc_device { 196 | struct uvc_context *ctx; 197 | int ref; 198 | libusb_device *usb_dev; 199 | }; 200 | 201 | typedef struct uvc_device_info { 202 | /** Configuration descriptor for USB device */ 203 | struct libusb_config_descriptor *config; 204 | /** VideoControl interface provided by device */ 205 | uvc_control_interface_t ctrl_if; 206 | /** VideoStreaming interfaces on the device */ 207 | uvc_streaming_interface_t *stream_ifs; 208 | } uvc_device_info_t; 209 | 210 | /* 211 | set a high number of transfer buffers. This uses a lot of ram, but 212 | avoids problems with scheduling delays on slow boards causing missed 213 | transfers. A better approach may be to make the transfer thread FIFO 214 | scheduled (if we have root). 215 | We could/should change this to allow reduce it to, say, 5 by default 216 | and then allow the user to change the number of buffers as required. 217 | */ 218 | #ifdef __APPLE__ 219 | #define LIBUVC_NUM_TRANSFER_BUFS 40 220 | #elif WIN32 221 | #define LIBUVC_NUM_TRANSFER_BUFS 50 222 | #else 223 | #define LIBUVC_NUM_TRANSFER_BUFS 100 224 | #endif 225 | 226 | #define LIBUVC_XFER_BUF_SIZE ( 16 * 1024 * 1024 ) 227 | 228 | struct uvc_stream_handle { 229 | struct uvc_device_handle *devh; 230 | struct uvc_stream_handle *prev, *next; 231 | struct uvc_streaming_interface *stream_if; 232 | 233 | /** if true, stream is running (streaming video to host) */ 234 | uint8_t running; 235 | /** Current control block */ 236 | struct uvc_stream_ctrl cur_ctrl; 237 | 238 | /* listeners may only access hold*, and only when holding a 239 | * lock on cb_mutex (probably signaled with cb_cond) */ 240 | int8_t fid; 241 | uint32_t seq, hold_seq; 242 | uint32_t pts, hold_pts; 243 | uint32_t last_scr, hold_last_scr; 244 | size_t got_bytes, hold_bytes; 245 | uint8_t *outbuf, *holdbuf; 246 | pthread_mutex_t cb_mutex; 247 | pthread_cond_t cb_cond; 248 | pthread_t cb_thread; 249 | uint32_t last_polled_seq; 250 | uvc_frame_callback_t *user_cb; 251 | void *user_ptr; 252 | struct libusb_transfer *transfers[LIBUVC_NUM_TRANSFER_BUFS]; 253 | uint8_t *transfer_bufs[LIBUVC_NUM_TRANSFER_BUFS]; 254 | struct uvc_frame frame; 255 | enum uvc_frame_format frame_format; 256 | int flying_xfers; 257 | /** Start time of device clock in host time, in us */ 258 | int64_t dev_clk_start_host_us; 259 | int64_t last_iso_ts_us; 260 | int64_t frame_ts_us; 261 | int64_t hold_frame_ts_us; 262 | int64_t pts_time_base; 263 | /** Transfer duration of frame in microframes */ 264 | int frame_xfer_len_mf; 265 | int packets_per_iso_xfer; 266 | int64_t pts_diff[DEBUG_PTS_LEN]; 267 | int pts_start; 268 | int pts_end; 269 | int64_t trts, hold_trts; 270 | int64_t avg_diff; 271 | int64_t initial_avg_diff; 272 | int64_t initial_host_ts; 273 | int64_t diff_measures; 274 | uint64_t corrected_clock_freq; 275 | }; 276 | 277 | /** Handle on an open UVC device 278 | * 279 | * @todo move most of this into a uvc_device struct? 280 | */ 281 | struct uvc_device_handle { 282 | struct uvc_device *dev; 283 | struct uvc_device_handle *prev, *next; 284 | /** Underlying USB device handle */ 285 | libusb_device_handle *usb_devh; 286 | struct uvc_device_info *info; 287 | struct libusb_transfer *status_xfer; 288 | uint8_t status_buf[32]; 289 | /** Function to call when we receive status updates from the camera */ 290 | uvc_status_callback_t *status_cb; 291 | void *status_user_ptr; 292 | /** Function to call when we receive button events from the camera */ 293 | uvc_button_callback_t *button_cb; 294 | void *button_user_ptr; 295 | 296 | uvc_stream_handle_t *streams; 297 | /** Whether the camera is an iSight that sends one header per frame */ 298 | uint8_t is_isight; 299 | uint32_t claimed; 300 | }; 301 | 302 | /** Context within which we communicate with devices */ 303 | struct uvc_context { 304 | /** Underlying context for USB communication */ 305 | struct libusb_context *usb_ctx; 306 | /** True iff libuvc initialized the underlying USB context */ 307 | uint8_t own_usb_ctx; 308 | /** List of open devices in this context */ 309 | uvc_device_handle_t *open_devices; 310 | pthread_t handler_thread; 311 | int kill_handler_thread; 312 | }; 313 | 314 | uvc_error_t uvc_query_stream_ctrl( 315 | uvc_device_handle_t *devh, 316 | uvc_stream_ctrl_t *ctrl, 317 | uint8_t probe, 318 | enum uvc_req_code req); 319 | 320 | void uvc_start_handler_thread(uvc_context_t *ctx); 321 | uvc_error_t uvc_claim_if(uvc_device_handle_t *devh, int idx, int should_detach_kernel_driver); 322 | uvc_error_t uvc_release_if(uvc_device_handle_t *devh, int idx); 323 | 324 | #endif // !def(LIBUVC_INTERNAL_H) 325 | /** @endcond */ 326 | 327 | -------------------------------------------------------------------------------- /include/utlist.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2007-2010, Troy D. Hanson http://uthash.sourceforge.net 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 12 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 13 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 14 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 15 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 16 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 17 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 18 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 19 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 20 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | #ifndef UTLIST_H 25 | #define UTLIST_H 26 | 27 | #define UTLIST_VERSION 1.9.1 28 | 29 | /* 30 | * This file contains macros to manipulate singly and doubly-linked lists. 31 | * 32 | * 1. LL_ macros: singly-linked lists. 33 | * 2. DL_ macros: doubly-linked lists. 34 | * 3. CDL_ macros: circular doubly-linked lists. 35 | * 36 | * To use singly-linked lists, your structure must have a "next" pointer. 37 | * To use doubly-linked lists, your structure must "prev" and "next" pointers. 38 | * Either way, the pointer to the head of the list must be initialized to NULL. 39 | * 40 | * ----------------.EXAMPLE ------------------------- 41 | * struct item { 42 | * int id; 43 | * struct item *prev, *next; 44 | * } 45 | * 46 | * struct item *list = NULL: 47 | * 48 | * int main() { 49 | * struct item *item; 50 | * ... allocate and populate item ... 51 | * DL_APPEND(list, item); 52 | * } 53 | * -------------------------------------------------- 54 | * 55 | * For doubly-linked lists, the append and delete macros are O(1) 56 | * For singly-linked lists, append and delete are O(n) but prepend is O(1) 57 | * The sort macro is O(n log(n)) for all types of single/double/circular lists. 58 | */ 59 | 60 | /* These macros use decltype or the earlier __typeof GNU extension. 61 | As decltype is only available in newer compilers (VS2010 or gcc 4.3+ 62 | when compiling c++ code), this code uses whatever method is needed 63 | or, for VS2008 where neither is available, uses casting workarounds. */ 64 | #ifdef _MSC_VER /* MS compiler */ 65 | #if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ 66 | #define LDECLTYPE(x) decltype(x) 67 | #else /* VS2008 or older (or VS2010 in C mode) */ 68 | #define NO_DECLTYPE 69 | #define LDECLTYPE(x) char* 70 | #endif 71 | #else /* GNU, Sun and other compilers */ 72 | #define LDECLTYPE(x) __typeof(x) 73 | #endif 74 | 75 | /* for VS2008 we use some workarounds to get around the lack of decltype, 76 | * namely, we always reassign our tmp variable to the list head if we need 77 | * to dereference its prev/next pointers, and save/restore the real head.*/ 78 | #ifdef NO_DECLTYPE 79 | #define _SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); } 80 | #define _NEXT(elt,list) ((char*)((list)->next)) 81 | #define _NEXTASGN(elt,list,to) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); } 82 | #define _PREV(elt,list) ((char*)((list)->prev)) 83 | #define _PREVASGN(elt,list,to) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); } 84 | #define _RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; } 85 | #define _CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); } 86 | #else 87 | #define _SV(elt,list) 88 | #define _NEXT(elt,list) ((elt)->next) 89 | #define _NEXTASGN(elt,list,to) ((elt)->next)=(to) 90 | #define _PREV(elt,list) ((elt)->prev) 91 | #define _PREVASGN(elt,list,to) ((elt)->prev)=(to) 92 | #define _RS(list) 93 | #define _CASTASGN(a,b) (a)=(b) 94 | #endif 95 | 96 | /****************************************************************************** 97 | * The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort * 98 | * Unwieldy variable names used here to avoid shadowing passed-in variables. * 99 | *****************************************************************************/ 100 | #define LL_SORT(list, cmp) \ 101 | do { \ 102 | LDECLTYPE(list) _ls_p; \ 103 | LDECLTYPE(list) _ls_q; \ 104 | LDECLTYPE(list) _ls_e; \ 105 | LDECLTYPE(list) _ls_tail; \ 106 | LDECLTYPE(list) _ls_oldhead; \ 107 | LDECLTYPE(list) _tmp; \ 108 | int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ 109 | if (list) { \ 110 | _ls_insize = 1; \ 111 | _ls_looping = 1; \ 112 | while (_ls_looping) { \ 113 | _CASTASGN(_ls_p,list); \ 114 | _CASTASGN(_ls_oldhead,list); \ 115 | list = NULL; \ 116 | _ls_tail = NULL; \ 117 | _ls_nmerges = 0; \ 118 | while (_ls_p) { \ 119 | _ls_nmerges++; \ 120 | _ls_q = _ls_p; \ 121 | _ls_psize = 0; \ 122 | for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ 123 | _ls_psize++; \ 124 | _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); \ 125 | if (!_ls_q) break; \ 126 | } \ 127 | _ls_qsize = _ls_insize; \ 128 | while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ 129 | if (_ls_psize == 0) { \ 130 | _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ 131 | } else if (_ls_qsize == 0 || !_ls_q) { \ 132 | _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ 133 | } else if (cmp(_ls_p,_ls_q) <= 0) { \ 134 | _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ 135 | } else { \ 136 | _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ 137 | } \ 138 | if (_ls_tail) { \ 139 | _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e); _RS(list); \ 140 | } else { \ 141 | _CASTASGN(list,_ls_e); \ 142 | } \ 143 | _ls_tail = _ls_e; \ 144 | } \ 145 | _ls_p = _ls_q; \ 146 | } \ 147 | _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL); _RS(list); \ 148 | if (_ls_nmerges <= 1) { \ 149 | _ls_looping=0; \ 150 | } \ 151 | _ls_insize *= 2; \ 152 | } \ 153 | } else _tmp=NULL; /* quiet gcc unused variable warning */ \ 154 | } while (0) 155 | 156 | #define DL_SORT(list, cmp) \ 157 | do { \ 158 | LDECLTYPE(list) _ls_p; \ 159 | LDECLTYPE(list) _ls_q; \ 160 | LDECLTYPE(list) _ls_e; \ 161 | LDECLTYPE(list) _ls_tail; \ 162 | LDECLTYPE(list) _ls_oldhead; \ 163 | LDECLTYPE(list) _tmp; \ 164 | int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ 165 | if (list) { \ 166 | _ls_insize = 1; \ 167 | _ls_looping = 1; \ 168 | while (_ls_looping) { \ 169 | _CASTASGN(_ls_p,list); \ 170 | _CASTASGN(_ls_oldhead,list); \ 171 | list = NULL; \ 172 | _ls_tail = NULL; \ 173 | _ls_nmerges = 0; \ 174 | while (_ls_p) { \ 175 | _ls_nmerges++; \ 176 | _ls_q = _ls_p; \ 177 | _ls_psize = 0; \ 178 | for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ 179 | _ls_psize++; \ 180 | _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); \ 181 | if (!_ls_q) break; \ 182 | } \ 183 | _ls_qsize = _ls_insize; \ 184 | while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ 185 | if (_ls_psize == 0) { \ 186 | _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ 187 | } else if (_ls_qsize == 0 || !_ls_q) { \ 188 | _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ 189 | } else if (cmp(_ls_p,_ls_q) <= 0) { \ 190 | _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ 191 | } else { \ 192 | _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ 193 | } \ 194 | if (_ls_tail) { \ 195 | _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e); _RS(list); \ 196 | } else { \ 197 | _CASTASGN(list,_ls_e); \ 198 | } \ 199 | _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail); _RS(list); \ 200 | _ls_tail = _ls_e; \ 201 | } \ 202 | _ls_p = _ls_q; \ 203 | } \ 204 | _CASTASGN(list->prev, _ls_tail); \ 205 | _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL); _RS(list); \ 206 | if (_ls_nmerges <= 1) { \ 207 | _ls_looping=0; \ 208 | } \ 209 | _ls_insize *= 2; \ 210 | } \ 211 | } else _tmp=NULL; /* quiet gcc unused variable warning */ \ 212 | } while (0) 213 | 214 | #define CDL_SORT(list, cmp) \ 215 | do { \ 216 | LDECLTYPE(list) _ls_p; \ 217 | LDECLTYPE(list) _ls_q; \ 218 | LDECLTYPE(list) _ls_e; \ 219 | LDECLTYPE(list) _ls_tail; \ 220 | LDECLTYPE(list) _ls_oldhead; \ 221 | LDECLTYPE(list) _tmp; \ 222 | LDECLTYPE(list) _tmp2; \ 223 | int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ 224 | if (list) { \ 225 | _ls_insize = 1; \ 226 | _ls_looping = 1; \ 227 | while (_ls_looping) { \ 228 | _CASTASGN(_ls_p,list); \ 229 | _CASTASGN(_ls_oldhead,list); \ 230 | list = NULL; \ 231 | _ls_tail = NULL; \ 232 | _ls_nmerges = 0; \ 233 | while (_ls_p) { \ 234 | _ls_nmerges++; \ 235 | _ls_q = _ls_p; \ 236 | _ls_psize = 0; \ 237 | for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ 238 | _ls_psize++; \ 239 | _SV(_ls_q,list); \ 240 | if (_NEXT(_ls_q,list) == _ls_oldhead) { \ 241 | _ls_q = NULL; \ 242 | } else { \ 243 | _ls_q = _NEXT(_ls_q,list); \ 244 | } \ 245 | _RS(list); \ 246 | if (!_ls_q) break; \ 247 | } \ 248 | _ls_qsize = _ls_insize; \ 249 | while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ 250 | if (_ls_psize == 0) { \ 251 | _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ 252 | if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ 253 | } else if (_ls_qsize == 0 || !_ls_q) { \ 254 | _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ 255 | if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ 256 | } else if (cmp(_ls_p,_ls_q) <= 0) { \ 257 | _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \ 258 | if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ 259 | } else { \ 260 | _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \ 261 | if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ 262 | } \ 263 | if (_ls_tail) { \ 264 | _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e); _RS(list); \ 265 | } else { \ 266 | _CASTASGN(list,_ls_e); \ 267 | } \ 268 | _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail); _RS(list); \ 269 | _ls_tail = _ls_e; \ 270 | } \ 271 | _ls_p = _ls_q; \ 272 | } \ 273 | _CASTASGN(list->prev,_ls_tail); \ 274 | _CASTASGN(_tmp2,list); \ 275 | _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_tmp2); _RS(list); \ 276 | if (_ls_nmerges <= 1) { \ 277 | _ls_looping=0; \ 278 | } \ 279 | _ls_insize *= 2; \ 280 | } \ 281 | } else _tmp=NULL; /* quiet gcc unused variable warning */ \ 282 | } while (0) 283 | 284 | /****************************************************************************** 285 | * singly linked list macros (non-circular) * 286 | *****************************************************************************/ 287 | #define LL_PREPEND(head,add) \ 288 | do { \ 289 | (add)->next = head; \ 290 | head = add; \ 291 | } while (0) 292 | 293 | #define LL_APPEND(head,add) \ 294 | do { \ 295 | LDECLTYPE(head) _tmp; \ 296 | (add)->next=NULL; \ 297 | if (head) { \ 298 | _tmp = head; \ 299 | while (_tmp->next) { _tmp = _tmp->next; } \ 300 | _tmp->next=(add); \ 301 | } else { \ 302 | (head)=(add); \ 303 | } \ 304 | } while (0) 305 | 306 | #define LL_DELETE(head,del) \ 307 | do { \ 308 | LDECLTYPE(head) _tmp; \ 309 | if ((head) == (del)) { \ 310 | (head)=(head)->next; \ 311 | } else { \ 312 | _tmp = head; \ 313 | while (_tmp->next && (_tmp->next != (del))) { \ 314 | _tmp = _tmp->next; \ 315 | } \ 316 | if (_tmp->next) { \ 317 | _tmp->next = ((del)->next); \ 318 | } \ 319 | } \ 320 | } while (0) 321 | 322 | /* Here are VS2008 replacements for LL_APPEND and LL_DELETE */ 323 | #define LL_APPEND_VS2008(head,add) \ 324 | do { \ 325 | if (head) { \ 326 | (add)->next = head; /* use add->next as a temp variable */ \ 327 | while ((add)->next->next) { (add)->next = (add)->next->next; } \ 328 | (add)->next->next=(add); \ 329 | } else { \ 330 | (head)=(add); \ 331 | } \ 332 | (add)->next=NULL; \ 333 | } while (0) 334 | 335 | #define LL_DELETE_VS2008(head,del) \ 336 | do { \ 337 | if ((head) == (del)) { \ 338 | (head)=(head)->next; \ 339 | } else { \ 340 | char *_tmp = (char*)(head); \ 341 | while (head->next && (head->next != (del))) { \ 342 | head = head->next; \ 343 | } \ 344 | if (head->next) { \ 345 | head->next = ((del)->next); \ 346 | } \ 347 | { \ 348 | char **_head_alias = (char**)&(head); \ 349 | *_head_alias = _tmp; \ 350 | } \ 351 | } \ 352 | } while (0) 353 | #ifdef NO_DECLTYPE 354 | #undef LL_APPEND 355 | #define LL_APPEND LL_APPEND_VS2008 356 | #undef LL_DELETE 357 | #define LL_DELETE LL_DELETE_VS2008 358 | #endif 359 | /* end VS2008 replacements */ 360 | 361 | #define LL_FOREACH(head,el) \ 362 | for(el=head;el;el=el->next) 363 | 364 | #define LL_FOREACH_SAFE(head,el,tmp) \ 365 | for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) 366 | 367 | #define LL_SEARCH_SCALAR(head,out,field,val) \ 368 | do { \ 369 | LL_FOREACH(head,out) { \ 370 | if ((out)->field == (val)) break; \ 371 | } \ 372 | } while(0) 373 | 374 | #define LL_SEARCH(head,out,elt,cmp) \ 375 | do { \ 376 | LL_FOREACH(head,out) { \ 377 | if ((cmp(out,elt))==0) break; \ 378 | } \ 379 | } while(0) 380 | 381 | /****************************************************************************** 382 | * doubly linked list macros (non-circular) * 383 | *****************************************************************************/ 384 | #define DL_PREPEND(head,add) \ 385 | do { \ 386 | (add)->next = head; \ 387 | if (head) { \ 388 | (add)->prev = (head)->prev; \ 389 | (head)->prev = (add); \ 390 | } else { \ 391 | (add)->prev = (add); \ 392 | } \ 393 | (head) = (add); \ 394 | } while (0) 395 | 396 | #define DL_APPEND(head,add) \ 397 | do { \ 398 | if (head) { \ 399 | (add)->prev = (head)->prev; \ 400 | (head)->prev->next = (add); \ 401 | (head)->prev = (add); \ 402 | (add)->next = NULL; \ 403 | } else { \ 404 | (head)=(add); \ 405 | (head)->prev = (head); \ 406 | (head)->next = NULL; \ 407 | } \ 408 | } while (0); 409 | 410 | #define DL_DELETE(head,del) \ 411 | do { \ 412 | if ((del)->prev == (del)) { \ 413 | (head)=NULL; \ 414 | } else if ((del)==(head)) { \ 415 | (del)->next->prev = (del)->prev; \ 416 | (head) = (del)->next; \ 417 | } else { \ 418 | (del)->prev->next = (del)->next; \ 419 | if ((del)->next) { \ 420 | (del)->next->prev = (del)->prev; \ 421 | } else { \ 422 | (head)->prev = (del)->prev; \ 423 | } \ 424 | } \ 425 | } while (0); 426 | 427 | 428 | #define DL_FOREACH(head,el) \ 429 | for(el=head;el;el=el->next) 430 | 431 | /* this version is safe for deleting the elements during iteration */ 432 | #define DL_FOREACH_SAFE(head,el,tmp) \ 433 | for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) 434 | 435 | /* these are identical to their singly-linked list counterparts */ 436 | #define DL_SEARCH_SCALAR LL_SEARCH_SCALAR 437 | #define DL_SEARCH LL_SEARCH 438 | 439 | /****************************************************************************** 440 | * circular doubly linked list macros * 441 | *****************************************************************************/ 442 | #define CDL_PREPEND(head,add) \ 443 | do { \ 444 | if (head) { \ 445 | (add)->prev = (head)->prev; \ 446 | (add)->next = (head); \ 447 | (head)->prev = (add); \ 448 | (add)->prev->next = (add); \ 449 | } else { \ 450 | (add)->prev = (add); \ 451 | (add)->next = (add); \ 452 | } \ 453 | (head)=(add); \ 454 | } while (0) 455 | 456 | #define CDL_DELETE(head,del) \ 457 | do { \ 458 | if ( ((head)==(del)) && ((head)->next == (head))) { \ 459 | (head) = 0L; \ 460 | } else { \ 461 | (del)->next->prev = (del)->prev; \ 462 | (del)->prev->next = (del)->next; \ 463 | if ((del) == (head)) (head)=(del)->next; \ 464 | } \ 465 | } while (0); 466 | 467 | #define CDL_FOREACH(head,el) \ 468 | for(el=head;el;el=(el->next==head ? 0L : el->next)) 469 | 470 | #define CDL_FOREACH_SAFE(head,el,tmp1,tmp2) \ 471 | for((el)=(head), ((tmp1)=(head)?((head)->prev):NULL); \ 472 | (el) && ((tmp2)=(el)->next, 1); \ 473 | ((el) = (((el)==(tmp1)) ? 0L : (tmp2)))) 474 | 475 | #define CDL_SEARCH_SCALAR(head,out,field,val) \ 476 | do { \ 477 | CDL_FOREACH(head,out) { \ 478 | if ((out)->field == (val)) break; \ 479 | } \ 480 | } while(0) 481 | 482 | #define CDL_SEARCH(head,out,elt,cmp) \ 483 | do { \ 484 | CDL_FOREACH(head,out) { \ 485 | if ((cmp(out,elt))==0) break; \ 486 | } \ 487 | } while(0) 488 | 489 | #endif /* UTLIST_H */ 490 | 491 | -------------------------------------------------------------------------------- /src/ctrl-gen.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import print_function 3 | from collections import OrderedDict 4 | import getopt 5 | import sys 6 | import yaml 7 | 8 | class quoted(str): pass 9 | 10 | def quoted_presenter(dumper, data): 11 | return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='"') 12 | yaml.add_representer(quoted, quoted_presenter) 13 | 14 | class literal(str): pass 15 | 16 | def literal_presenter(dumper, data): 17 | return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='|') 18 | yaml.add_representer(literal, literal_presenter) 19 | 20 | def ordered_dict_presenter(dumper, data): 21 | return dumper.represent_dict(data.items()) 22 | yaml.add_representer(OrderedDict, ordered_dict_presenter) 23 | 24 | def dict_constructor(loader, node): 25 | return OrderedDict(loader.construct_pairs(node)) 26 | _mapping_tag = yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG 27 | yaml.add_constructor(_mapping_tag, dict_constructor) 28 | 29 | class IntField(object): 30 | def __init__(self, name, position, length, signed): 31 | self.name = name 32 | self.position = position 33 | self.length = length 34 | self.signed = signed 35 | 36 | if not self.length in [1, 2, 4]: 37 | raise Exception("bad length " + str(self.length)) 38 | 39 | self.user_type = ('u' if not signed else '') + 'int' + str(length * 8) + '_t' 40 | 41 | def getter_sig(self): 42 | return "{0}* {1}".format(self.user_type, self.name) 43 | 44 | def unpack(self): 45 | if self.length == 1: 46 | return "*{0} = data[{1}];".format(self.name, self.position) 47 | elif self.length == 2: 48 | return "*{0} = SW_TO_SHORT(data + {1});".format(self.name, self.position) 49 | elif self.length == 4: 50 | return "*{0} = DW_TO_INT(data + {1});".format(self.name, self.position) 51 | 52 | def setter_sig(self): 53 | return "{0} {1}".format(self.user_type, self.name) 54 | 55 | def pack(self): 56 | if self.length == 1: 57 | return "data[{0}] = {1};".format(self.position, self.name) 58 | elif self.length == 2: 59 | return "SHORT_TO_SW({0}, data + {1});".format(self.name, self.position) 60 | elif self.length == 4: 61 | return "INT_TO_DW({0}, data + {1});".format(self.name, self.position) 62 | 63 | def spec(self): 64 | rep = [('position', self.position), ('length', self.length)] 65 | if self.signed: 66 | rep.append(('signed', True)) 67 | return rep 68 | 69 | @staticmethod 70 | def load(spec): 71 | return IntField(spec['name'], spec['position'], spec['length'], spec['signed'] if signed in spec else False) 72 | 73 | def load_field(name, spec): 74 | if spec['type'] == 'int': 75 | return IntField(name, spec['position'], spec['length'], spec.get('signed', False)) 76 | else: 77 | raise Exception("unknown field type '{0}'".format(spec['type'])) 78 | 79 | GETTER_TEMPLATE = """/** @ingroup ctrl 80 | * {gen_doc} 81 | * @param devh UVC device handle 82 | * {args_doc} 83 | * @param req_code UVC_GET_* request to execute 84 | */ 85 | uvc_error_t uvc_get_{control_name}(uvc_device_handle_t *devh, {args_signature}, enum uvc_req_code req_code) {{ 86 | uint8_t data[{control_length}]; 87 | uvc_error_t ret; 88 | 89 | ret = libusb_control_transfer( 90 | devh->usb_devh, 91 | REQ_TYPE_GET, req_code, 92 | {control_code} << 8, 93 | {unit_fn} << 8 | devh->info->ctrl_if.bInterfaceNumber, 94 | data, 95 | sizeof(data), 96 | 0); 97 | 98 | if (ret == sizeof(data)) {{ 99 | {unpack} 100 | return UVC_SUCCESS; 101 | }} else {{ 102 | return ret; 103 | }} 104 | }} 105 | """ 106 | 107 | SETTER_TEMPLATE = """/** @ingroup ctrl 108 | * {gen_doc} 109 | * @param devh UVC device handle 110 | * {args_doc} 111 | */ 112 | uvc_error_t uvc_set_{control_name}(uvc_device_handle_t *devh, {args_signature}) {{ 113 | uint8_t data[{control_length}]; 114 | uvc_error_t ret; 115 | 116 | {pack} 117 | 118 | ret = libusb_control_transfer( 119 | devh->usb_devh, 120 | REQ_TYPE_SET, UVC_SET_CUR, 121 | {control_code} << 8, 122 | {unit_fn} << 8 | devh->info->ctrl_if.bInterfaceNumber, 123 | data, 124 | sizeof(data), 125 | 0); 126 | 127 | if (ret == sizeof(data)) 128 | return UVC_SUCCESS; 129 | else 130 | return ret; 131 | }} 132 | """ 133 | 134 | def gen_decl(unit_name, unit, control_name, control): 135 | fields = [(load_field(field_name, field_details), field_details['doc']) for field_name, field_details in control['fields'].items()] if 'fields' in control else [] 136 | 137 | get_args_signature = ', '.join([field.getter_sig() for (field, desc) in fields]) 138 | set_args_signature = ', '.join([field.setter_sig() for (field, desc) in fields]) 139 | 140 | return "uvc_error_t uvc_get_{function_name}(uvc_device_handle_t *devh, {args_signature}, enum uvc_req_code req_code);\n".format(**{ 141 | "function_name": control_name, 142 | "args_signature": get_args_signature 143 | }) + "uvc_error_t uvc_set_{function_name}(uvc_device_handle_t *devh, {args_signature});\n".format(**{ 144 | "function_name": control_name, 145 | "args_signature": set_args_signature 146 | }) 147 | 148 | def gen_ctrl(unit_name, unit, control_name, control): 149 | fields = [(load_field(field_name, field_details), field_details['doc']) for field_name, field_details in control['fields'].items()] if 'fields' in control else [] 150 | 151 | get_args_signature = ', '.join([field.getter_sig() for (field, desc) in fields]) 152 | set_args_signature = ', '.join([field.setter_sig() for (field, desc) in fields]) 153 | unpack = "\n ".join([field.unpack() for (field, desc) in fields]) 154 | pack = "\n ".join([field.pack() for (field, desc) in fields]) 155 | 156 | get_gen_doc_raw = None 157 | set_gen_doc_raw = None 158 | 159 | if 'doc' in control: 160 | doc = control['doc'] 161 | 162 | if isinstance(doc, str): 163 | get_gen_doc_raw = "\n * ".join(doc.splitlines()) 164 | set_gen_doc_raw = get_gen_doc_raw 165 | else: 166 | if 'get' in doc: 167 | get_gen_doc_raw = "\n * ".join(doc['get'].splitlines()) 168 | if 'set' in doc: 169 | set_gen_doc_raw = "\n * ".join(doc['set'].splitlines()) 170 | 171 | if get_gen_doc_raw is not None: 172 | get_gen_doc = get_gen_doc_raw.format(gets_sets='Reads') 173 | else: 174 | get_gen_doc = '@brief Reads the ' + control['control'] + ' control.' 175 | 176 | if set_gen_doc_raw is not None: 177 | set_gen_doc = set_gen_doc_raw.format(gets_sets='Sets') 178 | else: 179 | set_gen_doc = '@brief Sets the ' + control['control'] + ' control.' 180 | 181 | get_args_doc = "\n * ".join(["@param[out] {0} {1}".format(field.name, desc) for (field, desc) in fields]) 182 | set_args_doc = "\n * ".join(["@param {0} {1}".format(field.name, desc) for (field, desc) in fields]) 183 | 184 | control_code = 'UVC_' + unit['control_prefix'] + '_' + control['control'] + '_CONTROL' 185 | 186 | unit_fn = "uvc_get_camera_terminal(devh)->bTerminalID" if (unit_name == "camera_terminal") else ("uvc_get_" + unit_name + "s(devh)->bUnitID") 187 | 188 | return GETTER_TEMPLATE.format( 189 | unit=unit, 190 | unit_fn=unit_fn, 191 | control_name=control_name, 192 | control_code=control_code, 193 | control_length=control['length'], 194 | args_signature=get_args_signature, 195 | args_doc=get_args_doc, 196 | gen_doc=get_gen_doc, 197 | unpack=unpack) + "\n\n" + SETTER_TEMPLATE.format( 198 | unit=unit, 199 | unit_fn=unit_fn, 200 | control_name=control_name, 201 | control_code=control_code, 202 | control_length=control['length'], 203 | args_signature=set_args_signature, 204 | args_doc=set_args_doc, 205 | gen_doc=set_gen_doc, 206 | pack=pack 207 | ) 208 | 209 | def export_unit(unit): 210 | def fmt_doc(doc): 211 | def wrap_doc_entry(entry): 212 | if "\n" in entry: 213 | return literal(entry) 214 | else: 215 | return entry 216 | 217 | if isinstance(doc, str): 218 | return wrap_doc_entry(doc) 219 | else: 220 | return OrderedDict([(mode, wrap_doc_entry(text)) for mode, text in doc.items()]) 221 | 222 | def fmt_ctrl(control_name, control_details): 223 | contents = OrderedDict() 224 | contents['control'] = control_details['control'] 225 | contents['length'] = control_details['length'] 226 | contents['fields'] = control_details['fields'] 227 | 228 | if 'doc' in control_details: 229 | contents['doc'] = fmt_doc(control_details['doc']) 230 | 231 | return (control_name, contents) 232 | 233 | unit_out = OrderedDict() 234 | unit_out['type'] = unit['type'] 235 | if 'guid' in unit: 236 | unit_out['guid'] = unit['guid'] 237 | if 'description' in unit: 238 | unit_out['description'] = unit['description'] 239 | if 'control_prefix' in unit: 240 | unit_out['control_prefix'] = unit['control_prefix'] 241 | unit_out['controls'] = OrderedDict([fmt_ctrl(ctrl_name, ctrl_details) for ctrl_name, ctrl_details in unit['controls'].items()]) 242 | return unit_out 243 | 244 | if __name__ == '__main__': 245 | try: 246 | opts, args = getopt.getopt(sys.argv[1:], "hi:", ["help", "input="]) 247 | except getopt.GetoptError as err: 248 | print(str(err)) 249 | usage() 250 | sys.exit(-1) 251 | 252 | inputs = [] 253 | 254 | for opt, val in opts: 255 | if opt in ('-h', '--help'): 256 | usage() 257 | sys.exit(0) 258 | elif opt in ('-i', '--input'): 259 | inputs.append(val) 260 | 261 | mode = None 262 | for arg in args: 263 | if arg in ('def', 'decl', 'yaml'): 264 | if mode is None: 265 | mode = arg 266 | else: 267 | print("Can't specify more than one mode") 268 | sys.exit(-1) 269 | else: 270 | print("Invalid mode '{0}'".format(arg)) 271 | sys.exit(-1) 272 | 273 | def iterunits(): 274 | for input_file in inputs: 275 | with open(input_file, "r") as fp: 276 | units = yaml.load(fp)['units'] 277 | for unit_name, unit_details in units.iteritems(): 278 | yield unit_name, unit_details 279 | 280 | if mode == 'def': 281 | print("""/* This is an AUTO-GENERATED file! Update it with the output of `ctrl-gen.py def`. */ 282 | #include "libuvc/libuvc.h" 283 | #include "libuvc/libuvc_internal.h" 284 | 285 | static const int REQ_TYPE_SET = 0x21; 286 | static const int REQ_TYPE_GET = 0xa1; 287 | """) 288 | fun = gen_ctrl 289 | elif mode == 'decl': 290 | fun = gen_decl 291 | elif mode == 'yaml': 292 | exported_units = OrderedDict() 293 | for unit_name, unit_details in iterunits(): 294 | exported_units[unit_name] = export_unit(unit_details) 295 | 296 | yaml.dump({'units': exported_units}, sys.stdout, default_flow_style=False) 297 | sys.exit(0) 298 | 299 | for unit_name, unit_details in iterunits(): 300 | for control_name, control_details in unit_details['controls'].iteritems(): 301 | code = fun(unit_name, unit_details, control_name, control_details) 302 | print(code) 303 | -------------------------------------------------------------------------------- /src/ctrl.c: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * Software License Agreement (BSD License) 3 | * 4 | * Copyright (C) 2010-2012 Ken Tossell 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 11 | * * Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * * Redistributions in binary form must reproduce the above 14 | * copyright notice, this list of conditions and the following 15 | * disclaimer in the documentation and/or other materials provided 16 | * with the distribution. 17 | * * Neither the name of the author nor other contributors may be 18 | * used to endorse or promote products derived from this software 19 | * without specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 | * POSSIBILITY OF SUCH DAMAGE. 33 | *********************************************************************/ 34 | /** 35 | * @defgroup ctrl Video capture and processing controls 36 | * @brief Functions for manipulating device settings and stream parameters 37 | * 38 | * The `uvc_get_*` and `uvc_set_*` functions are used to read and write the settings associated 39 | * with the device's input, processing and output units. 40 | */ 41 | 42 | #include "libuvc/libuvc.h" 43 | #include "libuvc/libuvc_internal.h" 44 | 45 | static const int REQ_TYPE_SET = 0x21; 46 | static const int REQ_TYPE_GET = 0xa1; 47 | 48 | /***** GENERIC CONTROLS *****/ 49 | /** 50 | * @brief Get the length of a control on a terminal or unit. 51 | * 52 | * @param devh UVC device handle 53 | * @param unit Unit or Terminal ID; obtain this from the uvc_extension_unit_t describing the extension unit 54 | * @param ctrl Vendor-specific control number to query 55 | * @return On success, the length of the control as reported by the device. Otherwise, 56 | * a uvc_error_t error describing the error encountered. 57 | * @ingroup ctrl 58 | */ 59 | int uvc_get_ctrl_len(uvc_device_handle_t *devh, uint8_t unit, uint8_t ctrl) 60 | { 61 | unsigned char buf[2]; 62 | 63 | int ret = libusb_control_transfer( 64 | devh->usb_devh, 65 | REQ_TYPE_GET, UVC_GET_LEN, 66 | ctrl << 8, 67 | unit << 8 | devh->info->ctrl_if.bInterfaceNumber, // XXX saki 68 | buf, 69 | 2, 70 | 0 /* timeout */); 71 | 72 | if (ret < 0) 73 | return ret; 74 | else 75 | return (unsigned short)SW_TO_SHORT(buf); 76 | } 77 | 78 | /** 79 | * @brief Perform a GET_* request from an extension unit. 80 | * 81 | * @param devh UVC device handle 82 | * @param unit Unit ID; obtain this from the uvc_extension_unit_t describing the extension unit 83 | * @param ctrl Control number to query 84 | * @param data Data buffer to be filled by the device 85 | * @param len Size of data buffer 86 | * @param req_code GET_* request to execute 87 | * @return On success, the number of bytes actually transferred. Otherwise, 88 | * a uvc_error_t error describing the error encountered. 89 | * @ingroup ctrl 90 | */ 91 | int uvc_get_ctrl(uvc_device_handle_t *devh, uint8_t unit, uint8_t ctrl, void *data, int len, enum uvc_req_code req_code) 92 | { 93 | return libusb_control_transfer( 94 | devh->usb_devh, 95 | REQ_TYPE_GET, req_code, 96 | ctrl << 8, 97 | unit << 8 | devh->info->ctrl_if.bInterfaceNumber, // XXX saki 98 | data, 99 | len, 100 | 0 /* timeout */); 101 | } 102 | 103 | /** 104 | * @brief Perform a SET_CUR request to a terminal or unit. 105 | * 106 | * @param devh UVC device handle 107 | * @param unit Unit or Terminal ID 108 | * @param ctrl Control number to set 109 | * @param data Data buffer to be sent to the device 110 | * @param len Size of data buffer 111 | * @return On success, the number of bytes actually transferred. Otherwise, 112 | * a uvc_error_t error describing the error encountered. 113 | * @ingroup ctrl 114 | */ 115 | int uvc_set_ctrl(uvc_device_handle_t *devh, uint8_t unit, uint8_t ctrl, void *data, int len) 116 | { 117 | return libusb_control_transfer( 118 | devh->usb_devh, 119 | REQ_TYPE_SET, UVC_SET_CUR, 120 | ctrl << 8, 121 | unit << 8 | devh->info->ctrl_if.bInterfaceNumber, // XXX saki 122 | data, 123 | len, 124 | 0 /* timeout */); 125 | } 126 | 127 | /***** INTERFACE CONTROLS *****/ 128 | uvc_error_t uvc_get_power_mode(uvc_device_handle_t *devh, enum uvc_device_power_mode *mode, enum uvc_req_code req_code) 129 | { 130 | uint8_t mode_char; 131 | uvc_error_t ret; 132 | 133 | ret = libusb_control_transfer( 134 | devh->usb_devh, 135 | REQ_TYPE_GET, req_code, 136 | UVC_VC_VIDEO_POWER_MODE_CONTROL << 8, 137 | devh->info->ctrl_if.bInterfaceNumber, // XXX saki 138 | &mode_char, 139 | sizeof(mode_char), 140 | 0); 141 | 142 | if (ret == 1) 143 | { 144 | *mode = mode_char; 145 | return UVC_SUCCESS; 146 | } 147 | else 148 | { 149 | return ret; 150 | } 151 | } 152 | 153 | uvc_error_t uvc_set_power_mode(uvc_device_handle_t *devh, enum uvc_device_power_mode mode) 154 | { 155 | uint8_t mode_char = mode; 156 | uvc_error_t ret; 157 | 158 | ret = libusb_control_transfer( 159 | devh->usb_devh, 160 | REQ_TYPE_SET, UVC_SET_CUR, 161 | UVC_VC_VIDEO_POWER_MODE_CONTROL << 8, 162 | devh->info->ctrl_if.bInterfaceNumber, // XXX saki 163 | &mode_char, 164 | sizeof(mode_char), 165 | 0); 166 | 167 | if (ret == 1) 168 | return UVC_SUCCESS; 169 | else 170 | return ret; 171 | } 172 | 173 | /** @todo Request Error Code Control (UVC 1.5, 4.2.1.2) */ 174 | -------------------------------------------------------------------------------- /src/diag.c: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * Software License Agreement (BSD License) 3 | * 4 | * Copyright (C) 2010-2012 Ken Tossell 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 11 | * * Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * * Redistributions in binary form must reproduce the above 14 | * copyright notice, this list of conditions and the following 15 | * disclaimer in the documentation and/or other materials provided 16 | * with the distribution. 17 | * * Neither the name of the author nor other contributors may be 18 | * used to endorse or promote products derived from this software 19 | * without specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 | * POSSIBILITY OF SUCH DAMAGE. 33 | *********************************************************************/ 34 | /** 35 | * @defgroup diag Diagnostics 36 | * @brief Interpretation of devices, error codes and negotiated stream parameters 37 | */ 38 | 39 | #include "libuvc/libuvc.h" 40 | #include "libuvc/libuvc_internal.h" 41 | 42 | /** @internal */ 43 | typedef struct _uvc_error_msg 44 | { 45 | uvc_error_t err; 46 | const char *msg; 47 | } _uvc_error_msg_t; 48 | 49 | static const _uvc_error_msg_t uvc_error_msgs[] = { 50 | {UVC_SUCCESS, "Success"}, 51 | {UVC_ERROR_IO, "I/O error"}, 52 | {UVC_ERROR_INVALID_PARAM, "Invalid parameter"}, 53 | {UVC_ERROR_ACCESS, "Access denied"}, 54 | {UVC_ERROR_NO_DEVICE, "No such device"}, 55 | {UVC_ERROR_NOT_FOUND, "Not found"}, 56 | {UVC_ERROR_BUSY, "Busy"}, 57 | {UVC_ERROR_TIMEOUT, "Timeout"}, 58 | {UVC_ERROR_OVERFLOW, "Overflow"}, 59 | {UVC_ERROR_PIPE, "Pipe"}, 60 | {UVC_ERROR_INTERRUPTED, "Interrupted"}, 61 | {UVC_ERROR_NO_MEM, "Out of memory"}, 62 | {UVC_ERROR_NOT_SUPPORTED, "Not supported"}, 63 | {UVC_ERROR_INVALID_DEVICE, "Invalid device"}, 64 | {UVC_ERROR_INVALID_MODE, "Invalid mode"}, 65 | {UVC_ERROR_CALLBACK_EXISTS, "Callback exists"}}; 66 | 67 | /** @brief Print a message explaining an error in the UVC driver 68 | * @ingroup diag 69 | * 70 | * @param err UVC error code 71 | * @param msg Optional custom message, prepended to output 72 | */ 73 | void uvc_perror(uvc_error_t err, const char *msg) 74 | { 75 | if (msg && *msg) 76 | { 77 | fputs(msg, stderr); 78 | fputs(": ", stderr); 79 | } 80 | 81 | fprintf(stderr, "%s (%d)\n", uvc_strerror(err), err); 82 | } 83 | 84 | /** @brief Return a string explaining an error in the UVC driver 85 | * @ingroup diag 86 | * 87 | * @param err UVC error code 88 | * @return error message 89 | */ 90 | const char *uvc_strerror(uvc_error_t err) 91 | { 92 | size_t idx; 93 | 94 | for (idx = 0; idx < sizeof(uvc_error_msgs) / sizeof(*uvc_error_msgs); ++idx) 95 | { 96 | if (uvc_error_msgs[idx].err == err) 97 | { 98 | return uvc_error_msgs[idx].msg; 99 | } 100 | } 101 | 102 | return "Unknown error"; 103 | } 104 | 105 | /** @brief Print the values in a stream control block 106 | * @ingroup diag 107 | * 108 | * @param devh UVC device 109 | * @param stream Output stream (stderr if NULL) 110 | */ 111 | void uvc_print_stream_ctrl(uvc_stream_ctrl_t *ctrl, FILE *stream) 112 | { 113 | if (stream == NULL) 114 | stream = stderr; 115 | 116 | fprintf(stream, "bmHint: %04x\n", ctrl->bmHint); 117 | fprintf(stream, "bFormatIndex: %d\n", ctrl->bFormatIndex); 118 | fprintf(stream, "bFrameIndex: %d\n", ctrl->bFrameIndex); 119 | fprintf(stream, "dwFrameInterval: %u\n", ctrl->dwFrameInterval); 120 | fprintf(stream, "wKeyFrameRate: %d\n", ctrl->wKeyFrameRate); 121 | fprintf(stream, "wPFrameRate: %d\n", ctrl->wPFrameRate); 122 | fprintf(stream, "wCompQuality: %d\n", ctrl->wCompQuality); 123 | fprintf(stream, "wCompWindowSize: %d\n", ctrl->wCompWindowSize); 124 | fprintf(stream, "wDelay: %d\n", ctrl->wDelay); 125 | fprintf(stream, "dwMaxVideoFrameSize: %u\n", ctrl->dwMaxVideoFrameSize); 126 | fprintf(stream, "dwMaxPayloadTransferSize: %u\n", ctrl->dwMaxPayloadTransferSize); 127 | fprintf(stream, "dwClockFrequency: %u\n", ctrl->dwClockFrequency); 128 | fprintf(stream, "bInterfaceNumber: %d\n", ctrl->bInterfaceNumber); 129 | } 130 | 131 | static const char *_uvc_name_for_format_subtype(uint8_t subtype) 132 | { 133 | switch (subtype) 134 | { 135 | case UVC_VS_FORMAT_UNCOMPRESSED: 136 | return "UncompressedFormat"; 137 | case UVC_VS_FORMAT_MJPEG: 138 | return "MJPEGFormat"; 139 | case UVC_VS_FORMAT_FRAME_BASED: 140 | return "FrameFormat"; 141 | default: 142 | return "Unknown"; 143 | } 144 | } 145 | 146 | /** @brief Print camera capabilities and configuration. 147 | * @ingroup diag 148 | * 149 | * @param devh UVC device 150 | * @param stream Output stream (stderr if NULL) 151 | */ 152 | void uvc_print_diag(uvc_device_handle_t *devh, FILE *stream) 153 | { 154 | if (stream == NULL) 155 | stream = stderr; 156 | 157 | if (devh->info->ctrl_if.bcdUVC) 158 | { 159 | uvc_streaming_interface_t *stream_if; 160 | int stream_idx = 0; 161 | 162 | uvc_device_descriptor_t *desc; 163 | uvc_get_device_descriptor(devh->dev, &desc); 164 | 165 | fprintf(stream, "DEVICE CONFIGURATION (%04x:%04x/%s) ---\n", 166 | desc->idVendor, desc->idProduct, 167 | desc->serialNumber ? desc->serialNumber : "[none]"); 168 | 169 | uvc_free_device_descriptor(desc); 170 | 171 | fprintf(stream, "Status: %s\n", devh->streams ? "streaming" : "idle"); 172 | 173 | fprintf(stream, "VideoControl:\n" 174 | "\tbcdUVC: 0x%04x\n", 175 | devh->info->ctrl_if.bcdUVC); 176 | 177 | DL_FOREACH(devh->info->stream_ifs, stream_if) 178 | { 179 | uvc_format_desc_t *fmt_desc; 180 | 181 | ++stream_idx; 182 | 183 | fprintf(stream, "VideoStreaming(%d):\n" 184 | "\tbEndpointAddress: %d\n\tFormats:\n", 185 | stream_idx, stream_if->bEndpointAddress); 186 | 187 | DL_FOREACH(stream_if->format_descs, fmt_desc) 188 | { 189 | uvc_frame_desc_t *frame_desc; 190 | int i; 191 | 192 | switch (fmt_desc->bDescriptorSubtype) 193 | { 194 | case UVC_VS_FORMAT_UNCOMPRESSED: 195 | case UVC_VS_FORMAT_MJPEG: 196 | case UVC_VS_FORMAT_FRAME_BASED: 197 | fprintf(stream, 198 | "\t\%s(%d)\n" 199 | "\t\t bits per pixel: %d\n" 200 | "\t\t GUID: ", 201 | _uvc_name_for_format_subtype(fmt_desc->bDescriptorSubtype), 202 | fmt_desc->bFormatIndex, 203 | fmt_desc->bBitsPerPixel); 204 | 205 | for (i = 0; i < 16; ++i) 206 | fprintf(stream, "%02x", fmt_desc->guidFormat[i]); 207 | 208 | fprintf(stream, " (%4s)\n", fmt_desc->fourccFormat); 209 | 210 | fprintf(stream, 211 | "\t\t default frame: %d\n" 212 | "\t\t aspect ratio: %dx%d\n" 213 | "\t\t interlace flags: %02x\n" 214 | "\t\t copy protect: %02x\n", 215 | fmt_desc->bDefaultFrameIndex, 216 | fmt_desc->bAspectRatioX, 217 | fmt_desc->bAspectRatioY, 218 | fmt_desc->bmInterlaceFlags, 219 | fmt_desc->bCopyProtect); 220 | 221 | DL_FOREACH(fmt_desc->frame_descs, frame_desc) 222 | { 223 | uint32_t *interval_ptr; 224 | 225 | fprintf(stream, 226 | "\t\t\tFrameDescriptor(%d)\n" 227 | "\t\t\t capabilities: %02x\n" 228 | "\t\t\t size: %dx%d\n" 229 | "\t\t\t bit rate: %d-%d\n" 230 | "\t\t\t max frame size: %d\n" 231 | "\t\t\t default interval: 1/%d\n", 232 | frame_desc->bFrameIndex, 233 | frame_desc->bmCapabilities, 234 | frame_desc->wWidth, 235 | frame_desc->wHeight, 236 | frame_desc->dwMinBitRate, 237 | frame_desc->dwMaxBitRate, 238 | frame_desc->dwMaxVideoFrameBufferSize, 239 | 10000000 / frame_desc->dwDefaultFrameInterval); 240 | if (frame_desc->intervals) 241 | { 242 | for (interval_ptr = frame_desc->intervals; 243 | *interval_ptr; 244 | ++interval_ptr) 245 | { 246 | fprintf(stream, 247 | "\t\t\t interval[%d]: 1/%d\n", 248 | (int)(interval_ptr - frame_desc->intervals), 249 | 10000000 / *interval_ptr); 250 | } 251 | } 252 | else 253 | { 254 | fprintf(stream, 255 | "\t\t\t min interval[%d] = 1/%d\n" 256 | "\t\t\t max interval[%d] = 1/%d\n", 257 | frame_desc->dwMinFrameInterval, 258 | 10000000 / frame_desc->dwMinFrameInterval, 259 | frame_desc->dwMaxFrameInterval, 260 | 10000000 / frame_desc->dwMaxFrameInterval); 261 | if (frame_desc->dwFrameIntervalStep) 262 | fprintf(stream, 263 | "\t\t\t interval step[%d] = 1/%d\n", 264 | frame_desc->dwFrameIntervalStep, 265 | 10000000 / frame_desc->dwFrameIntervalStep); 266 | } 267 | } 268 | break; 269 | default: 270 | fprintf(stream, "\t-UnknownFormat (%d)\n", 271 | fmt_desc->bDescriptorSubtype); 272 | } 273 | } 274 | } 275 | 276 | fprintf(stream, "END DEVICE CONFIGURATION\n"); 277 | } 278 | else 279 | { 280 | fprintf(stream, "uvc_print_diag: Device not configured!\n"); 281 | } 282 | } 283 | 284 | /** @brief Print all possible frame configuration. 285 | * @ingroup diag 286 | * 287 | * @param devh UVC device 288 | * @param stream Output stream (stderr if NULL) 289 | */ 290 | void uvc_print_frameformats(uvc_device_handle_t *devh) 291 | { 292 | 293 | if (devh->info->ctrl_if.bcdUVC) 294 | { 295 | uvc_streaming_interface_t *stream_if; 296 | int stream_idx = 0; 297 | DL_FOREACH(devh->info->stream_ifs, stream_if) 298 | { 299 | uvc_format_desc_t *fmt_desc; 300 | ++stream_idx; 301 | 302 | DL_FOREACH(stream_if->format_descs, fmt_desc) 303 | { 304 | uvc_frame_desc_t *frame_desc; 305 | int i; 306 | 307 | switch (fmt_desc->bDescriptorSubtype) 308 | { 309 | case UVC_VS_FORMAT_UNCOMPRESSED: 310 | case UVC_VS_FORMAT_MJPEG: 311 | case UVC_VS_FORMAT_FRAME_BASED: 312 | printf(" \%s(%d)\n" 313 | " bits per pixel: %d\n" 314 | " GUID: ", 315 | _uvc_name_for_format_subtype(fmt_desc->bDescriptorSubtype), 316 | fmt_desc->bFormatIndex, 317 | fmt_desc->bBitsPerPixel); 318 | 319 | for (i = 0; i < 16; ++i) 320 | printf("%02x", fmt_desc->guidFormat[i]); 321 | 322 | printf(" (%4s)\n", fmt_desc->fourccFormat); 323 | 324 | printf(" default frame: %d\n" 325 | " aspect ratio: %dx%d\n" 326 | " interlace flags: %02x\n" 327 | " copy protect: %02x\n", 328 | fmt_desc->bDefaultFrameIndex, 329 | fmt_desc->bAspectRatioX, 330 | fmt_desc->bAspectRatioY, 331 | fmt_desc->bmInterlaceFlags, 332 | fmt_desc->bCopyProtect); 333 | 334 | DL_FOREACH(fmt_desc->frame_descs, frame_desc) 335 | { 336 | uint32_t *interval_ptr; 337 | 338 | printf(" FrameDescriptor(%d)\n" 339 | " capabilities: %02x\n" 340 | " size: %dx%d\n" 341 | " bit rate: %d-%d\n" 342 | " max frame size: %d\n" 343 | " default interval: 1/%d\n", 344 | frame_desc->bFrameIndex, 345 | frame_desc->bmCapabilities, 346 | frame_desc->wWidth, 347 | frame_desc->wHeight, 348 | frame_desc->dwMinBitRate, 349 | frame_desc->dwMaxBitRate, 350 | frame_desc->dwMaxVideoFrameBufferSize, 351 | 10000000 / frame_desc->dwDefaultFrameInterval); 352 | if (frame_desc->intervals) 353 | { 354 | for (interval_ptr = frame_desc->intervals; 355 | *interval_ptr; 356 | ++interval_ptr) 357 | { 358 | printf(" interval[%d]: 1/%d\n", 359 | (int)(interval_ptr - frame_desc->intervals), 360 | 10000000 / *interval_ptr); 361 | } 362 | } 363 | else 364 | { 365 | printf(" min interval[%d] = 1/%d\n" 366 | " max interval[%d] = 1/%d\n", 367 | frame_desc->dwMinFrameInterval, 368 | 10000000 / frame_desc->dwMinFrameInterval, 369 | frame_desc->dwMaxFrameInterval, 370 | 10000000 / frame_desc->dwMaxFrameInterval); 371 | if (frame_desc->dwFrameIntervalStep) 372 | printf(" interval step[%d] = 1/%d\n", 373 | frame_desc->dwFrameIntervalStep, 374 | 10000000 / frame_desc->dwFrameIntervalStep); 375 | } 376 | } 377 | break; 378 | default: 379 | printf("\t-UnknownFormat (%d)\n", fmt_desc->bDescriptorSubtype); 380 | } 381 | } 382 | } 383 | } 384 | else 385 | { 386 | printf("uvc_print_frameformats: Device not configured!\n"); 387 | } 388 | } 389 | -------------------------------------------------------------------------------- /src/example.c: -------------------------------------------------------------------------------- 1 | #include "libuvc/libuvc.h" 2 | #include 3 | 4 | /* This callback function runs once per frame. Use it to perform any 5 | * quick processing you need, or have it put the frame into your application's 6 | * input queue. If this function takes too long, you'll start losing frames. */ 7 | void cb(uvc_frame_t *frame, void *ptr) 8 | { 9 | uvc_frame_t *bgr; 10 | uvc_error_t ret; 11 | 12 | /* We'll convert the image from YUV/JPEG to BGR, so allocate space */ 13 | bgr = uvc_allocate_frame(frame->width * frame->height * 3); 14 | if (!bgr) 15 | { 16 | printf("unable to allocate bgr frame!"); 17 | return; 18 | } 19 | 20 | /* Do the BGR conversion */ 21 | ret = uvc_any2bgr(frame, bgr); 22 | if (ret) 23 | { 24 | uvc_perror(ret, "uvc_any2bgr"); 25 | uvc_free_frame(bgr); 26 | return; 27 | } 28 | 29 | /* Call a user function: 30 | * 31 | * my_type *my_obj = (*my_type) ptr; 32 | * my_user_function(ptr, bgr); 33 | * my_other_function(ptr, bgr->data, bgr->width, bgr->height); 34 | */ 35 | 36 | /* Call a C++ method: 37 | * 38 | * my_type *my_obj = (*my_type) ptr; 39 | * my_obj->my_func(bgr); 40 | */ 41 | 42 | /* Use opencv.highgui to display the image: 43 | * 44 | * cvImg = cvCreateImageHeader( 45 | * cvSize(bgr->width, bgr->height), 46 | * IPL_DEPTH_8U, 47 | * 3); 48 | * 49 | * cvSetData(cvImg, bgr->data, bgr->width * 3); 50 | * 51 | * cvNamedWindow("Test", CV_WINDOW_AUTOSIZE); 52 | * cvShowImage("Test", cvImg); 53 | * cvWaitKey(10); 54 | * 55 | * cvReleaseImageHeader(&cvImg); 56 | */ 57 | 58 | uvc_free_frame(bgr); 59 | } 60 | 61 | int main(int argc, char **argv) 62 | { 63 | uvc_context_t *ctx; 64 | uvc_device_t *dev; 65 | uvc_device_handle_t *devh; 66 | uvc_stream_ctrl_t ctrl; 67 | uvc_error_t res; 68 | 69 | /* Initialize a UVC service context. Libuvc will set up its own libusb 70 | * context. Replace NULL with a libusb_context pointer to run libuvc 71 | * from an existing libusb context. */ 72 | res = uvc_init(&ctx, NULL); 73 | 74 | if (res < 0) 75 | { 76 | uvc_perror(res, "uvc_init"); 77 | return res; 78 | } 79 | 80 | puts("UVC initialized"); 81 | 82 | /* Locates the first attached UVC device, stores in dev */ 83 | res = uvc_find_device( 84 | ctx, &dev, 85 | 0, 0, NULL); /* filter devices: vendor_id, product_id, "serial_num" */ 86 | 87 | if (res < 0) 88 | { 89 | uvc_perror(res, "uvc_find_device"); /* no devices found */ 90 | } 91 | else 92 | { 93 | puts("Device found"); 94 | 95 | /* Try to open the device: requires exclusive access */ 96 | res = uvc_open(dev, &devh); 97 | 98 | if (res < 0) 99 | { 100 | uvc_perror(res, "uvc_open"); /* unable to open device */ 101 | } 102 | else 103 | { 104 | puts("Device opened"); 105 | 106 | /* Print out a message containing all the information that libuvc 107 | * knows about the device */ 108 | uvc_print_diag(devh, stderr); 109 | 110 | /* Try to negotiate a 640x480 30 fps YUYV stream profile */ 111 | res = uvc_get_stream_ctrl_format_size( 112 | devh, &ctrl, /* result stored in ctrl */ 113 | UVC_FRAME_FORMAT_YUYV, /* YUV 422, aka YUV 4:2:2. try _COMPRESSED */ 114 | 640, 480, 30 /* width, height, fps */ 115 | ); 116 | 117 | /* Print out the result */ 118 | uvc_print_stream_ctrl(&ctrl, stderr); 119 | 120 | if (res < 0) 121 | { 122 | uvc_perror(res, "get_mode"); /* device doesn't provide a matching stream */ 123 | } 124 | else 125 | { 126 | /* Start the video stream. The library will call user function cb: 127 | * cb(frame, (void*) 12345) 128 | */ 129 | res = uvc_start_streaming(devh, &ctrl, cb, 12345, 0); 130 | 131 | if (res < 0) 132 | { 133 | uvc_perror(res, "start_streaming"); /* unable to start stream */ 134 | } 135 | else 136 | { 137 | puts("Streaming..."); 138 | 139 | uvc_set_ae_mode(devh, 1); /* e.g., turn on auto exposure */ 140 | 141 | sleep(10); /* stream for 10 seconds */ 142 | 143 | /* End the stream. Blocks until last callback is serviced */ 144 | uvc_stop_streaming(devh); 145 | puts("Done streaming."); 146 | } 147 | } 148 | 149 | /* Release our handle on the device */ 150 | uvc_close(devh); 151 | puts("Device closed"); 152 | } 153 | 154 | /* Release the device descriptor */ 155 | uvc_unref_device(dev); 156 | } 157 | 158 | /* Close the UVC context. This closes and cleans up any existing device handles, 159 | * and it closes the libusb context if one was not provided. */ 160 | uvc_exit(ctx); 161 | puts("UVC exited"); 162 | 163 | return 0; 164 | } 165 | -------------------------------------------------------------------------------- /src/frame-mjpeg.c: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * Software License Agreement (BSD License) 3 | * 4 | * Copyright (C) 2014 Robert Xiao 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 11 | * * Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * * Redistributions in binary form must reproduce the above 14 | * copyright notice, this list of conditions and the following 15 | * disclaimer in the documentation and/or other materials provided 16 | * with the distribution. 17 | * * Neither the name of the author nor other contributors may be 18 | * used to endorse or promote products derived from this software 19 | * without specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 | * POSSIBILITY OF SUCH DAMAGE. 33 | *********************************************************************/ 34 | 35 | /** 36 | * @defgroup frame Frame processing 37 | */ 38 | #include "libuvc/libuvc.h" 39 | #include "libuvc/libuvc_internal.h" 40 | #include 41 | #include 42 | 43 | extern uvc_error_t uvc_ensure_frame_size(uvc_frame_t *frame, size_t need_bytes); 44 | 45 | struct error_mgr 46 | { 47 | struct jpeg_error_mgr super; 48 | jmp_buf jmp; 49 | }; 50 | 51 | static void _error_exit(j_common_ptr dinfo) 52 | { 53 | struct error_mgr *myerr = (struct error_mgr *)dinfo->err; 54 | (*dinfo->err->output_message)(dinfo); 55 | longjmp(myerr->jmp, 1); 56 | } 57 | 58 | /* ISO/IEC 10918-1:1993(E) K.3.3. Default Huffman tables used by MJPEG UVC devices 59 | which don't specify a Huffman table in the JPEG stream. */ 60 | static const unsigned char dc_lumi_len[] = 61 | {0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0}; 62 | static const unsigned char dc_lumi_val[] = 63 | {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; 64 | 65 | static const unsigned char dc_chromi_len[] = 66 | {0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}; 67 | static const unsigned char dc_chromi_val[] = 68 | {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; 69 | 70 | static const unsigned char ac_lumi_len[] = 71 | {0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d}; 72 | static const unsigned char ac_lumi_val[] = 73 | {0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 74 | 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 75 | 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 76 | 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 77 | 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, 78 | 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 79 | 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 80 | 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 81 | 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 82 | 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 83 | 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 84 | 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 85 | 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 86 | 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 87 | 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 88 | 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 89 | 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 90 | 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa}; 91 | static const unsigned char ac_chromi_len[] = 92 | {0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77}; 93 | static const unsigned char ac_chromi_val[] = 94 | {0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 95 | 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 96 | 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 97 | 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 98 | 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 99 | 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 100 | 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 101 | 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 102 | 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 103 | 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 104 | 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 105 | 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 106 | 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 107 | 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 108 | 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 109 | 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 110 | 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 111 | 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa}; 112 | 113 | #define COPY_HUFF_TABLE(dinfo, tbl, name) \ 114 | do \ 115 | { \ 116 | if (dinfo->tbl == NULL) \ 117 | dinfo->tbl = jpeg_alloc_huff_table((j_common_ptr)dinfo); \ 118 | memcpy(dinfo->tbl->bits, name##_len, sizeof(name##_len)); \ 119 | memset(dinfo->tbl->huffval, 0, sizeof(dinfo->tbl->huffval)); \ 120 | memcpy(dinfo->tbl->huffval, name##_val, sizeof(name##_val)); \ 121 | } while (0) 122 | 123 | static void insert_huff_tables(j_decompress_ptr dinfo) 124 | { 125 | COPY_HUFF_TABLE(dinfo, dc_huff_tbl_ptrs[0], dc_lumi); 126 | COPY_HUFF_TABLE(dinfo, dc_huff_tbl_ptrs[1], dc_chromi); 127 | COPY_HUFF_TABLE(dinfo, ac_huff_tbl_ptrs[0], ac_lumi); 128 | COPY_HUFF_TABLE(dinfo, ac_huff_tbl_ptrs[1], ac_chromi); 129 | } 130 | 131 | /** @brief Convert an MJPEG frame to RGB 132 | * @ingroup frame 133 | * 134 | * @param in MJPEG frame 135 | * @param out RGB frame 136 | */ 137 | uvc_error_t uvc_mjpeg2rgb(uvc_frame_t *in, uvc_frame_t *out) 138 | { 139 | struct jpeg_decompress_struct dinfo; 140 | struct error_mgr jerr; 141 | size_t lines_read; 142 | 143 | if (in->frame_format != UVC_FRAME_FORMAT_MJPEG) 144 | return UVC_ERROR_INVALID_PARAM; 145 | 146 | if (uvc_ensure_frame_size(out, in->width * in->height * 3) < 0) 147 | return UVC_ERROR_NO_MEM; 148 | 149 | out->width = in->width; 150 | out->height = in->height; 151 | out->frame_format = UVC_FRAME_FORMAT_RGB; 152 | out->step = in->width * 3; 153 | out->sequence = in->sequence; 154 | out->capture_time = in->capture_time; 155 | out->source = in->source; 156 | 157 | dinfo.err = jpeg_std_error(&jerr.super); 158 | jerr.super.error_exit = _error_exit; 159 | 160 | if (setjmp(jerr.jmp)) 161 | { 162 | goto fail; 163 | } 164 | 165 | jpeg_create_decompress(&dinfo); 166 | jpeg_mem_src(&dinfo, in->data, in->data_bytes); 167 | jpeg_read_header(&dinfo, TRUE); 168 | 169 | if (dinfo.dc_huff_tbl_ptrs[0] == NULL) 170 | { 171 | /* This frame is missing the Huffman tables: fill in the standard ones */ 172 | insert_huff_tables(&dinfo); 173 | } 174 | 175 | dinfo.out_color_space = JCS_RGB; 176 | dinfo.dct_method = JDCT_IFAST; 177 | 178 | jpeg_start_decompress(&dinfo); 179 | 180 | lines_read = 0; 181 | while (dinfo.output_scanline < dinfo.output_height) 182 | { 183 | unsigned char *buffer[1] = {(unsigned char *)out->data + lines_read * out->step}; 184 | int num_scanlines; 185 | 186 | num_scanlines = jpeg_read_scanlines(&dinfo, buffer, 1); 187 | lines_read += num_scanlines; 188 | } 189 | 190 | jpeg_finish_decompress(&dinfo); 191 | jpeg_destroy_decompress(&dinfo); 192 | return 0; 193 | 194 | fail: 195 | jpeg_destroy_decompress(&dinfo); 196 | return UVC_ERROR_OTHER; 197 | } 198 | -------------------------------------------------------------------------------- /src/frame.c: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * Software License Agreement (BSD License) 3 | * 4 | * Copyright (C) 2010-2012 Ken Tossell 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 11 | * * Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * * Redistributions in binary form must reproduce the above 14 | * copyright notice, this list of conditions and the following 15 | * disclaimer in the documentation and/or other materials provided 16 | * with the distribution. 17 | * * Neither the name of the author nor other contributors may be 18 | * used to endorse or promote products derived from this software 19 | * without specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 | * POSSIBILITY OF SUCH DAMAGE. 33 | *********************************************************************/ 34 | /** 35 | * @defgroup frame Frame processing 36 | * @brief Tools for managing frame buffers and converting between image formats 37 | */ 38 | #include "libuvc/libuvc.h" 39 | #include "libuvc/libuvc_internal.h" 40 | 41 | /** @internal */ 42 | uvc_error_t uvc_ensure_frame_size(uvc_frame_t *frame, size_t need_bytes) 43 | { 44 | if (frame->library_owns_data) 45 | { 46 | if (!frame->data || frame->data_bytes != need_bytes) 47 | { 48 | frame->data_bytes = need_bytes; 49 | frame->data = realloc(frame->data, frame->data_bytes); 50 | } 51 | if (!frame->data) 52 | return UVC_ERROR_NO_MEM; 53 | return UVC_SUCCESS; 54 | } 55 | else 56 | { 57 | if (!frame->data || frame->data_bytes < need_bytes) 58 | return UVC_ERROR_NO_MEM; 59 | return UVC_SUCCESS; 60 | } 61 | } 62 | 63 | /** @brief Allocate a frame structure 64 | * @ingroup frame 65 | * 66 | * @param data_bytes Number of bytes to allocate, or zero 67 | * @return New frame, or NULL on error 68 | */ 69 | uvc_frame_t *uvc_allocate_frame(size_t data_bytes) 70 | { 71 | uvc_frame_t *frame = malloc(sizeof(*frame)); 72 | 73 | if (!frame) 74 | return NULL; 75 | 76 | memset(frame, 0, sizeof(*frame)); 77 | 78 | frame->library_owns_data = 1; 79 | 80 | if (data_bytes > 0) 81 | { 82 | frame->data_bytes = data_bytes; 83 | frame->data = malloc(data_bytes); 84 | 85 | if (!frame->data) 86 | { 87 | free(frame); 88 | return NULL; 89 | } 90 | } 91 | 92 | return frame; 93 | } 94 | 95 | /** @brief Free a frame structure 96 | * @ingroup frame 97 | * 98 | * @param frame Frame to destroy 99 | */ 100 | void uvc_free_frame(uvc_frame_t *frame) 101 | { 102 | if (frame->data_bytes > 0 && frame->library_owns_data) 103 | free(frame->data); 104 | 105 | free(frame); 106 | } 107 | 108 | static inline unsigned char sat(int i) 109 | { 110 | return (unsigned char)(i >= 255 ? 255 : (i < 0 ? 0 : i)); 111 | } 112 | 113 | /** @brief Duplicate a frame, preserving color format 114 | * @ingroup frame 115 | * 116 | * @param in Original frame 117 | * @param out Duplicate frame 118 | */ 119 | uvc_error_t uvc_duplicate_frame(uvc_frame_t *in, uvc_frame_t *out) 120 | { 121 | if (uvc_ensure_frame_size(out, in->data_bytes) < 0) 122 | return UVC_ERROR_NO_MEM; 123 | 124 | out->width = in->width; 125 | out->height = in->height; 126 | out->frame_format = in->frame_format; 127 | out->step = in->step; 128 | out->sequence = in->sequence; 129 | out->capture_time = in->capture_time; 130 | out->source = in->source; 131 | 132 | memcpy(out->data, in->data, in->data_bytes); 133 | 134 | return UVC_SUCCESS; 135 | } 136 | 137 | #define YUYV2RGB_2(pyuv, prgb) \ 138 | { \ 139 | float r = 1.402f * ((pyuv)[3] - 128); \ 140 | float g = -0.34414f * ((pyuv)[1] - 128) - 0.71414f * ((pyuv)[3] - 128); \ 141 | float b = 1.772f * ((pyuv)[1] - 128); \ 142 | (prgb)[0] = sat(pyuv[0] + r); \ 143 | (prgb)[1] = sat(pyuv[0] + g); \ 144 | (prgb)[2] = sat(pyuv[0] + b); \ 145 | (prgb)[3] = sat(pyuv[2] + r); \ 146 | (prgb)[4] = sat(pyuv[2] + g); \ 147 | (prgb)[5] = sat(pyuv[2] + b); \ 148 | } 149 | #define IYUYV2RGB_2(pyuv, prgb) \ 150 | { \ 151 | int r = (22987 * ((pyuv)[3] - 128)) >> 14; \ 152 | int g = (-5636 * ((pyuv)[1] - 128) - 11698 * ((pyuv)[3] - 128)) >> 14; \ 153 | int b = (29049 * ((pyuv)[1] - 128)) >> 14; \ 154 | (prgb)[0] = sat(*(pyuv) + r); \ 155 | (prgb)[1] = sat(*(pyuv) + g); \ 156 | (prgb)[2] = sat(*(pyuv) + b); \ 157 | (prgb)[3] = sat((pyuv)[2] + r); \ 158 | (prgb)[4] = sat((pyuv)[2] + g); \ 159 | (prgb)[5] = sat((pyuv)[2] + b); \ 160 | } 161 | #define IYUYV2RGB_16(pyuv, prgb) \ 162 | IYUYV2RGB_8(pyuv, prgb); \ 163 | IYUYV2RGB_8(pyuv + 16, prgb + 24); 164 | #define IYUYV2RGB_8(pyuv, prgb) \ 165 | IYUYV2RGB_4(pyuv, prgb); \ 166 | IYUYV2RGB_4(pyuv + 8, prgb + 12); 167 | #define IYUYV2RGB_4(pyuv, prgb) \ 168 | IYUYV2RGB_2(pyuv, prgb); \ 169 | IYUYV2RGB_2(pyuv + 4, prgb + 6); 170 | 171 | /** @brief Convert a frame from YUYV to RGB 172 | * @ingroup frame 173 | * 174 | * @param in YUYV frame 175 | * @param out RGB frame 176 | */ 177 | uvc_error_t uvc_yuyv2rgb(uvc_frame_t *in, uvc_frame_t *out) 178 | { 179 | if (in->frame_format != UVC_FRAME_FORMAT_YUYV) 180 | return UVC_ERROR_INVALID_PARAM; 181 | 182 | if (uvc_ensure_frame_size(out, in->width * in->height * 3) < 0) 183 | return UVC_ERROR_NO_MEM; 184 | 185 | out->width = in->width; 186 | out->height = in->height; 187 | out->frame_format = UVC_FRAME_FORMAT_RGB; 188 | out->step = in->width * 3; 189 | out->sequence = in->sequence; 190 | out->capture_time = in->capture_time; 191 | out->source = in->source; 192 | 193 | uint8_t *pyuv = in->data; 194 | uint8_t *prgb = out->data; 195 | uint8_t *prgb_end = prgb + out->data_bytes; 196 | 197 | while (prgb < prgb_end) 198 | { 199 | IYUYV2RGB_8(pyuv, prgb); 200 | 201 | prgb += 3 * 8; 202 | pyuv += 2 * 8; 203 | } 204 | 205 | return UVC_SUCCESS; 206 | } 207 | 208 | #define IYUYV2BGR_2(pyuv, pbgr) \ 209 | { \ 210 | int r = (22987 * ((pyuv)[3] - 128)) >> 14; \ 211 | int g = (-5636 * ((pyuv)[1] - 128) - 11698 * ((pyuv)[3] - 128)) >> 14; \ 212 | int b = (29049 * ((pyuv)[1] - 128)) >> 14; \ 213 | (pbgr)[0] = sat(*(pyuv) + b); \ 214 | (pbgr)[1] = sat(*(pyuv) + g); \ 215 | (pbgr)[2] = sat(*(pyuv) + r); \ 216 | (pbgr)[3] = sat((pyuv)[2] + b); \ 217 | (pbgr)[4] = sat((pyuv)[2] + g); \ 218 | (pbgr)[5] = sat((pyuv)[2] + r); \ 219 | } 220 | #define IYUYV2BGR_16(pyuv, pbgr) \ 221 | IYUYV2BGR_8(pyuv, pbgr); \ 222 | IYUYV2BGR_8(pyuv + 16, pbgr + 24); 223 | #define IYUYV2BGR_8(pyuv, pbgr) \ 224 | IYUYV2BGR_4(pyuv, pbgr); \ 225 | IYUYV2BGR_4(pyuv + 8, pbgr + 12); 226 | #define IYUYV2BGR_4(pyuv, pbgr) \ 227 | IYUYV2BGR_2(pyuv, pbgr); \ 228 | IYUYV2BGR_2(pyuv + 4, pbgr + 6); 229 | 230 | /** @brief Convert a frame from YUYV to BGR 231 | * @ingroup frame 232 | * 233 | * @param in YUYV frame 234 | * @param out BGR frame 235 | */ 236 | uvc_error_t uvc_yuyv2bgr(uvc_frame_t *in, uvc_frame_t *out) 237 | { 238 | if (in->frame_format != UVC_FRAME_FORMAT_YUYV) 239 | return UVC_ERROR_INVALID_PARAM; 240 | 241 | if (uvc_ensure_frame_size(out, in->width * in->height * 3) < 0) 242 | return UVC_ERROR_NO_MEM; 243 | 244 | out->width = in->width; 245 | out->height = in->height; 246 | out->frame_format = UVC_FRAME_FORMAT_BGR; 247 | out->step = in->width * 3; 248 | out->sequence = in->sequence; 249 | out->capture_time = in->capture_time; 250 | out->source = in->source; 251 | 252 | uint8_t *pyuv = in->data; 253 | uint8_t *pbgr = out->data; 254 | uint8_t *pbgr_end = pbgr + out->data_bytes; 255 | uint8_t *pyuv_end = pyuv + in->data_bytes; 256 | while (pbgr < pbgr_end && pyuv < pyuv_end) 257 | { 258 | IYUYV2BGR_8(pyuv, pbgr); 259 | 260 | pbgr += 3 * 8; 261 | pyuv += 2 * 8; 262 | } 263 | 264 | return UVC_SUCCESS; 265 | } 266 | 267 | #define IYUYV2Y(pyuv, py) \ 268 | { \ 269 | (py)[0] = (pyuv[0]); \ 270 | } 271 | 272 | /** @brief Convert a frame from YUYV to Y (GRAY8) 273 | * @ingroup frame 274 | * 275 | * @param in YUYV frame 276 | * @param out GRAY8 frame 277 | */ 278 | uvc_error_t uvc_yuyv2y(uvc_frame_t *in, uvc_frame_t *out) 279 | { 280 | if (in->frame_format != UVC_FRAME_FORMAT_YUYV) 281 | return UVC_ERROR_INVALID_PARAM; 282 | 283 | if (uvc_ensure_frame_size(out, in->width * in->height) < 0) 284 | return UVC_ERROR_NO_MEM; 285 | 286 | out->width = in->width; 287 | out->height = in->height; 288 | out->frame_format = UVC_FRAME_FORMAT_GRAY8; 289 | out->step = in->width; 290 | out->sequence = in->sequence; 291 | out->capture_time = in->capture_time; 292 | out->source = in->source; 293 | 294 | uint8_t *pyuv = in->data; 295 | uint8_t *py = out->data; 296 | uint8_t *py_end = py + out->data_bytes; 297 | 298 | while (py < py_end) 299 | { 300 | IYUYV2Y(pyuv, py); 301 | 302 | py += 1; 303 | pyuv += 2; 304 | } 305 | 306 | return UVC_SUCCESS; 307 | } 308 | 309 | #define IYUYV2UV(pyuv, puv) \ 310 | { \ 311 | (puv)[0] = (pyuv[1]); \ 312 | } 313 | 314 | /** @brief Convert a frame from YUYV to UV (GRAY8) 315 | * @ingroup frame 316 | * 317 | * @param in YUYV frame 318 | * @param out GRAY8 frame 319 | */ 320 | uvc_error_t uvc_yuyv2uv(uvc_frame_t *in, uvc_frame_t *out) 321 | { 322 | if (in->frame_format != UVC_FRAME_FORMAT_YUYV) 323 | return UVC_ERROR_INVALID_PARAM; 324 | 325 | if (uvc_ensure_frame_size(out, in->width * in->height) < 0) 326 | return UVC_ERROR_NO_MEM; 327 | 328 | out->width = in->width; 329 | out->height = in->height; 330 | out->frame_format = UVC_FRAME_FORMAT_GRAY8; 331 | out->step = in->width; 332 | out->sequence = in->sequence; 333 | out->capture_time = in->capture_time; 334 | out->source = in->source; 335 | 336 | uint8_t *pyuv = in->data; 337 | uint8_t *puv = out->data; 338 | uint8_t *puv_end = puv + out->data_bytes; 339 | 340 | while (puv < puv_end) 341 | { 342 | IYUYV2UV(pyuv, puv); 343 | 344 | puv += 1; 345 | pyuv += 2; 346 | } 347 | 348 | return UVC_SUCCESS; 349 | } 350 | 351 | #define IUYVY2RGB_2(pyuv, prgb) \ 352 | { \ 353 | int r = (22987 * ((pyuv)[2] - 128)) >> 14; \ 354 | int g = (-5636 * ((pyuv)[0] - 128) - 11698 * ((pyuv)[2] - 128)) >> 14; \ 355 | int b = (29049 * ((pyuv)[0] - 128)) >> 14; \ 356 | (prgb)[0] = sat((pyuv)[1] + r); \ 357 | (prgb)[1] = sat((pyuv)[1] + g); \ 358 | (prgb)[2] = sat((pyuv)[1] + b); \ 359 | (prgb)[3] = sat((pyuv)[3] + r); \ 360 | (prgb)[4] = sat((pyuv)[3] + g); \ 361 | (prgb)[5] = sat((pyuv)[3] + b); \ 362 | } 363 | #define IUYVY2RGB_16(pyuv, prgb) \ 364 | IUYVY2RGB_8(pyuv, prgb); \ 365 | IUYVY2RGB_8(pyuv + 16, prgb + 24); 366 | #define IUYVY2RGB_8(pyuv, prgb) \ 367 | IUYVY2RGB_4(pyuv, prgb); \ 368 | IUYVY2RGB_4(pyuv + 8, prgb + 12); 369 | #define IUYVY2RGB_4(pyuv, prgb) \ 370 | IUYVY2RGB_2(pyuv, prgb); \ 371 | IUYVY2RGB_2(pyuv + 4, prgb + 6); 372 | 373 | /** @brief Convert a frame from UYVY to RGB 374 | * @ingroup frame 375 | * @param ini UYVY frame 376 | * @param out RGB frame 377 | */ 378 | uvc_error_t uvc_uyvy2rgb(uvc_frame_t *in, uvc_frame_t *out) 379 | { 380 | if (in->frame_format != UVC_FRAME_FORMAT_UYVY) 381 | return UVC_ERROR_INVALID_PARAM; 382 | 383 | if (uvc_ensure_frame_size(out, in->width * in->height * 3) < 0) 384 | return UVC_ERROR_NO_MEM; 385 | 386 | out->width = in->width; 387 | out->height = in->height; 388 | out->frame_format = UVC_FRAME_FORMAT_RGB; 389 | out->step = in->width * 3; 390 | out->sequence = in->sequence; 391 | out->capture_time = in->capture_time; 392 | out->source = in->source; 393 | 394 | uint8_t *pyuv = in->data; 395 | uint8_t *prgb = out->data; 396 | uint8_t *prgb_end = prgb + out->data_bytes; 397 | 398 | while (prgb < prgb_end) 399 | { 400 | IUYVY2RGB_8(pyuv, prgb); 401 | 402 | prgb += 3 * 8; 403 | pyuv += 2 * 8; 404 | } 405 | 406 | return UVC_SUCCESS; 407 | } 408 | 409 | #define IUYVY2BGR_2(pyuv, pbgr) \ 410 | { \ 411 | int r = (22987 * ((pyuv)[2] - 128)) >> 14; \ 412 | int g = (-5636 * ((pyuv)[0] - 128) - 11698 * ((pyuv)[2] - 128)) >> 14; \ 413 | int b = (29049 * ((pyuv)[0] - 128)) >> 14; \ 414 | (pbgr)[0] = sat((pyuv)[1] + b); \ 415 | (pbgr)[1] = sat((pyuv)[1] + g); \ 416 | (pbgr)[2] = sat((pyuv)[1] + r); \ 417 | (pbgr)[3] = sat((pyuv)[3] + b); \ 418 | (pbgr)[4] = sat((pyuv)[3] + g); \ 419 | (pbgr)[5] = sat((pyuv)[3] + r); \ 420 | } 421 | #define IUYVY2BGR_16(pyuv, pbgr) \ 422 | IUYVY2BGR_8(pyuv, pbgr); \ 423 | IUYVY2BGR_8(pyuv + 16, pbgr + 24); 424 | #define IUYVY2BGR_8(pyuv, pbgr) \ 425 | IUYVY2BGR_4(pyuv, pbgr); \ 426 | IUYVY2BGR_4(pyuv + 8, pbgr + 12); 427 | #define IUYVY2BGR_4(pyuv, pbgr) \ 428 | IUYVY2BGR_2(pyuv, pbgr); \ 429 | IUYVY2BGR_2(pyuv + 4, pbgr + 6); 430 | 431 | /** @brief Convert a frame from UYVY to BGR 432 | * @ingroup frame 433 | * @param ini UYVY frame 434 | * @param out BGR frame 435 | */ 436 | uvc_error_t uvc_uyvy2bgr(uvc_frame_t *in, uvc_frame_t *out) 437 | { 438 | if (in->frame_format != UVC_FRAME_FORMAT_UYVY) 439 | return UVC_ERROR_INVALID_PARAM; 440 | 441 | if (uvc_ensure_frame_size(out, in->width * in->height * 3) < 0) 442 | return UVC_ERROR_NO_MEM; 443 | 444 | out->width = in->width; 445 | out->height = in->height; 446 | out->frame_format = UVC_FRAME_FORMAT_BGR; 447 | out->step = in->width * 3; 448 | out->sequence = in->sequence; 449 | out->capture_time = in->capture_time; 450 | out->source = in->source; 451 | 452 | uint8_t *pyuv = in->data; 453 | uint8_t *pbgr = out->data; 454 | uint8_t *pbgr_end = pbgr + out->data_bytes; 455 | 456 | while (pbgr < pbgr_end) 457 | { 458 | IUYVY2BGR_8(pyuv, pbgr); 459 | 460 | pbgr += 3 * 8; 461 | pyuv += 2 * 8; 462 | } 463 | 464 | return UVC_SUCCESS; 465 | } 466 | 467 | /** @brief Convert a frame to RGB 468 | * @ingroup frame 469 | * 470 | * @param in non-RGB frame 471 | * @param out RGB frame 472 | */ 473 | uvc_error_t uvc_any2rgb(uvc_frame_t *in, uvc_frame_t *out) 474 | { 475 | switch (in->frame_format) 476 | { 477 | case UVC_FRAME_FORMAT_YUYV: 478 | return uvc_yuyv2rgb(in, out); 479 | case UVC_FRAME_FORMAT_UYVY: 480 | return uvc_uyvy2rgb(in, out); 481 | case UVC_FRAME_FORMAT_RGB: 482 | return uvc_duplicate_frame(in, out); 483 | default: 484 | return UVC_ERROR_NOT_SUPPORTED; 485 | } 486 | } 487 | 488 | /** @brief Convert a frame to BGR 489 | * @ingroup frame 490 | * 491 | * @param in non-BGR frame 492 | * @param out BGR frame 493 | */ 494 | uvc_error_t uvc_any2bgr(uvc_frame_t *in, uvc_frame_t *out) 495 | { 496 | switch (in->frame_format) 497 | { 498 | case UVC_FRAME_FORMAT_YUYV: 499 | return uvc_yuyv2bgr(in, out); 500 | case UVC_FRAME_FORMAT_UYVY: 501 | return uvc_uyvy2bgr(in, out); 502 | case UVC_FRAME_FORMAT_BGR: 503 | return uvc_duplicate_frame(in, out); 504 | default: 505 | return UVC_ERROR_NOT_SUPPORTED; 506 | } 507 | } 508 | -------------------------------------------------------------------------------- /src/init.c: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * Software License Agreement (BSD License) 3 | * 4 | * Copyright (C) 2010-2012 Ken Tossell 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 11 | * * Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * * Redistributions in binary form must reproduce the above 14 | * copyright notice, this list of conditions and the following 15 | * disclaimer in the documentation and/or other materials provided 16 | * with the distribution. 17 | * * Neither the name of the author nor other contributors may be 18 | * used to endorse or promote products derived from this software 19 | * without specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 | * POSSIBILITY OF SUCH DAMAGE. 33 | *********************************************************************/ 34 | /** 35 | \mainpage libuvc: a cross-platform library for USB video devices 36 | 37 | \b libuvc is a library that supports enumeration, control and streaming 38 | for USB Video Class (UVC) devices, such as consumer webcams. 39 | 40 | \section features Features 41 | \li UVC device \ref device "discovery and management" API 42 | \li \ref streaming "Video streaming" (device to host) with asynchronous/callback and synchronous/polling modes 43 | \li Read/write access to standard \ref ctrl "device settings" 44 | \li \ref frame "Conversion" between various formats: RGB, YUV, JPEG, etc. 45 | \li Tested on Mac and Linux, portable to Windows and some BSDs 46 | 47 | \section roadmap Roadmap 48 | \li Bulk-mode image capture 49 | \li One-shot image capture 50 | \li Improved support for standard settings 51 | \li Support for "extended" (vendor-defined) settings 52 | 53 | \section misc Misc. 54 | \p The source code can be found at https://github.com/ktossell/libuvc. To build 55 | the library, install libusb 1.0+ and run: 56 | 57 | \code 58 | $ git clone https://github.com/ktossell/libuvc.git 59 | $ cd libuvc 60 | $ mkdir build 61 | $ cd build 62 | $ cmake -DCMAKE_BUILD_TYPE=Release .. 63 | $ make && make install 64 | \endcode 65 | 66 | \section Example 67 | In this example, libuvc is used to acquire images in a 30 fps, 640x480 68 | YUV stream from a UVC device such as a standard webcam. 69 | 70 | \include example.c 71 | 72 | */ 73 | 74 | /** 75 | * @defgroup init Library initialization/deinitialization 76 | * @brief Setup routines used to construct UVC access contexts 77 | */ 78 | #include "libuvc/libuvc.h" 79 | #include "libuvc/libuvc_internal.h" 80 | 81 | /** @internal 82 | * @brief Event handler thread 83 | * There's one of these per UVC context. 84 | * @todo We shouldn't run this if we don't own the USB context 85 | */ 86 | void *_uvc_handle_events(void *arg) 87 | { 88 | uvc_context_t *ctx = (uvc_context_t *)arg; 89 | 90 | while (!ctx->kill_handler_thread) 91 | libusb_handle_events_completed(ctx->usb_ctx, &ctx->kill_handler_thread); 92 | return NULL; 93 | } 94 | 95 | /** @brief Initializes the UVC context 96 | * @ingroup init 97 | * 98 | * @note If you provide your own USB context, you must handle 99 | * libusb event processing using a function such as libusb_handle_events. 100 | * 101 | * @param[out] pctx The location where the context reference should be stored. 102 | * @param[in] usb_ctx Optional USB context to use 103 | * @return Error opening context or UVC_SUCCESS 104 | */ 105 | uvc_error_t uvc_init(uvc_context_t **pctx, struct libusb_context *usb_ctx) 106 | { 107 | uvc_error_t ret = UVC_SUCCESS; 108 | uvc_context_t *ctx = calloc(1, sizeof(*ctx)); 109 | 110 | if (usb_ctx == NULL) 111 | { 112 | ret = libusb_init(&ctx->usb_ctx); 113 | ctx->own_usb_ctx = 1; 114 | if (ret != UVC_SUCCESS) 115 | { 116 | free(ctx); 117 | ctx = NULL; 118 | } 119 | } 120 | else 121 | { 122 | ctx->own_usb_ctx = 0; 123 | ctx->usb_ctx = usb_ctx; 124 | } 125 | 126 | if (ctx != NULL) 127 | *pctx = ctx; 128 | 129 | return ret; 130 | } 131 | 132 | /** 133 | * @brief Closes the UVC context, shutting down any active cameras. 134 | * @ingroup init 135 | * 136 | * @note This function invalides any existing references to the context's 137 | * cameras. 138 | * 139 | * If no USB context was provided to #uvc_init, the UVC-specific USB 140 | * context will be destroyed. 141 | * 142 | * @param ctx UVC context to shut down 143 | */ 144 | void uvc_exit(uvc_context_t *ctx) 145 | { 146 | uvc_device_handle_t *devh; 147 | 148 | DL_FOREACH(ctx->open_devices, devh) 149 | { 150 | uvc_close(devh); 151 | } 152 | 153 | if (ctx->own_usb_ctx) 154 | libusb_exit(ctx->usb_ctx); 155 | 156 | free(ctx); 157 | } 158 | 159 | /** 160 | * @internal 161 | * @brief Spawns a handler thread for the context 162 | * @ingroup init 163 | * 164 | * This should be called at the end of a successful uvc_open if no devices 165 | * are already open (and being handled). 166 | */ 167 | void uvc_start_handler_thread(uvc_context_t *ctx) 168 | { 169 | if (ctx->own_usb_ctx) 170 | pthread_create(&ctx->handler_thread, NULL, _uvc_handle_events, (void *)ctx); 171 | } 172 | -------------------------------------------------------------------------------- /src/misc.c: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * Software License Agreement (BSD License) 3 | * 4 | * Copyright (C) 2010-2012 Ken Tossell 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 11 | * * Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * * Redistributions in binary form must reproduce the above 14 | * copyright notice, this list of conditions and the following 15 | * disclaimer in the documentation and/or other materials provided 16 | * with the distribution. 17 | * * Neither the name of the author nor other contributors may be 18 | * used to endorse or promote products derived from this software 19 | * without specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 | * POSSIBILITY OF SUCH DAMAGE. 33 | *********************************************************************/ 34 | #include 35 | #include 36 | 37 | #if __APPLE__ 38 | char *strndup(const char *s, size_t n) 39 | { 40 | size_t src_n = 0; 41 | const char *sp = s; 42 | char *d; 43 | 44 | while (*sp++) 45 | src_n++; 46 | 47 | if (src_n < n) 48 | n = src_n; 49 | 50 | d = malloc(n + 1); 51 | 52 | memcpy(d, s, n); 53 | 54 | d[n] = '\0'; 55 | 56 | return d; 57 | } 58 | #endif 59 | -------------------------------------------------------------------------------- /src/test.c: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * Software License Agreement (BSD License) 3 | * 4 | * Copyright (C) 2010-2012 Ken Tossell 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 11 | * * Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * * Redistributions in binary form must reproduce the above 14 | * copyright notice, this list of conditions and the following 15 | * disclaimer in the documentation and/or other materials provided 16 | * with the distribution. 17 | * * Neither the name of the author nor other contributors may be 18 | * used to endorse or promote products derived from this software 19 | * without specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 | * POSSIBILITY OF SUCH DAMAGE. 33 | *********************************************************************/ 34 | #include 35 | #include 36 | 37 | #include "libuvc/libuvc.h" 38 | 39 | void cb(uvc_frame_t *frame, void *ptr) 40 | { 41 | uvc_frame_t *bgr; 42 | uvc_error_t ret; 43 | IplImage *cvImg; 44 | 45 | printf("callback! length = %u, ptr = %d\n", frame->data_bytes, (int)ptr); 46 | 47 | bgr = uvc_allocate_frame(frame->width * frame->height * 3); 48 | if (!bgr) 49 | { 50 | printf("unable to allocate bgr frame!"); 51 | return; 52 | } 53 | 54 | ret = uvc_any2bgr(frame, bgr); 55 | if (ret) 56 | { 57 | uvc_perror(ret, "uvc_any2bgr"); 58 | uvc_free_frame(bgr); 59 | return; 60 | } 61 | 62 | cvImg = cvCreateImageHeader( 63 | cvSize(bgr->width, bgr->height), 64 | IPL_DEPTH_8U, 65 | 3); 66 | 67 | cvSetData(cvImg, bgr->data, bgr->width * 3); 68 | 69 | cvNamedWindow("Test", CV_WINDOW_AUTOSIZE); 70 | cvShowImage("Test", cvImg); 71 | cvWaitKey(10); 72 | 73 | cvReleaseImageHeader(&cvImg); 74 | 75 | uvc_free_frame(bgr); 76 | } 77 | 78 | int main(int argc, char **argv) 79 | { 80 | uvc_context_t *ctx; 81 | uvc_error_t res; 82 | uvc_device_t *dev; 83 | uvc_device_handle_t *devh; 84 | uvc_stream_ctrl_t ctrl; 85 | 86 | res = uvc_init(&ctx, NULL); 87 | 88 | if (res < 0) 89 | { 90 | uvc_perror(res, "uvc_init"); 91 | return res; 92 | } 93 | 94 | puts("UVC initialized"); 95 | 96 | res = uvc_find_device( 97 | ctx, &dev, 98 | 0, 0, NULL); 99 | 100 | if (res < 0) 101 | { 102 | uvc_perror(res, "uvc_find_device"); 103 | } 104 | else 105 | { 106 | puts("Device found"); 107 | 108 | res = uvc_open(dev, &devh); 109 | 110 | if (res < 0) 111 | { 112 | uvc_perror(res, "uvc_open"); 113 | } 114 | else 115 | { 116 | puts("Device opened"); 117 | 118 | uvc_print_diag(devh, stderr); 119 | 120 | res = uvc_get_stream_ctrl_format_size( 121 | devh, &ctrl, UVC_FRAME_FORMAT_YUYV, 640, 480, 30); 122 | 123 | uvc_print_stream_ctrl(&ctrl, stderr); 124 | 125 | if (res < 0) 126 | { 127 | uvc_perror(res, "get_mode"); 128 | } 129 | else 130 | { 131 | res = uvc_start_streaming(devh, &ctrl, cb, 12345, 0); 132 | 133 | if (res < 0) 134 | { 135 | uvc_perror(res, "start_streaming"); 136 | } 137 | else 138 | { 139 | puts("Streaming for 10 seconds..."); 140 | uvc_error_t resAEMODE = uvc_set_ae_mode(devh, 1); 141 | uvc_perror(resAEMODE, "set_ae_mode"); 142 | int i; 143 | for (i = 1; i <= 10; i++) 144 | { 145 | /* uvc_error_t resPT = uvc_set_pantilt_abs(devh, i * 20 * 3600, 0); */ 146 | /* uvc_perror(resPT, "set_pt_abs"); */ 147 | uvc_error_t resEXP = uvc_set_exposure_abs(devh, 20 + i * 5); 148 | uvc_perror(resEXP, "set_exp_abs"); 149 | 150 | sleep(1); 151 | } 152 | sleep(10); 153 | uvc_stop_streaming(devh); 154 | puts("Done streaming."); 155 | } 156 | } 157 | 158 | uvc_close(devh); 159 | puts("Device closed"); 160 | } 161 | 162 | uvc_unref_device(dev); 163 | } 164 | 165 | uvc_exit(ctx); 166 | puts("UVC exited"); 167 | 168 | return 0; 169 | } 170 | -------------------------------------------------------------------------------- /src/time_linux.h: -------------------------------------------------------------------------------- 1 | 2 | #include /* gettimeofday */ 3 | 4 | #define BILLION 1000000000L 5 | #define MILLION 1000000L 6 | 7 | #define NORMALISE_TIMESPEC(ts, uint_milli) \ 8 | do \ 9 | { \ 10 | ts.tv_sec += uint_milli / 1000u; \ 11 | ts.tv_nsec += (uint_milli % 1000u) * MILLION; \ 12 | ts.tv_sec += ts.tv_nsec / BILLION; \ 13 | ts.tv_nsec = ts.tv_nsec % BILLION; \ 14 | } while (0) 15 | 16 | /* 17 | * Get absolute future time for pthread timed calls 18 | * Solution 1: microseconds granularity 19 | */ 20 | struct timespec get_abs_future_time_coarse(unsigned milli) 21 | { 22 | struct timespec future; /* ns since 1 Jan 1970 to 1500 ms in the future */ 23 | clock_gettime(CLOCK_REALTIME, &future); 24 | NORMALISE_TIMESPEC(future, milli); 25 | return future; 26 | } 27 | -------------------------------------------------------------------------------- /src/time_mac.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | #include /* gettimeofday */ 6 | #include /* mach_absolute_time */ 7 | #include /* host_get_clock_service, mach_... */ 8 | #include /* clock_get_time */ 9 | 10 | #define BILLION 1000000000L 11 | #define MILLION 1000000L 12 | 13 | #define NORMALISE_TIMESPEC(ts, uint_milli) \ 14 | do \ 15 | { \ 16 | ts.tv_sec += uint_milli / 1000u; \ 17 | ts.tv_nsec += (uint_milli % 1000u) * MILLION; \ 18 | ts.tv_sec += ts.tv_nsec / BILLION; \ 19 | ts.tv_nsec = ts.tv_nsec % BILLION; \ 20 | } while (0) 21 | 22 | /* 23 | * Get absolute future time for pthread timed calls 24 | * Solution 1: microseconds granularity 25 | */ 26 | struct timespec get_abs_future_time_coarse(unsigned milli) 27 | { 28 | struct timespec future; /* ns since 1 Jan 1970 to 1500 ms in the future */ 29 | struct timeval micro = {0, 0}; /* 1 Jan 1970 */ 30 | 31 | (void)gettimeofday(µ, NULL); 32 | future.tv_sec = micro.tv_sec; 33 | future.tv_nsec = micro.tv_usec * 1000; 34 | NORMALISE_TIMESPEC(future, milli); 35 | return future; 36 | } 37 | -------------------------------------------------------------------------------- /src/time_windows.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define BILLION 1000000000L 6 | #define MILLION 1000000L 7 | 8 | #define NORMALISE_TIMESPEC(ts, uint_milli) \ 9 | do \ 10 | { \ 11 | ts.tv_sec += uint_milli / 1000u; \ 12 | ts.tv_nsec += (uint_milli % 1000u) * MILLION; \ 13 | ts.tv_sec += ts.tv_nsec / BILLION; \ 14 | ts.tv_nsec = ts.tv_nsec % BILLION; \ 15 | } while (0) 16 | 17 | struct timespec get_abs_future_time_coarse(unsigned milli) 18 | { 19 | struct _timeb timebuffer; 20 | _ftime(&timebuffer); // C4996 21 | // Note: _ftime is deprecated; consider using _ftime_s instead 22 | 23 | struct timespec future; 24 | future.tv_sec = timebuffer.time; 25 | future.tv_nsec = timebuffer.millitm * MILLION; 26 | NORMALISE_TIMESPEC(future, milli); 27 | return future; 28 | } -------------------------------------------------------------------------------- /standard-units.yaml: -------------------------------------------------------------------------------- 1 | units: 2 | camera_terminal: 3 | type: standard 4 | description: Standard camera input terminal (captures images from sensor) 5 | control_prefix: CT 6 | controls: 7 | scanning_mode: 8 | control: SCANNING_MODE 9 | length: 1 10 | fields: 11 | mode: 12 | type: int 13 | position: 0 14 | length: 1 15 | doc: '0: interlaced, 1: progressive' 16 | ae_mode: 17 | control: AE_MODE 18 | length: 1 19 | fields: 20 | mode: 21 | type: int 22 | position: 0 23 | length: 1 24 | doc: '1: manual mode; 2: auto mode; 4: shutter priority mode; 8: aperture 25 | priority mode' 26 | doc: 27 | get: |- 28 | @brief Reads camera's auto-exposure mode. 29 | 30 | See uvc_set_ae_mode() for a description of the available modes. 31 | set: |- 32 | @brief Sets camera's auto-exposure mode. 33 | 34 | Cameras may support any of the following AE modes: 35 | * UVC_AUTO_EXPOSURE_MODE_MANUAL (1) - manual exposure time, manual iris 36 | * UVC_AUTO_EXPOSURE_MODE_AUTO (2) - auto exposure time, auto iris 37 | * UVC_AUTO_EXPOSURE_MODE_SHUTTER_PRIORITY (4) - manual exposure time, auto iris 38 | * UVC_AUTO_EXPOSURE_MODE_APERTURE_PRIORITY (8) - auto exposure time, manual iris 39 | 40 | Most cameras provide manual mode and aperture priority mode. 41 | ae_priority: 42 | control: AE_PRIORITY 43 | length: 1 44 | fields: 45 | priority: 46 | type: int 47 | position: 0 48 | length: 1 49 | doc: '0: frame rate must remain constant; 1: frame rate may be varied 50 | for AE purposes' 51 | doc: 52 | get: |- 53 | @brief Checks whether the camera may vary the frame rate for exposure control reasons. 54 | See uvc_set_ae_priority() for a description of the `priority` field. 55 | set: |- 56 | @brief Chooses whether the camera may vary the frame rate for exposure control reasons. 57 | A `priority` value of zero means the camera may not vary its frame rate. A value of 1 58 | means the frame rate is variable. This setting has no effect outside of the `auto` and 59 | `shutter_priority` auto-exposure modes. 60 | exposure_abs: 61 | control: EXPOSURE_TIME_ABSOLUTE 62 | length: 4 63 | fields: 64 | time: 65 | type: int 66 | position: 0 67 | length: 4 68 | doc: '' 69 | doc: 70 | get: |- 71 | @brief Gets the absolute exposure time. 72 | 73 | See uvc_set_exposure_abs() for a description of the `time` field. 74 | set: |- 75 | @brief Sets the absolute exposure time. 76 | 77 | The `time` parameter should be provided in units of 0.0001 seconds (e.g., use the value 100 78 | for a 10ms exposure period). Auto exposure should be set to `manual` or `shutter_priority` 79 | before attempting to change this setting. 80 | exposure_rel: 81 | control: EXPOSURE_TIME_RELATIVE 82 | length: 1 83 | fields: 84 | step: 85 | type: int 86 | position: 0 87 | length: 1 88 | signed: true 89 | doc: number of steps by which to change the exposure time, or zero to 90 | set the default exposure time 91 | doc: '@brief {gets_sets} the exposure time relative to the current setting.' 92 | focus_abs: 93 | control: FOCUS_ABSOLUTE 94 | length: 2 95 | fields: 96 | focus: 97 | type: int 98 | position: 0 99 | length: 2 100 | doc: focal target distance in millimeters 101 | doc: '@brief {gets_sets} the distance at which an object is optimally focused.' 102 | focus_rel: 103 | control: FOCUS_RELATIVE 104 | length: 2 105 | fields: 106 | focus_rel: 107 | type: int 108 | position: 0 109 | length: 1 110 | signed: true 111 | doc: TODO 112 | speed: 113 | type: int 114 | position: 1 115 | length: 1 116 | doc: TODO 117 | focus_simple_range: 118 | control: FOCUS_SIMPLE 119 | length: 1 120 | fields: 121 | focus: 122 | type: int 123 | position: 0 124 | length: 1 125 | doc: TODO 126 | focus_auto: 127 | control: FOCUS_AUTO 128 | length: 1 129 | fields: 130 | state: 131 | type: int 132 | position: 0 133 | length: 1 134 | doc: TODO 135 | iris_abs: 136 | control: IRIS_ABSOLUTE 137 | length: 2 138 | fields: 139 | iris: 140 | type: int 141 | position: 0 142 | length: 2 143 | doc: TODO 144 | iris_rel: 145 | control: IRIS_RELATIVE 146 | length: 1 147 | fields: 148 | iris_rel: 149 | type: int 150 | position: 0 151 | length: 1 152 | doc: TODO 153 | zoom_abs: 154 | control: ZOOM_ABSOLUTE 155 | length: 2 156 | fields: 157 | focal_length: 158 | type: int 159 | position: 0 160 | length: 2 161 | doc: TODO 162 | zoom_rel: 163 | control: ZOOM_RELATIVE 164 | length: 3 165 | fields: 166 | zoom_rel: 167 | type: int 168 | position: 0 169 | length: 1 170 | signed: true 171 | doc: TODO 172 | digital_zoom: 173 | type: int 174 | position: 1 175 | length: 1 176 | doc: TODO 177 | speed: 178 | type: int 179 | position: 2 180 | length: 1 181 | doc: TODO 182 | pantilt_abs: 183 | control: PANTILT_ABSOLUTE 184 | length: 8 185 | fields: 186 | pan: 187 | type: int 188 | position: 0 189 | length: 4 190 | signed: true 191 | doc: TODO 192 | tilt: 193 | type: int 194 | position: 4 195 | length: 4 196 | signed: true 197 | doc: TODO 198 | pantilt_rel: 199 | control: PANTILT_RELATIVE 200 | length: 4 201 | fields: 202 | pan_rel: 203 | type: int 204 | position: 0 205 | length: 1 206 | signed: true 207 | doc: TODO 208 | pan_speed: 209 | type: int 210 | position: 1 211 | length: 1 212 | doc: TODO 213 | tilt_rel: 214 | type: int 215 | position: 2 216 | length: 1 217 | signed: true 218 | doc: TODO 219 | tilt_speed: 220 | type: int 221 | position: 3 222 | length: 1 223 | doc: TODO 224 | roll_abs: 225 | control: ROLL_ABSOLUTE 226 | length: 2 227 | fields: 228 | roll: 229 | type: int 230 | position: 0 231 | length: 2 232 | signed: true 233 | doc: TODO 234 | roll_rel: 235 | control: ROLL_RELATIVE 236 | length: 2 237 | fields: 238 | roll_rel: 239 | type: int 240 | position: 0 241 | length: 1 242 | signed: true 243 | doc: TODO 244 | speed: 245 | type: int 246 | position: 1 247 | length: 1 248 | doc: TODO 249 | privacy: 250 | control: PRIVACY 251 | length: 1 252 | fields: 253 | privacy: 254 | type: int 255 | position: 0 256 | length: 1 257 | doc: TODO 258 | digital_window: 259 | control: DIGITAL_WINDOW 260 | length: 12 261 | fields: 262 | window_top: 263 | type: int 264 | position: 0 265 | length: 2 266 | doc: TODO 267 | window_left: 268 | type: int 269 | position: 2 270 | length: 2 271 | doc: TODO 272 | window_bottom: 273 | type: int 274 | position: 4 275 | length: 2 276 | doc: TODO 277 | window_right: 278 | type: int 279 | position: 6 280 | length: 2 281 | doc: TODO 282 | num_steps: 283 | type: int 284 | position: 8 285 | length: 2 286 | doc: TODO 287 | num_steps_units: 288 | type: int 289 | position: 10 290 | length: 2 291 | doc: TODO 292 | digital_roi: 293 | control: REGION_OF_INTEREST 294 | length: 10 295 | fields: 296 | roi_top: 297 | type: int 298 | position: 0 299 | length: 2 300 | doc: TODO 301 | roi_left: 302 | type: int 303 | position: 2 304 | length: 2 305 | doc: TODO 306 | roi_bottom: 307 | type: int 308 | position: 4 309 | length: 2 310 | doc: TODO 311 | roi_right: 312 | type: int 313 | position: 6 314 | length: 2 315 | doc: TODO 316 | auto_controls: 317 | type: int 318 | position: 8 319 | length: 2 320 | doc: TODO 321 | processing_unit: 322 | type: standard 323 | description: Standard processing unit (processes images between other units) 324 | control_prefix: PU 325 | controls: 326 | backlight_compensation: 327 | control: BACKLIGHT_COMPENSATION 328 | length: 2 329 | fields: 330 | backlight_compensation: 331 | type: int 332 | position: 0 333 | length: 2 334 | doc: device-dependent backlight compensation mode; zero means backlight 335 | compensation is disabled 336 | brightness: 337 | control: BRIGHTNESS 338 | length: 2 339 | fields: 340 | brightness: 341 | type: int 342 | position: 0 343 | length: 2 344 | signed: true 345 | doc: TODO 346 | contrast: 347 | control: CONTRAST 348 | length: 2 349 | fields: 350 | contrast: 351 | type: int 352 | position: 0 353 | length: 2 354 | doc: TODO 355 | contrast_auto: 356 | control: CONTRAST_AUTO 357 | length: 1 358 | fields: 359 | contrast_auto: 360 | type: int 361 | position: 0 362 | length: 1 363 | doc: TODO 364 | gain: 365 | control: GAIN 366 | length: 2 367 | fields: 368 | gain: 369 | type: int 370 | position: 0 371 | length: 2 372 | doc: TODO 373 | power_line_frequency: 374 | control: POWER_LINE_FREQUENCY 375 | length: 1 376 | fields: 377 | power_line_frequency: 378 | type: int 379 | position: 0 380 | length: 1 381 | doc: TODO 382 | hue: 383 | control: HUE 384 | length: 2 385 | fields: 386 | hue: 387 | type: int 388 | position: 0 389 | length: 2 390 | signed: true 391 | doc: TODO 392 | hue_auto: 393 | control: HUE_AUTO 394 | length: 1 395 | fields: 396 | hue_auto: 397 | type: int 398 | position: 0 399 | length: 1 400 | doc: TODO 401 | saturation: 402 | control: SATURATION 403 | length: 2 404 | fields: 405 | saturation: 406 | type: int 407 | position: 0 408 | length: 2 409 | doc: TODO 410 | sharpness: 411 | control: SHARPNESS 412 | length: 2 413 | fields: 414 | sharpness: 415 | type: int 416 | position: 0 417 | length: 2 418 | doc: TODO 419 | gamma: 420 | control: GAMMA 421 | length: 2 422 | fields: 423 | gamma: 424 | type: int 425 | position: 0 426 | length: 2 427 | doc: TODO 428 | white_balance_temperature: 429 | control: WHITE_BALANCE_TEMPERATURE 430 | length: 2 431 | fields: 432 | temperature: 433 | type: int 434 | position: 0 435 | length: 2 436 | doc: TODO 437 | white_balance_temperature_auto: 438 | control: WHITE_BALANCE_TEMPERATURE_AUTO 439 | length: 1 440 | fields: 441 | temperature_auto: 442 | type: int 443 | position: 0 444 | length: 1 445 | doc: TODO 446 | white_balance_component: 447 | control: WHITE_BALANCE_COMPONENT 448 | length: 4 449 | fields: 450 | blue: 451 | type: int 452 | position: 0 453 | length: 2 454 | doc: TODO 455 | red: 456 | type: int 457 | position: 2 458 | length: 2 459 | doc: TODO 460 | white_balance_component_auto: 461 | control: WHITE_BALANCE_COMPONENT_AUTO 462 | length: 1 463 | fields: 464 | white_balance_component_auto: 465 | type: int 466 | position: 0 467 | length: 1 468 | doc: TODO 469 | digital_multiplier: 470 | control: DIGITAL_MULTIPLIER 471 | length: 2 472 | fields: 473 | multiplier_step: 474 | type: int 475 | position: 0 476 | length: 2 477 | doc: TODO 478 | digital_multiplier_limit: 479 | control: DIGITAL_MULTIPLIER_LIMIT 480 | length: 2 481 | fields: 482 | multiplier_step: 483 | type: int 484 | position: 0 485 | length: 2 486 | doc: TODO 487 | analog_video_standard: 488 | control: ANALOG_VIDEO_STANDARD 489 | length: 1 490 | fields: 491 | video_standard: 492 | type: int 493 | position: 0 494 | length: 1 495 | doc: TODO 496 | analog_video_lock_status: 497 | control: ANALOG_LOCK_STATUS 498 | length: 1 499 | fields: 500 | status: 501 | type: int 502 | position: 0 503 | length: 1 504 | doc: TODO 505 | selector_unit: 506 | type: standard 507 | description: Standard selector unit (controls connectivity between other units) 508 | control_prefix: SU 509 | controls: 510 | input_select: 511 | control: INPUT_SELECT 512 | length: 1 513 | fields: 514 | selector: 515 | type: int 516 | position: 0 517 | length: 1 518 | doc: TODO 519 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(test_enumerating_devices) 2 | target_sources(test_enumerating_devices PRIVATE test-enumerating-devices.c) 3 | target_link_libraries(test_enumerating_devices uvc) 4 | 5 | add_test(NAME test_enumerating_devices COMMAND test_enumerating_devices) 6 | -------------------------------------------------------------------------------- /tests/test-enumerating-devices.c: -------------------------------------------------------------------------------- 1 | #include "libuvc/libuvc.h" 2 | #include 3 | #include // putenv 4 | 5 | #define DL_FOREACH(head, el) \ 6 | for (el = head; el; el = el->next) 7 | 8 | int interval_to_fps(int interval) 9 | { 10 | return (int)(10000000. / interval); 11 | } 12 | 13 | int get_product_name(uvc_device_t *dev) 14 | { 15 | uvc_error_t res; 16 | uvc_device_descriptor_t *desc; 17 | if ((res = uvc_get_device_descriptor(dev, &desc)) == UVC_SUCCESS) 18 | { 19 | 20 | fprintf(stderr, "\n>>>> %s\n", desc->product); 21 | uvc_free_device_descriptor(desc); 22 | return 0; 23 | } 24 | uvc_perror(res, "get_product_name"); 25 | return -10001; 26 | } 27 | 28 | int load_device_config(uvc_device_t *dev) 29 | { 30 | int should_detach_kernel_driver = 0; 31 | uvc_error_t res; 32 | uvc_device_handle_t *devh; 33 | 34 | res = uvc_open(dev, &devh, 1); 35 | if (res != UVC_SUCCESS) 36 | { 37 | uvc_perror(res, "load_device_config"); 38 | return -10002; 39 | } 40 | 41 | uvc_stream_ctrl_t ctrl; 42 | const uvc_format_desc_t *format; 43 | const uvc_frame_desc_t *frame; 44 | 45 | DL_FOREACH(uvc_get_format_descs(devh), format) 46 | { 47 | DL_FOREACH(format->frame_descs, frame) 48 | { 49 | fprintf( 50 | stderr, 51 | ">>> Frame format w=%hu h=%hu fps=%hu\n", 52 | frame->wWidth, 53 | frame->wHeight, 54 | interval_to_fps(frame->intervals[0])); 55 | 56 | res = uvc_get_stream_ctrl_format_size( 57 | devh, 58 | &ctrl, 59 | UVC_FRAME_FORMAT_ANY, 60 | frame->wWidth, 61 | frame->wHeight, 62 | interval_to_fps(frame->intervals[0]), 63 | should_detach_kernel_driver); 64 | break; 65 | } 66 | break; 67 | } 68 | 69 | uvc_stream_handle_t *strmh; 70 | 71 | uvc_print_stream_ctrl(&ctrl, stderr); 72 | 73 | res = uvc_stream_open_ctrl(devh, &strmh, &ctrl, should_detach_kernel_driver); 74 | if (res != UVC_SUCCESS) 75 | return res; 76 | 77 | res = uvc_stream_start(strmh, NULL, NULL, 2, 0); 78 | if (res != UVC_SUCCESS) 79 | { 80 | uvc_stream_close(strmh); 81 | return res; 82 | } 83 | 84 | uvc_frame_t *uvc_frame = NULL; 85 | int num_frames_total = 0; 86 | int num_frames_broken = 0; 87 | 88 | for (; num_frames_total < 1000; num_frames_total++) 89 | { 90 | res = uvc_stream_get_frame(strmh, &uvc_frame, 10000); 91 | if (res != UVC_SUCCESS) 92 | { 93 | uvc_perror(res, "uvc_stream_get_frame"); 94 | } 95 | else if (uvc_frame->width * uvc_frame->height > uvc_frame->data_bytes) 96 | { 97 | num_frames_broken++; 98 | } 99 | } 100 | fprintf(stderr, "++++++++++++++++++++++\n"); 101 | fprintf(stderr, "%i / %i (%f %%) broken\n", num_frames_broken, num_frames_total, 100 * num_frames_broken / num_frames_total); 102 | 103 | uvc_stream_stop(strmh); 104 | uvc_stream_close(strmh); 105 | uvc_close(devh); 106 | return 0; 107 | } 108 | 109 | int enumerate_devices() 110 | { 111 | uvc_context_t *ctx; 112 | uvc_error_t res; 113 | 114 | /* Initialize a UVC service context. Libuvc will set up its own libusb 115 | * context. Replace NULL with a libusb_context pointer to run libuvc 116 | * from an existing libusb context. */ 117 | res = uvc_init(&ctx, NULL); 118 | 119 | if (res < 0) 120 | { 121 | uvc_perror(res, "uvc_init"); 122 | return res; 123 | } 124 | 125 | puts("UVC initialized"); 126 | 127 | uvc_device_t **dev_list; 128 | uvc_device_t *dev; 129 | 130 | res = uvc_get_device_list(ctx, &dev_list); 131 | if (res < 0) 132 | { 133 | uvc_perror(res, "uvc_get_device_list"); 134 | return res; 135 | } 136 | 137 | int idx = -1; 138 | int subtest_result; 139 | while ((dev = dev_list[++idx]) != NULL) 140 | { 141 | if ((subtest_result = get_product_name(dev)) < 0) 142 | { 143 | return subtest_result; 144 | } 145 | if ((subtest_result = load_device_config(dev)) < 0) 146 | { 147 | return subtest_result; 148 | } 149 | } 150 | 151 | uvc_free_device_list(dev_list, 1); 152 | 153 | /* Close the UVC context. This closes and cleans up any existing device handles, 154 | * and it closes the libusb context if one was not provided. */ 155 | uvc_exit(ctx); 156 | puts("UVC exited"); 157 | return 0; 158 | } 159 | 160 | int main(int argc, char **argv) 161 | { 162 | // putenv("LIBUSB_DEBUG=4"); 163 | return enumerate_devices(); 164 | } 165 | --------------------------------------------------------------------------------