Fix for DSS scaling error on very small screens
[apps/dual-camera-demo.git] / loopback.cpp
1 #include <stdlib.h>
2 #include <unistd.h>
3 #include <errno.h>
4 #include <string.h>
5 #include <fcntl.h>
6 #include <sys/mman.h>
7 #include <malloc.h>
8 #include <sys/stat.h>
9 #include <sys/ioctl.h>
11 #include <linux/fb.h>
12 #include <linux/omapfb.h>
13 #include <linux/videodev2.h>
15 #include "jpeg.h"
16 #include "loopback.h"
18 control status;
20 struct buf_info {
21     unsigned int length;
22     char *start;
23 };
25 /*
26  * Fbdev output device structure declaration
27  */
28 struct fbdev_device_info
29 {
30     int fd;
31     int width;
32     int height;
33     char dev_name[9];
34     char name[4];
35     int buf_current;
36     char *buf_start;
37     char *buf_start2;
38     unsigned int buf_length;
40     struct fb_fix_screeninfo fixinfo;
41     struct fb_var_screeninfo varinfo;
42     struct omapfb_display_info di;
43     struct omapfb_mem_info mi;
44     struct omapfb_plane_info pi;
45     struct omapfb_caps caps;
47     enum omapfb_update_mode update_mode;
49 } fb1_device, fb2_device;
51 /*
52  * V4L2 capture device structure declaration
53  */
54 struct v4l2_device_info {
55     int type;
56     int fd;
57     enum v4l2_memory memory_mode;
58     int num_buffers;
59     int width;
60     int height;
61     char dev_name[12];
62     char name[10];
64     struct v4l2_buffer buf;
65     struct v4l2_format fmt;
66     struct buf_info *buffers;
67 } cap0_device, cap1_device;
69 static int v4l2_init_device(struct v4l2_device_info *device)
70 {
71     int ret, i, j;
72     struct v4l2_requestbuffers reqbuf;
73     struct v4l2_buffer buf;
74     struct v4l2_format temp_fmt;
75     struct buf_info *temp_buffers;
76     struct v4l2_capability capability;
78     /* Open the capture device */
79     device->fd = open((const char *) device->dev_name, O_RDWR);
80     if (device->fd <= 0) {
81         printf("Cannot open %s device\n", device->dev_name);
82         return -1;
83     }
85     printf("\n%s: Opened Channel\n", device->name);
87     /* Check if the device is capable of streaming */
88     if (ioctl(device->fd, VIDIOC_QUERYCAP, &capability) < 0) {
89         perror("VIDIOC_QUERYCAP");
90         goto ERROR;
91     }
93     if (capability.capabilities & V4L2_CAP_STREAMING)
94         printf("%s: Capable of streaming\n", device->name);
95     else {
96         printf("%s: Not capable of streaming\n", device->name);
97         goto ERROR;
98     }
100     reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
101     temp_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
102     temp_fmt.fmt.pix.width = device->width;
103     temp_fmt.fmt.pix.height = device->height;
104     temp_fmt.fmt.pix.pixelformat = device->fmt.fmt.pix.pixelformat;
106     ret = ioctl(device->fd, VIDIOC_S_FMT, &temp_fmt);
107     if (ret < 0) {
108         perror("VIDIOC_S_FMT");
109         goto ERROR;
110     }
112     device->fmt = temp_fmt;
114     reqbuf.count = device->num_buffers;
115     reqbuf.memory = device->memory_mode;
116     ret = ioctl(device->fd, VIDIOC_REQBUFS, &reqbuf);
117     if (ret < 0) {
118         perror("Cannot allocate memory");
119         goto ERROR;
120     }
121     device->num_buffers = reqbuf.count;
122     printf("%s: Number of requested buffers = %u\n", device->name,
123            device->num_buffers);
125     temp_buffers = (struct buf_info *) malloc(sizeof(struct buf_info) *
126                           device->num_buffers);
127     if (!temp_buffers) {
128         printf("Cannot allocate memory\n");
129         goto ERROR;
130     }
132     for (i = 0; i < device->num_buffers; i++) {
133         buf.type = reqbuf.type;
134         buf.index = i;
135         buf.memory = reqbuf.memory;
136         ret = ioctl(device->fd, VIDIOC_QUERYBUF, &buf);
137         if (ret < 0) {
138             perror("VIDIOC_QUERYCAP");
139             device->num_buffers = i;
140             goto ERROR1;
141             return -1;
142         }
144         temp_buffers[i].length = buf.length;
145         temp_buffers[i].start = (char*)mmap(NULL, buf.length,
146                      PROT_READ | PROT_WRITE,
147                      MAP_SHARED, device->fd,
148                      buf.m.offset);
149         if (temp_buffers[i].start == MAP_FAILED) {
150             printf("Cannot mmap = %d buffer\n", i);
151             device->num_buffers = i;
152             goto ERROR1;
153         }
154         printf("temp_buffers[%d].start - %x\n", i,
155                 (unsigned int)temp_buffers[i].start);
156     }
158     device->buffers = temp_buffers;
160     printf("%s: Init done successfully\n", device->name);
161     return 0;
163 ERROR1:
164     for (j = 0; j < device->num_buffers; j++)
165         munmap(temp_buffers[j].start,
166                temp_buffers[j].length);
168     free(temp_buffers);
169 ERROR:
170     close(device->fd);
172     return -1;
175 static void v4l2_exit_device(struct v4l2_device_info *device)
177     int i;
179     for (i = 0; i < device->num_buffers; i++) {
180         munmap(device->buffers[i].start,
181                device->buffers[i].length);
182     }
184     free(device->buffers);
185     close(device->fd);
187     return;
191 /*
192  * Enable streaming for V4L2 capture device
193  */
194 static int v4l2_stream_on(struct v4l2_device_info *device)
196     int a, i, ret;
198     for (i = 0; i < device->num_buffers; ++i) {
199             struct v4l2_buffer buf;
201             buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
202             buf.memory = V4L2_MEMORY_MMAP;
203             buf.index = i;
205             ret = ioctl(device->fd, VIDIOC_QBUF, &buf);
206             if (ret < 0) {
207                 perror("VIDIOC_QBUF");
208                 device->num_buffers = i;
209                 return -1;
210             }
211     }
213     device->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
214     device->buf.index = 0;
215     device->buf.memory = device->memory_mode;
217     a = V4L2_BUF_TYPE_VIDEO_CAPTURE;
218     ret = ioctl(device->fd, VIDIOC_STREAMON, &a);
219     if (ret < 0) {
220         perror("VIDIOC_STREAMON");
221         return -1;
222     }
223     printf("%s: Stream on\n", device->name);
225     return 0;
228 /*
229  * Disable streaming for V4L2 capture device
230  */
231 static int v4l2_stream_off(struct v4l2_device_info *device)
233     int a, ret;
235     a = V4L2_BUF_TYPE_VIDEO_CAPTURE;
236     ret = ioctl(device->fd, VIDIOC_STREAMOFF, &a);
237     if (ret < 0) {
238         perror("VIDIOC_STREAMOFF");
239         return -1;
240     }
241     printf("%s: Stream off\n", device->name);
243     return 0;
246 /*
247  * Queue V4L2 buffer
248  */
249 static int v4l2_queue_buffer(struct v4l2_device_info *device)
251     int ret;
252     fd_set fds;
253     struct timeval tv;
255     FD_ZERO(&fds);
256     FD_SET(device->fd, &fds);
258     /* Timeout. */
259     tv.tv_sec = 10;
260     tv.tv_usec = 0;
262     ret = select(device->fd + 1, &fds, NULL, NULL, &tv);
264     if (-1 == ret) {
265         if (EINTR == errno) {
266             perror( "select\n");
267             return -1;
268         }
269     }
271     if (0 == ret) {
272         perror( "select timeout\n");
273         return -1;
274     }
276     /* Queue buffer for the v4l2 capture device */
277     ret = ioctl(device->fd, VIDIOC_QBUF,
278             &device->buf);
279     if (ret < 0) {
280         perror("VIDIOC_QBUF");
281         return -1;
282     }
284     return 0;
287 /*
288  * DeQueue V4L2 buffer
289  */
290 static int v4l2_dequeue_buffer(struct v4l2_device_info *device)
292     int ret;
293     fd_set fds;
294     struct timeval tv;
296     FD_ZERO(&fds);
297     FD_SET(device->fd, &fds);
299     /* Timeout. */
300     tv.tv_sec = 10;
301     tv.tv_usec = 0;
303     ret = select(device->fd + 1, &fds, NULL, NULL, &tv);
305     if (-1 == ret) {
306         if (EINTR == errno) {
307             perror( "select\n");
308             return -1;
309         }
310     }
312     if (0 == ret) {
313         perror( "select timeout\n");
314         return -1;
315     }
317     /* Dequeue buffer for the v4l2 capture device */
318     ret = ioctl(device->fd, VIDIOC_DQBUF,
319             &device->buf);
320     if (ret < 0) {
321         perror("VIDIOC_DQBUF");
322         return -1;
323     }
325     return 0;
328 /*
329  * Fbdev device init
330  */
331 static int fbdev_init_device(struct fbdev_device_info *device)
333     /* Open the display device */
334     if ((device->fd = open(device->dev_name, O_RDWR)) <= 0) {
335         printf("Cannot open %s.\n", device->name);
336         exit(0);
337     }
339     /* Get fix screen information */
340     if (ioctl(device->fd, FBIOGET_FSCREENINFO, &device->fixinfo) < 0) {
341         printf("Error reading fixed information for: %s\n", device->name);
342         exit(0);
343     }
345     /* Get variable screen information */
346     if (ioctl(device->fd, FBIOGET_VSCREENINFO, &device->varinfo) < 0) {
347         printf("Error reading variable information for: %s\n", device->name);
348         exit(0);
349     }
351     if (ioctl(device->fd, OMAPFB_GET_DISPLAY_INFO, &device->di)) {
352         printf("OMAPFB_GET_DISPLAY_INFO error for: %s\n", device->name);
353         exit(0);
354     }
356     /* Now the memory for the fb device needs to be set up */
358     if (ioctl(device->fd, OMAPFB_QUERY_PLANE, &device->pi)) {
359         printf("OMAPFB_QUERY_PLANE error for: %s\n", device->name);
360         exit(0);
361     }
363     if (device->pi.enabled) {
364         device->pi.enabled = 0;
365         if (ioctl(device->fd, OMAPFB_SETUP_PLANE, &device->pi)) {
366             printf("OMAPFB_SETUP_PLANE error for: %s\n", device->name);
367             exit(0);
368         }
369     }
371     printf("\nDisplay Screen Properties:\n");
372     printf("%s bpp: %d\n",device->name, device->varinfo.bits_per_pixel);
373     printf("%s di resolution: %dx%d\n",device->name,
374            device->di.xres, device->di.yres);
376     /* Store display resolution so GUI can be configured */
377     status.display_xres = device->di.xres;
378     status.display_yres = device->di.yres;
380     if (device->di.xres < 640) {
381         device->width = 640;
382         device->height = 480;
383     }
385     /* Set the input resolution of the video framebuffer to be the size
386      * of the camera image.  Later, the output size will be matched to
387      * the display to allow for up/down scaling */
388     device->varinfo.xres = device->width;
389     device->varinfo.yres = device->height;
390     device->varinfo.xres_virtual = device->width;
391     device->varinfo.yres_virtual = 2 * device->height;
393     device->varinfo.bits_per_pixel = 16;
394     device->varinfo.nonstd = OMAPFB_COLOR_YUY422;
396     if (ioctl(device->fd, OMAPFB_QUERY_MEM, &device->mi)) {
397         printf("OMAPFB_QUERY_PLANE error for: %s\n", device->name);
398         exit(0);
399     }
401     device->mi.size = device->varinfo.xres_virtual * device->varinfo.yres_virtual *
402             device->varinfo.bits_per_pixel / 8;
404     if (ioctl(device->fd, OMAPFB_SETUP_MEM, &device->mi)) {
405         printf("OMAPFB_QUERY_PLANE error for: %s\n", device->name);
406         exit(0);
407     }
409     if (ioctl(device->fd, FBIOPUT_VSCREENINFO, &device->varinfo) < 0) {
410         printf("Error setting variable information for: %s\n", device->name);
411         exit(0);
412     }
414     device->pi.pos_x = 0;
415     device->pi.pos_y = 0;
416     /* Set the the display plane output size to the detected resolution
417      * of the lcd/monitor.  This will cause the 800x600 camera image to
418      * be up/downscaled to fit the screen */
419     device->pi.out_width = device->di.xres;
420     device->pi.out_height = device->di.yres;
421     device->pi.enabled = 1;
423     /* Get device capabilities */
424     ioctl(device->fd,OMAPFB_GET_CAPS, &device->caps);
426     printf("Checking for manual update capability...\n");
427     if (device->caps.ctrl & OMAPFB_CAPS_MANUAL_UPDATE)
428             printf("Manual update supported\n");
430     ioctl(device->fd,OMAPFB_GET_UPDATE_MODE, &device->update_mode);
431     printf("OMAPFB_GET_UPDATE_MODE: %d\n", device->update_mode);
433     if (ioctl(device->fd, OMAPFB_SETUP_PLANE, &device->pi)) {
434         printf("OMAPFB_SETUP_PLANE error for: %s\n", device->name);
435         exit(0);
436     }
438     /* Get fix screen information */
439     if (ioctl(device->fd, FBIOGET_FSCREENINFO, &device->fixinfo) < 0) {
440         printf("Error reading fixed information for: %s\n", device->name);
441         exit(0);
442     }
444     /* Get variable screen information */
445     if (ioctl(device->fd, FBIOGET_VSCREENINFO, &device->varinfo) < 0) {
446         printf("Error reading variable information for: %s\n", device->name);
447         exit(0);
448     }
450     printf("Camera Display Overlay Properties:\n");
451     printf("resolution %dx%d virtual %dx%d, line_len %d\n",
452                 device->varinfo.xres, device->varinfo.yres,
453                 device->varinfo.xres_virtual, device->varinfo.yres_virtual,
454                 device->fixinfo.line_length);
456     /* Mmap the driver buffers in application space so that application
457      * can write on to them.  Buffers need to be 2x for double buffering
458      * to eliminate tearing
459      */
460     device->buf_length = device->fixinfo.line_length * device->varinfo.yres_virtual;
461     device->buf_start = (char *)mmap (0, device->buf_length,
462             (PROT_READ|PROT_WRITE), MAP_SHARED, device->fd, 0);
463     device->buf_start2 = device->buf_start + device->buf_length/2;
465     printf("1st buffer addr: %x\n", (unsigned int)device->buf_start);
466     printf("2nd buffer addr: %x\n", (unsigned int)device->buf_start2);
468     if (device->buf_start == MAP_FAILED) {
469         printf("MMap failed for %s\n", device->name);
470         exit(0);
471     }
473     return 0;
476 static void fbdev_exit_device(struct fbdev_device_info *device)
478     /* Clear framebuffer of data */
479     memset(device->buf_start, 0, device->buf_length);
481     device->pi.enabled = 0;
482     if (ioctl(device->fd, OMAPFB_SETUP_PLANE, &device->pi)) {
483         printf("OMAPFB_SETUP_PLANE error for: %s\n", device->name);
484     }
486     munmap(device->buf_start, device->buf_length);
487     close(device->fd);
489     return;
492 /*
493  * Set up the DSS for blending of video and graphics planes
494  */
495 static int fbdev_init_dss(void)
497     FILE *f;
499     /* Set manager for alphablending */
500     f = fopen("/sys/devices/platform/omapdss/manager0/alpha_blending_enabled", "w");
501     fprintf(f,"%d", 1);
502     fclose(f);
504     f = fopen("/sys/devices/platform/omapdss/manager0/trans_key_enabled", "w");
505     fprintf(f,"%d", 1);
506     fclose(f);
508     /* Set scalar for PiP video plane to 1/3 of main video plane */
509     fb2_device.pi.enabled = 0;
510     fb2_device.pi.out_width = fb1_device.pi.out_width/3;
511     fb2_device.pi.out_height = fb1_device.pi.out_height/3;
512     fb2_device.pi.pos_x = 25;
513     fb2_device.pi.pos_y = 25;
514     fb2_device.pi.enabled = 1;
516     if (ioctl(fb2_device.fd, OMAPFB_SETUP_PLANE, &fb2_device.pi)) {
517         printf("OMAPFB_SETUP_PLANE error for: %s\n", fb2_device.name);
518         return -1;
519     }
521     return 0;
524 /*
525  * Fbdev enable pip layer
526  */
527 int fbdev_enable_pip(void)
529     fb2_device.pi.enabled = 1;
530     if (ioctl(fb2_device.fd, OMAPFB_SETUP_PLANE, &fb2_device.pi)) {
531         printf("OMAPFB_SETUP_PLANE error for: %s\n", fb2_device.name);
532         return -1;
533     }
535     return 0;
538 /*
539  * Fbdev disable pip layer
540  */
541 int fbdev_disable_pip(void)
543     fb2_device.pi.enabled = 0;
544     if (ioctl(fb2_device.fd, OMAPFB_SETUP_PLANE, &fb2_device.pi)) {
545         printf("OMAPFB_SETUP_PLANE error for: %s\n", fb2_device.name);
546         return -1;
547     }
549     return 0;
552 /*
553  * Display v4l2 frame on fbdev device
554  */
555 static int display_frame(struct v4l2_device_info *v4l2_device, struct fbdev_device_info *fbdev_device)
557     int fb_size = fbdev_device->fixinfo.line_length*fbdev_device->varinfo.yres;
559     /* Request a capture buffer from the driver that can be copied to framebuffer */
560     v4l2_dequeue_buffer(v4l2_device);
562     /* Copy the new camera frame into the buffer that is not currently displayed */
563     if (fbdev_device->buf_current == 0)
564     {
565         /* Copy the contents of the v4l2 capture buffer to framebuffer */
566         memcpy(fbdev_device->buf_start2,
567         v4l2_device->buffers[v4l2_device->buf.index].start,
568         fb_size);
570         /* After the buffer copy is complete, tell the DSS to display the new data */
571         fbdev_device->varinfo.yoffset = 600;
572         ioctl(fbdev_device->fd,FBIOPAN_DISPLAY, fbdev_device->varinfo);
573         if (ioctl(fbdev_device->fd, FBIOPUT_VSCREENINFO, &fbdev_device->varinfo) < 0) {
574             printf("Error setting variable information for: %s\n", fbdev_device->name);
575             exit(0);
576         }
577         fbdev_device->buf_current=1;
578     }
579     else {
580         /* Copy the contents of the v4l2 capture buffer to framebuffer */
581         memcpy(fbdev_device->buf_start,
582         v4l2_device->buffers[v4l2_device->buf.index].start,
583         fb_size);
585         /* After the buffer copy is complete, tell the DSS to display the new data */
586         fbdev_device->varinfo.yoffset = 0;
587         ioctl(fbdev_device->fd,FBIOPAN_DISPLAY, fbdev_device->varinfo);
588         if (ioctl(fbdev_device->fd, FBIOPUT_VSCREENINFO, &fbdev_device->varinfo) < 0) {
589             printf("Error setting variable information for: %s\n", fbdev_device->name);
590             exit(0);
591         }
592         fbdev_device->buf_current=0;
593     }
596     /* Give the buffer back to the driver so it can be filled again */
597     v4l2_queue_buffer(v4l2_device);
599     return 0;
602 /*
603  * Capture v4l2 frame and save to jpeg
604  */
605 static int capture_frame(struct v4l2_device_info *v4l2_device)
607     /* Request a capture buffer from the driver that can be copied to framebuffer */
608     v4l2_dequeue_buffer(v4l2_device);
610     jpegWrite((unsigned char *)v4l2_device->buffers[cap0_device.buf.index].start,
611             status.num_jpeg, v4l2_device->width, v4l2_device->height);
613     /* Give the buffer back to the driver so it can be filled again */
614     v4l2_queue_buffer(v4l2_device);
616     return 0;
619 void default_parameters(void)
621     /* Main camera display */
622     strcpy(fb1_device.dev_name,"/dev/fb1");
623     strcpy(fb1_device.name,"fb1");
624     fb1_device.width=800;
625     fb1_device.height=600;
626     fb1_device.buf_current=0;
628     /* PiP camera display */
629     strcpy(fb2_device.dev_name,"/dev/fb2");
630     strcpy(fb2_device.name,"fb2");
631     fb2_device.width=800;
632     fb2_device.height=600;
633     fb2_device.buf_current=0;
635     /* Main camera */
636     cap0_device.memory_mode = V4L2_MEMORY_MMAP;
637     cap0_device.num_buffers = 3;
638     strcpy(cap0_device.dev_name,"/dev/video0");
639     strcpy(cap0_device.name,"Capture 0");
640     cap0_device.buffers = NULL;
641     cap0_device.fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
642     cap0_device.width = 800;
643     cap0_device.height = 600;
645     /* PiP camera */
646     cap1_device.memory_mode = V4L2_MEMORY_MMAP;
647     cap1_device.num_buffers = 3;
648     strcpy(cap1_device.dev_name,"/dev/video1");
649     strcpy(cap1_device.name,"Capture 1");
650     cap1_device.buffers = NULL;
651     cap1_device.fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
652     cap1_device.width = 800;
653     cap1_device.height = 600;
655     /* Set the default parameters for device options */
656     status.main_cam=0;
657     status.num_cams=2;
658     status.num_jpeg=0;
659     status.pip=true;
660     status.jpeg=false;
661     status.exit=false;
663     /* Ensure that jpeg image save directory exists */
664     mkdir("/usr/share/camera-images/", 0777);
666     return;
669 void exit_devices(void)
671     fbdev_exit_device(&fb1_device);
672     fbdev_exit_device(&fb2_device);
674     v4l2_exit_device(&cap0_device);
675     if (status.num_cams==2) {
676         v4l2_exit_device(&cap1_device);
677     }
680 void end_streaming(void)
682     v4l2_stream_off(&cap0_device);
684     if (status.num_cams==2) {
685        v4l2_stream_off(&cap1_device);
686     }
689 /*
690  * Initializes all fbdev and v4l2 devices for loopback
691  */
692 int init_loopback(void)
694     /* Declare properties for video and capture devices */
695     default_parameters();
697     /* Initialize the fbdev display devices */
698     if (fbdev_init_device(&fb1_device)) goto Error;
699     if (fbdev_init_device(&fb2_device)) goto Error;
701     /* Check to see if the display resolution is very small.  If so, the
702      * camera capture resolution needs to be lowered so that the scaling
703      * limits of the DSS are not reached */
704     if (fb1_device.di.xres < 640) {
705         /* Set capture 0 device resolution */
706         cap0_device.width = 640;
707         cap0_device.height = 480;
709         /* Set capture 1 device resolution */
710         cap1_device.width = 640;
711         cap1_device.height = 480;
712     }
714     /* Initialize the v4l2 capture devices */
715     if (v4l2_init_device(&cap0_device) < 0) goto Error;
716     if (v4l2_init_device(&cap1_device) < 0) {
717         /* If there is not a second camera, program can still continue */
718         status.num_cams=1;
719         status.pip=false;
720         printf("Only one camera detected\n");
721     }
723     /* Enable streaming for the v4l2 capture devices */
724     if (v4l2_stream_on(&cap0_device) < 0) goto Error;
725     if (status.num_cams==2) {
726         if (v4l2_stream_on(&cap1_device) < 0) goto Error;
727     }
729     /* Configure the DSS to blend video and graphics layers */
730     if (fbdev_init_dss() < 0 ) goto Error;
732     if (status.pip==false)
733         fbdev_disable_pip();
734     else
735         fbdev_enable_pip();
737     return 0;
739 Error:
740     exit_devices();
741     status.exit = true;
742     return -1;
745 /*
746  * Determines which camera feeds are being displayed and
747  * whether a jpeg image needs to be captured.
748  */
749 void process_frame(void) {
751     /* Display the main camera */
752     if (status.main_cam==0)
753         display_frame(&cap0_device, &fb1_device);
754     else
755         display_frame(&cap1_device, &fb1_device);
757     /* Display PiP if enabled */
758     if (status.pip==true) {
759         if (status.main_cam==0)
760             display_frame(&cap1_device, &fb2_device);
761         else
762             display_frame(&cap0_device, &fb2_device);
763     }
765     /* Save jpeg image if triggered */
766     if (status.jpeg==true) {
767         if (status.main_cam==0) {
768             capture_frame(&cap0_device);
769         }
770         else {
771             capture_frame(&cap1_device);
772         }
774         status.jpeg=false;
775         status.num_jpeg++;
776         if (status.num_jpeg==10)
777             status.num_jpeg=0;
778     }