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