blob: b9a42275ff069aad2641507d7fce640f298c2e66 [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{
673 int n;
674 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. */
680 for (n = 0; ; n++) {
681 fmt_enum.index = n;
682 fmt_enum.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
683 if(_xioctl(cd->handle, VIDIOC_ENUM_FMT, &fmt_enum)) {
684 break;
685 }
686 /* Skip the compressed ones. */
687 if ((fmt_enum.flags & V4L2_FMT_FLAG_COMPRESSED) == 0) {
688 fmt_num++;
689 }
690 }
691 if (fmt_num == 0) {
692 return 0;
693 }
694
695 /* Allocate, and initialize array for enumerated formats. */
696 *fmts = (QemuPixelFormat*)malloc(fmt_num * sizeof(QemuPixelFormat));
697 if (*fmts == NULL) {
698 E("%s: Memory allocation failure", __FUNCTION__);
699 return -1;
700 }
701 arr = *fmts;
702 memset(arr, 0, fmt_num * sizeof(QemuPixelFormat));
Vladimir Chtchetkine04d90d02011-10-21 12:39:53 -0700703 for (n = 0; n < fmt_num && out_num < fmt_num; n++) {
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700704 fmt_enum.index = n;
705 fmt_enum.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
706 if(_xioctl(cd->handle, VIDIOC_ENUM_FMT, &fmt_enum)) {
707 int nn;
708 /* Errors are not welcome here anymore. */
709 E("%s: Unexpected failure while getting pixel format: %s",
Vladimir Chtchetkinecdd8d782011-10-20 10:55:03 -0700710 __FUNCTION__, strerror(errno));
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700711 for (nn = 0; nn < out_num; nn++) {
712 _qemu_pixel_format_free(arr + nn);
713 }
714 free(arr);
715 return -1;
716 }
717 /* Skip the compressed ones. */
718 if ((fmt_enum.flags & V4L2_FMT_FLAG_COMPRESSED) == 0) {
719 arr[out_num].format = fmt_enum.pixelformat;
720 /* Enumerate frame dimensions supported for this format. */
721 arr[out_num].dim_num =
722 _camera_device_enum_format_sizes(cd, fmt_enum.pixelformat,
723 &arr[out_num].dims);
724 if (arr[out_num].dim_num > 0) {
725 out_num++;
726 } else if (arr[out_num].dim_num < 0) {
727 int nn;
728 E("Unable to enumerate supported dimensions for pixel format %d",
729 fmt_enum.pixelformat);
730 for (nn = 0; nn < out_num; nn++) {
731 _qemu_pixel_format_free(arr + nn);
732 }
733 free(arr);
734 return -1;
735 }
736 }
737 }
738
739 return out_num;
740}
741
742/* Collects information about an opened camera device.
743 * The information collected in this routine contains list of pixel formats,
744 * supported by the device, and list of frame dimensions supported by the camera
745 * for each pixel format.
746 * Param:
747 * cd - Opened camera device descriptor.
748 * cis - Upon success contains information collected from the camera device.
749 * Return:
750 * 0 on success, != 0 on failure.
751 */
752static int
753_camera_device_get_info(LinuxCameraDevice* cd, CameraInfo* cis)
754{
755 int f;
756 int chosen = -1;
757 QemuPixelFormat* formats = NULL;
758 int num_pix_fmts = _camera_device_enum_pixel_formats(cd, &formats);
759 if (num_pix_fmts <= 0) {
760 return num_pix_fmts;
761 }
762
763 /* Lets see if camera supports preferred formats */
764 for (f = 0; f < _preferred_format_num; f++) {
765 chosen = _get_format_index(_preferred_formats[f], formats, num_pix_fmts);
766 if (chosen >= 0) {
767 break;
768 }
769 }
770 if (chosen < 0) {
771 /* Camera doesn't support any of the chosen formats. Then it doesn't
772 * matter which one we choose. Lets choose the first one. */
773 chosen = 0;
774 }
775
776 cis->device_name = ASTRDUP(cd->device_name);
777 cis->inp_channel = cd->input_channel;
778 cis->pixel_format = formats[chosen].format;
779 cis->frame_sizes_num = formats[chosen].dim_num;
780 /* Swap instead of copy. */
781 cis->frame_sizes = formats[chosen].dims;
782 formats[chosen].dims = NULL;
783 cis->in_use = 0;
784
785 for (f = 0; f < num_pix_fmts; f++) {
786 _qemu_pixel_format_free(formats + f);
787 }
788 free(formats);
789
790 return 0;
791}
792
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700793/*******************************************************************************
794 * CameraDevice API
795 ******************************************************************************/
796
797CameraDevice*
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700798camera_device_open(const char* name, int inp_channel)
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700799{
800 struct v4l2_cropcap cropcap;
801 struct v4l2_crop crop;
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700802 LinuxCameraDevice* cd;
803
804 /* Allocate and initialize the descriptor. */
805 cd = _camera_device_alloc();
806 cd->device_name = name != NULL ? ASTRDUP(name) : ASTRDUP("/dev/video0");
807 cd->input_channel = inp_channel;
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700808
809 /* Open the device. */
810 if (_camera_device_open(cd)) {
811 _camera_device_free(cd);
812 return NULL;
813 }
814
815 /* Select video input, video standard and tune here. */
816 cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
817 _xioctl(cd->handle, VIDIOC_CROPCAP, &cropcap);
818 crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
819 crop.c = cropcap.defrect; /* reset to default */
820 _xioctl (cd->handle, VIDIOC_S_CROP, &crop);
821
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700822 return &cd->header;
823}
824
825int
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700826camera_device_start_capturing(CameraDevice* ccd,
827 uint32_t pixel_format,
828 int frame_width,
829 int frame_height)
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700830{
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700831 struct v4l2_format fmt;
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700832 LinuxCameraDevice* cd;
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700833 char fmt_str[5];
834 int r;
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700835
836 /* Sanity checks. */
837 if (ccd == NULL || ccd->opaque == NULL) {
838 E("%s: Invalid camera device descriptor", __FUNCTION__);
839 return -1;
840 }
841 cd = (LinuxCameraDevice*)ccd->opaque;
Vladimir Chtchetkinece31fbc2011-09-14 06:55:16 -0700842 if (cd->handle < 0) {
843 E("%s: Camera device is not opened", __FUNCTION__);
844 return -1;
845 }
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700846
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700847 /* Try to set pixel format with the given dimensions. */
848 CLEAR(fmt);
849 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
850 fmt.fmt.pix.width = frame_width;
851 fmt.fmt.pix.height = frame_height;
852 fmt.fmt.pix.pixelformat = pixel_format;
853 if (_xioctl(cd->handle, VIDIOC_S_FMT, &fmt) < 0) {
854 memcpy(fmt_str, &pixel_format, 4);
855 fmt_str[4] = '\0';
856 E("%s: Camera '%s' does not support pixel format '%s' with dimensions %dx%d",
857 __FUNCTION__, cd->device_name, fmt_str, frame_width, frame_height);
Vladimir Chtchetkinee3b840c2011-09-22 15:41:05 -0700858 _camera_device_reset(cd);
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700859 return -1;
860 }
861 /* VIDIOC_S_FMT may has changed some properties of the structure. Make sure
862 * that dimensions didn't change. */
863 if (fmt.fmt.pix.width != frame_width || fmt.fmt.pix.height != frame_height) {
864 memcpy(fmt_str, &pixel_format, 4);
865 fmt_str[4] = '\0';
866 E("%s: Dimensions %dx%d are wrong for pixel format '%s'",
867 __FUNCTION__, frame_width, frame_height, fmt_str);
Vladimir Chtchetkinee3b840c2011-09-22 15:41:05 -0700868 _camera_device_reset(cd);
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700869 return -1;
870 }
871 memcpy(&cd->actual_pixel_format, &fmt.fmt.pix, sizeof(struct v4l2_pix_format));
872
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700873 /*
874 * Lets initialize frame buffers, and see what kind of I/O we're going to
875 * use to retrieve frames.
876 */
877
878 /* First, lets see if we can do mapped I/O (as most performant one). */
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700879 r = _camera_device_mmap_framebuffer(cd);
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700880 if (r < 0) {
881 /* Some critical error has ocurred. Bail out. */
Vladimir Chtchetkinee3b840c2011-09-22 15:41:05 -0700882 _camera_device_reset(cd);
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700883 return -1;
884 } else if (r > 0) {
885 /* Device doesn't support memory mapping. Retrieve to the next performant
886 * one: preallocated user buffers. */
887 r = _camera_device_user_framebuffer(cd);
888 if (r < 0) {
889 /* Some critical error has ocurred. Bail out. */
Vladimir Chtchetkinee3b840c2011-09-22 15:41:05 -0700890 _camera_device_reset(cd);
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700891 return -1;
892 } else if (r > 0) {
893 /* The only thing left for us is direct reading from the device. */
894 if (!(cd->caps.capabilities & V4L2_CAP_READWRITE)) {
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700895 E("%s: Don't know how to access frames on device '%s'",
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700896 __FUNCTION__, cd->device_name);
Vladimir Chtchetkinee3b840c2011-09-22 15:41:05 -0700897 _camera_device_reset(cd);
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700898 return -1;
899 }
900 r = _camera_device_direct_framebuffer(cd);
901 if (r != 0) {
902 /* Any error at this point is a critical one. */
Vladimir Chtchetkinee3b840c2011-09-22 15:41:05 -0700903 _camera_device_reset(cd);
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700904 return -1;
905 }
906 }
907 }
908
909 /* Start capturing from the device. */
910 if (cd->io_type != CAMERA_IO_DIRECT) {
911 enum v4l2_buf_type type;
912 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
913 if (_xioctl (cd->handle, VIDIOC_STREAMON, &type) < 0) {
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700914 E("%s: VIDIOC_STREAMON on camera '%s' has failed: %s",
915 __FUNCTION__, cd->device_name, strerror(errno));
Vladimir Chtchetkinee3b840c2011-09-22 15:41:05 -0700916 _camera_device_reset(cd);
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700917 return -1;
918 }
919 }
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700920 return 0;
921}
922
923int
924camera_device_stop_capturing(CameraDevice* ccd)
925{
926 enum v4l2_buf_type type;
927 LinuxCameraDevice* cd;
928
929 /* Sanity checks. */
930 if (ccd == NULL || ccd->opaque == NULL) {
931 E("%s: Invalid camera device descriptor", __FUNCTION__);
932 return -1;
933 }
934 cd = (LinuxCameraDevice*)ccd->opaque;
Vladimir Chtchetkinece31fbc2011-09-14 06:55:16 -0700935 if (cd->handle < 0) {
936 E("%s: Camera device is not opened", __FUNCTION__);
937 return -1;
938 }
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700939
940 switch (cd->io_type) {
941 case CAMERA_IO_DIRECT:
942 /* Nothing to do. */
943 break;
944
945 case CAMERA_IO_MEMMAP:
946 case CAMERA_IO_USERPTR:
947 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
948 if (_xioctl(cd->handle, VIDIOC_STREAMOFF, &type) < 0) {
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700949 E("%s: VIDIOC_STREAMOFF on camera '%s' has failed: %s",
950 __FUNCTION__, cd->device_name, strerror(errno));
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700951 return -1;
952 }
953 break;
954 default:
955 E("%s: Unknown I/O method: %d", __FUNCTION__, cd->io_type);
956 return -1;
957 }
958
Vladimir Chtchetkinece31fbc2011-09-14 06:55:16 -0700959 /* Reopen the device to reset its internal state. It seems that if we don't
960 * do that, an attempt to reinit the device with different frame dimensions
961 * would fail. */
Vladimir Chtchetkinee3b840c2011-09-22 15:41:05 -0700962 _camera_device_reset(cd);
Vladimir Chtchetkinece31fbc2011-09-14 06:55:16 -0700963
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700964 return 0;
965}
966
967int
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700968camera_device_read_frame(CameraDevice* ccd,
969 ClientFrameBuffer* framebuffers,
970 int fbs_num)
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700971{
972 LinuxCameraDevice* cd;
973
974 /* Sanity checks. */
975 if (ccd == NULL || ccd->opaque == NULL) {
976 E("%s: Invalid camera device descriptor", __FUNCTION__);
977 return -1;
978 }
979 cd = (LinuxCameraDevice*)ccd->opaque;
Vladimir Chtchetkinece31fbc2011-09-14 06:55:16 -0700980 if (cd->handle < 0) {
981 E("%s: Camera device is not opened", __FUNCTION__);
982 return -1;
983 }
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700984
985 if (cd->io_type == CAMERA_IO_DIRECT) {
986 /* Read directly from the device. */
987 size_t total_read_bytes = 0;
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -0700988 /* There is one framebuffer allocated for direct read. */
989 void* buff = cd->framebuffers[0].data;
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -0700990 do {
991 int read_bytes =
992 read(cd->handle, buff + total_read_bytes,
993 cd->actual_pixel_format.sizeimage - total_read_bytes);
994 if (read_bytes < 0) {
995 switch (errno) {
996 case EIO:
997 case EAGAIN:
998 continue;
999 default:
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -07001000 E("%s: Unable to read from the camera device '%s': %s",
1001 __FUNCTION__, cd->device_name, strerror(errno));
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -07001002 return -1;
1003 }
1004 }
1005 total_read_bytes += read_bytes;
1006 } while (total_read_bytes < cd->actual_pixel_format.sizeimage);
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -07001007 /* Convert the read frame into the caller's framebuffers. */
1008 return convert_frame(buff, cd->actual_pixel_format.pixelformat,
1009 cd->actual_pixel_format.sizeimage,
1010 cd->actual_pixel_format.width,
1011 cd->actual_pixel_format.height,
1012 framebuffers, fbs_num);
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -07001013 } else {
1014 /* Dequeue next buffer from the device. */
1015 struct v4l2_buffer buf;
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -07001016 int res;
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -07001017 CLEAR(buf);
1018 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1019 buf.memory = cd->io_type == CAMERA_IO_MEMMAP ? V4L2_MEMORY_MMAP :
1020 V4L2_MEMORY_USERPTR;
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -07001021 for (;;) {
1022 const int res = _xioctl(cd->handle, VIDIOC_DQBUF, &buf);
1023 if (res >= 0) {
1024 break;
1025 } else if (errno == EAGAIN) {
1026 return 1; // Tells the caller to repeat.
1027 } else if (errno != EINTR && errno != EIO) {
1028 E("%s: VIDIOC_DQBUF on camera '%s' has failed: %s",
1029 __FUNCTION__, cd->device_name, strerror(errno));
1030 return -1;
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -07001031 }
1032 }
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -07001033
1034 /* Convert frame to the receiving buffers. */
1035 res = convert_frame(cd->framebuffers[buf.index].data,
1036 cd->actual_pixel_format.pixelformat,
1037 cd->actual_pixel_format.sizeimage,
1038 cd->actual_pixel_format.width,
1039 cd->actual_pixel_format.height,
1040 framebuffers, fbs_num);
1041
1042 /* Requeue the buffer back to the device. */
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -07001043 if (_xioctl(cd->handle, VIDIOC_QBUF, &buf) < 0) {
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -07001044 W("%s: VIDIOC_QBUF on camera '%s' has failed: %s",
1045 __FUNCTION__, cd->device_name, strerror(errno));
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -07001046 }
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -07001047
1048 return res;
Vladimir Chtchetkine4ed09fd2011-08-18 09:42:40 -07001049 }
1050}
1051
1052void
1053camera_device_close(CameraDevice* ccd)
1054{
1055 LinuxCameraDevice* cd;
1056
1057 /* Sanity checks. */
1058 if (ccd != NULL && ccd->opaque != NULL) {
1059 cd = (LinuxCameraDevice*)ccd->opaque;
1060 _camera_device_free(cd);
1061 } else {
1062 E("%s: Invalid camera device descriptor", __FUNCTION__);
1063 }
1064}
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -07001065
1066int
1067enumerate_camera_devices(CameraInfo* cis, int max)
1068{
1069 char dev_name[24];
1070 int found = 0;
1071 int n;
1072
1073 for (n = 0; n < max; n++) {
1074 CameraDevice* cd;
1075
1076 sprintf(dev_name, "/dev/video%d", n);
1077 cd = camera_device_open(dev_name, 0);
1078 if (cd != NULL) {
1079 LinuxCameraDevice* lcd = (LinuxCameraDevice*)cd->opaque;
1080 if (!_camera_device_get_info(lcd, cis + found)) {
Vladimir Chtchetkineb8dcaff2011-09-17 11:15:47 -07001081 char user_name[24];
1082 sprintf(user_name, "webcam%d", found);
1083 cis[found].display_name = ASTRDUP(user_name);
Vladimir Chtchetkinecf1c2c72011-09-04 09:51:40 -07001084 cis[found].in_use = 0;
1085 found++;
1086 }
1087 camera_device_close(cd);
1088 } else {
1089 break;
1090 }
1091 }
1092
1093 return found;
1094}