xref: /haiku/src/add-ons/media/media-add-ons/usb_webcam/addons/uvc/UVCCamDevice.cpp (revision 1345706a9ff6ad0dc041339a02d4259998b0765d)
1 /*
2  * Copyright 2009, Ithamar Adema, <ithamar.adema@team-embedded.nl>.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "UVCCamDevice.h"
8 #include "USB_video.h"
9 
10 #include <stdio.h>
11 
12 
13 usb_webcam_support_descriptor kSupportedDevices[] = {
14 	// ofcourse we support a generic UVC device...
15 	{{ CC_VIDEO, SC_VIDEOCONTROL, 0, 0, 0 }, "USB", "Video Class", "??" },
16 	// ...whilst the following IDs were 'stolen' from a recent Linux driver:
17 	{{ 0, 0, 0, 0x045e, 0x00f8, }, "Microsoft",     "Lifecam NX-6000",                 "??" },
18 	{{ 0, 0, 0, 0x045e, 0x0723, }, "Microsoft",     "Lifecam VX-7000",                 "??" },
19 	{{ 0, 0, 0, 0x046d, 0x08c1, }, "Logitech",      "QuickCam Fusion",                 "??" },
20 	{{ 0, 0, 0, 0x046d, 0x08c2, }, "Logitech",      "QuickCam Orbit MP",               "??" },
21 	{{ 0, 0, 0, 0x046d, 0x08c3, }, "Logitech",      "QuickCam Pro for Notebook",       "??" },
22 	{{ 0, 0, 0, 0x046d, 0x08c5, }, "Logitech",      "QuickCam Pro 5000",               "??" },
23 	{{ 0, 0, 0, 0x046d, 0x08c6, }, "Logitech",      "QuickCam OEM Dell Notebook",      "??" },
24 	{{ 0, 0, 0, 0x046d, 0x08c7, }, "Logitech",      "QuickCam OEM Cisco VT Camera II", "??" },
25 	{{ 0, 0, 0, 0x05ac, 0x8501, }, "Apple",         "Built-In iSight",                 "??" },
26 	{{ 0, 0, 0, 0x05e3, 0x0505, }, "Genesys Logic", "USB 2.0 PC Camera",               "??" },
27 	{{ 0, 0, 0, 0x0e8d, 0x0004, }, "N/A",           "MT6227",                          "??" },
28 	{{ 0, 0, 0, 0x174f, 0x5212, }, "Syntek",        "(HP Spartan)",                    "??" },
29 	{{ 0, 0, 0, 0x174f, 0x5931, }, "Syntek",        "(Samsung Q310)",                  "??" },
30 	{{ 0, 0, 0, 0x174f, 0x8a31, }, "Syntek",        "Asus F9SG",                       "??" },
31 	{{ 0, 0, 0, 0x174f, 0x8a33, }, "Syntek",        "Asus U3S",                        "??" },
32 	{{ 0, 0, 0, 0x17ef, 0x480b, }, "N/A",           "Lenovo Thinkpad SL500",           "??" },
33 	{{ 0, 0, 0, 0x18cd, 0xcafe, }, "Ecamm",         "Pico iMage",                      "??" },
34 	{{ 0, 0, 0, 0x19ab, 0x1000, }, "Bodelin",       "ProScopeHR",                      "??" },
35 	{{ 0, 0, 0, 0x1c4f, 0x3000, }, "SiGma Micro",   "USB Web Camera",                  "??" },
36 	{{ 0, 0, 0, 0, 0}, NULL, NULL, NULL }
37 };
38 
39 /* Table 2-1 Compression Formats of USB Video Payload Uncompressed */
40 uint8 yuy2_guid = {0x59, 0x55, 0x59, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00,
41 	0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71};
42 uint8 nv12_guid = {0x4e, 0x56, 0x31, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00,
43 	0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71};
44 
45 static void
46 print_guid(const uint8* buf)
47 {
48 	printf("%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
49 		buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7],
50 		buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]);
51 }
52 
53 
54 UVCCamDevice::UVCCamDevice(CamDeviceAddon &_addon, BUSBDevice* _device)
55 	: CamDevice(_addon, _device)
56 {
57 	const BUSBConfiguration* uc;
58 	const BUSBInterface* ui;
59 	usb_descriptor *generic;
60 	uint32 cfg, intf, di;
61 	uint8 buffer[1024];
62 
63 	generic = (usb_descriptor *)buffer;
64 
65 	for (cfg=0; cfg < _device->CountConfigurations(); cfg++) {
66 		uc = _device->ConfigurationAt(cfg);
67 		for (intf=0; intf < uc->CountInterfaces(); intf++) {
68 			ui = uc->InterfaceAt(intf);
69 
70 			if (ui->Class() == CC_VIDEO && ui->Subclass() == SC_VIDEOCONTROL) {
71 				printf("UVCCamDevice: (%lu,%lu): Found Video Control interface.\n", cfg, intf);
72 
73 				// look for class specific interface descriptors and parse them
74 				for (di=0; ui->OtherDescriptorAt(di,generic,sizeof(buffer)) == B_OK; ++di)
75 					if (generic->generic.descriptor_type == (USB_REQTYPE_CLASS | USB_DESCRIPTOR_INTERFACE))
76 						ParseVideoControl(buffer, generic->generic.length);
77 
78 				fInitStatus = B_OK;
79 			} else if (ui->Class() == CC_VIDEO && ui->Subclass() == SC_VIDEOSTREAMING) {
80 				printf("UVCCamDevice: (%lu,%lu): Found Video Control interface.\n", cfg, intf);
81 
82 				// look for class specific interface descriptors and parse them
83 				for (di=0; ui->OtherDescriptorAt(di,generic,sizeof(buffer)) == B_OK; ++di)
84 					if (generic->generic.descriptor_type == (USB_REQTYPE_CLASS | USB_DESCRIPTOR_INTERFACE))
85 						ParseVideoStreaming(buffer, generic->generic.length);
86 			}
87 		}
88 	}
89 }
90 
91 
92 void
93 UVCCamDevice::ParseVideoStreaming(const uint8* buffer, size_t len)
94 {
95 	int c, i, sz;
96 
97 	switch(buffer[2]) {
98 		case VS_INPUT_HEADER:
99 			c = buffer[3];
100 			printf("VS_INPUT_HEADER:\t#fmts=%d,ept=0x%x\n", c, buffer[6]);
101 			if (buffer[7] & 1) printf("\tDynamic Format Change supported\n");
102 			printf("\toutput terminal id=%d\n", buffer[8]);
103 			printf("\tstill capture method=%d\n", buffer[9]);
104 			if (buffer[10])
105 				printf("\ttrigger button fixed to still capture=%s\n", buffer[11] ? "no" : "yes");
106 			sz = buffer[12];
107 			for (i=0; i < c; i++) {
108 				printf("\tfmt%d: %s %s %s %s - %s %s\n", i,
109 					(buffer[13+(sz*i)] & 1) ? "wKeyFrameRate" : "",
110 					(buffer[13+(sz*i)] & 2) ? "wPFrameRate" : "",
111 					(buffer[13+(sz*i)] & 4) ? "wCompQuality" : "",
112 					(buffer[13+(sz*i)] & 8) ? "wCompWindowSize" : "",
113 					(buffer[13+(sz*i)] & 16) ? "<Generate Key Frame>" : "",
114 					(buffer[13+(sz*i)] & 32) ? "<Update Frame Segment>" : "");
115 			}
116 			break;
117 		case VS_FORMAT_UNCOMPRESSED:
118 			c = buffer[4];
119 			printf("VS_FORMAT_UNCOMPRESSED:\tbFormatIdx=%d,#frmdesc=%d,guid=", buffer[3], c);
120 			print_guid(buffer+5);
121 			printf("\n\t#bpp=%d,optfrmidx=%d,aspRX=%d,aspRY=%d\n", buffer[21], buffer[22],
122 				buffer[23], buffer[24]);
123 			printf("\tbmInterlaceFlags:\n");
124 			if (buffer[25] & 1) printf("\tInterlaced stream or variable\n");
125 			printf("\t%d fields per frame\n", (buffer[25] & 2) ? 1 : 2);
126 			if (buffer[25] & 4) printf("\tField 1 first\n");
127 			printf("\tField Pattern: ");
128 			switch((buffer[25] & 0x30) >> 4) {
129 				case 0: printf("Field 1 only\n"); break;
130 				case 1: printf("Field 2 only\n"); break;
131 				case 2: printf("Regular pattern of fields 1 and 2\n"); break;
132 				case 3: printf("Random pattern of fields 1 and 2\n"); break;
133 			}
134 			if (buffer[26]) printf("\tRestrict duplication\n"); break;
135 			break;
136 		case VS_FRAME_UNCOMPRESSED:
137 			printf("VS_FRAME_UNCOMPRESSED:\tbFrameIdx=%d,stillsupported=%s,fixedfrmrate=%s\n",
138 				buffer[3], (buffer[4]&1)?"yes":"no", (buffer[4]&2)?"yes":"no");
139 			printf("\twidth=%u,height=%u,min/max bitrate=%lu/%lu, maxbuf=%lu\n",
140 				*(uint16*)(buffer+5), *(uint16*)(buffer+7),
141 				*(uint32*)(buffer+9), *(uint32*)(buffer+13),
142 				*(uint32*)(buffer+17));
143 			printf("\tframe interval: %lu, #intervals(0=cont): %d\n", *(uint32*)(buffer+21), buffer[25]);
144 			//TODO print interval table
145 			break;
146 		case VS_COLORFORMAT:
147 			printf("VS_COLORFORMAT:\n\tbColorPrimaries: ");
148 			switch(buffer[3]) {
149 				case 0: printf("Unspecified\n"); break;
150 				case 1: printf("BT.709,sRGB\n"); break;
151 				case 2: printf("BT.470-2(M)\n"); break;
152 				case 3: printf("BT.470-2(B,G)\n"); break;
153 				case 4: printf("SMPTE 170M\n"); break;
154 				case 5: printf("SMPTE 240M\n"); break;
155 				default: printf("Invalid (%d)\n", buffer[3]);
156 			}
157 			printf("\tbTransferCharacteristics: ");
158 			switch(buffer[4]) {
159 				case 0: printf("Unspecified\n"); break;
160 				case 1: printf("BT.709\n"); break;
161 				case 2: printf("BT.470-2(M)\n"); break;
162 				case 3: printf("BT.470-2(B,G)\n"); break;
163 				case 4: printf("SMPTE 170M\n"); break;
164 				case 5: printf("SMPTE 240M\n"); break;
165 				case 6: printf("Linear (V=Lc)\n"); break;
166 				case 7: printf("sRGB\n"); break;
167 				default: printf("Invalid (%d)\n", buffer[4]);
168 			}
169 			printf("\tbMatrixCoefficients: ");
170 			switch(buffer[5]) {
171 				case 0: printf("Unspecified\n"); break;
172 				case 1: printf("BT.709\n"); break;
173 				case 2: printf("FCC\n"); break;
174 				case 3: printf("BT.470-2(B,G)\n"); break;
175 				case 4: printf("SMPTE 170M (BT.601)\n"); break;
176 				case 5: printf("SMPTE 240M\n"); break;
177 				default: printf("Invalid (%d)\n", buffer[5]);
178 			}
179 			break;
180 
181 		case VS_OUTPUT_HEADER:
182 			printf("VS_OUTPUT_HEADER:\t\n");
183 			break;
184 		case VS_STILL_IMAGE_FRAME:
185 			printf("VS_STILL_IMAGE_FRAME:\t\n");
186 			break;
187 		case VS_FORMAT_MJPEG:
188 			printf("VS_FORMAT_MJPEG:\t\n");
189 			break;
190 		case VS_FRAME_MJPEG:
191 			printf("VS_FRAME_MJPEG:\t\n");
192 			break;
193 		case VS_FORMAT_MPEG2TS:
194 			printf("VS_FORMAT_MPEG2TS:\t\n");
195 			break;
196 		case VS_FORMAT_DV:
197 			printf("VS_FORMAT_DV:\t\n");
198 			break;
199 		case VS_FORMAT_FRAME_BASED:
200 			printf("VS_FORMAT_FRAME_BASED:\t\n");
201 			break;
202 		case VS_FRAME_FRAME_BASED:
203 			printf("VS_FRAME_FRAME_BASED:\t\n");
204 			break;
205 		case VS_FORMAT_STREAM_BASED:
206 			printf("VS_FORMAT_STREAM_BASED:\t\n");
207 			break;
208 		default:
209 			printf("INVALID STREAM UNIT TYPE=%d!\n", buffer[2]);
210 	}
211 }
212 
213 
214 void
215 UVCCamDevice::ParseVideoControl(const uint8* buffer, size_t len)
216 {
217 	int c, i;
218 
219 	switch(buffer[2]) {
220 		case VC_HEADER:
221 			printf("VC_HEADER:\tUVC v%04x, clk %lu Hz\n", *(uint16*)(buffer+3), *(uint32*)(buffer+7));
222 			c = (len >= 12) ? buffer[11] : 0;
223 			for (i=0; i < c; i++)
224 				printf("\tStreaming Interface %d\n", buffer[12+i]);
225 			break;
226 
227 		case VC_INPUT_TERMINAL:
228 			printf("VC_INPUT_TERMINAL:\tid=%d,type=%04x,associated terminal=%d\n", buffer[3], *(uint16*)(buffer+4), buffer[6]);
229 			printf("\tDesc: %s\n", fDevice->DecodeStringDescriptor(buffer[7]));
230 			break;
231 
232 		case VC_OUTPUT_TERMINAL:
233 			printf("VC_OUTPUT_TERMINAL:\tid=%d,type=%04x,associated terminal=%d, src id=%d\n", buffer[3], *(uint16*)(buffer+4), buffer[6], buffer[7]);
234 			printf("\tDesc: %s\n", fDevice->DecodeStringDescriptor(buffer[8]));
235 			break;
236 
237 		case VC_SELECTOR_UNIT:
238 			printf("VC_SELECTOR_UNIT:\tid=%d,#pins=%d\n", buffer[3], buffer[4]);
239 			printf("\t");
240 			for (i=0; i < buffer[4]; i++)
241 				printf("%d ", buffer[5+i]);
242 			printf("\n");
243 			printf("\tDesc: %s\n", fDevice->DecodeStringDescriptor(buffer[5+buffer[4]]));
244 			break;
245 
246 		case VC_PROCESSING_UNIT:
247 			printf("VC_PROCESSING_UNIT:\tid=%d,src id=%d, digmul=%d\n", buffer[3], buffer[4], *(uint16*)(buffer+5));
248 			c = buffer[7];
249 			printf("\tbControlSize=%d\n", c);
250 			if (c >= 1) {
251 				if (buffer[8] & 1) printf("\tBrightness\n");
252 				if (buffer[8] & 2) printf("\tContrast\n");
253 				if (buffer[8] & 4) printf("\tHue\n");
254 				if (buffer[8] & 8) printf("\tSaturation\n");
255 				if (buffer[8] & 16) printf("\tSharpness\n");
256 				if (buffer[8] & 32) printf("\tGamma\n");
257 				if (buffer[8] & 64) printf("\tWhite Balance Temperature\n");
258 				if (buffer[8] & 128) printf("\tWhite Balance Component\n");
259 			}
260 			if (c >= 2) {
261 				if (buffer[9] & 1) printf("\tBacklight Compensation\n");
262 				if (buffer[9] & 2) printf("\tGain\n");
263 				if (buffer[9] & 4) printf("\tPower Line Frequency\n");
264 				if (buffer[9] & 8) printf("\t[AUTO] Hue\n");
265 				if (buffer[9] & 16) printf("\t[AUTO] White Balance Temperature\n");
266 				if (buffer[9] & 32) printf("\t[AUTO] White Balance Component\n");
267 				if (buffer[9] & 64) printf("\tDigital Multiplier\n");
268 				if (buffer[9] & 128) printf("\tDigital Multiplier Limit\n");
269 			}
270 			if (c >= 3) {
271 				if (buffer[10] & 1) printf("\tAnalog Video Standard\n");
272 				if (buffer[10] & 2) printf("\tAnalog Video Lock Status\n");
273 			}
274 			printf("\tDesc: %s\n", fDevice->DecodeStringDescriptor(buffer[8+c]));
275 			i=buffer[9+c];
276 			if (i & 2)  printf("\tNTSC  525/60\n");
277 			if (i & 4)  printf("\tPAL   625/50\n");
278 			if (i & 8)  printf("\tSECAM 625/50\n");
279 			if (i & 16) printf("\tNTSC  625/50\n");
280 			if (i & 32) printf("\tPAL   525/60\n");
281 			break;
282 
283 		case VC_EXTENSION_UNIT:
284 			printf("VC_EXTENSION_UNIT:\tid=%d, guid=", buffer[3]);
285 			print_guid(buffer+4);
286 			printf("\n\t#ctrls=%d, #pins=%d\n", buffer[20], buffer[21]);
287 			c = buffer[21];
288 			printf("\t");
289 			for (i=0; i < c; i++)
290 				printf("%d ", buffer[22+i]);
291 			printf("\n");
292 			printf("\tDesc: %s\n", fDevice->DecodeStringDescriptor(buffer[23+c+buffer[22+c]]));
293 			break;
294 
295 		default:
296 			printf("Unknown control %d\n", buffer[2]);
297 	}
298 }
299 
300 
301 UVCCamDevice::~UVCCamDevice()
302 {
303 }
304 
305 
306 bool
307 UVCCamDevice::SupportsIsochronous()
308 {
309 	return true;
310 }
311 
312 
313 status_t
314 UVCCamDevice::StartTransfer()
315 {
316 	return CamDevice::StartTransfer();
317 }
318 
319 
320 status_t
321 UVCCamDevice::StopTransfer()
322 {
323 	return CamDevice::StopTransfer();
324 }
325 
326 
327 UVCCamDeviceAddon::UVCCamDeviceAddon(WebCamMediaAddOn* webcam)
328 	: CamDeviceAddon(webcam)
329 {
330 	SetSupportedDevices(kSupportedDevices);
331 }
332 
333 
334 UVCCamDeviceAddon::~UVCCamDeviceAddon()
335 {
336 }
337 
338 
339 const char *
340 UVCCamDeviceAddon::BrandName()
341 {
342 	return "USB Video Class";
343 }
344 
345 
346 UVCCamDevice *
347 UVCCamDeviceAddon::Instantiate(CamRoster &roster, BUSBDevice *from)
348 {
349 	return new UVCCamDevice(*this, from);
350 }
351 
352 
353 extern "C" status_t
354 B_WEBCAM_MKINTFUNC(uvccam)
355 (WebCamMediaAddOn* webcam, CamDeviceAddon **addon)
356 {
357 	*addon = new UVCCamDeviceAddon(webcam);
358 	return B_OK;
359 }
360