00001
00002
00003
00004
00005
00006
00007 #include <stdio.h>
00008
00009 #include "capture.h"
00010
00011 int RGB_Y_tab[256];
00012 int B_U_tab[256];
00013 int G_U_tab[256];
00014 int G_V_tab[256];
00015 int R_V_tab[256];
00016 const int BITS_OUT = 16;
00017 char* dev_name = "/dev/video0";
00018 io_method io = IO_METHOD_MMAP;
00019
00020 int fd = -1;
00021 buffer* buffers = NULL;
00022 unsigned int n_buffers = 0;
00023
00024 int width = 320, height = 240;
00025 frame* currentFrame = NULL;
00026
00027 void errno_exit(const char *s)
00028 {
00029 printf ("%s error %d, %s\n",
00030 s, errno, strerror (errno));
00031 exit (0);
00032 }
00033
00034 int xioctl(int fd, int request, void *arg)
00035 {
00036 int r;
00037
00038 do r = ioctl (fd, request, arg);
00039 while (-1 == r && EINTR == errno);
00040
00041 return r;
00042 }
00043
00044 void colorspace_init()
00045 {
00046 const int VIDEOYUV_Y_OFFSET = 16;
00047 const int VIDEOYUV_Y_RANGE = 219;
00048 const int VIDEOYUV_UV_OFFSET = 128;
00049 const int VIDEOYUV_UV_RANGE = 224;
00050
00051 const double JPEGYUV_RGB_Y = 1.0;
00052 const double JPEGYUV_R_V = 1.402;
00053 const double JPEGYUV_G_U = -0.34414;
00054 const double JPEGYUV_G_V = -0.71414;
00055 const double JPEGYUV_B_U = 1.772;
00056
00057 const double VIDEOYUV_RGB_Y = JPEGYUV_RGB_Y * (255.0/VIDEOYUV_Y_RANGE);
00058 const double VIDEOYUV_R_V = JPEGYUV_R_V * (255.0/VIDEOYUV_UV_RANGE);
00059 const double VIDEOYUV_G_U = JPEGYUV_G_U * (255.0/VIDEOYUV_UV_RANGE);
00060 const double VIDEOYUV_G_V = JPEGYUV_G_V * (255.0/VIDEOYUV_UV_RANGE);
00061 const double VIDEOYUV_B_U = JPEGYUV_B_U * (255.0/VIDEOYUV_UV_RANGE);
00062
00063
00064
00065 const int half =
00066 BITS_OUT > 0
00067 ? 1<<(BITS_OUT-1)
00068 : 0;
00069
00070 const int scale = 1<<BITS_OUT;
00071
00072 int i;
00073 for (i = 0; i < 256; i++)
00074 {
00075 const int y = i-VIDEOYUV_Y_OFFSET;
00076 const int uv = i-VIDEOYUV_UV_OFFSET;
00077
00078 RGB_Y_tab[i] = half+(int)(0.5 + y * VIDEOYUV_RGB_Y * scale);
00079 R_V_tab[i] = (int)(0.5 + uv * VIDEOYUV_R_V * scale);
00080
00081
00082 G_U_tab[i] = (int)(0.5 - uv * VIDEOYUV_G_U * scale);
00083 G_V_tab[i] = (int)(0.5 - uv * VIDEOYUV_G_V * scale);
00084 B_U_tab[i] = (int)(0.5 + uv * VIDEOYUV_B_U * scale);
00085 }
00086 }
00087
00088
00089 void yuv422_to_rgb24_c(unsigned char* dst,
00090 const int w, const int h,
00091 const unsigned char* yuv422ptr,
00092 const int byteswap)
00093 {
00094 int i, j;
00095 if (byteswap)
00096 for (j = 0; j < h; ++j)
00097 for (i = 0; i < w; i += 2)
00098 {
00099
00100
00101 const unsigned char y1 = yuv422ptr[0];
00102 const unsigned char u = yuv422ptr[1];
00103 const unsigned char y2 = yuv422ptr[2];
00104 const unsigned char v = yuv422ptr[3];
00105
00106 yuv422ptr += 4;
00107
00108 const int r_v = R_V_tab[v];
00109 const int g_uv = - G_U_tab[u] - G_V_tab[v];
00110 const int b_u = B_U_tab[u];
00111
00112
00113 const int rgb_y1 = RGB_Y_tab[y1];
00114
00115 *dst++ = (rgb_y1 + r_v) >> BITS_OUT;
00116 *dst++ = (rgb_y1 + g_uv) >> BITS_OUT;
00117 *dst++ = (rgb_y1 + b_u) >> BITS_OUT;
00118
00119
00120 const int rgb_y2 = RGB_Y_tab[y2];
00121
00122 *dst++ = (rgb_y2 + r_v) >> BITS_OUT;
00123 *dst++ = (rgb_y2 + g_uv) >> BITS_OUT;
00124 *dst++ = (rgb_y2 + b_u) >> BITS_OUT;
00125 }
00126
00127 else
00128 for ( j = 0; j < h; ++j)
00129 for ( i = 0; i < w; i += 2)
00130 {
00131
00132
00133 const unsigned char y1 = yuv422ptr[1];
00134 const unsigned char u = yuv422ptr[0];
00135 const unsigned char y2 = yuv422ptr[3];
00136 const unsigned char v = yuv422ptr[2];
00137
00138 yuv422ptr += 4;
00139
00140 const int r_v = R_V_tab[v];
00141 const int g_uv = - G_U_tab[u] - G_V_tab[v];
00142 const int b_u = B_U_tab[u];
00143
00144
00145 const int rgb_y1 = RGB_Y_tab[y1];
00146
00147 *dst++ = (rgb_y1 + r_v) >> BITS_OUT;
00148 *dst++ = (rgb_y1 + g_uv) >> BITS_OUT;
00149 *dst++ = (rgb_y1 + b_u) >> BITS_OUT;
00150
00151
00152 const int rgb_y2 = RGB_Y_tab[y2];
00153
00154 *dst++ = (rgb_y2 + r_v) >> BITS_OUT;
00155 *dst++ = (rgb_y2 + g_uv) >> BITS_OUT;
00156 *dst++ = (rgb_y2 + b_u) >> BITS_OUT;
00157 }
00158 }
00159
00160 unsigned char clamp(int d)
00161 {
00162 int r = d;
00163 if (r > 255) r = 255;
00164 if (r < 0) r = 0;
00165
00166 return r;
00167 }
00168
00169 void yv12_to_rgb24_c(unsigned char* dst,
00170 int dst_stride,
00171 const unsigned char* y_src,
00172 const unsigned char* u_src,
00173 const unsigned char* v_src,
00174 int y_stride,
00175 int uv_stride,
00176 int width,
00177 int height)
00178 {
00179
00180 if (width & 1)
00181 printf("width must be even\n");
00182
00183 if (height & 1)
00184 printf("height must be even\n");
00185
00186 const int dst_dif = 6 * dst_stride - 3 * width;
00187 int y_dif = 2 * y_stride - width;
00188
00189 unsigned char* dst2 = dst + 3 * dst_stride;
00190 const unsigned char* y_src2 = y_src + y_stride;
00191
00192 if (height < 0) {
00193 height = -height;
00194 y_src += (height - 1) * y_stride;
00195 y_src2 = y_src - y_stride;
00196 u_src += (height / 2 - 1) * uv_stride;
00197 v_src += (height / 2 - 1) * uv_stride;
00198 y_dif = -width - 2 * y_stride;
00199 uv_stride = -uv_stride;
00200 }
00201
00202 int x,y;
00203 for (y = height / 2; y; y--) {
00204 for (x = 0; x < width / 2; x++) {
00205 const int u = u_src[x];
00206 const int v = v_src[x];
00207
00208 const int r_v = R_V_tab[v];
00209 const int g_uv = - G_U_tab[u] - G_V_tab[v];
00210 const int b_u = B_U_tab[u];
00211
00212 {
00213 const int rgb_y = RGB_Y_tab[*y_src];
00214 const int r = (rgb_y + r_v) >> BITS_OUT;
00215 const int g = (rgb_y + g_uv) >> BITS_OUT;
00216 const int b = (rgb_y + b_u) >> BITS_OUT;
00217 dst[0] = clamp(r);
00218 dst[1] = clamp(g);
00219 dst[2] = clamp(b);
00220 y_src++;
00221 }
00222 {
00223 const int rgb_y = RGB_Y_tab[*y_src];
00224 const int r = (rgb_y + r_v) >> BITS_OUT;
00225 const int g = (rgb_y + g_uv) >> BITS_OUT;
00226 const int b = (rgb_y + b_u) >> BITS_OUT;
00227 dst[3] = clamp(r);
00228 dst[4] = clamp(g);
00229 dst[5] = clamp(b);
00230 y_src++;
00231 }
00232 {
00233 const int rgb_y = RGB_Y_tab[*y_src2];
00234 const int r = (rgb_y + r_v) >> BITS_OUT;
00235 const int g = (rgb_y + g_uv) >> BITS_OUT;
00236 const int b = (rgb_y + b_u) >> BITS_OUT;
00237 dst2[0] = clamp(r);
00238 dst2[1] = clamp(g);
00239 dst2[2] = clamp(b);
00240 y_src2++;
00241 }
00242 {
00243 const int rgb_y = RGB_Y_tab[*y_src2];
00244 const int r = (rgb_y + r_v) >> BITS_OUT;
00245 const int g = (rgb_y + g_uv) >> BITS_OUT;
00246 const int b = (rgb_y + b_u) >> BITS_OUT;
00247 dst2[3] = clamp(r);
00248 dst2[4] = clamp(g);
00249 dst2[5] = clamp(b);
00250 y_src2++;
00251 }
00252
00253 dst += 6;
00254 dst2 += 6;
00255 }
00256
00257 dst += dst_dif;
00258 dst2 += dst_dif;
00259
00260 y_src += y_dif;
00261 y_src2 += y_dif;
00262
00263 u_src += uv_stride;
00264 v_src += uv_stride;
00265 }
00266 }
00267
00268 frame* process_image(const void *p, const int len)
00269 {
00270
00271 const int w2 = (width+1)/2;
00272 const int h2 = (height+1)/2;
00273
00274 yv12_to_rgb24_c(currentFrame->data,
00275 width,
00276 (const unsigned char*)p,
00277 (const unsigned char*)p + width*height,
00278 (const unsigned char*)p + width*height + w2*h2,
00279 width,
00280 w2,
00281 width,
00282 height);
00283
00284 return currentFrame;
00285 }
00286
00287 int read_frame(void)
00288 {
00289 struct v4l2_buffer buf;
00290 unsigned int i;
00291
00292 switch (io) {
00293 case IO_METHOD_READ:
00294 if (-1 == (i = read (fd, buffers[0].start, buffers[0].length))) {
00295 switch (errno) {
00296 case EAGAIN:
00297 return 0;
00298
00299 case EIO:
00300
00301
00302
00303
00304 default:
00305 errno_exit ("read");
00306 }
00307 }
00308
00309 process_image (buffers[0].start, buffers[0].length);
00310
00311 break;
00312
00313 case IO_METHOD_MMAP:
00314 CLEAR (buf);
00315
00316 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00317 buf.memory = V4L2_MEMORY_MMAP;
00318
00319
00320 if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) {
00321 switch (errno) {
00322 case EAGAIN:
00323 return 0;
00324
00325 case EIO:
00326
00327
00328
00329
00330 default:
00331 errno_exit ("VIDIOC_DQBUF");
00332 }
00333 }
00334
00335 assert (buf.index < n_buffers);
00336
00337 process_image (buffers[buf.index].start,buffers[buf.index].length );
00338
00339
00340 if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
00341 errno_exit ("VIDIOC_QBUF");
00342
00343 break;
00344
00345 case IO_METHOD_USERPTR:
00346 CLEAR (buf);
00347
00348 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00349 buf.memory = V4L2_MEMORY_USERPTR;
00350
00351 if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) {
00352 switch (errno) {
00353 case EAGAIN:
00354 return 0;
00355
00356 case EIO:
00357
00358
00359
00360
00361 default:
00362 errno_exit ("VIDIOC_DQBUF");
00363 }
00364 }
00365
00366 for (i = 0; i < n_buffers; ++i)
00367 if (buf.m.userptr == (unsigned long) buffers[i].start
00368 && buf.length == buffers[i].length)
00369 break;
00370
00371 assert (i < n_buffers);
00372
00373 process_image ((void *) buf.m.userptr, 0);
00374
00375 if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
00376 errno_exit ("VIDIOC_QBUF");
00377
00378 break;
00379 }
00380
00381 return 1;
00382 }
00383
00384 frame* get_frame(void)
00385 {
00386 struct v4l2_buffer buf;
00387 unsigned int i;
00388
00389 switch (io) {
00390 case IO_METHOD_READ:
00391 if (-1 == (i = read (fd, buffers[0].start, buffers[0].length))) {
00392 switch (errno) {
00393 case EAGAIN:
00394 return 0;
00395
00396 case EIO:
00397
00398
00399
00400
00401 default:
00402 errno_exit ("read");
00403 }
00404 }
00405
00406 return process_image (buffers[0].start, buffers[0].length);
00407
00408 break;
00409
00410 case IO_METHOD_MMAP:
00411 CLEAR (buf);
00412
00413 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00414 buf.memory = V4L2_MEMORY_MMAP;
00415
00416
00417 if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) {
00418 switch (errno) {
00419 case EAGAIN:
00420 return 0;
00421
00422 case EIO:
00423
00424 return 0;
00425
00426
00427
00428 default:
00429 errno_exit ("VIDIOC_DQBUF error");
00430 }
00431 }
00432
00433 assert (buf.index < n_buffers);
00434
00435 return process_image (buffers[buf.index].start,buffers[buf.index].length );
00436
00437
00438 if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
00439 errno_exit ("VIDIOC_QBUF");
00440
00441 break;
00442
00443 case IO_METHOD_USERPTR:
00444 CLEAR (buf);
00445
00446 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00447 buf.memory = V4L2_MEMORY_USERPTR;
00448
00449 if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) {
00450 switch (errno) {
00451 case EAGAIN:
00452 return 0;
00453
00454 case EIO:
00455
00456
00457
00458
00459 default:
00460 errno_exit ("VIDIOC_DQBUF");
00461 }
00462 }
00463
00464 for (i = 0; i < n_buffers; ++i)
00465 if (buf.m.userptr == (unsigned long) buffers[i].start
00466 && buf.length == buffers[i].length)
00467 break;
00468
00469 assert (i < n_buffers);
00470
00471 return process_image ((void *) buf.m.userptr, 0);
00472
00473 if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
00474 errno_exit ("VIDIOC_QBUF");
00475
00476 break;
00477 }
00478
00479 return NULL;
00480 }
00481 void mainloop(void)
00482 {
00483 unsigned int count;
00484
00485 count = 100;
00486
00487 while (count-- > 0) {
00488 for (;;) {
00489 fd_set fds;
00490 struct timeval tv;
00491 int r;
00492
00493 FD_ZERO (&fds);
00494 FD_SET (fd, &fds);
00495
00496
00497 tv.tv_sec = 2;
00498 tv.tv_usec = 0;
00499
00500 r = select (fd + 1, &fds, NULL, NULL, &tv);
00501
00502 if (-1 == r) {
00503 if (EINTR == errno)
00504 continue;
00505
00506 errno_exit ("select");
00507 }
00508
00509 if (0 == r) {
00510 fprintf (stderr, "select timeout\n");
00511 exit (EXIT_FAILURE);
00512 }
00513
00514 if (read_frame ())
00515 break;
00516
00517
00518 }
00519 }
00520 }
00521
00522 void stop_capturing(void)
00523 {
00524 enum v4l2_buf_type type;
00525
00526 switch (io) {
00527 case IO_METHOD_READ:
00528
00529 break;
00530
00531 case IO_METHOD_MMAP:
00532 case IO_METHOD_USERPTR:
00533 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00534
00535 if (-1 == xioctl (fd, VIDIOC_STREAMOFF, &type))
00536 errno_exit ("VIDIOC_STREAMOFF");
00537
00538 break;
00539 }
00540 }
00541
00542 void start_capturing(void)
00543 {
00544 unsigned int i;
00545 enum v4l2_buf_type type;
00546
00547 currentFrame = new frame;
00548 currentFrame->data = new unsigned char[width*height*3];
00549 currentFrame->width = width;
00550 currentFrame->height = height;
00551 currentFrame->pixType=0;
00552
00553
00554 switch (io) {
00555 case IO_METHOD_READ:
00556
00557 break;
00558
00559 case IO_METHOD_MMAP:
00560 for (i = 0; i < n_buffers; ++i) {
00561 struct v4l2_buffer buf;
00562
00563 CLEAR (buf);
00564
00565 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00566 buf.memory = V4L2_MEMORY_MMAP;
00567 buf.index = i;
00568
00569 if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
00570 errno_exit ("VIDIOC_QBUF");
00571 }
00572
00573 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00574
00575 if (-1 == xioctl (fd, VIDIOC_STREAMON, &type))
00576 errno_exit ("VIDIOC_STREAMON");
00577
00578 break;
00579
00580 case IO_METHOD_USERPTR:
00581 for (i = 0; i < n_buffers; ++i) {
00582 struct v4l2_buffer buf;
00583
00584 CLEAR (buf);
00585
00586 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00587 buf.memory = V4L2_MEMORY_USERPTR;
00588 buf.index = i;
00589 buf.m.userptr = (unsigned long) buffers[i].start;
00590 buf.length = buffers[i].length;
00591
00592 if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
00593 errno_exit ("VIDIOC_QBUF");
00594 }
00595
00596 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00597
00598 if (-1 == xioctl (fd, VIDIOC_STREAMON, &type))
00599 errno_exit ("VIDIOC_STREAMON");
00600
00601 break;
00602 }
00603 }
00604
00605 void uninit_device(void)
00606 {
00607 unsigned int i;
00608
00609 switch (io) {
00610 case IO_METHOD_READ:
00611 free (buffers[0].start);
00612 break;
00613
00614 case IO_METHOD_MMAP:
00615 for (i = 0; i < n_buffers; ++i)
00616 if (-1 == munmap (buffers[i].start, buffers[i].length))
00617 errno_exit ("munmap");
00618 break;
00619
00620 case IO_METHOD_USERPTR:
00621 for (i = 0; i < n_buffers; ++i)
00622 free (buffers[i].start);
00623 break;
00624 }
00625
00626 if (currentFrame != NULL)
00627 if (currentFrame->data != NULL)
00628 free(currentFrame->data);
00629 free(currentFrame);
00630
00631 free (buffers);
00632 }
00633
00634 void init_read(unsigned int buffer_size)
00635 {
00636 buffers = (struct buffer*)calloc (1, sizeof (*buffers));
00637
00638 if (!buffers) {
00639 fprintf (stderr, "Out of memory\n");
00640 exit (EXIT_FAILURE);
00641 }
00642
00643 buffers[0].length = buffer_size;
00644 buffers[0].start = malloc (buffer_size);
00645
00646 if (!buffers[0].start) {
00647 fprintf (stderr, "Out of memory\n");
00648 exit (EXIT_FAILURE);
00649 }
00650 }
00651
00652 void init_mmap(void)
00653 {
00654 struct v4l2_requestbuffers req;
00655
00656 CLEAR (req);
00657
00658 req.count = 1;
00659 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00660 req.memory = V4L2_MEMORY_MMAP;
00661
00662 if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req)) {
00663 if (EINVAL == errno) {
00664 fprintf (stderr, "%s does not support "
00665 "memory mapping\n", dev_name);
00666 exit (EXIT_FAILURE);
00667 } else {
00668 errno_exit ("VIDIOC_REQBUFS");
00669 }
00670 }
00671
00672 if (req.count < 2) {
00673 fprintf (stderr, "Insufficient buffer memory on %s\n",
00674 dev_name);
00675 exit (EXIT_FAILURE);
00676 }
00677
00678 buffers = (struct buffer*)calloc (req.count, sizeof (*buffers));
00679
00680 if (!buffers) {
00681 fprintf (stderr, "Out of memory\n");
00682 exit (EXIT_FAILURE);
00683 }
00684
00685 for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
00686 struct v4l2_buffer buf;
00687
00688 CLEAR (buf);
00689
00690 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00691 buf.memory = V4L2_MEMORY_MMAP;
00692 buf.index = n_buffers;
00693
00694 if (-1 == xioctl (fd, VIDIOC_QUERYBUF, &buf))
00695 errno_exit ("VIDIOC_QUERYBUF");
00696
00697 buffers[n_buffers].length = buf.length;
00698 buffers[n_buffers].start =
00699 mmap (NULL ,
00700 buf.length,
00701 PROT_READ | PROT_WRITE ,
00702 MAP_SHARED ,
00703 fd, buf.m.offset);
00704
00705 if (MAP_FAILED == buffers[n_buffers].start)
00706 errno_exit ("mmap");
00707 }
00708 }
00709
00710 void init_userp(unsigned int buffer_size)
00711 {
00712 struct v4l2_requestbuffers req;
00713
00714 CLEAR (req);
00715
00716 req.count = 4;
00717 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00718 req.memory = V4L2_MEMORY_USERPTR;
00719
00720 if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req)) {
00721 if (EINVAL == errno) {
00722 fprintf (stderr, "%s does not support "
00723 "user pointer i/o\n", dev_name);
00724 exit (EXIT_FAILURE);
00725 } else {
00726 errno_exit ("VIDIOC_REQBUFS");
00727 }
00728 }
00729
00730 buffers = (struct buffer*)calloc (4, sizeof (*buffers));
00731
00732 if (!buffers) {
00733 fprintf (stderr, "Out of memory\n");
00734 exit (EXIT_FAILURE);
00735 }
00736
00737 for (n_buffers = 0; n_buffers < 4; ++n_buffers) {
00738 buffers[n_buffers].length = buffer_size;
00739 buffers[n_buffers].start = malloc (buffer_size);
00740
00741 if (!buffers[n_buffers].start) {
00742 fprintf (stderr, "Out of memory\n");
00743 exit (EXIT_FAILURE);
00744 }
00745 }
00746 }
00747
00748 void init_device(int pix_fmt)
00749 {
00750 struct v4l2_capability cap;
00751 struct v4l2_cropcap cropcap;
00752 struct v4l2_crop crop;
00753 struct v4l2_format fmt;
00754 unsigned int min;
00755
00756 colorspace_init();
00757
00758 printf("Settting to pixformat %i\n", pix_fmt);
00759 if (-1 == xioctl (fd, VIDIOC_QUERYCAP, &cap)) {
00760 if (EINVAL == errno) {
00761 fprintf (stderr, "%s is no V4L2 device\n",
00762 dev_name);
00763 exit (EXIT_FAILURE);
00764 } else {
00765 errno_exit ("VIDIOC_QUERYCAP");
00766 }
00767 }
00768
00769 printf("V4L2 kernel driver: %s\n", cap.driver);
00770 printf("FrameGrabber board name is: %s\n", cap.card);
00771 printf("FrameGrabber board bus info: %s\n", cap.bus_info);
00772 if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)
00773 printf(" > Supports video capture\n");
00774 else printf("Not a video capture device.\n");
00775 if (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)
00776 printf(" > Supports video output\n");
00777 if (cap.capabilities & V4L2_CAP_VIDEO_OVERLAY)
00778 printf(" > Supports video overlay\n");
00779 if (cap.capabilities & V4L2_CAP_VBI_CAPTURE)
00780 printf(" > Supports raw VBI capture\n");
00781 if (cap.capabilities & V4L2_CAP_VBI_OUTPUT)
00782 printf(" > Supports raw VBI output\n");
00783
00784
00785 #ifdef V4L2_CAP_SLICED_VBI_CAPTURE
00786 if (cap.capabilities & V4L2_CAP_SLICED_VBI_CAPTURE)
00787 printf(" > Supports sliced VBI capture\n");
00788 #endif
00789 #ifdef V4L2_CAP_SLICED_VBI_OUTPUT
00790 if (cap.capabilities & V4L2_CAP_SLICED_VBI_OUTPUT)
00791 printf(" > Supports sliced VBI_OUTPUT\n");
00792 #endif
00793 if (cap.capabilities & V4L2_CAP_RDS_CAPTURE)
00794 printf(" > Supports RDS capture\n");
00795 if (cap.capabilities & V4L2_CAP_TUNER)
00796 printf(" > Has an RF tuner and/or modulator\n");
00797 if (cap.capabilities & V4L2_CAP_AUDIO)
00798 printf(" > Supports audio input and/or output\n");
00799 if (cap.capabilities & V4L2_CAP_READWRITE)
00800 printf(" > Supports read/write I/O method\n");
00801 if (cap.capabilities & V4L2_CAP_ASYNCIO)
00802 printf(" > Supports asynchronous I/O method\n");
00803 if (cap.capabilities & V4L2_CAP_STREAMING)
00804 printf(" > Supports streaming I/O (MMAP) method\n");
00805
00806
00807
00808
00809 struct v4l2_queryctrl ctrl;
00810 int cid;
00811 for (cid = V4L2_CID_BASE; cid < V4L2_CID_LASTP1; cid ++)
00812 {
00813 memset(&ctrl, 0, sizeof(ctrl));
00814 ctrl.id = cid;
00815
00816
00817 if (xioctl(fd, VIDIOC_QUERYCTRL, &ctrl) == 0 &&
00818 ctrl.type != 0)
00819 {
00820
00821
00822 struct v4l2_control control; control.id = cid;
00823 switch(cid)
00824 {
00825 case V4L2_CID_BRIGHTNESS:
00826 control.value = 64;
00827 if (xioctl(fd, VIDIOC_S_CTRL, &control) == -1)
00828 printf("Failed to set brightness to %d (VIDIOC_S_CTRL)\n",
00829 control.value);
00830 break;
00831 case V4L2_CID_CONTRAST:
00832 control.value = 0;
00833 if (xioctl(fd, VIDIOC_S_CTRL, &control) == -1)
00834 printf("Failed to set contrast to %d (VIDIOC_S_CTRL)\n",
00835 control.value);
00836 break;
00837 case V4L2_CID_WHITENESS:
00838
00839
00840
00841
00842
00843
00844 break;
00845 case V4L2_CID_SATURATION:
00846 control.value = 0;
00847 if (xioctl(fd, VIDIOC_S_CTRL, &control) == -1)
00848 printf("Failed to set saturation to %d (VIDIOC_S_CTRL)\n",
00849 control.value);
00850 break;
00851 case V4L2_CID_HUE:
00852 control.value = 32768;
00853 if (xioctl(fd, VIDIOC_S_CTRL, &control) == -1)
00854 printf("Failed to set hue to %d (VIDIOC_S_CTRL)\n",
00855 control.value);
00856 break;
00857
00858 default: break;
00859 }
00860
00861
00862 int val = -1;
00863 if (xioctl(fd, VIDIOC_G_CTRL, &control) == 0)
00864 val = control.value;
00865
00866 switch(ctrl.type)
00867 {
00868 case V4L2_CTRL_TYPE_INTEGER:
00869 printf("CONTROL: %s=%d (Def=%d, Rng=[%d .. %d])%s\n",
00870 ctrl.name, val, ctrl.default_value,
00871 ctrl.minimum, ctrl.maximum,
00872 ctrl.flags & V4L2_CTRL_FLAG_DISABLED ?
00873 " (DISABLED)" : "");
00874 break;
00875
00876 case V4L2_CTRL_TYPE_BOOLEAN:
00877 printf("CONTROL: %s=%s (Def=%s)%s\n",
00878 ctrl.name, val ? "true" : "false",
00879 ctrl.default_value ? "true" : "false",
00880 ctrl.flags & V4L2_CTRL_FLAG_DISABLED ?
00881 " (DISABLED)" : "");
00882 break;
00883
00884 case V4L2_CTRL_TYPE_MENU:
00885 printf("CONTROL: %s=[menu type not yet implemented]%s\n",
00886 ctrl.name,
00887 ctrl.flags & V4L2_CTRL_FLAG_DISABLED ?
00888 " (DISABLED)" : "");
00889 break;
00890 case V4L2_CTRL_TYPE_BUTTON:
00891 printf("CONTROL: %s=[button]%s\n",
00892 ctrl.name,
00893 ctrl.flags & V4L2_CTRL_FLAG_DISABLED ?
00894 " (DISABLED)" : "");
00895 break;
00896
00897 default: break;
00898 }
00899 }
00900 }
00901
00902
00903 int i;
00904 for (i = 0; ; i++)
00905 {
00906 struct v4l2_input inp;
00907 memset(&inp, 0, sizeof(inp));
00908 inp.index = i;
00909 if (xioctl(fd, VIDIOC_ENUMINPUT, &inp) != 0) break;
00910 printf("Video input %d is '%s'\n", i, inp.name);
00911 }
00912
00913
00914
00915
00916
00917 if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
00918 fprintf (stderr, "%s is no video capture device\n",
00919 dev_name);
00920 exit (EXIT_FAILURE);
00921 }
00922
00923 switch (io) {
00924 case IO_METHOD_READ:
00925 if (!(cap.capabilities & V4L2_CAP_READWRITE)) {
00926 fprintf (stderr, "%s does not support read i/o\n",
00927 dev_name);
00928 exit (EXIT_FAILURE);
00929 }
00930
00931 break;
00932
00933 case IO_METHOD_MMAP:
00934 case IO_METHOD_USERPTR:
00935 if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
00936 fprintf (stderr, "%s does not support streaming i/o\n",
00937 dev_name);
00938 exit (EXIT_FAILURE);
00939 }
00940
00941 break;
00942 }
00943
00944
00945
00946 int channel = 0;
00947 if (xioctl(fd, VIDIOC_S_INPUT, &channel) < 0)
00948 printf("Cannot select video input %d\n", channel);
00949 else
00950 printf("Selected video input %d\n", channel);
00951
00952
00953
00954
00955
00956
00957
00958
00959 CLEAR (cropcap);
00960 cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00961
00962 if (0 == xioctl (fd, VIDIOC_CROPCAP, &cropcap)) {
00963 printf("Video capture bounds: (%d, %d) -> (%d, %d)\n",
00964 cropcap.bounds.left, cropcap.bounds.top,
00965 cropcap.bounds.left + cropcap.bounds.width - 1,
00966 cropcap.bounds.top + cropcap.bounds.height - 1);
00967 printf("Video default capture rectangle: (%d, %d) -> (%d, %d)\n",
00968 cropcap.defrect.left, cropcap.defrect.top,
00969 cropcap.defrect.left + cropcap.defrect.width - 1,
00970 cropcap.defrect.top + cropcap.defrect.height - 1);
00971
00972 } else {
00973 printf("Failed to get cropping capabilities -- IGNORED.\n");
00974 }
00975
00976 memset (&crop, 0, sizeof(crop));
00977 crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00978 crop.c = cropcap.defrect;
00979 if (xioctl(fd, VIDIOC_S_CROP, &crop) == -1)
00980 printf("Failed to reset cropping settings -- IGNORED.\n");
00981
00982
00983
00984
00985
00986 CLEAR (fmt);
00987 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00988 fmt.fmt.pix.width = width;
00989 fmt.fmt.pix.height = height;
00990 fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
00991 int fmt_to_use = -1;
00992
00993 for (i = 0; ; i ++)
00994 {
00995 struct v4l2_fmtdesc fdesc;
00996 memset(&fdesc, 0, sizeof(fdesc));
00997 fdesc.index = i;
00998 fdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00999 if (xioctl(fd, VIDIOC_ENUM_FMT, &fdesc) != 0) break;
01000 unsigned int f;
01001 for (f = 0; f < (unsigned int)IROBOT_VIDFMT_AUTO; f ++)
01002 if (v4l2format[f] == fdesc.pixelformat) break;
01003
01004
01005 fmt.fmt.pix.pixelformat = fdesc.pixelformat;
01006 int worked = 0;
01007 if (xioctl(fd, VIDIOC_TRY_FMT, &fmt) == 0)
01008 {
01009 worked = 1;
01010 if (fmt_to_use == -1) fmt_to_use = fdesc.pixelformat;
01011 }
01012 printf("Video Format: Use '%i' for '%s (Fourcc: %c%c%c%c)'%s%s\n",
01013 f == IROBOT_VIDFMT_AUTO ? -1 : f,
01014 fdesc.description,
01015 ((char*)(&fdesc.pixelformat))[0],
01016 ((char*)(&fdesc.pixelformat))[1],
01017 ((char*)(&fdesc.pixelformat))[2],
01018 ((char*)(&fdesc.pixelformat))[3],
01019 fdesc.flags & V4L2_FMT_FLAG_COMPRESSED ? " (COMPRESSED)" : "",
01020 worked ? " [OK]" : " [FAILED TO SET]");
01021 }
01022 printf("Using format %i\n", fmt_to_use);
01023
01024
01025 struct v4l2_streamparm sparm;
01026 memset(&sparm, 0, sizeof(sparm));
01027 sparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
01028 if (xioctl(fd, VIDIOC_G_PARM, &sparm) == -1)
01029 {
01030 printf("Cannot get video standard params - ASSUMING NTSC\n");
01031 }
01032 else
01033 printf("Capture at %.2f fps\n",
01034 (float)sparm.parm.capture.timeperframe.numerator/
01035 (float)sparm.parm.capture.timeperframe.denominator);
01036
01037
01038 fmt.fmt.pix.pixelformat = v4l2format[11];
01039
01040 if (xioctl(fd, VIDIOC_S_FMT, &fmt) == -1)
01041 printf("Cannot set requested video mode/resolution %i [%dx%d], probably unsupported by hardware.",
01042 fmt_to_use, width, height);
01043
01044 if (xioctl(fd, VIDIOC_G_FMT, &fmt) == 0)
01045 printf("Video mode/resolution set to %i [%dx%d]\n",
01046 fmt_to_use,
01047 fmt.fmt.pix.width, fmt.fmt.pix.height);
01048
01049 if ((int)fmt.fmt.pix.width != width ||
01050 (int)fmt.fmt.pix.height != height)
01051 printf("Hardware suggests changing input dims to %dx%d instead of "
01052 "requested %dx%d\n",
01053 fmt.fmt.pix.width, fmt.fmt.pix.height,
01054 width, height);
01055
01056 width = fmt.fmt.pix.width;
01057 height = fmt.fmt.pix.height;
01058
01059
01060
01061
01062 switch (io) {
01063 case IO_METHOD_READ:
01064 init_read (fmt.fmt.pix.sizeimage);
01065 break;
01066
01067 case IO_METHOD_MMAP:
01068 printf("Using MMap\n");
01069 init_mmap ();
01070 break;
01071
01072 case IO_METHOD_USERPTR:
01073 init_userp (fmt.fmt.pix.sizeimage);
01074 break;
01075 }
01076 }
01077
01078 void close_device(void)
01079 {
01080 if (-1 == close (fd))
01081 errno_exit ("close");
01082
01083 fd = -1;
01084 }
01085
01086 void open_device(void)
01087 {
01088 struct stat st;
01089
01090 if (-1 == stat (dev_name, &st)) {
01091 fprintf (stderr, "Cannot identify '%s': %d, %s\n",
01092 dev_name, errno, strerror (errno));
01093 exit (EXIT_FAILURE);
01094 }
01095
01096 if (!S_ISCHR (st.st_mode)) {
01097 fprintf (stderr, "%s is no device\n", dev_name);
01098 exit (EXIT_FAILURE);
01099 }
01100
01101 fd = open (dev_name, O_RDWR | O_NONBLOCK, 0);
01102
01103 if (-1 == fd) {
01104 fprintf (stderr, "Cannot open '%s': %d, %s\n",
01105 dev_name, errno, strerror (errno));
01106 exit (EXIT_FAILURE);
01107 }
01108 }