1 /*
2 * Copyright 2011, Gabriel Hartmann, gabriel.hartmann@gmail.com.
3 * Copyright 2011, Jérôme Duval, korli@users.berlios.de.
4 * Copyright 2009, Ithamar Adema, <ithamar.adema@team-embedded.nl>.
5 * Distributed under the terms of the MIT License.
6 */
7
8
9 #include "UVCCamDevice.h"
10 #include "UVCDeframer.h"
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <ParameterWeb.h>
15 #include <media/Buffer.h>
16
17
18 usb_webcam_support_descriptor kSupportedDevices[] = {
19 // ofcourse we support a generic UVC device...
20 {{ USB_VIDEO_DEVICE_CLASS, USB_VIDEO_INTERFACE_VIDEOCONTROL_SUBCLASS, 0, 0, 0 }, "Generic UVC", "Video Class", "??" },
21 {{ 0xEF, 0x02, 0, 0, 0 }, "Miscellaneous device", "Interface association", "??" },
22 // ...whilst the following IDs were 'stolen' from a recent Linux driver:
23 {{ 0, 0, 0, 0x045e, 0x00f8, }, "Microsoft", "Lifecam NX-6000", "??" },
24 {{ 0, 0, 0, 0x045e, 0x0723, }, "Microsoft", "Lifecam VX-7000", "??" },
25 {{ 0, 0, 0, 0x046d, 0x08c1, }, "Logitech", "QuickCam Fusion", "??" },
26 {{ 0, 0, 0, 0x046d, 0x08c2, }, "Logitech", "QuickCam Orbit MP", "??" },
27 {{ 0, 0, 0, 0x046d, 0x08c3, }, "Logitech", "QuickCam Pro for Notebook", "??" },
28 {{ 0, 0, 0, 0x046d, 0x08c5, }, "Logitech", "QuickCam Pro 5000", "??" },
29 {{ 0, 0, 0, 0x046d, 0x08c6, }, "Logitech", "QuickCam OEM Dell Notebook", "??" },
30 {{ 0, 0, 0, 0x046d, 0x08c7, }, "Logitech", "QuickCam OEM Cisco VT Camera II", "??" },
31 {{ 0, 0, 0, 0x046d, 0x0821, }, "Logitech", "HD Pro Webcam C910", "??" },
32 {{ 0, 0, 0, 0x05ac, 0x8501, }, "Apple", "Built-In iSight", "??" },
33 {{ 0, 0, 0, 0x05e3, 0x0505, }, "Genesys Logic", "USB 2.0 PC Camera", "??" },
34 {{ 0, 0, 0, 0x0e8d, 0x0004, }, "N/A", "MT6227", "??" },
35 {{ 0, 0, 0, 0x174f, 0x5212, }, "Syntek", "(HP Spartan)", "??" },
36 {{ 0, 0, 0, 0x174f, 0x5931, }, "Syntek", "(Samsung Q310)", "??" },
37 {{ 0, 0, 0, 0x174f, 0x8a31, }, "Syntek", "Asus F9SG", "??" },
38 {{ 0, 0, 0, 0x174f, 0x8a33, }, "Syntek", "Asus U3S", "??" },
39 {{ 0, 0, 0, 0x17ef, 0x480b, }, "N/A", "Lenovo Thinkpad SL500", "??" },
40 {{ 0, 0, 0, 0x18cd, 0xcafe, }, "Ecamm", "Pico iMage", "??" },
41 {{ 0, 0, 0, 0x19ab, 0x1000, }, "Bodelin", "ProScopeHR", "??" },
42 {{ 0, 0, 0, 0x1c4f, 0x3000, }, "SiGma Micro", "USB Web Camera", "??" },
43 {{ 0, 0, 0, 0, 0}, NULL, NULL, NULL }
44 };
45
46 /* Table 2-1 Compression Formats of USB Video Payload Uncompressed */
47 usbvc_guid kYUY2Guid = {0x59, 0x55, 0x59, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80,
48 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71};
49 usbvc_guid kNV12Guid = {0x4e, 0x56, 0x31, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80,
50 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71};
51
52 static void
print_guid(const usbvc_guid guid)53 print_guid(const usbvc_guid guid)
54 {
55 if (!memcmp(guid, kYUY2Guid, sizeof(usbvc_guid)))
56 printf("YUY2");
57 else if (!memcmp(guid, kNV12Guid, sizeof(usbvc_guid)))
58 printf("NV12");
59 else {
60 printf("%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:"
61 "%02x:%02x:%02x:%02x", guid[0], guid[1], guid[2], guid[3], guid[4],
62 guid[5], guid[6], guid[7], guid[8], guid[9], guid[10], guid[11],
63 guid[12], guid[13], guid[14], guid[15]);
64 }
65 }
66
67
UVCCamDevice(CamDeviceAddon & _addon,BUSBDevice * _device)68 UVCCamDevice::UVCCamDevice(CamDeviceAddon& _addon, BUSBDevice* _device)
69 : CamDevice(_addon, _device),
70 fHeaderDescriptor(NULL),
71 fInterruptIn(NULL),
72 fUncompressedFormatIndex(1),
73 fUncompressedFrameIndex(1)
74 {
75 fDeframer = new UVCDeframer(this);
76 SetDataInput(fDeframer);
77
78 const BUSBConfiguration* config;
79 const BUSBInterface* interface;
80 usb_descriptor* generic;
81 uint8 buffer[1024];
82
83 generic = (usb_descriptor*)buffer;
84
85 for (uint32 i = 0; i < _device->CountConfigurations(); i++) {
86 config = _device->ConfigurationAt(i);
87 if (config == NULL)
88 continue;
89 _device->SetConfiguration(config);
90 for (uint32 j = 0; j < config->CountInterfaces(); j++) {
91 interface = config->InterfaceAt(j);
92 if (interface == NULL)
93 continue;
94
95 if (interface->Class() == USB_VIDEO_DEVICE_CLASS && interface->Subclass()
96 == USB_VIDEO_INTERFACE_VIDEOCONTROL_SUBCLASS) {
97 printf("UVCCamDevice: (%" B_PRIu32 ",%" B_PRIu32 "): Found Video Control "
98 "interface.\n", i, j);
99
100 // look for class specific interface descriptors and parse them
101 for (uint32 k = 0; interface->OtherDescriptorAt(k, generic,
102 sizeof(buffer)) == B_OK; k++) {
103 if (generic->generic.descriptor_type != (USB_REQTYPE_CLASS
104 | USB_DESCRIPTOR_INTERFACE))
105 continue;
106 fControlIndex = interface->Index();
107 _ParseVideoControl((const usbvc_class_descriptor*)generic,
108 generic->generic.length);
109 }
110 for (uint32 k = 0; k < interface->CountEndpoints(); k++) {
111 const BUSBEndpoint* e = interface->EndpointAt(i);
112 if (e && e->IsInterrupt() && e->IsInput()) {
113 fInterruptIn = e;
114 break;
115 }
116 }
117 fInitStatus = B_OK;
118 } else if (interface->Class() == USB_VIDEO_DEVICE_CLASS && interface->Subclass()
119 == USB_VIDEO_INTERFACE_VIDEOSTREAMING_SUBCLASS) {
120 printf("UVCCamDevice: (%" B_PRIu32 ",%" B_PRIu32 "): Found Video Streaming "
121 "interface.\n", i, j);
122
123 // look for class specific interface descriptors and parse them
124 for (uint32 k = 0; interface->OtherDescriptorAt(k, generic,
125 sizeof(buffer)) == B_OK; k++) {
126 if (generic->generic.descriptor_type != (USB_REQTYPE_CLASS
127 | USB_DESCRIPTOR_INTERFACE))
128 continue;
129 fStreamingIndex = interface->Index();
130 _ParseVideoStreaming((const usbvc_class_descriptor*)generic,
131 generic->generic.length);
132 }
133
134 for (uint32 k = 0; k < interface->CountEndpoints(); k++) {
135 const BUSBEndpoint* e = interface->EndpointAt(i);
136 if (e && e->IsIsochronous() && e->IsInput()) {
137 fIsoIn = e;
138 break;
139 }
140 }
141 }
142 }
143 }
144 }
145
146
~UVCCamDevice()147 UVCCamDevice::~UVCCamDevice()
148 {
149 free(fHeaderDescriptor);
150 }
151
152
153 void
_ParseVideoStreaming(const usbvc_class_descriptor * _descriptor,size_t len)154 UVCCamDevice::_ParseVideoStreaming(const usbvc_class_descriptor* _descriptor,
155 size_t len)
156 {
157 switch (_descriptor->descriptorSubtype) {
158 case USB_VIDEO_VS_INPUT_HEADER:
159 {
160 const usb_video_class_specific_vs_interface_input_header_descriptor* descriptor
161 = (const usb_video_class_specific_vs_interface_input_header_descriptor*)_descriptor;
162 printf("VS_INPUT_HEADER:\t#fmts=%d,ept=0x%x (%s)\n", descriptor->num_formats,
163 descriptor->_endpoint_address.endpoint_number,
164 descriptor->_endpoint_address.direction ? "IN" : "OUT");
165 if (descriptor->_info.dynamic_format_change_support)
166 printf("\tDynamic Format Change supported\n");
167 printf("\toutput terminal id=%d\n", descriptor->terminal_link);
168 printf("\tstill capture method=%d\n", descriptor->still_capture_method);
169 if (descriptor->trigger_support) {
170 printf("\ttrigger button fixed to still capture=%s\n",
171 descriptor->trigger_usage ? "no" : "yes");
172 }
173 const struct usb_video_class_specific_vs_interface_input_header_descriptor::ma_controls*
174 controls = descriptor->_ma_controls;
175 for (uint8 i = 0; i < descriptor->num_formats; i++,
176 controls =
177 (const struct usb_video_class_specific_vs_interface_input_header_descriptor
178 ::ma_controls*)((const char*)controls + descriptor->control_size)) {
179 printf("\tfmt%d: %s %s %s %s - %s %s\n", i,
180 (controls->key_frame_rate) ? "wKeyFrameRate" : "",
181 (controls->p_frame_rate) ? "wPFrameRate" : "",
182 (controls->comp_quality) ? "wCompQuality" : "",
183 (controls->comp_window_size) ? "wCompWindowSize" : "",
184 (controls->generate_key_frame) ? "<Generate Key Frame>" : "",
185 (controls->update_frame_segment) ? "<Update Frame Segment>" : "");
186 }
187 break;
188 }
189 case USB_VIDEO_VS_FORMAT_UNCOMPRESSED:
190 {
191 const usbvc_format_descriptor* descriptor
192 = (const usbvc_format_descriptor*)_descriptor;
193 fUncompressedFormatIndex = descriptor->formatIndex;
194 printf("VS_FORMAT_UNCOMPRESSED:\tbFormatIdx=%d,#frmdesc=%d,guid=",
195 descriptor->formatIndex, descriptor->numFrameDescriptors);
196 print_guid(descriptor->uncompressed.format);
197 printf("\n\t#bpp=%d,optfrmidx=%d,aspRX=%d,aspRY=%d\n",
198 descriptor->uncompressed.bytesPerPixel,
199 descriptor->uncompressed.defaultFrameIndex,
200 descriptor->uncompressed.aspectRatioX,
201 descriptor->uncompressed.aspectRatioY);
202 printf("\tbmInterlaceFlags:\n");
203 if (descriptor->uncompressed.interlaceFlags & 1)
204 printf("\tInterlaced stream or variable\n");
205 printf("\t%d fields per frame\n",
206 (descriptor->uncompressed.interlaceFlags & 2) ? 1 : 2);
207 if (descriptor->uncompressed.interlaceFlags & 4)
208 printf("\tField 1 first\n");
209 printf("\tField Pattern: ");
210 switch ((descriptor->uncompressed.interlaceFlags & 0x30) >> 4) {
211 case 0: printf("Field 1 only\n"); break;
212 case 1: printf("Field 2 only\n"); break;
213 case 2: printf("Regular pattern of fields 1 and 2\n"); break;
214 case 3: printf("Random pattern of fields 1 and 2\n"); break;
215 }
216 if (descriptor->uncompressed.copyProtect)
217 printf("\tRestrict duplication\n");
218 break;
219 }
220 case USB_VIDEO_VS_FRAME_MJPEG:
221 case USB_VIDEO_VS_FRAME_UNCOMPRESSED:
222 {
223 const usb_video_frame_descriptor* descriptor
224 = (const usb_video_frame_descriptor*)_descriptor;
225 if (_descriptor->descriptorSubtype == USB_VIDEO_VS_FRAME_UNCOMPRESSED) {
226 printf("VS_FRAME_UNCOMPRESSED:");
227 fUncompressedFrames.AddItem(
228 new usb_video_frame_descriptor(*descriptor));
229 } else {
230 printf("VS_FRAME_MJPEG:");
231 fMJPEGFrames.AddItem(new usb_video_frame_descriptor(*descriptor));
232 }
233 printf("\tbFrameIdx=%d,stillsupported=%s,"
234 "fixedframerate=%s\n", descriptor->frame_index,
235 (descriptor->capabilities & 1) ? "yes" : "no",
236 (descriptor->capabilities & 2) ? "yes" : "no");
237 printf("\twidth=%u,height=%u,min/max bitrate=%" B_PRIu32 "/%" B_PRIu32 ", maxbuf=%" B_PRIu32 "\n",
238 descriptor->width, descriptor->height,
239 descriptor->min_bit_rate, descriptor->max_bit_rate,
240 descriptor->max_video_frame_buffer_size);
241 printf("\tdefault frame interval: %" B_PRIu32 ", #intervals(0=cont): %d\n",
242 descriptor->default_frame_interval, descriptor->frame_interval_type);
243 if (descriptor->frame_interval_type == 0) {
244 printf("min/max frame interval=%" B_PRIu32 "/%" B_PRIu32 ", step=%" B_PRIu32 "\n",
245 descriptor->continuous.min_frame_interval,
246 descriptor->continuous.max_frame_interval,
247 descriptor->continuous.frame_interval_step);
248 } else for (uint8 i = 0; i < descriptor->frame_interval_type; i++) {
249 printf("\tdiscrete frame interval: %" B_PRIu32 "\n",
250 descriptor->discrete_frame_intervals[i]);
251 }
252 break;
253 }
254 case USB_VIDEO_VS_COLORFORMAT:
255 {
256 const usb_video_color_matching_descriptor* descriptor
257 = (const usb_video_color_matching_descriptor*)_descriptor;
258 printf("VS_COLORFORMAT:\n\tbColorPrimaries: ");
259 switch (descriptor->color_primaries) {
260 case 0: printf("Unspecified\n"); break;
261 case 1: printf("BT.709,sRGB\n"); break;
262 case 2: printf("BT.470-2(M)\n"); break;
263 case 3: printf("BT.470-2(B,G)\n"); break;
264 case 4: printf("SMPTE 170M\n"); break;
265 case 5: printf("SMPTE 240M\n"); break;
266 default: printf("Invalid (%d)\n", descriptor->color_primaries);
267 }
268 printf("\tbTransferCharacteristics: ");
269 switch (descriptor->transfer_characteristics) {
270 case 0: printf("Unspecified\n"); break;
271 case 1: printf("BT.709\n"); break;
272 case 2: printf("BT.470-2(M)\n"); break;
273 case 3: printf("BT.470-2(B,G)\n"); break;
274 case 4: printf("SMPTE 170M\n"); break;
275 case 5: printf("SMPTE 240M\n"); break;
276 case 6: printf("Linear (V=Lc)\n"); break;
277 case 7: printf("sRGB\n"); break;
278 default: printf("Invalid (%d)\n",
279 descriptor->transfer_characteristics);
280 }
281 printf("\tbMatrixCoefficients: ");
282 switch (descriptor->matrix_coefficients) {
283 case 0: printf("Unspecified\n"); break;
284 case 1: printf("BT.709\n"); break;
285 case 2: printf("FCC\n"); break;
286 case 3: printf("BT.470-2(B,G)\n"); break;
287 case 4: printf("SMPTE 170M (BT.601)\n"); break;
288 case 5: printf("SMPTE 240M\n"); break;
289 default: printf("Invalid (%d)\n", descriptor->matrix_coefficients);
290 }
291 break;
292 }
293 case USB_VIDEO_VS_OUTPUT_HEADER:
294 {
295 const usb_video_class_specific_vs_interface_output_header_descriptor* descriptor
296 = (const usb_video_class_specific_vs_interface_output_header_descriptor*)_descriptor;
297 printf("VS_OUTPUT_HEADER:\t#fmts=%d,ept=0x%x (%s)\n",
298 descriptor->num_formats, descriptor->_endpoint_address.endpoint_number,
299 descriptor->_endpoint_address.direction ? "IN" : "OUT");
300 printf("\toutput terminal id=%d\n", descriptor->terminal_link);
301 const struct usb_video_class_specific_vs_interface_output_header_descriptor::ma_controls*
302 controls = descriptor->_ma_controls;
303 for (uint8 i = 0; i < descriptor->num_formats; i++,
304 controls
305 = (const struct usb_video_class_specific_vs_interface_output_header_descriptor
306 ::ma_controls*)((const char*)controls + descriptor->control_size)) {
307 printf("\tfmt%d: %s %s %s %s\n", i,
308 (controls->key_frame_rate) ? "wKeyFrameRate" : "",
309 (controls->p_frame_rate) ? "wPFrameRate" : "",
310 (controls->comp_quality) ? "wCompQuality" : "",
311 (controls->comp_window_size) ? "wCompWindowSize" : "");
312 }
313 break;
314 }
315 case USB_VIDEO_VS_STILL_IMAGE_FRAME:
316 {
317 const usb_video_still_image_frame_descriptor* descriptor
318 = (const usb_video_still_image_frame_descriptor*)_descriptor;
319 printf("VS_STILL_IMAGE_FRAME:\t#imageSizes=%d,compressions=%d,"
320 "ept=0x%x\n", descriptor->num_image_size_patterns,
321 descriptor->NumCompressionPatterns(),
322 descriptor->endpoint_address);
323 for (uint8 i = 0; i < descriptor->num_image_size_patterns; i++) {
324 printf("imageSize%d: %dx%d\n", i,
325 descriptor->_pattern_size[i].width,
326 descriptor->_pattern_size[i].height);
327 }
328 for (uint8 i = 0; i < descriptor->NumCompressionPatterns(); i++) {
329 printf("compression%d: %d\n", i,
330 descriptor->CompressionPatterns()[i]);
331 }
332 break;
333 }
334 case USB_VIDEO_VS_FORMAT_MJPEG:
335 {
336 const usbvc_format_descriptor* descriptor
337 = (const usbvc_format_descriptor*)_descriptor;
338 fMJPEGFormatIndex = descriptor->formatIndex;
339 printf("VS_FORMAT_MJPEG:\tbFormatIdx=%d,#frmdesc=%d\n",
340 descriptor->formatIndex, descriptor->numFrameDescriptors);
341 printf("\t#flgs=%d,optfrmidx=%d,aspRX=%d,aspRY=%d\n",
342 descriptor->mjpeg.flags,
343 descriptor->mjpeg.defaultFrameIndex,
344 descriptor->mjpeg.aspectRatioX,
345 descriptor->mjpeg.aspectRatioY);
346 printf("\tbmInterlaceFlags:\n");
347 if (descriptor->mjpeg.interlaceFlags & 1)
348 printf("\tInterlaced stream or variable\n");
349 printf("\t%d fields per frame\n",
350 (descriptor->mjpeg.interlaceFlags & 2) ? 1 : 2);
351 if (descriptor->mjpeg.interlaceFlags & 4)
352 printf("\tField 1 first\n");
353 printf("\tField Pattern: ");
354 switch ((descriptor->mjpeg.interlaceFlags & 0x30) >> 4) {
355 case 0: printf("Field 1 only\n"); break;
356 case 1: printf("Field 2 only\n"); break;
357 case 2: printf("Regular pattern of fields 1 and 2\n"); break;
358 case 3: printf("Random pattern of fields 1 and 2\n"); break;
359 }
360 if (descriptor->mjpeg.copyProtect)
361 printf("\tRestrict duplication\n");
362 break;
363 }
364 case USB_VIDEO_VS_FORMAT_MPEG2TS:
365 printf("VS_FORMAT_MPEG2TS:\t\n");
366 break;
367 case USB_VIDEO_VS_FORMAT_DV:
368 printf("VS_FORMAT_DV:\t\n");
369 break;
370 case USB_VIDEO_VS_FORMAT_FRAME_BASED:
371 printf("VS_FORMAT_FRAME_BASED:\t\n");
372 break;
373 case USB_VIDEO_VS_FRAME_FRAME_BASED:
374 printf("VS_FRAME_FRAME_BASED:\t\n");
375 break;
376 case USB_VIDEO_VS_FORMAT_STREAM_BASED:
377 printf("VS_FORMAT_STREAM_BASED:\t\n");
378 break;
379 default:
380 printf("INVALID STREAM UNIT TYPE=%d!\n",
381 _descriptor->descriptorSubtype);
382 }
383 }
384
385
386 void
_ParseVideoControl(const usbvc_class_descriptor * _descriptor,size_t len)387 UVCCamDevice::_ParseVideoControl(const usbvc_class_descriptor* _descriptor,
388 size_t len)
389 {
390 switch (_descriptor->descriptorSubtype) {
391 case USB_VIDEO_VC_HEADER:
392 {
393 if (fHeaderDescriptor != NULL) {
394 printf("ERROR: multiple VC_HEADER! Skipping...\n");
395 break;
396 }
397 fHeaderDescriptor = (usbvc_interface_header_descriptor*)malloc(len);
398 memcpy(fHeaderDescriptor, _descriptor, len);
399 printf("VC_HEADER:\tUVC v%x.%02x, clk %.5f MHz\n",
400 fHeaderDescriptor->version >> 8,
401 fHeaderDescriptor->version & 0xff,
402 fHeaderDescriptor->clockFrequency / 1000000.0);
403 for (uint8 i = 0; i < fHeaderDescriptor->numInterfacesNumbers; i++) {
404 printf("\tStreaming Interface %d\n",
405 fHeaderDescriptor->interfaceNumbers[i]);
406 }
407 break;
408 }
409 case USB_VIDEO_VC_INPUT_TERMINAL:
410 {
411 const usbvc_input_terminal_descriptor* descriptor
412 = (const usbvc_input_terminal_descriptor*)_descriptor;
413 printf("VC_INPUT_TERMINAL:\tid=%d,type=%04x,associated terminal="
414 "%d\n", descriptor->terminalID, descriptor->terminalType,
415 descriptor->associatedTerminal);
416 printf("\tDesc: %s\n",
417 fDevice->DecodeStringDescriptor(descriptor->terminal));
418 if (descriptor->terminalType == 0x201) {
419 const usb_video_camera_terminal_descriptor* desc
420 = (const usb_video_camera_terminal_descriptor*)descriptor;
421 printf("\tObjectiveFocalLength Min/Max %d/%d\n",
422 desc->objective_focal_length_min,
423 desc->objective_focal_length_max);
424 printf("\tOcularFocalLength %d\n", desc->ocular_focal_length);
425 printf("\tControlSize %d\n", desc->control_size);
426 }
427 break;
428 }
429 case USB_VIDEO_VC_OUTPUT_TERMINAL:
430 {
431 const usb_video_output_terminal_descriptor* descriptor
432 = (const usb_video_output_terminal_descriptor*)_descriptor;
433 printf("VC_OUTPUT_TERMINAL:\tid=%d,type=%04x,associated terminal="
434 "%d, src id=%d\n", descriptor->terminal_id,
435 descriptor->terminal_type, descriptor->associated_terminal,
436 descriptor->source_id);
437 printf("\tDesc: %s\n",
438 fDevice->DecodeStringDescriptor(descriptor->terminal));
439 break;
440 }
441 case USB_VIDEO_VC_SELECTOR_UNIT:
442 {
443 const usb_video_selector_unit_descriptor* descriptor
444 = (const usb_video_selector_unit_descriptor*)_descriptor;
445 printf("VC_SELECTOR_UNIT:\tid=%d,#pins=%d\n",
446 descriptor->unit_id, descriptor->num_input_pins);
447 printf("\t");
448 for (uint8 i = 0; i < descriptor->num_input_pins; i++)
449 printf("%d ", descriptor->source_id[i]);
450 printf("\n");
451 printf("\tDesc: %s\n",
452 fDevice->DecodeStringDescriptor(descriptor->Selector()));
453 break;
454 }
455 case USB_VIDEO_VC_PROCESSING_UNIT:
456 {
457 const usb_video_processing_unit_descriptor* descriptor
458 = (const usb_video_processing_unit_descriptor*)_descriptor;
459 fControlRequestIndex = fControlIndex + (descriptor->unit_id << 8);
460 printf("VC_PROCESSING_UNIT:\t unit id=%d,src id=%d, digmul=%d\n",
461 descriptor->unit_id, descriptor->source_id,
462 descriptor->max_multiplier);
463 printf("\tbControlSize=%d\n", descriptor->control_size);
464 if (descriptor->control_size >= 1) {
465 if (descriptor->controls[0] & 1)
466 printf("\tBrightness\n");
467 if (descriptor->controls[0] & 2)
468 printf("\tContrast\n");
469 if (descriptor->controls[0] & 4)
470 printf("\tHue\n");
471 if (descriptor->controls[0] & 8)
472 printf("\tSaturation\n");
473 if (descriptor->controls[0] & 16)
474 printf("\tSharpness\n");
475 if (descriptor->controls[0] & 32)
476 printf("\tGamma\n");
477 if (descriptor->controls[0] & 64)
478 printf("\tWhite Balance Temperature\n");
479 if (descriptor->controls[0] & 128)
480 printf("\tWhite Balance Component\n");
481 }
482 if (descriptor->control_size >= 2) {
483 if (descriptor->controls[1] & 1)
484 printf("\tBacklight Compensation\n");
485 if (descriptor->controls[1] & 2)
486 printf("\tGain\n");
487 if (descriptor->controls[1] & 4)
488 printf("\tPower Line Frequency\n");
489 if (descriptor->controls[1] & 8)
490 printf("\t[AUTO] Hue\n");
491 if (descriptor->controls[1] & 16)
492 printf("\t[AUTO] White Balance Temperature\n");
493 if (descriptor->controls[1] & 32)
494 printf("\t[AUTO] White Balance Component\n");
495 if (descriptor->controls[1] & 64)
496 printf("\tDigital Multiplier\n");
497 if (descriptor->controls[1] & 128)
498 printf("\tDigital Multiplier Limit\n");
499 }
500 if (descriptor->control_size >= 3) {
501 if (descriptor->controls[2] & 1)
502 printf("\tAnalog Video Standard\n");
503 if (descriptor->controls[2] & 2)
504 printf("\tAnalog Video Lock Status\n");
505 }
506 printf("\tDesc: %s\n",
507 fDevice->DecodeStringDescriptor(descriptor->Processing()));
508 if (descriptor->VideoStandards()._video_standards.ntsc_525_60)
509 printf("\tNTSC 525/60\n");
510 if (descriptor->VideoStandards()._video_standards.pal_625_50)
511 printf("\tPAL 625/50\n");
512 if (descriptor->VideoStandards()._video_standards.secam_625_50)
513 printf("\tSECAM 625/50\n");
514 if (descriptor->VideoStandards()._video_standards.ntsc_625_50)
515 printf("\tNTSC 625/50\n");
516 if (descriptor->VideoStandards()._video_standards.pal_525_60)
517 printf("\tPAL 525/60\n");
518 break;
519 }
520 case USB_VIDEO_VC_EXTENSION_UNIT:
521 {
522 const usb_video_extension_unit_descriptor* descriptor
523 = (const usb_video_extension_unit_descriptor*)_descriptor;
524 printf("VC_EXTENSION_UNIT:\tid=%d, guid=", descriptor->unit_id);
525 print_guid(descriptor->guid_extension_code);
526 printf("\n\t#ctrls=%d, #pins=%d\n", descriptor->num_controls,
527 descriptor->num_input_pins);
528 printf("\t");
529 for (uint8 i = 0; i < descriptor->num_input_pins; i++)
530 printf("%d ", descriptor->source_id[i]);
531 printf("\n");
532 printf("\tDesc: %s\n",
533 fDevice->DecodeStringDescriptor(descriptor->Extension()));
534 break;
535 }
536 default:
537 printf("Unknown control %d\n", _descriptor->descriptorSubtype);
538 }
539 }
540
541
542 bool
SupportsIsochronous()543 UVCCamDevice::SupportsIsochronous()
544 {
545 return true;
546 }
547
548
549 status_t
StartTransfer()550 UVCCamDevice::StartTransfer()
551 {
552 if (_ProbeCommitFormat() != B_OK || _SelectBestAlternate() != B_OK)
553 return B_ERROR;
554 return CamDevice::StartTransfer();
555 }
556
557
558 status_t
StopTransfer()559 UVCCamDevice::StopTransfer()
560 {
561 _SelectIdleAlternate();
562 return CamDevice::StopTransfer();
563 }
564
565
566 status_t
SuggestVideoFrame(uint32 & width,uint32 & height)567 UVCCamDevice::SuggestVideoFrame(uint32& width, uint32& height)
568 {
569 printf("UVCCamDevice::SuggestVideoFrame(%" B_PRIu32 ", %" B_PRIu32 ")\n", width, height);
570 // As in AcceptVideoFrame(), the suggestion should probably just be the
571 // first advertised uncompressed format, but current applications prefer
572 // 320x240, so this is tried first here as a suggestion.
573 width = 320;
574 height = 240;
575 if (!AcceptVideoFrame(width, height)) {
576 const usb_video_frame_descriptor* descriptor
577 = (const usb_video_frame_descriptor*)fUncompressedFrames.FirstItem();
578 width = (*descriptor).width;
579 height = (*descriptor).height;
580 }
581 return B_OK;
582 }
583
584
585 status_t
AcceptVideoFrame(uint32 & width,uint32 & height)586 UVCCamDevice::AcceptVideoFrame(uint32& width, uint32& height)
587 {
588 printf("UVCCamDevice::AcceptVideoFrame(%" B_PRIu32 ", %" B_PRIu32 ")\n", width, height);
589 if (width <= 0 || height <= 0) {
590 // Uncomment below when applications support dimensions other than 320x240
591 // This code selects the first listed available uncompressed frame format
592 /*
593 const usbvc_frame_descriptor* descriptor
594 = (const usbvc_frame_descriptor*)fUncompressedFrames.FirstItem();
595 width = (*descriptor).width;
596 height = (*descriptor).height;
597 SetVideoFrame(BRect(0, 0, width - 1, height - 1));
598 return B_OK;
599 */
600
601 width = 320;
602 height = 240;
603 }
604
605 for (int i = 0; i<fUncompressedFrames.CountItems(); i++) {
606 const usb_video_frame_descriptor* descriptor
607 = (const usb_video_frame_descriptor*)fUncompressedFrames.ItemAt(i);
608 if ((*descriptor).width == width && (*descriptor).height == height) {
609 fUncompressedFrameIndex = i;
610 SetVideoFrame(BRect(0, 0, width - 1, height - 1));
611 return B_OK;
612 }
613 }
614
615 fprintf(stderr, "UVCCamDevice::AcceptVideoFrame() Invalid frame dimensions"
616 "\n");
617 return B_ERROR;
618 }
619
620
621 status_t
_ProbeCommitFormat()622 UVCCamDevice::_ProbeCommitFormat()
623 {
624 printf("UVCCamDevice::_ProbeCommitFormat()\n");
625 printf("UVCCamDevice::fStreamingIndex = %" B_PRIu32 "\n", fStreamingIndex);
626
627 /*
628 char error;
629 printf("BEFORE ERROR CODE CHECK.\n");
630 fDevice->ControlTransfer(
631 USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN, GET_CUR,
632 VS_STREAM_ERROR_CODE_CONTROL << 8, fStreamingIndex, 1, &error);
633 printf("Error code = Ox%x\n", error);
634 */
635
636 usb_video_probe_and_commit_controls request;
637 memset(&request, 0, sizeof(request));
638 request._hint.frame_interval = 1;
639 request.frame_interval = 333333;
640 request.format_index = fUncompressedFormatIndex;
641 request.frame_index = fUncompressedFrameIndex;
642 size_t length = fHeaderDescriptor->version > 0x100 ? 34 : 26;
643 size_t actualLength = fDevice->ControlTransfer(
644 USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT, USB_VIDEO_RC_SET_CUR,
645 USB_VIDEO_VS_PROBE_CONTROL << 8, fStreamingIndex, length, &request);
646 if (actualLength != length) {
647 fprintf(stderr, "UVCCamDevice::_ProbeFormat() SET_CUR ProbeControl1"
648 " failed %ld\n", actualLength);
649 return B_ERROR;
650 }
651
652 /*
653 usbvc_probecommit response;
654 actualLength = fDevice->ControlTransfer(
655 USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN, GET_MAX,
656 VS_PROBE_CONTROL << 8, fStreamingIndex, sizeof(response), &response);
657 if (actualLength != sizeof(response)) {
658 fprintf(stderr, "UVCCamDevice::_ProbeFormat() GetMax ProbeControl"
659 " failed\n");
660 return B_ERROR;
661 }
662
663 printf("usbvc_probecommit response.compQuality %d\n", response.compQuality);
664 request.compQuality = response.compQuality;
665 */
666
667
668 usb_video_probe_and_commit_controls response;
669 memset(&response, 0, sizeof(response));
670 actualLength = fDevice->ControlTransfer(
671 USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN, USB_VIDEO_RC_GET_CUR,
672 USB_VIDEO_VS_PROBE_CONTROL << 8, fStreamingIndex, length, &response);
673
674 /*
675 actualLength = fDevice->ControlTransfer(
676 USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT, SET_CUR,
677 VS_PROBE_CONTROL << 8, fStreamingIndex, length, &request);
678 if (actualLength != length) {
679 fprintf(stderr, "UVCCamDevice::_ProbeFormat() SetCur ProbeControl2"
680 " failed\n");
681 return B_ERROR;
682 }
683 */
684
685 actualLength = fDevice->ControlTransfer(
686 USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT, USB_VIDEO_RC_SET_CUR,
687 USB_VIDEO_VS_COMMIT_CONTROL << 8, fStreamingIndex, length, &request);
688 if (actualLength != length) {
689 fprintf(stderr, "UVCCamDevice::_ProbeFormat() SetCur CommitControl"
690 " failed\n");
691 return B_ERROR;
692 }
693
694
695 fMaxVideoFrameSize = response.max_video_frame_size;
696 fMaxPayloadTransferSize = response.max_payload_transfer_size;
697 printf("usbvc_probecommit setup done maxVideoFrameSize:%" B_PRIu32 ""
698 " maxPayloadTransferSize:%" B_PRIu32 "\n", fMaxVideoFrameSize,
699 fMaxPayloadTransferSize);
700
701 printf("UVCCamDevice::_ProbeCommitFormat()\n --> SUCCESSFUL\n");
702 return B_OK;
703 }
704
705
706 status_t
_SelectBestAlternate()707 UVCCamDevice::_SelectBestAlternate()
708 {
709 printf("UVCCamDevice::_SelectBestAlternate()\n");
710 const BUSBConfiguration* config = fDevice->ActiveConfiguration();
711 const BUSBInterface* streaming = config->InterfaceAt(fStreamingIndex);
712 if (streaming == NULL)
713 return B_BAD_INDEX;
714
715 uint32 bestBandwidth = 0;
716 uint32 alternateIndex = 0;
717 uint32 endpointIndex = 0;
718
719 for (uint32 i = 0; i < streaming->CountAlternates(); i++) {
720 const BUSBInterface* alternate = streaming->AlternateAt(i);
721 for (uint32 j = 0; j < alternate->CountEndpoints(); j++) {
722 const BUSBEndpoint* endpoint = alternate->EndpointAt(j);
723 if (!endpoint->IsIsochronous() || !endpoint->IsInput())
724 continue;
725 if (fMaxPayloadTransferSize > endpoint->MaxPacketSize())
726 continue;
727 if (bestBandwidth != 0
728 && bestBandwidth < endpoint->MaxPacketSize())
729 continue;
730 bestBandwidth = endpoint->MaxPacketSize();
731 endpointIndex = j;
732 alternateIndex = i;
733 }
734 }
735
736 if (bestBandwidth == 0) {
737 fprintf(stderr, "UVCCamDevice::_SelectBestAlternate()"
738 " couldn't find a valid alternate\n");
739 return B_ERROR;
740 }
741
742 printf("UVCCamDevice::_SelectBestAlternate() %" B_PRIu32 "\n", bestBandwidth);
743 if (((BUSBInterface*)streaming)->SetAlternate(alternateIndex) != B_OK) {
744 fprintf(stderr, "UVCCamDevice::_SelectBestAlternate()"
745 " selecting alternate failed\n");
746 return B_ERROR;
747 }
748
749 fIsoIn = streaming->EndpointAt(endpointIndex);
750
751 return B_OK;
752 }
753
754
755 status_t
_SelectIdleAlternate()756 UVCCamDevice::_SelectIdleAlternate()
757 {
758 printf("UVCCamDevice::_SelectIdleAlternate()\n");
759 const BUSBConfiguration* config = fDevice->ActiveConfiguration();
760 const BUSBInterface* streaming = config->InterfaceAt(fStreamingIndex);
761 if (streaming == NULL)
762 return B_BAD_INDEX;
763 if (((BUSBInterface*)streaming)->SetAlternate(0) != B_OK) {
764 fprintf(stderr, "UVCCamDevice::_SelectIdleAlternate()"
765 " selecting alternate failed\n");
766 return B_ERROR;
767 }
768
769 fIsoIn = NULL;
770
771 return B_OK;
772 }
773
774
775 void
_AddProcessingParameter(BParameterGroup * group,int32 index,const usb_video_processing_unit_descriptor * descriptor)776 UVCCamDevice::_AddProcessingParameter(BParameterGroup* group,
777 int32 index, const usb_video_processing_unit_descriptor* descriptor)
778 {
779 BParameterGroup* subgroup;
780 uint16 wValue = 0; // Control Selector
781 float minValue = 0.0;
782 float maxValue = 100.0;
783 if (descriptor->control_size >= 1) {
784 if (descriptor->controls[0] & 1) {
785 // debug_printf("\tBRIGHTNESS\n");
786 fBrightness = _AddParameter(group, &subgroup, index,
787 USB_VIDEO_PU_BRIGHTNESS_CONTROL, "Brightness");
788 }
789 if (descriptor->controls[0] & 2) {
790 // debug_printf("\tCONSTRAST\n");
791 fContrast = _AddParameter(group, &subgroup, index + 1,
792 USB_VIDEO_PU_CONTRAST_CONTROL, "Contrast");
793 }
794 if (descriptor->controls[0] & 4) {
795 // debug_printf("\tHUE\n");
796 fHue = _AddParameter(group, &subgroup, index + 2,
797 USB_VIDEO_PU_HUE_CONTROL, "Hue");
798 if (descriptor->control_size >= 2) {
799 if (descriptor->controls[1] & 8) {
800 fHueAuto = _AddAutoParameter(subgroup, index + 3,
801 USB_VIDEO_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL);
802 }
803 }
804 }
805 if (descriptor->controls[0] & 8) {
806 // debug_printf("\tSATURATION\n");
807 fSaturation = _AddParameter(group, &subgroup, index + 4,
808 USB_VIDEO_PU_SATURATION_CONTROL, "Saturation");
809 }
810 if (descriptor->controls[0] & 16) {
811 // debug_printf("\tSHARPNESS\n");
812 fSharpness = _AddParameter(group, &subgroup, index + 5,
813 USB_VIDEO_PU_SHARPNESS_CONTROL, "Sharpness");
814 }
815 if (descriptor->controls[0] & 32) {
816 // debug_printf("\tGamma\n");
817 fGamma = _AddParameter(group, &subgroup, index + 6,
818 USB_VIDEO_PU_GAMMA_CONTROL, "Gamma");
819 }
820 if (descriptor->controls[0] & 64) {
821 // debug_printf("\tWHITE BALANCE TEMPERATURE\n");
822 fWBTemp = _AddParameter(group, &subgroup, index + 7,
823 USB_VIDEO_PU_WHITE_BALANCE_TEMPERATURE_CONTROL, "WB Temperature");
824 if (descriptor->control_size >= 2) {
825 if (descriptor->controls[1] & 16) {
826 fWBTempAuto = _AddAutoParameter(subgroup, index + 8,
827 USB_VIDEO_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL);
828 }
829 }
830 }
831 if (descriptor->controls[0] & 128) {
832 // debug_printf("\tWhite Balance Component\n");
833 fWBComponent = _AddParameter(group, &subgroup, index + 9,
834 USB_VIDEO_PU_WHITE_BALANCE_COMPONENT_CONTROL, "WB Component");
835 if (descriptor->control_size >= 2) {
836 if (descriptor->controls[1] & 32) {
837 fWBTempAuto = _AddAutoParameter(subgroup, index + 10,
838 USB_VIDEO_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL);
839 }
840 }
841 }
842 }
843 if (descriptor->control_size >= 2) {
844 if (descriptor->controls[1] & 1) {
845 // debug_printf("\tBACKLIGHT COMPENSATION\n");
846 int16 data;
847 wValue = USB_VIDEO_PU_BACKLIGHT_COMPENSATION_CONTROL << 8;
848 fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
849 USB_VIDEO_RC_GET_MAX, wValue, fControlRequestIndex, sizeof(data), &data);
850 maxValue = (float)data;
851 fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
852 USB_VIDEO_RC_GET_MIN, wValue, fControlRequestIndex, sizeof(data), &data);
853 minValue = (float)data;
854 fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
855 USB_VIDEO_RC_GET_CUR, wValue, fControlRequestIndex, sizeof(data), &data);
856 fBacklightCompensation = (float)data;
857 subgroup = group->MakeGroup("Backlight Compensation");
858 if (maxValue - minValue == 1) { // Binary Switch
859 fBinaryBacklightCompensation = true;
860 subgroup->MakeDiscreteParameter(index + 11,
861 B_MEDIA_RAW_VIDEO, "Backlight Compensation",
862 B_ENABLE);
863 } else { // Range of values
864 fBinaryBacklightCompensation = false;
865 subgroup->MakeContinuousParameter(index + 11,
866 B_MEDIA_RAW_VIDEO, "Backlight Compensation",
867 B_GAIN, "", minValue, maxValue, 1.0 / (maxValue - minValue));
868 }
869 }
870 if (descriptor->controls[1] & 2) {
871 // debug_printf("\tGAIN\n");
872 fGain = _AddParameter(group, &subgroup, index + 12, USB_VIDEO_PU_GAIN_CONTROL,
873 "Gain");
874 }
875 if (descriptor->controls[1] & 4) {
876 // debug_printf("\tPOWER LINE FREQUENCY\n");
877 wValue = USB_VIDEO_PU_POWER_LINE_FREQUENCY_CONTROL << 8;
878 int8 data;
879 if (fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
880 USB_VIDEO_RC_GET_CUR, wValue, fControlRequestIndex, sizeof(data), &data)
881 == sizeof(data)) {
882 fPowerlineFrequency = data;
883 }
884 subgroup = group->MakeGroup("Power Line Frequency");
885 subgroup->MakeContinuousParameter(index + 13,
886 B_MEDIA_RAW_VIDEO, "Frequency", B_GAIN, "", 0, 60.0, 1.0 / 60.0);
887 }
888 // TODO Determine whether controls apply to these
889 /*
890 if (descriptor->controls[1] & 64)
891 debug_printf("\tDigital Multiplier\n");
892 if (descriptor->controls[1] & 128)
893 debug_printf("\tDigital Multiplier Limit\n");
894 */
895 }
896 // TODO Determine whether controls apply to these
897 /*
898 if (descriptor->controlSize >= 3) {
899 if (descriptor->controls[2] & 1)
900 debug_printf("\tAnalog Video Standard\n");
901 if (descriptor->controls[2] & 2)
902 debug_printf("\tAnalog Video Lock Status\n");
903 }
904 */
905
906 }
907
908
909
910 float
_AddParameter(BParameterGroup * group,BParameterGroup ** subgroup,int32 index,uint16 wValue,const char * name)911 UVCCamDevice::_AddParameter(BParameterGroup* group,
912 BParameterGroup** subgroup, int32 index, uint16 wValue, const char* name)
913 {
914 float minValue = 0.0;
915 float maxValue = 100.0;
916 float currValue = 0.0;
917 int16 data;
918
919 wValue <<= 8;
920
921 if (fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
922 USB_VIDEO_RC_GET_MAX, wValue, fControlRequestIndex, sizeof(data), &data)
923 == sizeof(data)) {
924 maxValue = (float)data;
925 }
926 if (fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
927 USB_VIDEO_RC_GET_MIN, wValue, fControlRequestIndex, sizeof(data), &data)
928 == sizeof(data)) {
929 minValue = (float)data;
930 }
931 if (fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
932 USB_VIDEO_RC_GET_CUR, wValue, fControlRequestIndex, sizeof(data), &data)
933 == sizeof(data)) {
934 currValue = (float)data;
935 }
936
937 *subgroup = group->MakeGroup(name);
938 (*subgroup)->MakeContinuousParameter(index,
939 B_MEDIA_RAW_VIDEO, name, B_GAIN, "", minValue, maxValue,
940 1.0 / (maxValue - minValue));
941 return currValue;
942 }
943
944
945 uint8
_AddAutoParameter(BParameterGroup * subgroup,int32 index,uint16 wValue)946 UVCCamDevice::_AddAutoParameter(BParameterGroup* subgroup, int32 index,
947 uint16 wValue)
948 {
949 uint8 data;
950 wValue <<= 8;
951
952 fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
953 USB_VIDEO_RC_GET_CUR, wValue, fControlRequestIndex, 1, &data);
954 subgroup->MakeDiscreteParameter(index, B_MEDIA_RAW_VIDEO, "Auto",
955 B_ENABLE);
956
957 return data;
958 }
959
960
961 void
AddParameters(BParameterGroup * group,int32 & index)962 UVCCamDevice::AddParameters(BParameterGroup* group, int32& index)
963 {
964 printf("UVCCamDevice::AddParameters()\n");
965 fFirstParameterID = index;
966 // debug_printf("fIndex = %d\n",fIndex);
967 CamDevice::AddParameters(group, index);
968
969 const BUSBConfiguration* config;
970 const BUSBInterface* interface;
971 uint8 buffer[1024];
972
973 usb_descriptor* generic = (usb_descriptor*)buffer;
974
975 for (uint32 i = 0; i < fDevice->CountConfigurations(); i++) {
976 config = fDevice->ConfigurationAt(i);
977 if (config == NULL)
978 continue;
979 fDevice->SetConfiguration(config);
980 for (uint32 j = 0; j < config->CountInterfaces(); j++) {
981 interface = config->InterfaceAt(j);
982 if (interface == NULL)
983 continue;
984 if (interface->Class() != USB_VIDEO_DEVICE_CLASS || interface->Subclass()
985 != USB_VIDEO_INTERFACE_VIDEOCONTROL_SUBCLASS)
986 continue;
987 for (uint32 k = 0; interface->OtherDescriptorAt(k, generic,
988 sizeof(buffer)) == B_OK; k++) {
989 if (generic->generic.descriptor_type != (USB_REQTYPE_CLASS
990 | USB_DESCRIPTOR_INTERFACE))
991 continue;
992
993 if (((const usbvc_class_descriptor*)generic)->descriptorSubtype
994 == USB_VIDEO_VC_PROCESSING_UNIT) {
995 _AddProcessingParameter(group, index,
996 (const usb_video_processing_unit_descriptor*)generic);
997 }
998 }
999 }
1000 }
1001 }
1002
1003
1004 status_t
GetParameterValue(int32 id,bigtime_t * last_change,void * value,size_t * size)1005 UVCCamDevice::GetParameterValue(int32 id, bigtime_t* last_change, void* value,
1006 size_t* size)
1007 {
1008 printf("UVCCAmDevice::GetParameterValue(%" B_PRId32 ")\n", id - fFirstParameterID);
1009 float* currValue;
1010 int* currValueInt;
1011 int16 data;
1012 uint16 wValue = 0;
1013 switch (id - fFirstParameterID) {
1014 case 0:
1015 // debug_printf("\tBrightness:\n");
1016 // debug_printf("\tValue = %f\n",fBrightness);
1017 *size = sizeof(float);
1018 currValue = (float*)value;
1019 *currValue = fBrightness;
1020 *last_change = fLastParameterChanges;
1021 return B_OK;
1022 case 1:
1023 // debug_printf("\tContrast:\n");
1024 // debug_printf("\tValue = %f\n",fContrast);
1025 *size = sizeof(float);
1026 currValue = (float*)value;
1027 *currValue = fContrast;
1028 *last_change = fLastParameterChanges;
1029 return B_OK;
1030 case 2:
1031 // debug_printf("\tHue:\n");
1032 // debug_printf("\tValue = %f\n",fHue);
1033 *size = sizeof(float);
1034 currValue = (float*)value;
1035 *currValue = fHue;
1036 *last_change = fLastParameterChanges;
1037 return B_OK;
1038 case 4:
1039 // debug_printf("\tSaturation:\n");
1040 // debug_printf("\tValue = %f\n",fSaturation);
1041 *size = sizeof(float);
1042 currValue = (float*)value;
1043 *currValue = fSaturation;
1044 *last_change = fLastParameterChanges;
1045 return B_OK;
1046 case 5:
1047 // debug_printf("\tSharpness:\n");
1048 // debug_printf("\tValue = %f\n",fSharpness);
1049 *size = sizeof(float);
1050 currValue = (float*)value;
1051 *currValue = fSharpness;
1052 *last_change = fLastParameterChanges;
1053 return B_OK;
1054 case 7:
1055 // debug_printf("\tWB Temperature:\n");
1056 *size = sizeof(float);
1057 currValue = (float*)value;
1058 wValue = USB_VIDEO_PU_WHITE_BALANCE_TEMPERATURE_CONTROL << 8;
1059 if (fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
1060 USB_VIDEO_RC_GET_CUR, wValue, fControlRequestIndex, sizeof(data), &data)
1061 == sizeof(data)) {
1062 fWBTemp = (float)data;
1063 }
1064 // debug_printf("\tValue = %f\n",fWBTemp);
1065 *currValue = fWBTemp;
1066 *last_change = fLastParameterChanges;
1067 return B_OK;
1068 case 8:
1069 // debug_printf("\tWB Temperature Auto:\n");
1070 // debug_printf("\tValue = %d\n",fWBTempAuto);
1071 *size = sizeof(int);
1072 currValueInt = ((int*)value);
1073 *currValueInt = fWBTempAuto;
1074 *last_change = fLastParameterChanges;
1075 return B_OK;
1076 case 11:
1077 if (!fBinaryBacklightCompensation) {
1078 // debug_printf("\tBacklight Compensation:\n");
1079 // debug_printf("\tValue = %f\n",fBacklightCompensation);
1080 *size = sizeof(float);
1081 currValue = (float*)value;
1082 *currValue = fBacklightCompensation;
1083 *last_change = fLastParameterChanges;
1084 } else {
1085 // debug_printf("\tBacklight Compensation:\n");
1086 // debug_printf("\tValue = %d\n",fBacklightCompensationBinary);
1087 currValueInt = (int*)value;
1088 *currValueInt = fBacklightCompensationBinary;
1089 *last_change = fLastParameterChanges;
1090 }
1091 return B_OK;
1092 case 12:
1093 // debug_printf("\tGain:\n");
1094 // debug_printf("\tValue = %f\n",fGain);
1095 *size = sizeof(float);
1096 currValue = (float*)value;
1097 *currValue = fGain;
1098 *last_change = fLastParameterChanges;
1099 return B_OK;
1100 case 13:
1101 // debug_printf("\tPowerline Frequency:\n");
1102 // debug_printf("\tValue = %d\n",fPowerlineFrequency);
1103 *size = sizeof(float);
1104 currValue = (float*)value;
1105 switch (fPowerlineFrequency) {
1106 case 0:
1107 *currValue = 0.0;
1108 break;
1109 case 1:
1110 *currValue = 50.0;
1111 break;
1112 case 2:
1113 *currValue = 60.0;
1114 break;
1115 }
1116 *last_change = fLastParameterChanges;
1117 return B_OK;
1118
1119 }
1120 return B_BAD_VALUE;
1121 }
1122
1123
1124 status_t
SetParameterValue(int32 id,bigtime_t when,const void * value,size_t size)1125 UVCCamDevice::SetParameterValue(int32 id, bigtime_t when, const void* value,
1126 size_t size)
1127 {
1128 printf("UVCCamDevice::SetParameterValue(%" B_PRId32 ")\n", id - fFirstParameterID);
1129 switch (id - fFirstParameterID) {
1130 case 0:
1131 // debug_printf("\tBrightness:\n");
1132 if (!value || (size != sizeof(float)))
1133 return B_BAD_VALUE;
1134 fBrightness = *((float*)value);
1135 fLastParameterChanges = when;
1136 return _SetParameterValue(USB_VIDEO_PU_BRIGHTNESS_CONTROL, (int16)fBrightness);
1137 case 1:
1138 // debug_printf("\tContrast:\n");
1139 if (!value || (size != sizeof(float)))
1140 return B_BAD_VALUE;
1141 fContrast = *((float*)value);
1142 fLastParameterChanges = when;
1143 return _SetParameterValue(USB_VIDEO_PU_CONTRAST_CONTROL, (int16)fContrast);
1144 case 2:
1145 // debug_printf("\tHue:\n");
1146 if (!value || (size != sizeof(float)))
1147 return B_BAD_VALUE;
1148 fHue = *((float*)value);
1149 fLastParameterChanges = when;
1150 return _SetParameterValue(USB_VIDEO_PU_HUE_CONTROL, (int16)fHue);
1151 case 4:
1152 // debug_printf("\tSaturation:\n");
1153 if (!value || (size != sizeof(float)))
1154 return B_BAD_VALUE;
1155 fSaturation = *((float*)value);
1156 fLastParameterChanges = when;
1157 return _SetParameterValue(USB_VIDEO_PU_SATURATION_CONTROL, (int16)fSaturation);
1158 case 5:
1159 // debug_printf("\tSharpness:\n");
1160 if (!value || (size != sizeof(float)))
1161 return B_BAD_VALUE;
1162 fSharpness = *((float*)value);
1163 fLastParameterChanges = when;
1164 return _SetParameterValue(USB_VIDEO_PU_SHARPNESS_CONTROL, (int16)fSharpness);
1165 case 7:
1166 if (fWBTempAuto)
1167 return B_OK;
1168 // debug_printf("\tWB Temperature:\n");
1169 if (!value || (size != sizeof(float)))
1170 return B_BAD_VALUE;
1171 fWBTemp = *((float*)value);
1172 fLastParameterChanges = when;
1173 return _SetParameterValue(USB_VIDEO_PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
1174 (int16)fWBTemp);
1175 case 8:
1176 // debug_printf("\tWB Temperature Auto:\n");
1177 if (!value || (size != sizeof(int)))
1178 return B_BAD_VALUE;
1179 fWBTempAuto = *((int*)value);
1180 fLastParameterChanges = when;
1181 return _SetParameterValue(
1182 USB_VIDEO_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL, (int8)fWBTempAuto);
1183 case 11:
1184 if (!fBinaryBacklightCompensation) {
1185 // debug_printf("\tBacklight Compensation:\n");
1186 if (!value || (size != sizeof(float)))
1187 return B_BAD_VALUE;
1188 fBacklightCompensation = *((float*)value);
1189 } else {
1190 // debug_printf("\tBacklight Compensation:\n");
1191 if (!value || (size != sizeof(int)))
1192 return B_BAD_VALUE;
1193 fBacklightCompensationBinary = *((int*)value);
1194 }
1195 fLastParameterChanges = when;
1196 return _SetParameterValue(USB_VIDEO_PU_BACKLIGHT_COMPENSATION_CONTROL,
1197 (int16)fBacklightCompensationBinary);
1198 case 12:
1199 // debug_printf("\tGain:\n");
1200 if (!value || (size != sizeof(float)))
1201 return B_BAD_VALUE;
1202 fGain = *((float*)value);
1203 fLastParameterChanges = when;
1204 return _SetParameterValue(USB_VIDEO_PU_GAIN_CONTROL, (int16)fGain);
1205 case 13:
1206 // debug_printf("\tPowerline Frequency:\n");
1207 // debug_printf("\tValue = %f\n",*((float*)value));
1208 if (!value || (size != sizeof(float)))
1209 return B_BAD_VALUE;
1210 float inValue = *((float*)value);
1211 fPowerlineFrequency = 0;
1212 if (inValue > 45.0 && inValue < 55.0) {
1213 fPowerlineFrequency = 1;
1214 }
1215 if (inValue >= 55.0) {
1216 fPowerlineFrequency = 2;
1217 }
1218 fLastParameterChanges = when;
1219 return _SetParameterValue(USB_VIDEO_PU_POWER_LINE_FREQUENCY_CONTROL,
1220 (int8)fPowerlineFrequency);
1221
1222 }
1223 return B_BAD_VALUE;
1224 }
1225
1226
1227 status_t
_SetParameterValue(uint16 wValue,int16 setValue)1228 UVCCamDevice::_SetParameterValue(uint16 wValue, int16 setValue)
1229 {
1230 return (fDevice->ControlTransfer(USB_REQTYPE_CLASS
1231 | USB_REQTYPE_INTERFACE_OUT, USB_VIDEO_RC_SET_CUR, wValue << 8, fControlRequestIndex,
1232 sizeof(setValue), &setValue)) == sizeof(setValue);
1233 }
1234
1235
1236 status_t
_SetParameterValue(uint16 wValue,int8 setValue)1237 UVCCamDevice::_SetParameterValue(uint16 wValue, int8 setValue)
1238 {
1239 return (fDevice->ControlTransfer(USB_REQTYPE_CLASS
1240 | USB_REQTYPE_INTERFACE_OUT, USB_VIDEO_RC_SET_CUR, wValue << 8, fControlRequestIndex,
1241 sizeof(setValue), &setValue)) == sizeof(setValue);
1242 }
1243
1244
1245 status_t
FillFrameBuffer(BBuffer * buffer,bigtime_t * stamp)1246 UVCCamDevice::FillFrameBuffer(BBuffer* buffer, bigtime_t* stamp)
1247 {
1248 memset(buffer->Data(), 0, buffer->SizeAvailable());
1249 status_t err = fDeframer->WaitFrame(2000000);
1250 if (err < B_OK) {
1251 fprintf(stderr, "WaitFrame: %" B_PRIx32 "\n", err);
1252 return err;
1253 }
1254
1255 CamFrame* f;
1256 err = fDeframer->GetFrame(&f, stamp);
1257 if (err < B_OK) {
1258 fprintf(stderr, "GetFrame: %" B_PRIx32 "\n", err);
1259 return err;
1260 }
1261
1262 long int w = (long)(VideoFrame().right - VideoFrame().left + 1);
1263 long int h = (long)(VideoFrame().bottom - VideoFrame().top + 1);
1264
1265 if (buffer->SizeAvailable() >= (size_t)w * h * 4) {
1266 // TODO: The Video Producer only outputs B_RGB32. This is OK for most
1267 // applications. This could be leveraged if applications can
1268 // consume B_YUV422.
1269 _DecodeColor((unsigned char*)buffer->Data(),
1270 (unsigned char*)f->Buffer(), w, h);
1271 }
1272 delete f;
1273 return B_OK;
1274 }
1275
1276
1277 void
_DecodeColor(unsigned char * dst,unsigned char * src,int32 width,int32 height)1278 UVCCamDevice::_DecodeColor(unsigned char* dst, unsigned char* src,
1279 int32 width, int32 height)
1280 {
1281 long int i;
1282 unsigned char* rawpt, * scanpt;
1283 long int size;
1284
1285 rawpt = src;
1286 scanpt = dst;
1287 size = width*height;
1288
1289 for ( i = 0; i < size; i++ ) {
1290 if ( (i/width) % 2 == 0 ) {
1291 if ( (i % 2) == 0 ) {
1292 /* B */
1293 if ( (i > width) && ((i % width) > 0) ) {
1294 *scanpt++ = (*(rawpt-width-1)+*(rawpt-width+1)
1295 + *(rawpt+width-1)+*(rawpt+width+1))/4; /* R */
1296 *scanpt++ = (*(rawpt-1)+*(rawpt+1)
1297 + *(rawpt+width)+*(rawpt-width))/4; /* G */
1298 *scanpt++ = *rawpt; /* B */
1299 } else {
1300 /* first line or left column */
1301 *scanpt++ = *(rawpt+width+1); /* R */
1302 *scanpt++ = (*(rawpt+1)+*(rawpt+width))/2; /* G */
1303 *scanpt++ = *rawpt; /* B */
1304 }
1305 } else {
1306 /* (B)G */
1307 if ( (i > width) && ((i % width) < (width-1)) ) {
1308 *scanpt++ = (*(rawpt+width)+*(rawpt-width))/2; /* R */
1309 *scanpt++ = *rawpt; /* G */
1310 *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2; /* B */
1311 } else {
1312 /* first line or right column */
1313 *scanpt++ = *(rawpt+width); /* R */
1314 *scanpt++ = *rawpt; /* G */
1315 *scanpt++ = *(rawpt-1); /* B */
1316 }
1317 }
1318 } else {
1319 if ( (i % 2) == 0 ) {
1320 /* G(R) */
1321 if ( (i < (width*(height-1))) && ((i % width) > 0) ) {
1322 *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2; /* R */
1323 *scanpt++ = *rawpt; /* G */
1324 *scanpt++ = (*(rawpt+width)+*(rawpt-width))/2; /* B */
1325 } else {
1326 /* bottom line or left column */
1327 *scanpt++ = *(rawpt+1); /* R */
1328 *scanpt++ = *rawpt; /* G */
1329 *scanpt++ = *(rawpt-width); /* B */
1330 }
1331 } else {
1332 /* R */
1333 if ( i < (width*(height-1)) && ((i % width) < (width-1)) ) {
1334 *scanpt++ = *rawpt; /* R */
1335 *scanpt++ = (*(rawpt-1)+*(rawpt+1)
1336 + *(rawpt-width)+*(rawpt+width))/4; /* G */
1337 *scanpt++ = (*(rawpt-width-1)+*(rawpt-width+1)
1338 + *(rawpt+width-1)+*(rawpt+width+1))/4; /* B */
1339 } else {
1340 /* bottom line or right column */
1341 *scanpt++ = *rawpt; /* R */
1342 *scanpt++ = (*(rawpt-1)+*(rawpt-width))/2; /* G */
1343 *scanpt++ = *(rawpt-width-1); /* B */
1344 }
1345 }
1346 }
1347 rawpt++;
1348 }
1349 }
1350
1351
1352
1353
UVCCamDeviceAddon(WebCamMediaAddOn * webcam)1354 UVCCamDeviceAddon::UVCCamDeviceAddon(WebCamMediaAddOn* webcam)
1355 : CamDeviceAddon(webcam)
1356 {
1357 printf("UVCCamDeviceAddon::UVCCamDeviceAddon(WebCamMediaAddOn* webcam)\n");
1358 SetSupportedDevices(kSupportedDevices);
1359 }
1360
1361
~UVCCamDeviceAddon()1362 UVCCamDeviceAddon::~UVCCamDeviceAddon()
1363 {
1364 }
1365
1366
1367 const char *
BrandName()1368 UVCCamDeviceAddon::BrandName()
1369 {
1370 printf("UVCCamDeviceAddon::BrandName()\n");
1371 return "USB Video Class";
1372 }
1373
1374
1375 UVCCamDevice *
Instantiate(CamRoster & roster,BUSBDevice * from)1376 UVCCamDeviceAddon::Instantiate(CamRoster& roster, BUSBDevice* from)
1377 {
1378 printf("UVCCamDeviceAddon::Instantiate()\n");
1379 return new UVCCamDevice(*this, from);
1380 }
1381
1382
1383 extern "C" status_t
B_WEBCAM_MKINTFUNC(uvccam)1384 B_WEBCAM_MKINTFUNC(uvccam)
1385 (WebCamMediaAddOn* webcam, CamDeviceAddon **addon)
1386 {
1387 *addon = new UVCCamDeviceAddon(webcam);
1388 return B_OK;
1389 }
1390