blob: e56ffaedbf93b2331a0d2394665286dbd0103bda [file] [log] [blame]
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * Contains code that is used to capture video frames from a camera device
19 * on Linux. This code uses V4L2 API to work with camera devices, and requires
20 * Linux kernel version at least 2.5
21 */
22
23#include <sys/mman.h>
24#include <sys/stat.h>
25#include <sys/ioctl.h>
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -070026#include "android/camera/camera-capture.h"
27#include "android/camera/camera-format-converters.h"
28
Vladimir Chtchetkinec68dbbe2011-09-23 07:58:34 -070029#define E(...) derror(__VA_ARGS__)
30#define W(...) dwarning(__VA_ARGS__)
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -070031#define D(...) VERBOSE_PRINT(camera,__VA_ARGS__)
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -070032#define D_ACTIVE VERBOSE_CHECK(camera)
33
34/* the T(...) macro is used to dump traffic */
35#define T_ACTIVE 0
36
37#if T_ACTIVE
38#define T(...) VERBOSE_PRINT(camera,__VA_ARGS__)
39#else
40#define T(...) ((void)0)
41#endif
42
43#define CLEAR(x) memset (&(x), 0, sizeof(x))
44
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -070045/* Pixel format descriptor.
46 * Instances of this descriptor are created during camera device enumeration, and
47 * an instance of this structure describing pixel format chosen for the camera
48 * emulation is saved by the camera factory service to represent an emulating
49 * camera properties.
50 */
51typedef struct QemuPixelFormat {
52 /* Pixel format in V4L2_PIX_FMT_XXX form. */
53 uint32_t format;
54 /* Frame dimensions supported by this format. */
55 CameraFrameDim* dims;
56 /* Number of frame dimensions supported by this format. */
57 int dim_num;
58} QemuPixelFormat;
59
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -070060/* Describes a framebuffer. */
61typedef struct CameraFrameBuffer {
62 /* Framebuffer data. */
63 uint8_t* data;
64 /* Framebuffer data size. */
65 size_t size;
66} CameraFrameBuffer;
67
68/* Defines type of the I/O used to obtain frames from the device. */
69typedef enum CameraIoType {
70 /* Framebuffers are shared via memory mapping. */
71 CAMERA_IO_MEMMAP,
72 /* Framebuffers are available via user pointers. */
73 CAMERA_IO_USERPTR,
74 /* Framebuffers are to be read from the device. */
75 CAMERA_IO_DIRECT
76} CameraIoType;
77
78typedef struct LinuxCameraDevice LinuxCameraDevice;
79/*
80 * Describes a connection to an actual camera device.
81 */
82struct LinuxCameraDevice {
83 /* Common header. */
84 CameraDevice header;
85
86 /* Camera device name. (default is /dev/video0) */
87 char* device_name;
88 /* Input channel. (default is 0) */
89 int input_channel;
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -070090
91 /*
92 * Set by the framework after initializing camera connection.
93 */
94
95 /* Handle to the opened camera device. */
96 int handle;
97 /* Device capabilities. */
98 struct v4l2_capability caps;
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -070099 /* Actual pixel format reported by the device when capturing is started. */
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700100 struct v4l2_pix_format actual_pixel_format;
101 /* Defines type of the I/O to use to retrieve frames from the device. */
102 CameraIoType io_type;
103 /* Allocated framebuffers. */
104 struct CameraFrameBuffer* framebuffers;
105 /* Actual number of allocated framebuffers. */
106 int framebuffer_num;
107};
108
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700109/* Preferred pixel formats arranged from the most to the least desired.
110 *
111 * More than anything else this array is defined by an existance of format
112 * conversion between the camera supported formats, and formats that are
113 * supported by camera framework in the guest system. Currently, guest supports
114 * only YV12 pixel format for data, and RGB32 for preview. So, this array should
115 * contain only those formats, for which converters are implemented. Generally
116 * speaking, the order in which entries should be arranged in this array matters
117 * only as far as conversion speed is concerned. So, formats with the fastest
118 * converters should be put closer to the top of the array, while slower ones
119 * should be put closer to the bottom. But as far as functionality is concerned,
120 * the orser doesn't matter, and any format can be placed anywhere in this array,
121 * as long as conversion for it exists.
122 */
123static const uint32_t _preferred_formats[] =
124{
125 /* Native format for the emulated camera: no conversion at all. */
Vladimir Chtchetkineddd59b12011-09-21 14:58:10 -0700126 V4L2_PIX_FMT_YUV420,
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700127 V4L2_PIX_FMT_YVU420,
128 /* Continue with YCbCr: less math than with RGB */
129 V4L2_PIX_FMT_NV12,
130 V4L2_PIX_FMT_NV21,
131 V4L2_PIX_FMT_YUYV,
132 /* End with RGB. */
133 V4L2_PIX_FMT_RGB32,
134 V4L2_PIX_FMT_RGB24,
135 V4L2_PIX_FMT_RGB565,
136};
137/* Number of entries in _preferred_formats array. */
138static const int _preferred_format_num =
139 sizeof(_preferred_formats)/sizeof(*_preferred_formats);
140
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700141/*******************************************************************************
142 * Helper routines
143 ******************************************************************************/
144
145/* IOCTL wrapper. */
146static int
147_xioctl(int fd, int request, void *arg) {
148 int r;
149 do {
150 r = ioctl(fd, request, arg);
151 } while (-1 == r && EINTR == errno);
152 return r;
153}
154
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700155/* Frees resource allocated for QemuPixelFormat instance, excluding the instance
156 * itself.
157 */
158static void _qemu_pixel_format_free(QemuPixelFormat* fmt)
159{
160 if (fmt != NULL) {
161 if (fmt->dims != NULL)
162 free(fmt->dims);
163 }
164}
165
166/* Returns an index of the given pixel format in an array containing pixel
167 * format descriptors.
168 * This routine is used to choose a pixel format for a camera device. The idea
169 * is that when the camera service enumerates all pixel formats for all cameras
170 * connected to the host, we need to choose just one, which would be most
171 * appropriate for camera emulation. To do that, the camera service will run
172 * formats, contained in _preferred_formats array against enumerated pixel
173 * formats to pick the first format that match.
174 * Param:
175 * fmt - Pixel format, for which to obtain the index.
176 * formats - Array containing list of pixel formats, supported by the camera
177 * device.
178 * size - Number of elements in the 'formats' array.
179 * Return:
180 * Index of the matched entry in the array, or -1 if no entry has been found.
181 */
182static int
183_get_format_index(uint32_t fmt, QemuPixelFormat* formats, int size)
184{
185 int f;
186 for (f = 0; f < size && formats[f].format != fmt; f++);
187 return f < size ? f : -1;
188}
189
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700190/*******************************************************************************
191 * CameraFrameBuffer routines
192 ******************************************************************************/
193
194/* Frees array of framebuffers, depending on the I/O method the array has been
195 * initialized for.
196 * Note that this routine doesn't frees the array itself.
197 * Param:
198 * fb, num - Array data, and its size.
199 * io_type - Type of the I/O the array has been initialized for.
200 */
201static void
202_free_framebuffers(CameraFrameBuffer* fb, int num, CameraIoType io_type)
203{
204 if (fb != NULL) {
205 int n;
206
207 switch (io_type) {
208 case CAMERA_IO_MEMMAP:
209 /* Unmap framebuffers. */
210 for (n = 0; n < num; n++) {
211 if (fb[n].data != NULL) {
212 munmap(fb[n].data, fb[n].size);
213 fb[n].data = NULL;
214 fb[n].size = 0;
215 }
216 }
217 break;
218
219 case CAMERA_IO_USERPTR:
220 case CAMERA_IO_DIRECT:
221 /* Free framebuffers. */
222 for (n = 0; n < num; n++) {
223 if (fb[n].data != NULL) {
224 free(fb[n].data);
225 fb[n].data = NULL;
226 fb[n].size = 0;
227 }
228 }
229 break;
230
231 default:
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700232 E("%s: Invalid I/O type %d", __FUNCTION__, io_type);
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700233 break;
234 }
235 }
236}
237
238/*******************************************************************************
239 * CameraDevice routines
240 ******************************************************************************/
241
242/* Allocates an instance of LinuxCameraDevice structure.
243 * Return:
244 * Allocated instance of LinuxCameraDevice structure. Note that this routine
245 * also sets 'opaque' field in the 'header' structure to point back to the
246 * containing LinuxCameraDevice instance.
247 */
248static LinuxCameraDevice*
249_camera_device_alloc(void)
250{
251 LinuxCameraDevice* cd;
252
253 ANEW0(cd);
254 memset(cd, 0, sizeof(*cd));
255 cd->header.opaque = cd;
256 cd->handle = -1;
257
258 return cd;
259}
260
261/* Uninitializes and frees CameraDevice structure.
262 */
263static void
264_camera_device_free(LinuxCameraDevice* lcd)
265{
266 if (lcd != NULL) {
267 /* Closing handle will also disconnect from the driver. */
268 if (lcd->handle >= 0) {
269 close(lcd->handle);
270 }
271 if (lcd->device_name != NULL) {
272 free(lcd->device_name);
273 }
274 if (lcd->framebuffers != NULL) {
275 _free_framebuffers(lcd->framebuffers, lcd->framebuffer_num,
276 lcd->io_type);
277 free(lcd->framebuffers);
278 }
279 AFREE(lcd);
280 } else {
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700281 E("%s: No descriptor", __FUNCTION__);
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700282 }
283}
284
Vladimir Chtchetkinee3b840c2011-09-22 15:41:05 -0700285/* Resets camera device after capturing.
286 * Since new capture request may require different frame dimensions we must
287 * reset camera device by reopening its handle. Otherwise attempts to set up new
288 * frame properties (different from the previous one) may fail. */
289static void
290_camera_device_reset(LinuxCameraDevice* cd)
291{
292 struct v4l2_cropcap cropcap;
293 struct v4l2_crop crop;
294
295 /* Free capturing framebuffers first. */
296 if (cd->framebuffers != NULL) {
297 _free_framebuffers(cd->framebuffers, cd->framebuffer_num, cd->io_type);
298 free(cd->framebuffers);
299 cd->framebuffers = NULL;
300 cd->framebuffer_num = 0;
301 }
302
303 /* Reset device handle. */
304 close(cd->handle);
305 cd->handle = open(cd->device_name, O_RDWR | O_NONBLOCK, 0);
306
307 if (cd->handle >= 0) {
308 /* Select video input, video standard and tune here. */
309 cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
310 _xioctl(cd->handle, VIDIOC_CROPCAP, &cropcap);
311 crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
312 crop.c = cropcap.defrect; /* reset to default */
313 _xioctl (cd->handle, VIDIOC_S_CROP, &crop);
314 }
315}
316
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700317/* Memory maps buffers and shares mapped memory with the device.
318 * Return:
319 * 0 Framebuffers have been mapped.
320 * -1 A critical error has ocurred.
321 * 1 Memory mapping is not available.
322 */
323static int
324_camera_device_mmap_framebuffer(LinuxCameraDevice* cd)
325{
326 struct v4l2_requestbuffers req;
327 CLEAR(req);
328 req.count = 4;
329 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
330 req.memory = V4L2_MEMORY_MMAP;
331
332 /* Request memory mapped buffers. Note that device can return less buffers
333 * than requested. */
334 if(_xioctl(cd->handle, VIDIOC_REQBUFS, &req)) {
335 if (EINVAL == errno) {
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700336 D("%s: Device '%s' does not support memory mapping",
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700337 __FUNCTION__, cd->device_name);
338 return 1;
339 } else {
340 E("%s: VIDIOC_REQBUFS has failed: %s",
341 __FUNCTION__, strerror(errno));
342 return -1;
343 }
344 }
345
346 /* Allocate framebuffer array. */
347 cd->framebuffers = calloc(req.count, sizeof(CameraFrameBuffer));
348 if (cd->framebuffers == NULL) {
349 E("%s: Not enough memory to allocate framebuffer array", __FUNCTION__);
350 return -1;
351 }
352
353 /* Map every framebuffer to the shared memory, and queue it
354 * with the device. */
355 for(cd->framebuffer_num = 0; cd->framebuffer_num < req.count;
356 cd->framebuffer_num++) {
357 /* Map framebuffer. */
358 struct v4l2_buffer buf;
359 CLEAR(buf);
360 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
361 buf.memory = V4L2_MEMORY_MMAP;
362 buf.index = cd->framebuffer_num;
363 if(_xioctl(cd->handle, VIDIOC_QUERYBUF, &buf) < 0) {
364 E("%s: VIDIOC_QUERYBUF has failed: %s",
365 __FUNCTION__, strerror(errno));
366 return -1;
367 }
368 cd->framebuffers[cd->framebuffer_num].size = buf.length;
369 cd->framebuffers[cd->framebuffer_num].data =
370 mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED,
371 cd->handle, buf.m.offset);
372 if (MAP_FAILED == cd->framebuffers[cd->framebuffer_num].data) {
373 E("%s: Memory mapping has failed: %s",
374 __FUNCTION__, strerror(errno));
375 return -1;
376 }
377
378 /* Queue the mapped buffer. */
379 CLEAR(buf);
380 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
381 buf.memory = V4L2_MEMORY_MMAP;
382 buf.index = cd->framebuffer_num;
383 if (_xioctl(cd->handle, VIDIOC_QBUF, &buf) < 0) {
384 E("%s: VIDIOC_QBUF has failed: %s", __FUNCTION__, strerror(errno));
385 return -1;
386 }
387 }
388
389 cd->io_type = CAMERA_IO_MEMMAP;
390
391 return 0;
392}
393
394/* Allocates frame buffers and registers them with the device.
395 * Return:
396 * 0 Framebuffers have been mapped.
397 * -1 A critical error has ocurred.
398 * 1 Device doesn't support user pointers.
399 */
400static int
401_camera_device_user_framebuffer(LinuxCameraDevice* cd)
402{
403 struct v4l2_requestbuffers req;
404 CLEAR (req);
405 req.count = 4;
406 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
407 req.memory = V4L2_MEMORY_USERPTR;
408
409 /* Request user buffers. Note that device can return less buffers
410 * than requested. */
411 if(_xioctl(cd->handle, VIDIOC_REQBUFS, &req)) {
412 if (EINVAL == errno) {
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700413 D("%s: Device '%s' does not support user pointers",
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700414 __FUNCTION__, cd->device_name);
415 return 1;
416 } else {
417 E("%s: VIDIOC_REQBUFS has failed: %s",
418 __FUNCTION__, strerror(errno));
419 return -1;
420 }
421 }
422
423 /* Allocate framebuffer array. */
424 cd->framebuffers = calloc(req.count, sizeof(CameraFrameBuffer));
425 if (cd->framebuffers == NULL) {
426 E("%s: Not enough memory to allocate framebuffer array", __FUNCTION__);
427 return -1;
428 }
429
430 /* Allocate buffers, queueing them wit the device at the same time */
431 for(cd->framebuffer_num = 0; cd->framebuffer_num < req.count;
432 cd->framebuffer_num++) {
433 cd->framebuffers[cd->framebuffer_num].size =
434 cd->actual_pixel_format.sizeimage;
435 cd->framebuffers[cd->framebuffer_num].data =
436 malloc(cd->framebuffers[cd->framebuffer_num].size);
437 if (cd->framebuffers[cd->framebuffer_num].data == NULL) {
438 E("%s: Not enough memory to allocate framebuffer", __FUNCTION__);
439 return -1;
440 }
441
442 /* Queue the user buffer. */
443 struct v4l2_buffer buf;
444 CLEAR(buf);
445 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
446 buf.memory = V4L2_MEMORY_USERPTR;
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700447 buf.m.userptr = (unsigned long)cd->framebuffers[cd->framebuffer_num].data;
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700448 buf.length = cd->framebuffers[cd->framebuffer_num].size;
449 if (_xioctl(cd->handle, VIDIOC_QBUF, &buf) < 0) {
450 E("%s: VIDIOC_QBUF has failed: %s", __FUNCTION__, strerror(errno));
451 return -1;
452 }
453 }
454
455 cd->io_type = CAMERA_IO_USERPTR;
456
457 return 0;
458}
459
460/* Allocate frame buffer for direct read from the device.
461 * Return:
462 * 0 Framebuffers have been mapped.
463 * -1 A critical error has ocurred.
464 * 1 Memory mapping is not available.
465 */
466static int
467_camera_device_direct_framebuffer(LinuxCameraDevice* cd)
468{
469 /* Allocate framebuffer array. */
470 cd->framebuffer_num = 1;
471 cd->framebuffers = malloc(sizeof(CameraFrameBuffer));
472 if (cd->framebuffers == NULL) {
473 E("%s: Not enough memory to allocate framebuffer array", __FUNCTION__);
474 return -1;
475 }
476
477 cd->framebuffers[0].size = cd->actual_pixel_format.sizeimage;
478 cd->framebuffers[0].data = malloc(cd->framebuffers[0].size);
479 if (cd->framebuffers[0].data == NULL) {
480 E("%s: Not enough memory to allocate framebuffer", __FUNCTION__);
481 return -1;
482 }
483
484 cd->io_type = CAMERA_IO_DIRECT;
485
486 return 0;
487}
488
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700489/* Opens camera device.
490 * Param:
491 * cd - Camera device descriptor to open the camera for.
492 * Return:
493 * 0 on success, != 0 on failure.
494 */
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700495static int
496_camera_device_open(LinuxCameraDevice* cd)
497{
498 struct stat st;
499
500 if (stat(cd->device_name, &st)) {
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700501 return -1;
502 }
503
504 if (!S_ISCHR(st.st_mode)) {
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700505 E("%s: '%s' is not a device", __FUNCTION__, cd->device_name);
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700506 return -1;
507 }
508
509 /* Open handle to the device, and query device capabilities. */
510 cd->handle = open(cd->device_name, O_RDWR | O_NONBLOCK, 0);
511 if (cd->handle < 0) {
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700512 E("%s: Cannot open camera device '%s': %s",
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700513 __FUNCTION__, cd->device_name, strerror(errno));
514 return -1;
515 }
516 if (_xioctl(cd->handle, VIDIOC_QUERYCAP, &cd->caps) < 0) {
517 if (EINVAL == errno) {
518 E("%s: Camera '%s' is not a V4L2 device",
519 __FUNCTION__, cd->device_name);
520 close(cd->handle);
521 cd->handle = -1;
522 return -1;
523 } else {
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700524 E("%s: Unable to query capabilities for camera device '%s'",
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700525 __FUNCTION__, cd->device_name);
526 close(cd->handle);
527 cd->handle = -1;
528 return -1;
529 }
530 }
531
532 /* Make sure that camera supports minimal requirements. */
533 if (!(cd->caps.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
534 E("%s: Camera '%s' is not a video capture device",
535 __FUNCTION__, cd->device_name);
536 close(cd->handle);
537 cd->handle = -1;
538 return -1;
539 }
540
541 return 0;
542}
543
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700544/* Enumerates frame sizes for the given pixel format.
545 * Param:
546 * cd - Opened camera device descriptor.
547 * fmt - Pixel format to enum frame sizes for.
548 * sizes - Upon success contains an array of supported frame sizes. The size of
549 * the array is defined by the value, returned from this routine. The caller
550 * is responsible for freeing memory allocated for this array.
551 * Return:
552 * On success returns number of entries in the 'sizes' array. On failure returns
553 * a negative value.
554 */
555static int
556_camera_device_enum_format_sizes(LinuxCameraDevice* cd,
557 uint32_t fmt,
558 CameraFrameDim** sizes)
559{
560 int n;
561 int sizes_num = 0;
562 int out_num = 0;
563 struct v4l2_frmsizeenum size_enum;
564 CameraFrameDim* arr;
565
566 /* Calculate number of supported sizes for the given format. */
567 for (n = 0; ; n++) {
568 size_enum.index = n;
569 size_enum.pixel_format = fmt;
570 if(_xioctl(cd->handle, VIDIOC_ENUM_FRAMESIZES, &size_enum)) {
571 break;
572 }
573 if (size_enum.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
574 /* Size is in the simpe width, height form. */
575 sizes_num++;
576 } else if (size_enum.type == V4L2_FRMSIZE_TYPE_STEPWISE) {
577 /* Sizes are represented as min/max width and height with a step for
578 * each dimension. Since at the end we want to list each supported
579 * size in the array (that's the only format supported by the guest
580 * camera framework), we need to calculate how many array entries
581 * this will generate. */
582 const uint32_t dif_widths =
583 (size_enum.stepwise.max_width - size_enum.stepwise.min_width) /
584 size_enum.stepwise.step_width + 1;
585 const uint32_t dif_heights =
586 (size_enum.stepwise.max_height - size_enum.stepwise.min_height) /
587 size_enum.stepwise.step_height + 1;
588 sizes_num += dif_widths * dif_heights;
589 } else if (size_enum.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) {
590 /* Special stepwise case, when steps are set to 1. We still need to
591 * flatten this for the guest, but the array may be too big.
592 * Fortunately, we don't need to be fancy, so three sizes would be
593 * sufficient here: min, max, and one in the middle. */
594 sizes_num += 3;
595 }
596
597 }
598 if (sizes_num == 0) {
599 return 0;
600 }
601
602 /* Allocate, and initialize the array of supported entries. */
603 *sizes = (CameraFrameDim*)malloc(sizes_num * sizeof(CameraFrameDim));
604 if (*sizes == NULL) {
605 E("%s: Memory allocation failure", __FUNCTION__);
606 return -1;
607 }
608 arr = *sizes;
609 for (n = 0; out_num < sizes_num; n++) {
610 size_enum.index = n;
611 size_enum.pixel_format = fmt;
612 if(_xioctl(cd->handle, VIDIOC_ENUM_FRAMESIZES, &size_enum)) {
613 /* Errors are not welcome here anymore. */
614 E("%s: Unexpected failure while getting pixel dimensions: %s",
Vladimir Chtchetkinecdd8d782011-10-20 10:55:03 -0700615 __FUNCTION__, strerror(errno));
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700616 free(arr);
617 return -1;
618 }
619
620 if (size_enum.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
621 arr[out_num].width = size_enum.discrete.width;
622 arr[out_num].height = size_enum.discrete.height;
623 out_num++;
624 } else if (size_enum.type == V4L2_FRMSIZE_TYPE_STEPWISE) {
625 uint32_t w;
626 for (w = size_enum.stepwise.min_width;
627 w <= size_enum.stepwise.max_width;
628 w += size_enum.stepwise.step_width) {
629 uint32_t h;
630 for (h = size_enum.stepwise.min_height;
631 h <= size_enum.stepwise.max_height;
632 h += size_enum.stepwise.step_height) {
633 arr[out_num].width = w;
634 arr[out_num].height = h;
635 out_num++;
636 }
637 }
638 } else if (size_enum.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) {
639 /* min */
640 arr[out_num].width = size_enum.stepwise.min_width;
641 arr[out_num].height = size_enum.stepwise.min_height;
642 out_num++;
643 /* one in the middle */
644 arr[out_num].width =
645 (size_enum.stepwise.min_width + size_enum.stepwise.max_width) / 2;
646 arr[out_num].height =
647 (size_enum.stepwise.min_height + size_enum.stepwise.max_height) / 2;
648 out_num++;
649 /* max */
650 arr[out_num].width = size_enum.stepwise.max_width;
651 arr[out_num].height = size_enum.stepwise.max_height;
652 out_num++;
653 }
654 }
655
656 return out_num;
657}
658
659/* Enumerates pixel formats, supported by the device.
660 * Note that this routine will enumerate only raw (uncompressed) formats.
661 * Param:
662 * cd - Opened camera device descriptor.
663 * fmts - Upon success contains an array of supported pixel formats. The size of
664 * the array is defined by the value, returned from this routine. The caller
665 * is responsible for freeing memory allocated for this array.
666 * Return:
667 * On success returns number of entries in the 'fmts' array. On failure returns
668 * a negative value.
669 */
670static int
671_camera_device_enum_pixel_formats(LinuxCameraDevice* cd, QemuPixelFormat** fmts)
672{
Vladimir Chtchetkine79570c32011-10-21 18:22:06 -0700673 int n, max_fmt;
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700674 int fmt_num = 0;
675 int out_num = 0;
676 struct v4l2_fmtdesc fmt_enum;
677 QemuPixelFormat* arr;
678
679 /* Calculate number of supported formats. */
Vladimir Chtchetkine79570c32011-10-21 18:22:06 -0700680 for (max_fmt = 0; ; max_fmt++) {
681 memset(&fmt_enum, 0, sizeof(fmt_enum));
682 fmt_enum.index = max_fmt;
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700683 fmt_enum.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
684 if(_xioctl(cd->handle, VIDIOC_ENUM_FMT, &fmt_enum)) {
685 break;
686 }
687 /* Skip the compressed ones. */
688 if ((fmt_enum.flags & V4L2_FMT_FLAG_COMPRESSED) == 0) {
689 fmt_num++;
690 }
691 }
692 if (fmt_num == 0) {
693 return 0;
694 }
695
696 /* Allocate, and initialize array for enumerated formats. */
697 *fmts = (QemuPixelFormat*)malloc(fmt_num * sizeof(QemuPixelFormat));
698 if (*fmts == NULL) {
699 E("%s: Memory allocation failure", __FUNCTION__);
700 return -1;
701 }
702 arr = *fmts;
703 memset(arr, 0, fmt_num * sizeof(QemuPixelFormat));
Vladimir Chtchetkine79570c32011-10-21 18:22:06 -0700704 for (n = 0; n < max_fmt && out_num < fmt_num; n++) {
705 memset(&fmt_enum, 0, sizeof(fmt_enum));
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700706 fmt_enum.index = n;
707 fmt_enum.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
708 if(_xioctl(cd->handle, VIDIOC_ENUM_FMT, &fmt_enum)) {
709 int nn;
710 /* Errors are not welcome here anymore. */
711 E("%s: Unexpected failure while getting pixel format: %s",
Vladimir Chtchetkinecdd8d782011-10-20 10:55:03 -0700712 __FUNCTION__, strerror(errno));
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700713 for (nn = 0; nn < out_num; nn++) {
714 _qemu_pixel_format_free(arr + nn);
715 }
716 free(arr);
717 return -1;
718 }
719 /* Skip the compressed ones. */
720 if ((fmt_enum.flags & V4L2_FMT_FLAG_COMPRESSED) == 0) {
721 arr[out_num].format = fmt_enum.pixelformat;
722 /* Enumerate frame dimensions supported for this format. */
723 arr[out_num].dim_num =
724 _camera_device_enum_format_sizes(cd, fmt_enum.pixelformat,
725 &arr[out_num].dims);
726 if (arr[out_num].dim_num > 0) {
727 out_num++;
728 } else if (arr[out_num].dim_num < 0) {
729 int nn;
730 E("Unable to enumerate supported dimensions for pixel format %d",
731 fmt_enum.pixelformat);
732 for (nn = 0; nn < out_num; nn++) {
733 _qemu_pixel_format_free(arr + nn);
734 }
735 free(arr);
736 return -1;
737 }
738 }
739 }
740
741 return out_num;
742}
743
744/* Collects information about an opened camera device.
745 * The information collected in this routine contains list of pixel formats,
746 * supported by the device, and list of frame dimensions supported by the camera
747 * for each pixel format.
748 * Param:
749 * cd - Opened camera device descriptor.
750 * cis - Upon success contains information collected from the camera device.
751 * Return:
752 * 0 on success, != 0 on failure.
753 */
754static int
755_camera_device_get_info(LinuxCameraDevice* cd, CameraInfo* cis)
756{
757 int f;
758 int chosen = -1;
759 QemuPixelFormat* formats = NULL;
760 int num_pix_fmts = _camera_device_enum_pixel_formats(cd, &formats);
761 if (num_pix_fmts <= 0) {
Vladimir Chtchetkine79570c32011-10-21 18:22:06 -0700762 return -1;
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700763 }
764
765 /* Lets see if camera supports preferred formats */
766 for (f = 0; f < _preferred_format_num; f++) {
767 chosen = _get_format_index(_preferred_formats[f], formats, num_pix_fmts);
768 if (chosen >= 0) {
769 break;
770 }
771 }
772 if (chosen < 0) {
773 /* Camera doesn't support any of the chosen formats. Then it doesn't
774 * matter which one we choose. Lets choose the first one. */
775 chosen = 0;
776 }
777
778 cis->device_name = ASTRDUP(cd->device_name);
779 cis->inp_channel = cd->input_channel;
780 cis->pixel_format = formats[chosen].format;
781 cis->frame_sizes_num = formats[chosen].dim_num;
782 /* Swap instead of copy. */
783 cis->frame_sizes = formats[chosen].dims;
784 formats[chosen].dims = NULL;
785 cis->in_use = 0;
786
787 for (f = 0; f < num_pix_fmts; f++) {
788 _qemu_pixel_format_free(formats + f);
789 }
790 free(formats);
791
792 return 0;
793}
794
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700795/*******************************************************************************
796 * CameraDevice API
797 ******************************************************************************/
798
799CameraDevice*
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700800camera_device_open(const char* name, int inp_channel)
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700801{
802 struct v4l2_cropcap cropcap;
803 struct v4l2_crop crop;
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700804 LinuxCameraDevice* cd;
805
806 /* Allocate and initialize the descriptor. */
807 cd = _camera_device_alloc();
808 cd->device_name = name != NULL ? ASTRDUP(name) : ASTRDUP("/dev/video0");
809 cd->input_channel = inp_channel;
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700810
811 /* Open the device. */
812 if (_camera_device_open(cd)) {
813 _camera_device_free(cd);
814 return NULL;
815 }
816
817 /* Select video input, video standard and tune here. */
818 cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
819 _xioctl(cd->handle, VIDIOC_CROPCAP, &cropcap);
820 crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
821 crop.c = cropcap.defrect; /* reset to default */
822 _xioctl (cd->handle, VIDIOC_S_CROP, &crop);
823
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700824 return &cd->header;
825}
826
827int
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700828camera_device_start_capturing(CameraDevice* ccd,
829 uint32_t pixel_format,
830 int frame_width,
831 int frame_height)
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700832{
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700833 struct v4l2_format fmt;
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700834 LinuxCameraDevice* cd;
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700835 char fmt_str[5];
836 int r;
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700837
838 /* Sanity checks. */
839 if (ccd == NULL || ccd->opaque == NULL) {
840 E("%s: Invalid camera device descriptor", __FUNCTION__);
841 return -1;
842 }
843 cd = (LinuxCameraDevice*)ccd->opaque;
Vladimir Chtchetkinece31fbc2011-09-14 06:55:16 -0700844 if (cd->handle < 0) {
845 E("%s: Camera device is not opened", __FUNCTION__);
846 return -1;
847 }
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700848
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700849 /* Try to set pixel format with the given dimensions. */
850 CLEAR(fmt);
851 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
852 fmt.fmt.pix.width = frame_width;
853 fmt.fmt.pix.height = frame_height;
854 fmt.fmt.pix.pixelformat = pixel_format;
855 if (_xioctl(cd->handle, VIDIOC_S_FMT, &fmt) < 0) {
856 memcpy(fmt_str, &pixel_format, 4);
857 fmt_str[4] = '\0';
858 E("%s: Camera '%s' does not support pixel format '%s' with dimensions %dx%d",
859 __FUNCTION__, cd->device_name, fmt_str, frame_width, frame_height);
Vladimir Chtchetkinee3b840c2011-09-22 15:41:05 -0700860 _camera_device_reset(cd);
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700861 return -1;
862 }
863 /* VIDIOC_S_FMT may has changed some properties of the structure. Make sure
864 * that dimensions didn't change. */
865 if (fmt.fmt.pix.width != frame_width || fmt.fmt.pix.height != frame_height) {
866 memcpy(fmt_str, &pixel_format, 4);
867 fmt_str[4] = '\0';
868 E("%s: Dimensions %dx%d are wrong for pixel format '%s'",
869 __FUNCTION__, frame_width, frame_height, fmt_str);
Vladimir Chtchetkinee3b840c2011-09-22 15:41:05 -0700870 _camera_device_reset(cd);
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700871 return -1;
872 }
873 memcpy(&cd->actual_pixel_format, &fmt.fmt.pix, sizeof(struct v4l2_pix_format));
874
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700875 /*
876 * Lets initialize frame buffers, and see what kind of I/O we're going to
877 * use to retrieve frames.
878 */
879
880 /* First, lets see if we can do mapped I/O (as most performant one). */
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700881 r = _camera_device_mmap_framebuffer(cd);
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700882 if (r < 0) {
883 /* Some critical error has ocurred. Bail out. */
Vladimir Chtchetkinee3b840c2011-09-22 15:41:05 -0700884 _camera_device_reset(cd);
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700885 return -1;
886 } else if (r > 0) {
887 /* Device doesn't support memory mapping. Retrieve to the next performant
888 * one: preallocated user buffers. */
889 r = _camera_device_user_framebuffer(cd);
890 if (r < 0) {
891 /* Some critical error has ocurred. Bail out. */
Vladimir Chtchetkinee3b840c2011-09-22 15:41:05 -0700892 _camera_device_reset(cd);
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700893 return -1;
894 } else if (r > 0) {
895 /* The only thing left for us is direct reading from the device. */
896 if (!(cd->caps.capabilities & V4L2_CAP_READWRITE)) {
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700897 E("%s: Don't know how to access frames on device '%s'",
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700898 __FUNCTION__, cd->device_name);
Vladimir Chtchetkinee3b840c2011-09-22 15:41:05 -0700899 _camera_device_reset(cd);
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700900 return -1;
901 }
902 r = _camera_device_direct_framebuffer(cd);
903 if (r != 0) {
904 /* Any error at this point is a critical one. */
Vladimir Chtchetkinee3b840c2011-09-22 15:41:05 -0700905 _camera_device_reset(cd);
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700906 return -1;
907 }
908 }
909 }
910
911 /* Start capturing from the device. */
912 if (cd->io_type != CAMERA_IO_DIRECT) {
913 enum v4l2_buf_type type;
914 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
915 if (_xioctl (cd->handle, VIDIOC_STREAMON, &type) < 0) {
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700916 E("%s: VIDIOC_STREAMON on camera '%s' has failed: %s",
917 __FUNCTION__, cd->device_name, strerror(errno));
Vladimir Chtchetkinee3b840c2011-09-22 15:41:05 -0700918 _camera_device_reset(cd);
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700919 return -1;
920 }
921 }
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700922 return 0;
923}
924
925int
926camera_device_stop_capturing(CameraDevice* ccd)
927{
928 enum v4l2_buf_type type;
929 LinuxCameraDevice* cd;
930
931 /* Sanity checks. */
932 if (ccd == NULL || ccd->opaque == NULL) {
933 E("%s: Invalid camera device descriptor", __FUNCTION__);
934 return -1;
935 }
936 cd = (LinuxCameraDevice*)ccd->opaque;
Vladimir Chtchetkinece31fbc2011-09-14 06:55:16 -0700937 if (cd->handle < 0) {
938 E("%s: Camera device is not opened", __FUNCTION__);
939 return -1;
940 }
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700941
942 switch (cd->io_type) {
943 case CAMERA_IO_DIRECT:
944 /* Nothing to do. */
945 break;
946
947 case CAMERA_IO_MEMMAP:
948 case CAMERA_IO_USERPTR:
949 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
950 if (_xioctl(cd->handle, VIDIOC_STREAMOFF, &type) < 0) {
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700951 E("%s: VIDIOC_STREAMOFF on camera '%s' has failed: %s",
952 __FUNCTION__, cd->device_name, strerror(errno));
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700953 return -1;
954 }
955 break;
956 default:
957 E("%s: Unknown I/O method: %d", __FUNCTION__, cd->io_type);
958 return -1;
959 }
960
Vladimir Chtchetkinece31fbc2011-09-14 06:55:16 -0700961 /* Reopen the device to reset its internal state. It seems that if we don't
962 * do that, an attempt to reinit the device with different frame dimensions
963 * would fail. */
Vladimir Chtchetkinee3b840c2011-09-22 15:41:05 -0700964 _camera_device_reset(cd);
Vladimir Chtchetkinece31fbc2011-09-14 06:55:16 -0700965
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700966 return 0;
967}
968
969int
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700970camera_device_read_frame(CameraDevice* ccd,
971 ClientFrameBuffer* framebuffers,
Vladimir Chtchetkine37fb84f2011-11-23 13:03:37 -0800972 int fbs_num,
973 float r_scale,
974 float g_scale,
975 float b_scale,
976 float exp_comp)
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700977{
978 LinuxCameraDevice* cd;
979
980 /* Sanity checks. */
981 if (ccd == NULL || ccd->opaque == NULL) {
982 E("%s: Invalid camera device descriptor", __FUNCTION__);
983 return -1;
984 }
985 cd = (LinuxCameraDevice*)ccd->opaque;
Vladimir Chtchetkinece31fbc2011-09-14 06:55:16 -0700986 if (cd->handle < 0) {
987 E("%s: Camera device is not opened", __FUNCTION__);
988 return -1;
989 }
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700990
991 if (cd->io_type == CAMERA_IO_DIRECT) {
992 /* Read directly from the device. */
993 size_t total_read_bytes = 0;
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700994 /* There is one framebuffer allocated for direct read. */
995 void* buff = cd->framebuffers[0].data;
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700996 do {
997 int read_bytes =
998 read(cd->handle, buff + total_read_bytes,
999 cd->actual_pixel_format.sizeimage - total_read_bytes);
1000 if (read_bytes < 0) {
1001 switch (errno) {
1002 case EIO:
1003 case EAGAIN:
1004 continue;
1005 default:
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -07001006 E("%s: Unable to read from the camera device '%s': %s",
1007 __FUNCTION__, cd->device_name, strerror(errno));
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -07001008 return -1;
1009 }
1010 }
1011 total_read_bytes += read_bytes;
1012 } while (total_read_bytes < cd->actual_pixel_format.sizeimage);
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -07001013 /* Convert the read frame into the caller's framebuffers. */
1014 return convert_frame(buff, cd->actual_pixel_format.pixelformat,
1015 cd->actual_pixel_format.sizeimage,
1016 cd->actual_pixel_format.width,
1017 cd->actual_pixel_format.height,
Vladimir Chtchetkine37fb84f2011-11-23 13:03:37 -08001018 framebuffers, fbs_num,
1019 r_scale, g_scale, b_scale, exp_comp);
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -07001020 } else {
1021 /* Dequeue next buffer from the device. */
1022 struct v4l2_buffer buf;
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -07001023 int res;
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -07001024 CLEAR(buf);
1025 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1026 buf.memory = cd->io_type == CAMERA_IO_MEMMAP ? V4L2_MEMORY_MMAP :
1027 V4L2_MEMORY_USERPTR;
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -07001028 for (;;) {
1029 const int res = _xioctl(cd->handle, VIDIOC_DQBUF, &buf);
1030 if (res >= 0) {
1031 break;
1032 } else if (errno == EAGAIN) {
1033 return 1; // Tells the caller to repeat.
1034 } else if (errno != EINTR && errno != EIO) {
1035 E("%s: VIDIOC_DQBUF on camera '%s' has failed: %s",
1036 __FUNCTION__, cd->device_name, strerror(errno));
1037 return -1;
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -07001038 }
1039 }
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -07001040
1041 /* Convert frame to the receiving buffers. */
1042 res = convert_frame(cd->framebuffers[buf.index].data,
1043 cd->actual_pixel_format.pixelformat,
1044 cd->actual_pixel_format.sizeimage,
1045 cd->actual_pixel_format.width,
1046 cd->actual_pixel_format.height,
Vladimir Chtchetkine37fb84f2011-11-23 13:03:37 -08001047 framebuffers, fbs_num,
1048 r_scale, g_scale, b_scale, exp_comp);
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -07001049
1050 /* Requeue the buffer back to the device. */
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -07001051 if (_xioctl(cd->handle, VIDIOC_QBUF, &buf) < 0) {
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -07001052 W("%s: VIDIOC_QBUF on camera '%s' has failed: %s",
1053 __FUNCTION__, cd->device_name, strerror(errno));
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -07001054 }
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -07001055
1056 return res;
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -07001057 }
1058}
1059
1060void
1061camera_device_close(CameraDevice* ccd)
1062{
1063 LinuxCameraDevice* cd;
1064
1065 /* Sanity checks. */
1066 if (ccd != NULL && ccd->opaque != NULL) {
1067 cd = (LinuxCameraDevice*)ccd->opaque;
1068 _camera_device_free(cd);
1069 } else {
1070 E("%s: Invalid camera device descriptor", __FUNCTION__);
1071 }
1072}
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -07001073
1074int
1075enumerate_camera_devices(CameraInfo* cis, int max)
1076{
1077 char dev_name[24];
1078 int found = 0;
1079 int n;
1080
1081 for (n = 0; n < max; n++) {
1082 CameraDevice* cd;
1083
1084 sprintf(dev_name, "/dev/video%d", n);
1085 cd = camera_device_open(dev_name, 0);
1086 if (cd != NULL) {
1087 LinuxCameraDevice* lcd = (LinuxCameraDevice*)cd->opaque;
1088 if (!_camera_device_get_info(lcd, cis + found)) {
Vladimir Chtchetkineb8dcaff2011-09-17 11:15:47 -07001089 char user_name[24];
1090 sprintf(user_name, "webcam%d", found);
1091 cis[found].display_name = ASTRDUP(user_name);
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -07001092 cis[found].in_use = 0;
1093 found++;
1094 }
1095 camera_device_close(cd);
1096 } else {
1097 break;
1098 }
1099 }
1100
1101 return found;
1102}