uvc-gadget: Use new kernel API header
[uvc-gadget.git] / uvc-gadget.c
1 /*
2  * UVC gadget test application
3  *
4  * Copyright (C) 2010 Ideas on board SPRL <laurent.pinchart@ideasonboard.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  */
19
20 #include <sys/time.h>
21 #include <sys/ioctl.h>
22 #include <sys/mman.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <sys/select.h>
26
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <stdint.h>
32 #include <string.h>
33 #include <errno.h>
34
35 #include <linux/usb/ch9.h>
36 #include <linux/usb/g_uvc.h>
37 #include <linux/usb/video.h>
38 #include <linux/videodev2.h>
39
40 #define UVC_INTF_CONTROL        0
41 #define UVC_INTF_STREAMING      1
42
43 #define clamp(val, min, max) ({                 \
44         typeof(val) __val = (val);              \
45         typeof(min) __min = (min);              \
46         typeof(max) __max = (max);              \
47         (void) (&__val == &__min);              \
48         (void) (&__val == &__max);              \
49         __val = __val < __min ? __min: __val;   \
50         __val > __max ? __max: __val; })
51
52 #define ARRAY_SIZE(a)   ((sizeof(a) / sizeof(a[0])))
53
54 struct uvc_device
55 {
56         int fd;
57
58         struct uvc_streaming_control probe;
59         struct uvc_streaming_control commit;
60
61         int control;
62
63         unsigned int fcc;
64         unsigned int width;
65         unsigned int height;
66
67         void **mem;
68         unsigned int nbufs;
69         unsigned int bufsize;
70
71         unsigned int bulk;
72         uint8_t color;
73         unsigned int imgsize;
74         void *imgdata;
75 };
76
77 static struct uvc_device *
78 uvc_open(const char *devname)
79 {
80         struct uvc_device *dev;
81         struct v4l2_capability cap;
82         int ret;
83         int fd;
84
85         fd = open(devname, O_RDWR | O_NONBLOCK);
86         if (fd == -1) {
87                 printf("v4l2 open failed: %s (%d)\n", strerror(errno), errno);
88                 return NULL;
89         }
90
91         printf("open succeeded, file descriptor = %d\n", fd);
92
93         ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);
94         if (ret < 0) {
95                 printf("unable to query device: %s (%d)\n", strerror(errno),
96                         errno);
97                 close(fd);
98                 return NULL;
99         }
100
101         printf("device is %s on bus %s\n", cap.card, cap.bus_info);
102
103         dev = malloc(sizeof *dev);
104         if (dev == NULL) {
105                 close(fd);
106                 return NULL;
107         }
108
109         memset(dev, 0, sizeof *dev);
110         dev->fd = fd;
111
112         return dev;
113 }
114
115 static void
116 uvc_close(struct uvc_device *dev)
117 {
118         close(dev->fd);
119         free(dev->imgdata);
120         free(dev->mem);
121         free(dev);
122 }
123
124 /* ---------------------------------------------------------------------------
125  * Video streaming
126  */
127
128 static void
129 uvc_video_fill_buffer(struct uvc_device *dev, struct v4l2_buffer *buf)
130 {
131         unsigned int bpl;
132         unsigned int i;
133
134         switch (dev->fcc) {
135         case V4L2_PIX_FMT_YUYV:
136                 /* Fill the buffer with video data. */
137                 bpl = dev->width * 2;
138                 for (i = 0; i < dev->height; ++i)
139                         memset(dev->mem[buf->index] + i*bpl, dev->color++, bpl);
140
141                 buf->bytesused = bpl * dev->height;
142                 break;
143
144         case V4L2_PIX_FMT_MJPEG:
145                 memcpy(dev->mem[buf->index], dev->imgdata, dev->imgsize);
146                 buf->bytesused = dev->imgsize;
147                 break;
148         }
149 }
150
151 static int
152 uvc_video_process(struct uvc_device *dev)
153 {
154         struct v4l2_buffer buf;
155         int ret;
156
157         memset(&buf, 0, sizeof buf);
158         buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
159         buf.memory = V4L2_MEMORY_MMAP;
160
161         if ((ret = ioctl(dev->fd, VIDIOC_DQBUF, &buf)) < 0) {
162                 printf("Unable to dequeue buffer: %s (%d).\n", strerror(errno),
163                         errno);
164                 return ret;
165         }
166
167         uvc_video_fill_buffer(dev, &buf);
168
169         if ((ret = ioctl(dev->fd, VIDIOC_QBUF, &buf)) < 0) {
170                 printf("Unable to requeue buffer: %s (%d).\n", strerror(errno),
171                         errno);
172                 return ret;
173         }
174
175         return 0;
176 }
177
178 static int
179 uvc_video_reqbufs(struct uvc_device *dev, int nbufs)
180 {
181         struct v4l2_requestbuffers rb;
182         struct v4l2_buffer buf;
183         unsigned int i;
184         int ret;
185
186         for (i = 0; i < dev->nbufs; ++i)
187                 munmap(dev->mem[i], dev->bufsize);
188
189         free(dev->mem);
190         dev->mem = 0;
191         dev->nbufs = 0;
192
193         memset(&rb, 0, sizeof rb);
194         rb.count = nbufs;
195         rb.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
196         rb.memory = V4L2_MEMORY_MMAP;
197
198         ret = ioctl(dev->fd, VIDIOC_REQBUFS, &rb);
199         if (ret < 0) {
200                 printf("Unable to allocate buffers: %s (%d).\n",
201                         strerror(errno), errno);
202                 return ret;
203         }
204
205         printf("%u buffers allocated.\n", rb.count);
206
207         /* Map the buffers. */
208         dev->mem = malloc(rb.count * sizeof dev->mem[0]);
209
210         for (i = 0; i < rb.count; ++i) {
211                 memset(&buf, 0, sizeof buf);
212                 buf.index = i;
213                 buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
214                 buf.memory = V4L2_MEMORY_MMAP;
215                 ret = ioctl(dev->fd, VIDIOC_QUERYBUF, &buf);
216                 if (ret < 0) {
217                         printf("Unable to query buffer %u: %s (%d).\n", i,
218                                 strerror(errno), errno);
219                         return -1;
220                 }
221                 printf("length: %u offset: %u\n", buf.length, buf.m.offset);
222
223                 dev->mem[i] = mmap(0, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, dev->fd, buf.m.offset);
224                 if (dev->mem[i] == MAP_FAILED) {
225                         printf("Unable to map buffer %u: %s (%d)\n", i,
226                                 strerror(errno), errno);
227                         return -1;
228                 }
229                 printf("Buffer %u mapped at address %p.\n", i, dev->mem[i]);
230         }
231
232         dev->bufsize = buf.length;
233         dev->nbufs = rb.count;
234
235         return 0;
236 }
237
238 static int
239 uvc_video_stream(struct uvc_device *dev, int enable)
240 {
241         struct v4l2_buffer buf;
242         unsigned int i;
243         int type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
244         int ret;
245
246         if (!enable) {
247                 printf("Stopping video stream.\n");
248                 ioctl(dev->fd, VIDIOC_STREAMOFF, &type);
249                 return 0;
250         }
251
252         printf("Starting video stream.\n");
253
254         for (i = 0; i < dev->nbufs; ++i) {
255                 memset(&buf, 0, sizeof buf);
256
257                 buf.index = i;
258                 buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
259                 buf.memory = V4L2_MEMORY_MMAP;
260
261                 uvc_video_fill_buffer(dev, &buf);
262
263                 printf("Queueing buffer %u.\n", i);
264                 if ((ret = ioctl(dev->fd, VIDIOC_QBUF, &buf)) < 0) {
265                         printf("Unable to queue buffer: %s (%d).\n",
266                                 strerror(errno), errno);
267                         break;
268                 }
269         }
270
271         ioctl(dev->fd, VIDIOC_STREAMON, &type);
272         return ret;
273 }
274
275 static int
276 uvc_video_set_format(struct uvc_device *dev)
277 {
278         struct v4l2_format fmt;
279         int ret;
280
281         printf("Setting format to 0x%08x %ux%u\n",
282                 dev->fcc, dev->width, dev->height);
283
284         memset(&fmt, 0, sizeof fmt);
285         fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
286         fmt.fmt.pix.width = dev->width;
287         fmt.fmt.pix.height = dev->height;
288         fmt.fmt.pix.pixelformat = dev->fcc;
289         fmt.fmt.pix.field = V4L2_FIELD_NONE;
290         if (dev->fcc == V4L2_PIX_FMT_MJPEG)
291                 fmt.fmt.pix.sizeimage = dev->imgsize * 1.5;
292
293         if ((ret = ioctl(dev->fd, VIDIOC_S_FMT, &fmt)) < 0)
294                 printf("Unable to set format: %s (%d).\n",
295                         strerror(errno), errno);
296
297         return ret;
298 }
299
300 static int
301 uvc_video_init(struct uvc_device *dev __attribute__((__unused__)))
302 {
303         return 0;
304 }
305
306 /* ---------------------------------------------------------------------------
307  * Request processing
308  */
309
310 struct uvc_frame_info
311 {
312         unsigned int width;
313         unsigned int height;
314         unsigned int intervals[8];
315 };
316
317 struct uvc_format_info
318 {
319         unsigned int fcc;
320         const struct uvc_frame_info *frames;
321 };
322
323 static const struct uvc_frame_info uvc_frames_yuyv[] = {
324         {  640, 360, { 666666, 10000000, 50000000, 0 }, },
325         { 1280, 720, { 50000000, 0 }, },
326         { 0, 0, { 0, }, },
327 };
328
329 static const struct uvc_frame_info uvc_frames_mjpeg[] = {
330         {  640, 360, { 666666, 10000000, 50000000, 0 }, },
331         { 1280, 720, { 50000000, 0 }, },
332         { 0, 0, { 0, }, },
333 };
334
335 static const struct uvc_format_info uvc_formats[] = {
336         { V4L2_PIX_FMT_YUYV, uvc_frames_yuyv },
337         { V4L2_PIX_FMT_MJPEG, uvc_frames_mjpeg },
338 };
339
340 static void
341 uvc_fill_streaming_control(struct uvc_device *dev,
342                            struct uvc_streaming_control *ctrl,
343                            int iframe, int iformat)
344 {
345         const struct uvc_format_info *format;
346         const struct uvc_frame_info *frame;
347         unsigned int nframes;
348
349         if (iformat < 0)
350                 iformat = ARRAY_SIZE(uvc_formats) + iformat;
351         if (iformat < 0 || iformat >= (int)ARRAY_SIZE(uvc_formats))
352                 return;
353         format = &uvc_formats[iformat];
354
355         nframes = 0;
356         while (format->frames[nframes].width != 0)
357                 ++nframes;
358
359         if (iframe < 0)
360                 iframe = nframes + iframe;
361         if (iframe < 0 || iframe >= (int)nframes)
362                 return;
363         frame = &format->frames[iframe];
364
365         memset(ctrl, 0, sizeof *ctrl);
366
367         ctrl->bmHint = 1;
368         ctrl->bFormatIndex = iformat + 1;
369         ctrl->bFrameIndex = iframe + 1;
370         ctrl->dwFrameInterval = frame->intervals[0];
371         switch (format->fcc) {
372         case V4L2_PIX_FMT_YUYV:
373                 ctrl->dwMaxVideoFrameSize = frame->width * frame->height * 2;
374                 break;
375         case V4L2_PIX_FMT_MJPEG:
376                 ctrl->dwMaxVideoFrameSize = dev->imgsize;
377                 break;
378         }
379         ctrl->dwMaxPayloadTransferSize = 512;   /* TODO this should be filled by the driver. */
380         ctrl->bmFramingInfo = 3;
381         ctrl->bPreferedVersion = 1;
382         ctrl->bMaxVersion = 1;
383 }
384
385 static void
386 uvc_events_process_standard(struct uvc_device *dev, struct usb_ctrlrequest *ctrl,
387                             struct uvc_request_data *resp)
388 {
389         printf("standard request\n");
390         (void)dev;
391         (void)ctrl;
392         (void)resp;
393 }
394
395 static void
396 uvc_events_process_control(struct uvc_device *dev, uint8_t req, uint8_t cs,
397                            struct uvc_request_data *resp)
398 {
399         printf("control request (req %02x cs %02x)\n", req, cs);
400         (void)dev;
401         (void)resp;
402 }
403
404 static void
405 uvc_events_process_streaming(struct uvc_device *dev, uint8_t req, uint8_t cs,
406                              struct uvc_request_data *resp)
407 {
408         struct uvc_streaming_control *ctrl;
409
410         printf("streaming request (req %02x cs %02x)\n", req, cs);
411
412         if (cs != UVC_VS_PROBE_CONTROL && cs != UVC_VS_COMMIT_CONTROL)
413                 return;
414
415         ctrl = (struct uvc_streaming_control *)&resp->data;
416         resp->length = sizeof *ctrl;
417
418         switch (req) {
419         case UVC_SET_CUR:
420                 dev->control = cs;
421                 resp->length = 34;
422                 break;
423
424         case UVC_GET_CUR:
425                 if (cs == UVC_VS_PROBE_CONTROL)
426                         memcpy(ctrl, &dev->probe, sizeof *ctrl);
427                 else
428                         memcpy(ctrl, &dev->commit, sizeof *ctrl);
429                 break;
430
431         case UVC_GET_MIN:
432         case UVC_GET_MAX:
433         case UVC_GET_DEF:
434                 uvc_fill_streaming_control(dev, ctrl, req == UVC_GET_MAX ? -1 : 0,
435                                            req == UVC_GET_MAX ? -1 : 0);
436                 break;
437
438         case UVC_GET_RES:
439                 memset(ctrl, 0, sizeof *ctrl);
440                 break;
441
442         case UVC_GET_LEN:
443                 resp->data[0] = 0x00;
444                 resp->data[1] = 0x22;
445                 resp->length = 2;
446                 break;
447
448         case UVC_GET_INFO:
449                 resp->data[0] = 0x03;
450                 resp->length = 1;
451                 break;
452         }
453 }
454
455 static void
456 uvc_events_process_class(struct uvc_device *dev, struct usb_ctrlrequest *ctrl,
457                          struct uvc_request_data *resp)
458 {
459         if ((ctrl->bRequestType & USB_RECIP_MASK) != USB_RECIP_INTERFACE)
460                 return;
461
462         switch (ctrl->wIndex & 0xff) {
463         case UVC_INTF_CONTROL:
464                 uvc_events_process_control(dev, ctrl->bRequest, ctrl->wValue >> 8, resp);
465                 break;
466
467         case UVC_INTF_STREAMING:
468                 uvc_events_process_streaming(dev, ctrl->bRequest, ctrl->wValue >> 8, resp);
469                 break;
470
471         default:
472                 break;
473         }
474 }
475
476 static void
477 uvc_events_process_setup(struct uvc_device *dev, struct usb_ctrlrequest *ctrl,
478                          struct uvc_request_data *resp)
479 {
480         dev->control = 0;
481
482         printf("bRequestType %02x bRequest %02x wValue %04x wIndex %04x "
483                 "wLength %04x\n", ctrl->bRequestType, ctrl->bRequest,
484                 ctrl->wValue, ctrl->wIndex, ctrl->wLength);
485
486         switch (ctrl->bRequestType & USB_TYPE_MASK) {
487         case USB_TYPE_STANDARD:
488                 uvc_events_process_standard(dev, ctrl, resp);
489                 break;
490
491         case USB_TYPE_CLASS:
492                 uvc_events_process_class(dev, ctrl, resp);
493                 break;
494
495         default:
496                 break;
497         }
498 }
499
500 static void
501 uvc_events_process_data(struct uvc_device *dev, struct uvc_request_data *data)
502 {
503         struct uvc_streaming_control *target;
504         struct uvc_streaming_control *ctrl;
505         const struct uvc_format_info *format;
506         const struct uvc_frame_info *frame;
507         const unsigned int *interval;
508         unsigned int iformat, iframe;
509         unsigned int nframes;
510
511         switch (dev->control) {
512         case UVC_VS_PROBE_CONTROL:
513                 printf("setting probe control, length = %d\n", data->length);
514                 target = &dev->probe;
515                 break;
516
517         case UVC_VS_COMMIT_CONTROL:
518                 printf("setting commit control, length = %d\n", data->length);
519                 target = &dev->commit;
520                 break;
521
522         default:
523                 printf("setting unknown control, length = %d\n", data->length);
524                 return;
525         }
526
527         ctrl = (struct uvc_streaming_control *)&data->data;
528         iformat = clamp((unsigned int)ctrl->bFormatIndex, 1U,
529                         (unsigned int)ARRAY_SIZE(uvc_formats));
530         format = &uvc_formats[iformat-1];
531
532         nframes = 0;
533         while (format->frames[nframes].width != 0)
534                 ++nframes;
535
536         iframe = clamp((unsigned int)ctrl->bFrameIndex, 1U, nframes);
537         frame = &format->frames[iframe-1];
538         interval = frame->intervals;
539
540         while (interval[0] < ctrl->dwFrameInterval && interval[1])
541                 ++interval;
542
543         target->bFormatIndex = iformat;
544         target->bFrameIndex = iframe;
545         switch (format->fcc) {
546         case V4L2_PIX_FMT_YUYV:
547                 target->dwMaxVideoFrameSize = frame->width * frame->height * 2;
548                 break;
549         case V4L2_PIX_FMT_MJPEG:
550                 if (dev->imgsize == 0)
551                         printf("WARNING: MJPEG requested and no image loaded.\n");
552                 target->dwMaxVideoFrameSize = dev->imgsize;
553                 break;
554         }
555         target->dwFrameInterval = *interval;
556
557         if (dev->control == UVC_VS_COMMIT_CONTROL) {
558                 dev->fcc = format->fcc;
559                 dev->width = frame->width;
560                 dev->height = frame->height;
561
562                 uvc_video_set_format(dev);
563                 if (dev->bulk)
564                         uvc_video_stream(dev, 1);
565         }
566 }
567
568 static void
569 uvc_events_process(struct uvc_device *dev)
570 {
571         struct v4l2_event v4l2_event;
572         struct uvc_event *uvc_event = (void *)&v4l2_event.u.data;
573         struct uvc_request_data resp;
574         int ret;
575
576         ret = ioctl(dev->fd, VIDIOC_DQEVENT, &v4l2_event);
577         if (ret < 0) {
578                 printf("VIDIOC_DQEVENT failed: %s (%d)\n", strerror(errno),
579                         errno);
580                 return;
581         }
582
583         memset(&resp, 0, sizeof resp);
584         resp.length = -EL2HLT;
585
586         switch (v4l2_event.type) {
587         case UVC_EVENT_CONNECT:
588         case UVC_EVENT_DISCONNECT:
589                 return;
590
591         case UVC_EVENT_SETUP:
592                 uvc_events_process_setup(dev, &uvc_event->req, &resp);
593                 break;
594
595         case UVC_EVENT_DATA:
596                 uvc_events_process_data(dev, &uvc_event->data);
597                 return;
598
599         case UVC_EVENT_STREAMON:
600                 uvc_video_reqbufs(dev, 4);
601                 uvc_video_stream(dev, 1);
602                 return;
603
604         case UVC_EVENT_STREAMOFF:
605                 uvc_video_stream(dev, 0);
606                 uvc_video_reqbufs(dev, 0);
607                 return;
608         }
609
610         ioctl(dev->fd, UVCIOC_SEND_RESPONSE, &resp);
611         if (ret < 0) {
612                 printf("UVCIOC_S_EVENT failed: %s (%d)\n", strerror(errno),
613                         errno);
614                 return;
615         }
616 }
617
618 static void
619 uvc_events_init(struct uvc_device *dev)
620 {
621         struct v4l2_event_subscription sub;
622
623         uvc_fill_streaming_control(dev, &dev->probe, 0, 0);
624         uvc_fill_streaming_control(dev, &dev->commit, 0, 0);
625
626         if (dev->bulk) {
627                 /* FIXME Crude hack, must be negotiated with the driver. */
628                 dev->probe.dwMaxPayloadTransferSize = 16 * 1024;
629                 dev->commit.dwMaxPayloadTransferSize = 16 * 1024;
630         }
631
632
633         memset(&sub, 0, sizeof sub);
634         sub.type = UVC_EVENT_SETUP;
635         ioctl(dev->fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
636         sub.type = UVC_EVENT_DATA;
637         ioctl(dev->fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
638         sub.type = UVC_EVENT_STREAMON;
639         ioctl(dev->fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
640         sub.type = UVC_EVENT_STREAMOFF;
641         ioctl(dev->fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
642 }
643
644 /* ---------------------------------------------------------------------------
645  * main
646  */
647
648 static void image_load(struct uvc_device *dev, const char *img)
649 {
650         int fd = -1;
651
652         if (img == NULL)
653                 return;
654
655         fd = open(img, O_RDONLY);
656         if (fd == -1) {
657                 printf("Unable to open MJPEG image '%s'\n", img);
658                 return;
659         }
660
661         dev->imgsize = lseek(fd, 0, SEEK_END);
662         lseek(fd, 0, SEEK_SET);
663         dev->imgdata = malloc(dev->imgsize);
664         if (dev->imgdata == NULL) {
665                 printf("Unable to allocate memory for MJPEG image\n");
666                 dev->imgsize = 0;
667                 return;
668         }
669
670         read(fd, dev->imgdata, dev->imgsize);
671         close(fd);
672 }
673
674 static void usage(const char *argv0)
675 {
676         fprintf(stderr, "Usage: %s [options]\n", argv0);
677         fprintf(stderr, "Available options are\n");
678         fprintf(stderr, " -b            Use bulk mode\n");
679         fprintf(stderr, " -d device     Video device\n");
680         fprintf(stderr, " -h            Print this help screen and exit\n");
681         fprintf(stderr, " -i image      MJPEG image\n");
682 }
683
684 int main(int argc, char *argv[])
685 {
686         char *device = "/dev/video0";
687         struct uvc_device *dev;
688         int bulk_mode = 0;
689         char *mjpeg_image = NULL;
690         fd_set fds;
691         int ret, opt;
692
693         while ((opt = getopt(argc, argv, "bd:hi:")) != -1) {
694                 switch (opt) {
695                 case 'b':
696                         bulk_mode = 1;
697                         break;
698
699                 case 'd':
700                         device = optarg;
701                         break;
702
703                 case 'h':
704                         usage(argv[0]);
705                         return 0;
706
707                 case 'i':
708                         mjpeg_image = optarg;
709                         break;
710
711                 default:
712                         fprintf(stderr, "Invalid option '-%c'\n", opt);
713                         usage(argv[0]);
714                         return 1;
715                 }
716         }
717
718         dev = uvc_open(device);
719         if (dev == NULL)
720                 return 1;
721
722         image_load(dev, mjpeg_image);
723
724         dev->bulk = bulk_mode;
725
726         uvc_events_init(dev);
727         uvc_video_init(dev);
728
729         FD_ZERO(&fds);
730         FD_SET(dev->fd, &fds);
731
732         while (1) {
733                 fd_set efds = fds;
734                 fd_set wfds = fds;
735
736                 ret = select(dev->fd + 1, NULL, &wfds, &efds, NULL);
737                 if (FD_ISSET(dev->fd, &efds))
738                         uvc_events_process(dev);
739                 if (FD_ISSET(dev->fd, &wfds))
740                         uvc_video_process(dev);
741         }
742
743         uvc_close(dev);
744         return 0;
745 }
746