video streaming using websocket. but,streaming is very slower than 0.1fps.
Dependencies: BaseUsbHost EthernetInterface WebSocketClient mbed-rtos mbed
Fork of BaseUsbHost_example by
UvcCam/UvcCam.cpp@7:5dc595bbff58, 2013-02-19 (annotated)
- Committer:
- va009039
- Date:
- Tue Feb 19 15:50:06 2013 +0000
- Revision:
- 7:5dc595bbff58
video streaming using websocket
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
va009039 | 7:5dc595bbff58 | 1 | // UvcCam.cpp 2013/2/11 |
va009039 | 7:5dc595bbff58 | 2 | #include "mbed.h" |
va009039 | 7:5dc595bbff58 | 3 | #include "rtos.h" |
va009039 | 7:5dc595bbff58 | 4 | #include "BaseUsbHost.h" |
va009039 | 7:5dc595bbff58 | 5 | //#define DEBUG |
va009039 | 7:5dc595bbff58 | 6 | #include "BaseUsbHostDebug.h" |
va009039 | 7:5dc595bbff58 | 7 | #define TEST |
va009039 | 7:5dc595bbff58 | 8 | #include "BaseUsbHostTest.h" |
va009039 | 7:5dc595bbff58 | 9 | #include "UvcCam.h" |
va009039 | 7:5dc595bbff58 | 10 | #include <string> |
va009039 | 7:5dc595bbff58 | 11 | |
va009039 | 7:5dc595bbff58 | 12 | UvcCam::UvcCam(int formatIndex, int frameIndex, uint32_t interval, ControlEp* ctlEp) |
va009039 | 7:5dc595bbff58 | 13 | { |
va009039 | 7:5dc595bbff58 | 14 | uint8_t buf[34]; |
va009039 | 7:5dc595bbff58 | 15 | int rc; |
va009039 | 7:5dc595bbff58 | 16 | int alt; |
va009039 | 7:5dc595bbff58 | 17 | int cfg2; |
va009039 | 7:5dc595bbff58 | 18 | |
va009039 | 7:5dc595bbff58 | 19 | if (ctlEp == NULL) { // root hub |
va009039 | 7:5dc595bbff58 | 20 | DBG_OHCI(LPC_USB->HcRhPortStatus1); |
va009039 | 7:5dc595bbff58 | 21 | TEST_ASSERT_FALSE(LPC_USB->HcRhPortStatus1 & 0x200); |
va009039 | 7:5dc595bbff58 | 22 | ctlEp = new ControlEp(); |
va009039 | 7:5dc595bbff58 | 23 | TEST_ASSERT_TRUE(ctlEp); |
va009039 | 7:5dc595bbff58 | 24 | } |
va009039 | 7:5dc595bbff58 | 25 | bool r = check(ctlEp); |
va009039 | 7:5dc595bbff58 | 26 | TEST_ASSERT(r); |
va009039 | 7:5dc595bbff58 | 27 | m_ctlEp = ctlEp; |
va009039 | 7:5dc595bbff58 | 28 | |
va009039 | 7:5dc595bbff58 | 29 | rc = ctlEp->GetDescriptor(1, 0, buf, sizeof(StandardDeviceDescriptor)); |
va009039 | 7:5dc595bbff58 | 30 | TEST_ASSERT(rc == USB_OK); |
va009039 | 7:5dc595bbff58 | 31 | StandardDeviceDescriptor* sd = reinterpret_cast<StandardDeviceDescriptor*>(buf); |
va009039 | 7:5dc595bbff58 | 32 | VERBOSE("vid: %04x\n", sd->idVendor); |
va009039 | 7:5dc595bbff58 | 33 | VERBOSE("pid: %04x\n", sd->idProduct); |
va009039 | 7:5dc595bbff58 | 34 | string s = ctlEp->GetStringDescriptor(sd->iManufacturer); |
va009039 | 7:5dc595bbff58 | 35 | VERBOSE("iManufacturer: %s\n", s.c_str()); |
va009039 | 7:5dc595bbff58 | 36 | s = ctlEp->GetStringDescriptor(sd->iProduct); |
va009039 | 7:5dc595bbff58 | 37 | VERBOSE("iProduct: %s\n", s.c_str()); |
va009039 | 7:5dc595bbff58 | 38 | vid = sd->idVendor; |
va009039 | 7:5dc595bbff58 | 39 | pid = sd->idProduct; |
va009039 | 7:5dc595bbff58 | 40 | |
va009039 | 7:5dc595bbff58 | 41 | UvcCfg* cfg = new UvcCfg(formatIndex, frameIndex, ctlEp); |
va009039 | 7:5dc595bbff58 | 42 | TEST_ASSERT(cfg); |
va009039 | 7:5dc595bbff58 | 43 | |
va009039 | 7:5dc595bbff58 | 44 | int param_len = 34; |
va009039 | 7:5dc595bbff58 | 45 | TEST_ASSERT(cfg->bcdUVC >= 0x0100); |
va009039 | 7:5dc595bbff58 | 46 | if (cfg->bcdUVC == 0x0100) { // UVC ver. 1.0 |
va009039 | 7:5dc595bbff58 | 47 | param_len = 26; |
va009039 | 7:5dc595bbff58 | 48 | } |
va009039 | 7:5dc595bbff58 | 49 | |
va009039 | 7:5dc595bbff58 | 50 | int addr = m_ctlEp->GetAddr(); |
va009039 | 7:5dc595bbff58 | 51 | m_isoEp = new IsochronousEp(addr, cfg->bEndpointAddress, cfg->wMaxPacketSize); |
va009039 | 7:5dc595bbff58 | 52 | TEST_ASSERT_TRUE(m_isoEp); |
va009039 | 7:5dc595bbff58 | 53 | |
va009039 | 7:5dc595bbff58 | 54 | //#define USE_PROBE |
va009039 | 7:5dc595bbff58 | 55 | |
va009039 | 7:5dc595bbff58 | 56 | #ifdef USE_PROBE |
va009039 | 7:5dc595bbff58 | 57 | rc = Control(GET_INFO, VS_PROBE_CONTROL, 1, buf, 1); |
va009039 | 7:5dc595bbff58 | 58 | TEST_ASSERT(rc == USB_OK); |
va009039 | 7:5dc595bbff58 | 59 | DBG_BYTES("GET_INFO Prob", buf, 1); |
va009039 | 7:5dc595bbff58 | 60 | |
va009039 | 7:5dc595bbff58 | 61 | rc = Control(GET_DEF, VS_PROBE_CONTROL, 1, buf, param_len); |
va009039 | 7:5dc595bbff58 | 62 | TEST_ASSERT(rc == USB_OK); |
va009039 | 7:5dc595bbff58 | 63 | DBG_BYTES("GET_DEF Probe", buf, param_len); |
va009039 | 7:5dc595bbff58 | 64 | |
va009039 | 7:5dc595bbff58 | 65 | rc = Control(GET_MIN, VS_PROBE_CONTROL, 1, buf, param_len); |
va009039 | 7:5dc595bbff58 | 66 | TEST_ASSERT(rc == USB_OK); |
va009039 | 7:5dc595bbff58 | 67 | DBG_BYTES("GET_MIN Probe", buf, param_len); |
va009039 | 7:5dc595bbff58 | 68 | |
va009039 | 7:5dc595bbff58 | 69 | rc = Control(GET_MAX, VS_PROBE_CONTROL, 1, buf, param_len); |
va009039 | 7:5dc595bbff58 | 70 | TEST_ASSERT(rc == USB_OK); |
va009039 | 7:5dc595bbff58 | 71 | DBG_BYTES("GET_MAX Probe", buf, param_len); |
va009039 | 7:5dc595bbff58 | 72 | |
va009039 | 7:5dc595bbff58 | 73 | rc = Control(GET_CUR, VS_PROBE_CONTROL, 1, buf, param_len); |
va009039 | 7:5dc595bbff58 | 74 | TEST_ASSERT(rc == USB_OK); |
va009039 | 7:5dc595bbff58 | 75 | DBG_BYTES("GET_CUR Probe", buf, param_len); |
va009039 | 7:5dc595bbff58 | 76 | #endif // USE_PROBE |
va009039 | 7:5dc595bbff58 | 77 | |
va009039 | 7:5dc595bbff58 | 78 | rc = Control(GET_INFO, VS_COMMIT_CONTROL, 1, buf, 1); |
va009039 | 7:5dc595bbff58 | 79 | TEST_ASSERT(rc == USB_OK); |
va009039 | 7:5dc595bbff58 | 80 | DBG_BYTES("GET_INFO Commit", buf, 1); |
va009039 | 7:5dc595bbff58 | 81 | |
va009039 | 7:5dc595bbff58 | 82 | memset(buf, 0, param_len); |
va009039 | 7:5dc595bbff58 | 83 | buf[2] = cfg->FormatIndex; |
va009039 | 7:5dc595bbff58 | 84 | buf[3] = cfg->FrameIndex; |
va009039 | 7:5dc595bbff58 | 85 | *reinterpret_cast<uint32_t*>(buf+4) = interval; |
va009039 | 7:5dc595bbff58 | 86 | |
va009039 | 7:5dc595bbff58 | 87 | DBG_BYTES("SET_CUR Commit", buf, param_len); |
va009039 | 7:5dc595bbff58 | 88 | rc = Control(SET_CUR, VS_COMMIT_CONTROL, 1, buf, param_len); |
va009039 | 7:5dc595bbff58 | 89 | TEST_ASSERT(rc == USB_OK); |
va009039 | 7:5dc595bbff58 | 90 | |
va009039 | 7:5dc595bbff58 | 91 | rc = Control(GET_CUR, VS_COMMIT_CONTROL, 1, buf, param_len); |
va009039 | 7:5dc595bbff58 | 92 | TEST_ASSERT(rc == USB_OK); |
va009039 | 7:5dc595bbff58 | 93 | TEST_ASSERT_EQUAL(buf[2], cfg->FormatIndex); |
va009039 | 7:5dc595bbff58 | 94 | TEST_ASSERT_EQUAL(buf[3], cfg->FrameIndex); |
va009039 | 7:5dc595bbff58 | 95 | TEST_ASSERT_EQUAL(*reinterpret_cast<uint32_t*>(buf+4), interval); |
va009039 | 7:5dc595bbff58 | 96 | DBG_BYTES("GET_CUR Commit", buf, param_len); |
va009039 | 7:5dc595bbff58 | 97 | |
va009039 | 7:5dc595bbff58 | 98 | rc = m_ctlEp->GetConfiguration(&cfg2); |
va009039 | 7:5dc595bbff58 | 99 | TEST_ASSERT_EQUAL(rc, USB_OK); |
va009039 | 7:5dc595bbff58 | 100 | DBG("config: %d\n", cfg2); |
va009039 | 7:5dc595bbff58 | 101 | |
va009039 | 7:5dc595bbff58 | 102 | rc = m_ctlEp->SetConfiguration(1); |
va009039 | 7:5dc595bbff58 | 103 | TEST_ASSERT_EQUAL(rc, USB_OK); |
va009039 | 7:5dc595bbff58 | 104 | |
va009039 | 7:5dc595bbff58 | 105 | rc = m_ctlEp->GetConfiguration(&cfg2); |
va009039 | 7:5dc595bbff58 | 106 | TEST_ASSERT_EQUAL(rc, USB_OK); |
va009039 | 7:5dc595bbff58 | 107 | DBG("config: %d\n", cfg2); |
va009039 | 7:5dc595bbff58 | 108 | TEST_ASSERT_EQUAL(cfg2, 1); |
va009039 | 7:5dc595bbff58 | 109 | |
va009039 | 7:5dc595bbff58 | 110 | rc = m_ctlEp->GetInterface(cfg->bInterface, &alt); |
va009039 | 7:5dc595bbff58 | 111 | TEST_ASSERT_EQUAL(rc, USB_OK); |
va009039 | 7:5dc595bbff58 | 112 | DBG("alt: %d\n", alt); |
va009039 | 7:5dc595bbff58 | 113 | |
va009039 | 7:5dc595bbff58 | 114 | rc = m_ctlEp->SetInterfaceAlternate(cfg->bInterface, cfg->bAlternate); |
va009039 | 7:5dc595bbff58 | 115 | TEST_ASSERT_EQUAL(rc, USB_OK); |
va009039 | 7:5dc595bbff58 | 116 | |
va009039 | 7:5dc595bbff58 | 117 | rc = m_ctlEp->GetInterface(cfg->bInterface, &alt); |
va009039 | 7:5dc595bbff58 | 118 | TEST_ASSERT_EQUAL(rc, USB_OK); |
va009039 | 7:5dc595bbff58 | 119 | DBG("alt: %d\n", alt); |
va009039 | 7:5dc595bbff58 | 120 | TEST_ASSERT_EQUAL(alt, cfg->bAlternate); |
va009039 | 7:5dc595bbff58 | 121 | delete cfg; |
va009039 | 7:5dc595bbff58 | 122 | |
va009039 | 7:5dc595bbff58 | 123 | for(int i = 0; i < 16; i++) { |
va009039 | 7:5dc595bbff58 | 124 | report_cc_count[i] = 0; |
va009039 | 7:5dc595bbff58 | 125 | report_ps_cc_count[i] = 0; |
va009039 | 7:5dc595bbff58 | 126 | } |
va009039 | 7:5dc595bbff58 | 127 | |
va009039 | 7:5dc595bbff58 | 128 | LPC_USB->HcControl |= OR_CONTROL_PLE; // PeriodicListEnable |
va009039 | 7:5dc595bbff58 | 129 | LPC_USB->HcControl |= OR_CONTROL_IE; // IsochronousEnable |
va009039 | 7:5dc595bbff58 | 130 | } |
va009039 | 7:5dc595bbff58 | 131 | |
va009039 | 7:5dc595bbff58 | 132 | bool UvcCam::check(ControlEp* ctlEp) |
va009039 | 7:5dc595bbff58 | 133 | { |
va009039 | 7:5dc595bbff58 | 134 | if (ctlEp == NULL) { |
va009039 | 7:5dc595bbff58 | 135 | return false; |
va009039 | 7:5dc595bbff58 | 136 | } |
va009039 | 7:5dc595bbff58 | 137 | uint8_t buf[18]; |
va009039 | 7:5dc595bbff58 | 138 | int r = ctlEp->GetDescriptor(1, 0, buf, 8); |
va009039 | 7:5dc595bbff58 | 139 | if (r != USB_OK) { |
va009039 | 7:5dc595bbff58 | 140 | return false; |
va009039 | 7:5dc595bbff58 | 141 | } |
va009039 | 7:5dc595bbff58 | 142 | DBG_HEX(buf, 8); |
va009039 | 7:5dc595bbff58 | 143 | const uint8_t desc[] = {0x12,0x01,0x00,0x02,0xef,0x02,0x01}; |
va009039 | 7:5dc595bbff58 | 144 | if (memcmp(buf, desc, sizeof(desc)) != 0) { |
va009039 | 7:5dc595bbff58 | 145 | return false; |
va009039 | 7:5dc595bbff58 | 146 | } |
va009039 | 7:5dc595bbff58 | 147 | r = ctlEp->GetDescriptor(1, 0, buf, sizeof(buf)); |
va009039 | 7:5dc595bbff58 | 148 | if (r != USB_OK) { |
va009039 | 7:5dc595bbff58 | 149 | return false; |
va009039 | 7:5dc595bbff58 | 150 | } |
va009039 | 7:5dc595bbff58 | 151 | DBG_HEX(buf, 18); |
va009039 | 7:5dc595bbff58 | 152 | return true; |
va009039 | 7:5dc595bbff58 | 153 | } |
va009039 | 7:5dc595bbff58 | 154 | |
va009039 | 7:5dc595bbff58 | 155 | #define DESCRIPTOR_TYPE_DEVICE 1 |
va009039 | 7:5dc595bbff58 | 156 | #define DESCRIPTOR_TYPE_CONFIGURATION 2 |
va009039 | 7:5dc595bbff58 | 157 | #define DESCRIPTOR_TYPE_STRING 3 |
va009039 | 7:5dc595bbff58 | 158 | #define DESCRIPTOR_TYPE_INTERFACE 4 |
va009039 | 7:5dc595bbff58 | 159 | #define DESCRIPTOR_TYPE_ENDPOINT 5 |
va009039 | 7:5dc595bbff58 | 160 | |
va009039 | 7:5dc595bbff58 | 161 | #define DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION 0x0b |
va009039 | 7:5dc595bbff58 | 162 | |
va009039 | 7:5dc595bbff58 | 163 | #define DESCRIPTOR_TYPE_HID 0x21 |
va009039 | 7:5dc595bbff58 | 164 | #define DESCRIPTOR_TYPE_REPORT 0x22 |
va009039 | 7:5dc595bbff58 | 165 | #define DESCRIPTOR_TYPE_PHYSICAL 0x23 |
va009039 | 7:5dc595bbff58 | 166 | #define DESCRIPTOR_TYPE_CS_INTERFACE 0x24 |
va009039 | 7:5dc595bbff58 | 167 | #define DESCRIPTOR_TYPE_CS_ENDPOINT 0x25 |
va009039 | 7:5dc595bbff58 | 168 | #define DESCRIPTOR_TYPE_HUB 0x29 |
va009039 | 7:5dc595bbff58 | 169 | |
va009039 | 7:5dc595bbff58 | 170 | #define CLASS_AUDIO 0x02 |
va009039 | 7:5dc595bbff58 | 171 | #define CLASS_HUB 0x09 |
va009039 | 7:5dc595bbff58 | 172 | |
va009039 | 7:5dc595bbff58 | 173 | #define IF_EQ_THEN_PRINTF(A,B) if (A == B) {VERBOSE("%s\n", #A); |
va009039 | 7:5dc595bbff58 | 174 | #define ENDIF } |
va009039 | 7:5dc595bbff58 | 175 | |
va009039 | 7:5dc595bbff58 | 176 | #define CC_AUDIO 0x01 |
va009039 | 7:5dc595bbff58 | 177 | #define SC_AUDIOCONTROL 0x01 |
va009039 | 7:5dc595bbff58 | 178 | #define SC_AUDIOSTREAMING 0x02 |
va009039 | 7:5dc595bbff58 | 179 | |
va009039 | 7:5dc595bbff58 | 180 | #define AC_HEADER 0x01 |
va009039 | 7:5dc595bbff58 | 181 | #define AC_INPUT_TERMINAL 0x02 |
va009039 | 7:5dc595bbff58 | 182 | #define AC_OUTPUT_TERMINAL 0x03 |
va009039 | 7:5dc595bbff58 | 183 | #define AC_FEATURE_UNIT 0x06 |
va009039 | 7:5dc595bbff58 | 184 | |
va009039 | 7:5dc595bbff58 | 185 | // Input Terminal Types |
va009039 | 7:5dc595bbff58 | 186 | #define ITT_CAMERA 0x0201 |
va009039 | 7:5dc595bbff58 | 187 | |
va009039 | 7:5dc595bbff58 | 188 | static int LE16(const uint8_t* d) |
va009039 | 7:5dc595bbff58 | 189 | { |
va009039 | 7:5dc595bbff58 | 190 | return d[0] | (d[1] << 8); |
va009039 | 7:5dc595bbff58 | 191 | } |
va009039 | 7:5dc595bbff58 | 192 | |
va009039 | 7:5dc595bbff58 | 193 | static int LE24(const uint8_t* d) { |
va009039 | 7:5dc595bbff58 | 194 | return d[0] | (d[1]<<8) | (d[2] << 16); |
va009039 | 7:5dc595bbff58 | 195 | } |
va009039 | 7:5dc595bbff58 | 196 | |
va009039 | 7:5dc595bbff58 | 197 | static int LE32(const uint8_t* d) { |
va009039 | 7:5dc595bbff58 | 198 | return d[0] |(d[1]<<8) | (d[2] << 16) |(d[3] << 24) ; |
va009039 | 7:5dc595bbff58 | 199 | } |
va009039 | 7:5dc595bbff58 | 200 | |
va009039 | 7:5dc595bbff58 | 201 | struct GUID { |
va009039 | 7:5dc595bbff58 | 202 | uint8_t data[16]; |
va009039 | 7:5dc595bbff58 | 203 | string to_string() { |
va009039 | 7:5dc595bbff58 | 204 | string s; |
va009039 | 7:5dc595bbff58 | 205 | for(int i = 0; i < 16; i++) { |
va009039 | 7:5dc595bbff58 | 206 | char buf[3]; |
va009039 | 7:5dc595bbff58 | 207 | snprintf(buf, sizeof(buf), "%02x", data[i]); |
va009039 | 7:5dc595bbff58 | 208 | s += buf; |
va009039 | 7:5dc595bbff58 | 209 | if (i == 3 || i == 5 || i == 7 || i == 9) { |
va009039 | 7:5dc595bbff58 | 210 | s += "-"; |
va009039 | 7:5dc595bbff58 | 211 | } |
va009039 | 7:5dc595bbff58 | 212 | } |
va009039 | 7:5dc595bbff58 | 213 | return s; |
va009039 | 7:5dc595bbff58 | 214 | } |
va009039 | 7:5dc595bbff58 | 215 | bool isFormat(const char* fmt) { |
va009039 | 7:5dc595bbff58 | 216 | int len = strlen(fmt); |
va009039 | 7:5dc595bbff58 | 217 | return memcmp(data, fmt, len) == 0; |
va009039 | 7:5dc595bbff58 | 218 | } |
va009039 | 7:5dc595bbff58 | 219 | }; |
va009039 | 7:5dc595bbff58 | 220 | |
va009039 | 7:5dc595bbff58 | 221 | UvcCfg::UvcCfg(int formatIndex, int frameIndex, ControlEp* ctlEp):wMaxPacketSize(0),_ctlEp(ctlEp) |
va009039 | 7:5dc595bbff58 | 222 | { |
va009039 | 7:5dc595bbff58 | 223 | TEST_ASSERT(ctlEp); |
va009039 | 7:5dc595bbff58 | 224 | switch(formatIndex) { |
va009039 | 7:5dc595bbff58 | 225 | case UVC_MJPEG: _payload = UVC_MJPEG; break; |
va009039 | 7:5dc595bbff58 | 226 | case UVC_YUY2: _payload = UVC_YUY2; break; |
va009039 | 7:5dc595bbff58 | 227 | default: _payload = UVC_MJPEG; break; |
va009039 | 7:5dc595bbff58 | 228 | } |
va009039 | 7:5dc595bbff58 | 229 | |
va009039 | 7:5dc595bbff58 | 230 | switch(frameIndex) { |
va009039 | 7:5dc595bbff58 | 231 | case UVC_160x120: _width = 160; _height = 120; break; |
va009039 | 7:5dc595bbff58 | 232 | case UVC_176x144: _width = 176; _height = 144; break; |
va009039 | 7:5dc595bbff58 | 233 | case UVC_320x176: _width = 320; _height = 176; break; |
va009039 | 7:5dc595bbff58 | 234 | case UVC_320x240: _width = 320; _height = 240; break; |
va009039 | 7:5dc595bbff58 | 235 | case UVC_352x288: _width = 352; _height = 288; break; |
va009039 | 7:5dc595bbff58 | 236 | case UVC_432x240: _width = 432; _height = 240; break; |
va009039 | 7:5dc595bbff58 | 237 | case UVC_640x480: _width = 640; _height = 480; break; |
va009039 | 7:5dc595bbff58 | 238 | case UVC_544x288: _width = 544; _height = 288; break; |
va009039 | 7:5dc595bbff58 | 239 | case UVC_640x360: _width = 640; _height = 360; break; |
va009039 | 7:5dc595bbff58 | 240 | case UVC_752x416: _width = 752; _height = 416; break; |
va009039 | 7:5dc595bbff58 | 241 | case UVC_800x448: _width = 800; _height = 448; break; |
va009039 | 7:5dc595bbff58 | 242 | case UVC_800x600: _width = 800; _height = 600; break; |
va009039 | 7:5dc595bbff58 | 243 | default: _width = 160; _height = 120; break; |
va009039 | 7:5dc595bbff58 | 244 | } |
va009039 | 7:5dc595bbff58 | 245 | int index = 0; |
va009039 | 7:5dc595bbff58 | 246 | uint8_t temp[4]; |
va009039 | 7:5dc595bbff58 | 247 | int rc = ctlEp->GetDescriptor(USB_DESCRIPTOR_TYPE_CONFIGURATION, index, temp, sizeof(temp)); |
va009039 | 7:5dc595bbff58 | 248 | TEST_ASSERT(rc == USB_OK); |
va009039 | 7:5dc595bbff58 | 249 | DBG_BYTES("Config Descriptor 4bytes", temp, sizeof(temp)); |
va009039 | 7:5dc595bbff58 | 250 | TEST_ASSERT(temp[0] == 9); |
va009039 | 7:5dc595bbff58 | 251 | TEST_ASSERT(temp[1] == 0x02); |
va009039 | 7:5dc595bbff58 | 252 | int TotalLength = LE16(temp+2); |
va009039 | 7:5dc595bbff58 | 253 | DBG("TotalLength: %d\n", TotalLength); |
va009039 | 7:5dc595bbff58 | 254 | |
va009039 | 7:5dc595bbff58 | 255 | uint8_t* buf = new uint8_t[TotalLength]; |
va009039 | 7:5dc595bbff58 | 256 | TEST_ASSERT(buf); |
va009039 | 7:5dc595bbff58 | 257 | rc = ctlEp->GetDescriptor(USB_DESCRIPTOR_TYPE_CONFIGURATION, index, buf, TotalLength); |
va009039 | 7:5dc595bbff58 | 258 | TEST_ASSERT(rc == USB_OK); |
va009039 | 7:5dc595bbff58 | 259 | if (rc != USB_OK) { |
va009039 | 7:5dc595bbff58 | 260 | delete[] buf; |
va009039 | 7:5dc595bbff58 | 261 | return; |
va009039 | 7:5dc595bbff58 | 262 | } |
va009039 | 7:5dc595bbff58 | 263 | _parserConfigurationDescriptor(buf, TotalLength); |
va009039 | 7:5dc595bbff58 | 264 | delete[] buf; |
va009039 | 7:5dc595bbff58 | 265 | } |
va009039 | 7:5dc595bbff58 | 266 | |
va009039 | 7:5dc595bbff58 | 267 | void UvcCfg::_parserAudioControl(uint8_t* buf, int len) { |
va009039 | 7:5dc595bbff58 | 268 | int subtype = buf[2]; |
va009039 | 7:5dc595bbff58 | 269 | IF_EQ_THEN_PRINTF(AC_HEADER, subtype) |
va009039 | 7:5dc595bbff58 | 270 | VERBOSE("ADC: %04x\n", LE16(buf+3)); |
va009039 | 7:5dc595bbff58 | 271 | VERBOSE("TotalLength: %d\n", LE16(buf+5)); |
va009039 | 7:5dc595bbff58 | 272 | VERBOSE("InCollection: %d\n", buf[7]); |
va009039 | 7:5dc595bbff58 | 273 | for (int n = 1; n <= buf[7]; n++) { |
va009039 | 7:5dc595bbff58 | 274 | VERBOSE("aInterfaceNr(%d): %d\n", n, buf[8+n-1]); |
va009039 | 7:5dc595bbff58 | 275 | } |
va009039 | 7:5dc595bbff58 | 276 | ENDIF |
va009039 | 7:5dc595bbff58 | 277 | IF_EQ_THEN_PRINTF(AC_INPUT_TERMINAL, subtype) |
va009039 | 7:5dc595bbff58 | 278 | VERBOSE("TerminalID: %d\n", buf[3]); |
va009039 | 7:5dc595bbff58 | 279 | VERBOSE("TerminalType: %04X\n", LE16(buf+4)); |
va009039 | 7:5dc595bbff58 | 280 | VERBOSE("AssocTermianl: %d\n", buf[6]); |
va009039 | 7:5dc595bbff58 | 281 | VERBOSE("NrChannels: %d\n", buf[7]); |
va009039 | 7:5dc595bbff58 | 282 | ENDIF |
va009039 | 7:5dc595bbff58 | 283 | IF_EQ_THEN_PRINTF(AC_OUTPUT_TERMINAL, subtype) |
va009039 | 7:5dc595bbff58 | 284 | VERBOSE("TerminalID: %d\n", buf[3]); |
va009039 | 7:5dc595bbff58 | 285 | VERBOSE("TerminalType: %04X\n", LE16(buf+4)); |
va009039 | 7:5dc595bbff58 | 286 | VERBOSE("AssocTermianl: %d\n", buf[6]); |
va009039 | 7:5dc595bbff58 | 287 | ENDIF |
va009039 | 7:5dc595bbff58 | 288 | IF_EQ_THEN_PRINTF(AC_FEATURE_UNIT, subtype) |
va009039 | 7:5dc595bbff58 | 289 | VERBOSE("UnitID: %d\n", buf[3]); |
va009039 | 7:5dc595bbff58 | 290 | VERBOSE("SourceID: %d\n", buf[4]); |
va009039 | 7:5dc595bbff58 | 291 | VERBOSE("ControlSize: %d\n", buf[5]); |
va009039 | 7:5dc595bbff58 | 292 | ENDIF |
va009039 | 7:5dc595bbff58 | 293 | } |
va009039 | 7:5dc595bbff58 | 294 | |
va009039 | 7:5dc595bbff58 | 295 | #define AS_GENERAL 0x01 |
va009039 | 7:5dc595bbff58 | 296 | #define AS_FORMAT_TYPE 0x02 |
va009039 | 7:5dc595bbff58 | 297 | |
va009039 | 7:5dc595bbff58 | 298 | void UvcCfg::_parserAudioStream(uint8_t* buf, int len) { |
va009039 | 7:5dc595bbff58 | 299 | int subtype = buf[2]; |
va009039 | 7:5dc595bbff58 | 300 | IF_EQ_THEN_PRINTF(AS_GENERAL, subtype) |
va009039 | 7:5dc595bbff58 | 301 | VERBOSE("TerminalLink: %d\n", buf[3]); |
va009039 | 7:5dc595bbff58 | 302 | VERBOSE("Delay: %d\n", buf[4]); |
va009039 | 7:5dc595bbff58 | 303 | VERBOSE("FormatTag: %04x\n", LE16(buf+5)); |
va009039 | 7:5dc595bbff58 | 304 | ENDIF |
va009039 | 7:5dc595bbff58 | 305 | IF_EQ_THEN_PRINTF(AS_FORMAT_TYPE, subtype) |
va009039 | 7:5dc595bbff58 | 306 | VERBOSE("FormatType: %d\n", buf[3]); |
va009039 | 7:5dc595bbff58 | 307 | VERBOSE("NrChannels: %d\n", buf[4]); |
va009039 | 7:5dc595bbff58 | 308 | VERBOSE("SubFrameSize: %d\n", buf[5]); |
va009039 | 7:5dc595bbff58 | 309 | VERBOSE("BitResolution: %d\n", buf[6]); |
va009039 | 7:5dc595bbff58 | 310 | VERBOSE("SamFreqType: %d\n", buf[7]); |
va009039 | 7:5dc595bbff58 | 311 | VERBOSE("SamFreq(1): %d\n", LE24(buf+8)); |
va009039 | 7:5dc595bbff58 | 312 | ENDIF |
va009039 | 7:5dc595bbff58 | 313 | } |
va009039 | 7:5dc595bbff58 | 314 | |
va009039 | 7:5dc595bbff58 | 315 | #define CC_VIDEO 0x0e |
va009039 | 7:5dc595bbff58 | 316 | |
va009039 | 7:5dc595bbff58 | 317 | #define SC_VIDEOCONTROL 0x01 |
va009039 | 7:5dc595bbff58 | 318 | #define SC_VIDEOSTREAMING 0x02 |
va009039 | 7:5dc595bbff58 | 319 | |
va009039 | 7:5dc595bbff58 | 320 | #define VC_HEADER 0x01 |
va009039 | 7:5dc595bbff58 | 321 | #define VC_INPUT_TERMINAL 0x02 |
va009039 | 7:5dc595bbff58 | 322 | #define VC_OUTPUT_TERMINAL 0x03 |
va009039 | 7:5dc595bbff58 | 323 | #define VC_SELECTOR_UNIT 0x04 |
va009039 | 7:5dc595bbff58 | 324 | #define VC_PROCESSING_UNIT 0x05 |
va009039 | 7:5dc595bbff58 | 325 | #define VC_EXTENSION_UNIT 0x06 |
va009039 | 7:5dc595bbff58 | 326 | |
va009039 | 7:5dc595bbff58 | 327 | void UvcCfg::_parserVideoControl(uint8_t* buf, int len) { |
va009039 | 7:5dc595bbff58 | 328 | int subtype = buf[2]; |
va009039 | 7:5dc595bbff58 | 329 | IF_EQ_THEN_PRINTF(VC_HEADER, subtype) |
va009039 | 7:5dc595bbff58 | 330 | bcdUVC = LE16(buf+3); |
va009039 | 7:5dc595bbff58 | 331 | VERBOSE("UVC: %04x\n", bcdUVC); |
va009039 | 7:5dc595bbff58 | 332 | VERBOSE("TotalLength: %d\n", LE16(buf+5)); |
va009039 | 7:5dc595bbff58 | 333 | VERBOSE("ClockFrequency: %d\n", LE32(buf+7)); |
va009039 | 7:5dc595bbff58 | 334 | VERBOSE("InCollection: %d\n", buf[11]); |
va009039 | 7:5dc595bbff58 | 335 | VERBOSE("aInterfaceNr(1): %d\n", buf[12]); |
va009039 | 7:5dc595bbff58 | 336 | ENDIF |
va009039 | 7:5dc595bbff58 | 337 | IF_EQ_THEN_PRINTF(VC_INPUT_TERMINAL, subtype) |
va009039 | 7:5dc595bbff58 | 338 | VERBOSE("TerminalID: %d\n", buf[3]); |
va009039 | 7:5dc595bbff58 | 339 | uint16_t tt = LE16(buf+4); |
va009039 | 7:5dc595bbff58 | 340 | VERBOSE("TerminalType: %04X\n", tt); |
va009039 | 7:5dc595bbff58 | 341 | VERBOSE("AssocTerminal: %d\n", buf[6]); |
va009039 | 7:5dc595bbff58 | 342 | VERBOSE("Terminal: %d\n", buf[7]); |
va009039 | 7:5dc595bbff58 | 343 | if (tt == ITT_CAMERA) { // camera |
va009039 | 7:5dc595bbff58 | 344 | int bControlSize = buf[14]; |
va009039 | 7:5dc595bbff58 | 345 | VERBOSE("ControlSize: %d\n", bControlSize); |
va009039 | 7:5dc595bbff58 | 346 | for(int i = 0; i < bControlSize; i++) { |
va009039 | 7:5dc595bbff58 | 347 | uint8_t bControls = buf[15+i]; |
va009039 | 7:5dc595bbff58 | 348 | VERBOSE("Controls(%d): %02X\n", i, bControls); |
va009039 | 7:5dc595bbff58 | 349 | } |
va009039 | 7:5dc595bbff58 | 350 | } |
va009039 | 7:5dc595bbff58 | 351 | ENDIF |
va009039 | 7:5dc595bbff58 | 352 | IF_EQ_THEN_PRINTF(VC_OUTPUT_TERMINAL, subtype) |
va009039 | 7:5dc595bbff58 | 353 | VERBOSE("TerminalID: %d\n", buf[3]); |
va009039 | 7:5dc595bbff58 | 354 | VERBOSE("TerminalType: %04X\n", LE16(buf+4)); |
va009039 | 7:5dc595bbff58 | 355 | VERBOSE("AssocTerminal: %d\n", buf[6]); |
va009039 | 7:5dc595bbff58 | 356 | VERBOSE("SourceID: %d\n", buf[7]); |
va009039 | 7:5dc595bbff58 | 357 | VERBOSE("Terminal: %d\n", buf[8]); |
va009039 | 7:5dc595bbff58 | 358 | ENDIF |
va009039 | 7:5dc595bbff58 | 359 | IF_EQ_THEN_PRINTF(VC_SELECTOR_UNIT, subtype) |
va009039 | 7:5dc595bbff58 | 360 | VERBOSE("UnitID: %d\n", buf[3]); |
va009039 | 7:5dc595bbff58 | 361 | ENDIF |
va009039 | 7:5dc595bbff58 | 362 | IF_EQ_THEN_PRINTF(VC_PROCESSING_UNIT, subtype) |
va009039 | 7:5dc595bbff58 | 363 | VERBOSE("UnitID: %d\n", buf[3]); |
va009039 | 7:5dc595bbff58 | 364 | VERBOSE("SourceID: %d\n", buf[4]); |
va009039 | 7:5dc595bbff58 | 365 | VERBOSE("MaxMultiplier: %d\n", LE16(buf+5)); |
va009039 | 7:5dc595bbff58 | 366 | VERBOSE("ControlSize: %d\n", buf[7]); |
va009039 | 7:5dc595bbff58 | 367 | int pos = 8; |
va009039 | 7:5dc595bbff58 | 368 | for (int n = 1; n <= buf[7]; n++) { |
va009039 | 7:5dc595bbff58 | 369 | VERBOSE("Controls(%d): %02X\n", n , buf[pos]); |
va009039 | 7:5dc595bbff58 | 370 | pos++; |
va009039 | 7:5dc595bbff58 | 371 | } |
va009039 | 7:5dc595bbff58 | 372 | VERBOSE("Processing: %d\n", buf[pos]); |
va009039 | 7:5dc595bbff58 | 373 | pos++; |
va009039 | 7:5dc595bbff58 | 374 | VERBOSE("VideoStanders: %02X\n", buf[pos]); |
va009039 | 7:5dc595bbff58 | 375 | ENDIF |
va009039 | 7:5dc595bbff58 | 376 | IF_EQ_THEN_PRINTF(VC_EXTENSION_UNIT, subtype) |
va009039 | 7:5dc595bbff58 | 377 | VERBOSE("UnitID: %d\n", buf[3]); |
va009039 | 7:5dc595bbff58 | 378 | GUID* guid = reinterpret_cast<GUID*>(buf+4); |
va009039 | 7:5dc595bbff58 | 379 | string s = guid->to_string(); |
va009039 | 7:5dc595bbff58 | 380 | VERBOSE("guidExtensionCode: %s\n", s.c_str()); |
va009039 | 7:5dc595bbff58 | 381 | VERBOSE("NumControls: %d\n", buf[20]); |
va009039 | 7:5dc595bbff58 | 382 | int p = buf[21]; |
va009039 | 7:5dc595bbff58 | 383 | VERBOSE("NrInPins: %d\n", p); |
va009039 | 7:5dc595bbff58 | 384 | int pos = 22; |
va009039 | 7:5dc595bbff58 | 385 | for (int n = 1; n <= p; n++) { |
va009039 | 7:5dc595bbff58 | 386 | VERBOSE("SourceID(%d): %d\n", n, buf[pos]); |
va009039 | 7:5dc595bbff58 | 387 | pos++; |
va009039 | 7:5dc595bbff58 | 388 | } |
va009039 | 7:5dc595bbff58 | 389 | int bControlSize = buf[pos]; |
va009039 | 7:5dc595bbff58 | 390 | pos++; |
va009039 | 7:5dc595bbff58 | 391 | VERBOSE("ControlSize: %d\n", bControlSize); |
va009039 | 7:5dc595bbff58 | 392 | pos++; |
va009039 | 7:5dc595bbff58 | 393 | for(int i = 0; i < bControlSize; i++) { |
va009039 | 7:5dc595bbff58 | 394 | VERBOSE("Control(%d): %02X\n", i, buf[pos]); |
va009039 | 7:5dc595bbff58 | 395 | pos++; |
va009039 | 7:5dc595bbff58 | 396 | } |
va009039 | 7:5dc595bbff58 | 397 | VERBOSE("iExtension: %d\n", buf[pos]); |
va009039 | 7:5dc595bbff58 | 398 | ENDIF |
va009039 | 7:5dc595bbff58 | 399 | } |
va009039 | 7:5dc595bbff58 | 400 | |
va009039 | 7:5dc595bbff58 | 401 | #define VS_INPUT_HEADER 0x01 |
va009039 | 7:5dc595bbff58 | 402 | #define VS_STILL_FRAME 0x03 |
va009039 | 7:5dc595bbff58 | 403 | #define VS_FORMAT_UNCOMPRESSED 0x04 |
va009039 | 7:5dc595bbff58 | 404 | #define VS_FRAME_UNCOMPRESSED 0x05 |
va009039 | 7:5dc595bbff58 | 405 | #define VS_FORMAT_MJPEG 0x06 |
va009039 | 7:5dc595bbff58 | 406 | #define VS_FRAME_MJPEG 0x07 |
va009039 | 7:5dc595bbff58 | 407 | #define VS_COLOR_FORMAT 0x0d |
va009039 | 7:5dc595bbff58 | 408 | |
va009039 | 7:5dc595bbff58 | 409 | void UvcCfg::_parserVideoStream(uint8_t* buf, int len) { |
va009039 | 7:5dc595bbff58 | 410 | int subtype = buf[2]; |
va009039 | 7:5dc595bbff58 | 411 | IF_EQ_THEN_PRINTF(VS_INPUT_HEADER, subtype) |
va009039 | 7:5dc595bbff58 | 412 | VERBOSE("NumFormats: %d\n", buf[3]); |
va009039 | 7:5dc595bbff58 | 413 | VERBOSE("TotalLength: %d\n", LE16(buf+4)); |
va009039 | 7:5dc595bbff58 | 414 | VERBOSE("EndpointAddress: %02X\n", buf[6]); |
va009039 | 7:5dc595bbff58 | 415 | VERBOSE("Info: %02X\n", buf[7]); |
va009039 | 7:5dc595bbff58 | 416 | VERBOSE("TerminalLink: %d\n", buf[8]); |
va009039 | 7:5dc595bbff58 | 417 | VERBOSE("StillCaptureMethod: %d\n", buf[9]); |
va009039 | 7:5dc595bbff58 | 418 | VERBOSE("TriggerSupport: %d\n", buf[10]); |
va009039 | 7:5dc595bbff58 | 419 | VERBOSE("TriggerUsage: %d\n", buf[11]); |
va009039 | 7:5dc595bbff58 | 420 | VERBOSE("ControlSize: %d\n", buf[12]); |
va009039 | 7:5dc595bbff58 | 421 | int pos = 13; |
va009039 | 7:5dc595bbff58 | 422 | for (int n = 1; n <= buf[12]; n++) { |
va009039 | 7:5dc595bbff58 | 423 | VERBOSE("Controls(%d): %02X\n", n, buf[pos]); |
va009039 | 7:5dc595bbff58 | 424 | pos++; |
va009039 | 7:5dc595bbff58 | 425 | } |
va009039 | 7:5dc595bbff58 | 426 | bEndpointAddress = buf[6]; |
va009039 | 7:5dc595bbff58 | 427 | ENDIF |
va009039 | 7:5dc595bbff58 | 428 | IF_EQ_THEN_PRINTF(VS_STILL_FRAME, subtype) |
va009039 | 7:5dc595bbff58 | 429 | VERBOSE("EndpointAdress: %02X\n", buf[3]); |
va009039 | 7:5dc595bbff58 | 430 | VERBOSE("NumImageSizePatterns: %d\n", buf[4]); |
va009039 | 7:5dc595bbff58 | 431 | int ptn = buf[4]; |
va009039 | 7:5dc595bbff58 | 432 | int pos = 5; |
va009039 | 7:5dc595bbff58 | 433 | for (int n = 1; n <= ptn; n++) { |
va009039 | 7:5dc595bbff58 | 434 | VERBOSE("Width(%d): %d\n", n, LE16(buf+pos)); |
va009039 | 7:5dc595bbff58 | 435 | VERBOSE("Height(%d): %d\n", n, LE16(buf+pos+2)); |
va009039 | 7:5dc595bbff58 | 436 | pos += 4; |
va009039 | 7:5dc595bbff58 | 437 | } |
va009039 | 7:5dc595bbff58 | 438 | VERBOSE("NumCompressPtn: %d\n", buf[pos]); |
va009039 | 7:5dc595bbff58 | 439 | ptn = buf[pos++]; |
va009039 | 7:5dc595bbff58 | 440 | for (int n = 1; n <= ptn; n++) { |
va009039 | 7:5dc595bbff58 | 441 | VERBOSE("Compress(%d): %d\n", n, buf[pos]); |
va009039 | 7:5dc595bbff58 | 442 | pos++; |
va009039 | 7:5dc595bbff58 | 443 | } |
va009039 | 7:5dc595bbff58 | 444 | ENDIF |
va009039 | 7:5dc595bbff58 | 445 | IF_EQ_THEN_PRINTF(VS_FORMAT_UNCOMPRESSED, subtype) |
va009039 | 7:5dc595bbff58 | 446 | VERBOSE("FormatIndex: %d\n", buf[3]); |
va009039 | 7:5dc595bbff58 | 447 | VERBOSE("NumFrameDescriptors: %d\n", buf[4]); |
va009039 | 7:5dc595bbff58 | 448 | GUID* guid = reinterpret_cast<GUID*>(buf+5); |
va009039 | 7:5dc595bbff58 | 449 | string s = guid->to_string(); |
va009039 | 7:5dc595bbff58 | 450 | if (guid->isFormat("YUY2")) { |
va009039 | 7:5dc595bbff58 | 451 | VERBOSE("GUID: %s YUY2\n", s.c_str()); |
va009039 | 7:5dc595bbff58 | 452 | } else if (guid->isFormat("NV12")) { |
va009039 | 7:5dc595bbff58 | 453 | VERBOSE("GUID: %s NV12\n", s.c_str()); |
va009039 | 7:5dc595bbff58 | 454 | } else { |
va009039 | 7:5dc595bbff58 | 455 | VERBOSE("GUID: %s\n", s.c_str()); |
va009039 | 7:5dc595bbff58 | 456 | } |
va009039 | 7:5dc595bbff58 | 457 | VERBOSE("DefaultFrameIndex: %d\n", buf[22]); |
va009039 | 7:5dc595bbff58 | 458 | if (_payload == UVC_YUY2) { |
va009039 | 7:5dc595bbff58 | 459 | FormatIndex = buf[3]; |
va009039 | 7:5dc595bbff58 | 460 | } |
va009039 | 7:5dc595bbff58 | 461 | ENDIF |
va009039 | 7:5dc595bbff58 | 462 | IF_EQ_THEN_PRINTF(VS_FRAME_UNCOMPRESSED, subtype) |
va009039 | 7:5dc595bbff58 | 463 | VERBOSE("FrameIndex: %d\n", buf[3]); |
va009039 | 7:5dc595bbff58 | 464 | VERBOSE("Capabilites: %d\n", buf[4]); |
va009039 | 7:5dc595bbff58 | 465 | VERBOSE("Width: %d\n", LE16(buf+5)); |
va009039 | 7:5dc595bbff58 | 466 | VERBOSE("Height: %d\n", LE16(buf+7)); |
va009039 | 7:5dc595bbff58 | 467 | VERBOSE("MinBitRate: %d\n", LE32(buf+9)); |
va009039 | 7:5dc595bbff58 | 468 | VERBOSE("MaxBitRate: %d\n", LE32(buf+13)); |
va009039 | 7:5dc595bbff58 | 469 | VERBOSE("MaxVideoFrameBufferSize: %d\n", LE32(buf+17)); |
va009039 | 7:5dc595bbff58 | 470 | VERBOSE("DefaultFrameInterval: %d\n", LE32(buf+21)); |
va009039 | 7:5dc595bbff58 | 471 | VERBOSE("FrameIntervalType: %d\n", buf[25]); |
va009039 | 7:5dc595bbff58 | 472 | int it = buf[25]; |
va009039 | 7:5dc595bbff58 | 473 | uint32_t max_fi = 333333; // 30.0fps |
va009039 | 7:5dc595bbff58 | 474 | if (it == 0) { |
va009039 | 7:5dc595bbff58 | 475 | VERBOSE("FrameMinInterval: %d\n", buf[26]); |
va009039 | 7:5dc595bbff58 | 476 | VERBOSE("FrameMaxInterval: %d\n", buf[30]); |
va009039 | 7:5dc595bbff58 | 477 | VERBOSE("FrameIntervalStep: %d\n", buf[34]); |
va009039 | 7:5dc595bbff58 | 478 | } else { |
va009039 | 7:5dc595bbff58 | 479 | int pos = 26; |
va009039 | 7:5dc595bbff58 | 480 | for (int n = 1; n <= it; n++) { |
va009039 | 7:5dc595bbff58 | 481 | uint32_t fi = LE32(buf+pos); |
va009039 | 7:5dc595bbff58 | 482 | if (fi >= max_fi) { |
va009039 | 7:5dc595bbff58 | 483 | max_fi = fi; |
va009039 | 7:5dc595bbff58 | 484 | } |
va009039 | 7:5dc595bbff58 | 485 | float fps = 1e+7 / fi; |
va009039 | 7:5dc595bbff58 | 486 | VERBOSE("FrameInterval(%u): %d (%.1f fps)\n", n, fi, fps); |
va009039 | 7:5dc595bbff58 | 487 | pos += 4; |
va009039 | 7:5dc595bbff58 | 488 | } |
va009039 | 7:5dc595bbff58 | 489 | } |
va009039 | 7:5dc595bbff58 | 490 | if (_payload == UVC_YUY2) { |
va009039 | 7:5dc595bbff58 | 491 | if (_width == LE16(buf+5) && _height == LE16(buf+7)) { |
va009039 | 7:5dc595bbff58 | 492 | FrameIndex = buf[3]; |
va009039 | 7:5dc595bbff58 | 493 | } |
va009039 | 7:5dc595bbff58 | 494 | if (dwFrameInterval == 0) { |
va009039 | 7:5dc595bbff58 | 495 | dwFrameInterval = max_fi; |
va009039 | 7:5dc595bbff58 | 496 | } |
va009039 | 7:5dc595bbff58 | 497 | } |
va009039 | 7:5dc595bbff58 | 498 | ENDIF |
va009039 | 7:5dc595bbff58 | 499 | IF_EQ_THEN_PRINTF(VS_FORMAT_MJPEG, subtype) |
va009039 | 7:5dc595bbff58 | 500 | VERBOSE("FormatIndex: %d\n", buf[3]); |
va009039 | 7:5dc595bbff58 | 501 | VERBOSE("NumFrameDescriptors: %d\n", buf[4]); |
va009039 | 7:5dc595bbff58 | 502 | VERBOSE("Flags: %d\n", buf[5]); |
va009039 | 7:5dc595bbff58 | 503 | VERBOSE("DefaultFrameIndex: %d\n", buf[6]); |
va009039 | 7:5dc595bbff58 | 504 | if (_payload == UVC_MJPEG) { |
va009039 | 7:5dc595bbff58 | 505 | FormatIndex = buf[3]; |
va009039 | 7:5dc595bbff58 | 506 | } |
va009039 | 7:5dc595bbff58 | 507 | ENDIF |
va009039 | 7:5dc595bbff58 | 508 | IF_EQ_THEN_PRINTF(VS_FRAME_MJPEG, subtype) |
va009039 | 7:5dc595bbff58 | 509 | VERBOSE("FrameIndex: %d\n", buf[3]); |
va009039 | 7:5dc595bbff58 | 510 | VERBOSE("Capabilites: %d\n", buf[4]); |
va009039 | 7:5dc595bbff58 | 511 | VERBOSE("Width: %d\n", LE16(buf+5)); |
va009039 | 7:5dc595bbff58 | 512 | VERBOSE("Height: %d\n", LE16(buf+7)); |
va009039 | 7:5dc595bbff58 | 513 | VERBOSE("MinBitRate: %d\n", LE32(buf+9)); |
va009039 | 7:5dc595bbff58 | 514 | VERBOSE("MaxBitRate: %d\n", LE32(buf+13)); |
va009039 | 7:5dc595bbff58 | 515 | VERBOSE("MaxVideoFrameBufferSize: %d\n", LE32(buf+17)); |
va009039 | 7:5dc595bbff58 | 516 | VERBOSE("DefaultFrameInterval: %d\n", LE32(buf+21)); |
va009039 | 7:5dc595bbff58 | 517 | VERBOSE("FrameIntervalType: %d\n", buf[25]); |
va009039 | 7:5dc595bbff58 | 518 | int it = buf[25]; |
va009039 | 7:5dc595bbff58 | 519 | uint32_t max_fi = 333333; // 30.0fps |
va009039 | 7:5dc595bbff58 | 520 | if (it == 0) { |
va009039 | 7:5dc595bbff58 | 521 | VERBOSE("FrameMinInterval: %d\n", buf[26]); |
va009039 | 7:5dc595bbff58 | 522 | VERBOSE("FrameMaxInterval: %d\n", buf[30]); |
va009039 | 7:5dc595bbff58 | 523 | VERBOSE("FrameIntervalStep: %d\n", buf[34]); |
va009039 | 7:5dc595bbff58 | 524 | } else { |
va009039 | 7:5dc595bbff58 | 525 | int pos = 26; |
va009039 | 7:5dc595bbff58 | 526 | for (int n = 1; n <= it; n++) { |
va009039 | 7:5dc595bbff58 | 527 | uint32_t fi = LE32(buf+pos); |
va009039 | 7:5dc595bbff58 | 528 | if (fi >= max_fi) { |
va009039 | 7:5dc595bbff58 | 529 | max_fi = fi; |
va009039 | 7:5dc595bbff58 | 530 | } |
va009039 | 7:5dc595bbff58 | 531 | float fps = 1e+7 / fi; |
va009039 | 7:5dc595bbff58 | 532 | VERBOSE("FrameInterval(%u): %d (%.1f fps)\n", n, fi, fps); |
va009039 | 7:5dc595bbff58 | 533 | pos += 4; |
va009039 | 7:5dc595bbff58 | 534 | } |
va009039 | 7:5dc595bbff58 | 535 | } |
va009039 | 7:5dc595bbff58 | 536 | if (_payload == UVC_MJPEG) { |
va009039 | 7:5dc595bbff58 | 537 | if (_width == LE16(buf+5) && _height == LE16(buf+7)) { |
va009039 | 7:5dc595bbff58 | 538 | FrameIndex = buf[3]; |
va009039 | 7:5dc595bbff58 | 539 | } |
va009039 | 7:5dc595bbff58 | 540 | if (dwFrameInterval == 0) { |
va009039 | 7:5dc595bbff58 | 541 | dwFrameInterval = max_fi; |
va009039 | 7:5dc595bbff58 | 542 | } |
va009039 | 7:5dc595bbff58 | 543 | } |
va009039 | 7:5dc595bbff58 | 544 | ENDIF |
va009039 | 7:5dc595bbff58 | 545 | IF_EQ_THEN_PRINTF(VS_COLOR_FORMAT, subtype) |
va009039 | 7:5dc595bbff58 | 546 | ENDIF |
va009039 | 7:5dc595bbff58 | 547 | } |
va009039 | 7:5dc595bbff58 | 548 | |
va009039 | 7:5dc595bbff58 | 549 | void UvcCfg::_parserConfigurationDescriptor(uint8_t* buf, int len) { |
va009039 | 7:5dc595bbff58 | 550 | int pos = 0; |
va009039 | 7:5dc595bbff58 | 551 | _IfClass = 0; |
va009039 | 7:5dc595bbff58 | 552 | _IfSubClass = 0; |
va009039 | 7:5dc595bbff58 | 553 | while (pos < len) { |
va009039 | 7:5dc595bbff58 | 554 | int type = buf[pos+1]; |
va009039 | 7:5dc595bbff58 | 555 | //DBG_BYTES(TYPE_Str(type), buf+pos, buf[pos]); |
va009039 | 7:5dc595bbff58 | 556 | IF_EQ_THEN_PRINTF(DESCRIPTOR_TYPE_CONFIGURATION, type) |
va009039 | 7:5dc595bbff58 | 557 | VERBOSE("NumInterfaces: %d\n", buf[pos+4]); |
va009039 | 7:5dc595bbff58 | 558 | ENDIF |
va009039 | 7:5dc595bbff58 | 559 | IF_EQ_THEN_PRINTF(DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION, type) |
va009039 | 7:5dc595bbff58 | 560 | VERBOSE("FirstInterface: %d\n", buf[pos+2]); |
va009039 | 7:5dc595bbff58 | 561 | VERBOSE("InterfaceCount: %d\n", buf[pos+3]); |
va009039 | 7:5dc595bbff58 | 562 | VERBOSE("FunctionClass: %02X\n", buf[pos+4]); |
va009039 | 7:5dc595bbff58 | 563 | VERBOSE("FunctionSubClass: %02X\n", buf[pos+5]); |
va009039 | 7:5dc595bbff58 | 564 | VERBOSE("FunctionProtocol: %02X\n", buf[pos+6]); |
va009039 | 7:5dc595bbff58 | 565 | VERBOSE("Function: %d\n", buf[pos+7]); |
va009039 | 7:5dc595bbff58 | 566 | ENDIF |
va009039 | 7:5dc595bbff58 | 567 | IF_EQ_THEN_PRINTF(DESCRIPTOR_TYPE_INTERFACE,type) |
va009039 | 7:5dc595bbff58 | 568 | VERBOSE("InterfaceNumber: %d\n", buf[pos+2]); |
va009039 | 7:5dc595bbff58 | 569 | VERBOSE("AlternateSetting: %d\n", buf[pos+3]); |
va009039 | 7:5dc595bbff58 | 570 | VERBOSE("NumEndpoint: %d\n", buf[pos+4]); |
va009039 | 7:5dc595bbff58 | 571 | VERBOSE("InterfaceClass: %02X\n", buf[pos+5]); |
va009039 | 7:5dc595bbff58 | 572 | VERBOSE("InterfaceSubClass: %02X\n", buf[pos+6]); |
va009039 | 7:5dc595bbff58 | 573 | VERBOSE("InterfaceProtocol: %02X\n", buf[pos+7]); |
va009039 | 7:5dc595bbff58 | 574 | VERBOSE("Interface: %d\n", buf[pos+8]); |
va009039 | 7:5dc595bbff58 | 575 | _If = buf[pos+2]; |
va009039 | 7:5dc595bbff58 | 576 | _Ifalt = buf[pos+3]; |
va009039 | 7:5dc595bbff58 | 577 | _IfClass = buf[pos+5]; |
va009039 | 7:5dc595bbff58 | 578 | _IfSubClass = buf[pos+6]; |
va009039 | 7:5dc595bbff58 | 579 | ENDIF |
va009039 | 7:5dc595bbff58 | 580 | IF_EQ_THEN_PRINTF(DESCRIPTOR_TYPE_ENDPOINT, type) |
va009039 | 7:5dc595bbff58 | 581 | VERBOSE("EndpointAddress: %02X\n", buf[pos+2]); |
va009039 | 7:5dc595bbff58 | 582 | VERBOSE("Attributes: %02X\n", buf[pos+3]); |
va009039 | 7:5dc595bbff58 | 583 | VERBOSE("MaxPacketSize: %d\n", LE16(buf+pos+4)); |
va009039 | 7:5dc595bbff58 | 584 | VERBOSE("Interval: %d\n", buf[pos+6]); |
va009039 | 7:5dc595bbff58 | 585 | if (_IfClass == CC_VIDEO && _IfSubClass == SC_VIDEOSTREAMING) { |
va009039 | 7:5dc595bbff58 | 586 | if (bEndpointAddress == buf[pos+2]) { |
va009039 | 7:5dc595bbff58 | 587 | if (wMaxPacketSize == 0) { |
va009039 | 7:5dc595bbff58 | 588 | wMaxPacketSize = LE16(buf+pos+4); |
va009039 | 7:5dc595bbff58 | 589 | } |
va009039 | 7:5dc595bbff58 | 590 | if (wMaxPacketSize == LE16(buf+pos+4)) { |
va009039 | 7:5dc595bbff58 | 591 | bInterface = _If; |
va009039 | 7:5dc595bbff58 | 592 | bAlternate = _Ifalt; |
va009039 | 7:5dc595bbff58 | 593 | } |
va009039 | 7:5dc595bbff58 | 594 | } |
va009039 | 7:5dc595bbff58 | 595 | } |
va009039 | 7:5dc595bbff58 | 596 | ENDIF |
va009039 | 7:5dc595bbff58 | 597 | IF_EQ_THEN_PRINTF(DESCRIPTOR_TYPE_CS_INTERFACE, type) |
va009039 | 7:5dc595bbff58 | 598 | IF_EQ_THEN_PRINTF(CC_VIDEO, _IfClass) |
va009039 | 7:5dc595bbff58 | 599 | IF_EQ_THEN_PRINTF(SC_VIDEOCONTROL, _IfSubClass) |
va009039 | 7:5dc595bbff58 | 600 | _parserVideoControl(buf+pos, buf[pos]); |
va009039 | 7:5dc595bbff58 | 601 | ENDIF |
va009039 | 7:5dc595bbff58 | 602 | IF_EQ_THEN_PRINTF(SC_VIDEOSTREAMING, _IfSubClass) |
va009039 | 7:5dc595bbff58 | 603 | _parserVideoStream(buf+pos, buf[pos]); |
va009039 | 7:5dc595bbff58 | 604 | ENDIF |
va009039 | 7:5dc595bbff58 | 605 | ENDIF |
va009039 | 7:5dc595bbff58 | 606 | IF_EQ_THEN_PRINTF(CC_AUDIO, _IfClass) |
va009039 | 7:5dc595bbff58 | 607 | IF_EQ_THEN_PRINTF(SC_AUDIOCONTROL, _IfSubClass) |
va009039 | 7:5dc595bbff58 | 608 | _parserAudioControl(buf+pos, buf[pos]); |
va009039 | 7:5dc595bbff58 | 609 | ENDIF |
va009039 | 7:5dc595bbff58 | 610 | IF_EQ_THEN_PRINTF(SC_AUDIOSTREAMING, _IfSubClass) |
va009039 | 7:5dc595bbff58 | 611 | _parserAudioStream(buf+pos, buf[pos]); |
va009039 | 7:5dc595bbff58 | 612 | ENDIF |
va009039 | 7:5dc595bbff58 | 613 | ENDIF |
va009039 | 7:5dc595bbff58 | 614 | ENDIF |
va009039 | 7:5dc595bbff58 | 615 | IF_EQ_THEN_PRINTF(DESCRIPTOR_TYPE_HUB, type) |
va009039 | 7:5dc595bbff58 | 616 | ENDIF |
va009039 | 7:5dc595bbff58 | 617 | pos += buf[pos]; |
va009039 | 7:5dc595bbff58 | 618 | } |
va009039 | 7:5dc595bbff58 | 619 | } |
va009039 | 7:5dc595bbff58 | 620 |