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, const bool color)
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 if (!color)
00285 {
00286 const unsigned char* sPtr = currentFrame->data;
00287 for(int i=0; i<width*height; i++)
00288 {
00289 currentFrame->lumData[i] = (*sPtr + *(sPtr+1) + *(sPtr+2))/3;
00290 sPtr += 3;
00291 }
00292 }
00293
00294 return currentFrame;
00295 }
00296
00297 int read_frame(void)
00298 {
00299 struct v4l2_buffer buf;
00300 unsigned int i;
00301
00302 switch (io) {
00303 case IO_METHOD_READ:
00304 if (-1 == (i = read (fd, buffers[0].start, buffers[0].length))) {
00305 switch (errno) {
00306 case EAGAIN:
00307 return 0;
00308
00309 case EIO:
00310
00311
00312
00313
00314 default:
00315 errno_exit ("read");
00316 }
00317 }
00318
00319 process_image (buffers[0].start, buffers[0].length);
00320
00321 break;
00322
00323 case IO_METHOD_MMAP:
00324 CLEAR (buf);
00325
00326 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00327 buf.memory = V4L2_MEMORY_MMAP;
00328
00329
00330 if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) {
00331 switch (errno) {
00332 case EAGAIN:
00333 return 0;
00334
00335 case EIO:
00336
00337
00338
00339
00340 default:
00341 errno_exit ("VIDIOC_DQBUF");
00342 }
00343 }
00344
00345 assert (buf.index < n_buffers);
00346
00347 process_image (buffers[buf.index].start,buffers[buf.index].length );
00348
00349
00350 if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
00351 errno_exit ("VIDIOC_QBUF");
00352
00353 break;
00354
00355 case IO_METHOD_USERPTR:
00356 CLEAR (buf);
00357
00358 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00359 buf.memory = V4L2_MEMORY_USERPTR;
00360
00361 if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) {
00362 switch (errno) {
00363 case EAGAIN:
00364 return 0;
00365
00366 case EIO:
00367
00368
00369
00370
00371 default:
00372 errno_exit ("VIDIOC_DQBUF");
00373 }
00374 }
00375
00376 for (i = 0; i < n_buffers; ++i)
00377 if (buf.m.userptr == (unsigned long) buffers[i].start
00378 && buf.length == buffers[i].length)
00379 break;
00380
00381 assert (i < n_buffers);
00382
00383 process_image ((void *) buf.m.userptr, 0);
00384
00385 if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
00386 errno_exit ("VIDIOC_QBUF");
00387
00388 break;
00389 }
00390
00391 return 1;
00392 }
00393
00394 frame* get_frame(bool color)
00395 {
00396 struct v4l2_buffer buf;
00397 unsigned int i;
00398
00399 switch (io) {
00400 case IO_METHOD_READ:
00401 if (-1 == (i = read (fd, buffers[0].start, buffers[0].length))) {
00402 switch (errno) {
00403 case EAGAIN:
00404 return 0;
00405
00406 case EIO:
00407
00408
00409
00410
00411 default:
00412 errno_exit ("read");
00413 }
00414 }
00415
00416 return process_image (buffers[0].start, buffers[0].length, color);
00417
00418 break;
00419
00420 case IO_METHOD_MMAP:
00421 CLEAR (buf);
00422
00423 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00424 buf.memory = V4L2_MEMORY_MMAP;
00425
00426
00427 if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) {
00428 switch (errno) {
00429 case EAGAIN:
00430 return 0;
00431
00432 case EIO:
00433
00434 return 0;
00435
00436
00437
00438 default:
00439 errno_exit ("VIDIOC_DQBUF error");
00440 }
00441 }
00442
00443 assert (buf.index < n_buffers);
00444
00445
00446
00447 if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
00448 errno_exit ("VIDIOC_QBUF");
00449
00450 return process_image (buffers[buf.index].start,buffers[buf.index].length, color );
00451 break;
00452
00453 case IO_METHOD_USERPTR:
00454 CLEAR (buf);
00455
00456 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00457 buf.memory = V4L2_MEMORY_USERPTR;
00458
00459 if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) {
00460 switch (errno) {
00461 case EAGAIN:
00462 return 0;
00463
00464 case EIO:
00465
00466
00467
00468
00469 default:
00470 errno_exit ("VIDIOC_DQBUF");
00471 }
00472 }
00473
00474 for (i = 0; i < n_buffers; ++i)
00475 if (buf.m.userptr == (unsigned long) buffers[i].start
00476 && buf.length == buffers[i].length)
00477 break;
00478
00479 assert (i < n_buffers);
00480
00481 return process_image ((void *) buf.m.userptr, 0, color);
00482
00483 if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
00484 errno_exit ("VIDIOC_QBUF");
00485
00486 break;
00487 }
00488
00489 return NULL;
00490 }
00491
00492 void mainloop(void)
00493 {
00494 unsigned int count;
00495
00496 count = 100;
00497
00498 while (count-- > 0) {
00499 for (;;) {
00500 fd_set fds;
00501 struct timeval tv;
00502 int r;
00503
00504 FD_ZERO (&fds);
00505 FD_SET (fd, &fds);
00506
00507
00508 tv.tv_sec = 2;
00509 tv.tv_usec = 0;
00510
00511 r = select (fd + 1, &fds, NULL, NULL, &tv);
00512
00513 if (-1 == r) {
00514 if (EINTR == errno)
00515 continue;
00516
00517 errno_exit ("select");
00518 }
00519
00520 if (0 == r) {
00521 fprintf (stderr, "select timeout\n");
00522 exit (EXIT_FAILURE);
00523 }
00524
00525 if (read_frame ())
00526 break;
00527
00528
00529 }
00530 }
00531 }
00532
00533 void stop_capturing(void)
00534 {
00535 enum v4l2_buf_type type;
00536
00537 switch (io) {
00538 case IO_METHOD_READ:
00539
00540 break;
00541
00542 case IO_METHOD_MMAP:
00543 case IO_METHOD_USERPTR:
00544 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00545
00546 if (-1 == xioctl (fd, VIDIOC_STREAMOFF, &type))
00547 errno_exit ("VIDIOC_STREAMOFF");
00548
00549 break;
00550 }
00551 }
00552
00553 void start_capturing(void)
00554 {
00555 unsigned int i;
00556 enum v4l2_buf_type type;
00557
00558 currentFrame = new frame;
00559 currentFrame->data = new unsigned char[width*height*3];
00560 currentFrame->lumData = new unsigned char[width*height];
00561 currentFrame->width = width;
00562 currentFrame->height = height;
00563 currentFrame->pixType=0;
00564
00565
00566 switch (io) {
00567 case IO_METHOD_READ:
00568
00569 break;
00570
00571 case IO_METHOD_MMAP:
00572 for (i = 0; i < n_buffers; ++i) {
00573 struct v4l2_buffer buf;
00574
00575 CLEAR (buf);
00576
00577 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00578 buf.memory = V4L2_MEMORY_MMAP;
00579 buf.index = i;
00580
00581 if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
00582 errno_exit ("VIDIOC_QBUF");
00583 }
00584
00585 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00586
00587 if (-1 == xioctl (fd, VIDIOC_STREAMON, &type))
00588 errno_exit ("VIDIOC_STREAMON");
00589
00590 break;
00591
00592 case IO_METHOD_USERPTR:
00593 for (i = 0; i < n_buffers; ++i) {
00594 struct v4l2_buffer buf;
00595
00596 CLEAR (buf);
00597
00598 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00599 buf.memory = V4L2_MEMORY_USERPTR;
00600 buf.index = i;
00601 buf.m.userptr = (unsigned long) buffers[i].start;
00602 buf.length = buffers[i].length;
00603
00604 if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
00605 errno_exit ("VIDIOC_QBUF");
00606 }
00607
00608 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00609
00610 if (-1 == xioctl (fd, VIDIOC_STREAMON, &type))
00611 errno_exit ("VIDIOC_STREAMON");
00612
00613 break;
00614 }
00615 }
00616
00617 void uninit_device(void)
00618 {
00619 unsigned int i;
00620
00621 switch (io) {
00622 case IO_METHOD_READ:
00623 free (buffers[0].start);
00624 break;
00625
00626 case IO_METHOD_MMAP:
00627 for (i = 0; i < n_buffers; ++i)
00628 if (-1 == munmap (buffers[i].start, buffers[i].length))
00629 errno_exit ("munmap");
00630 break;
00631
00632 case IO_METHOD_USERPTR:
00633 for (i = 0; i < n_buffers; ++i)
00634 free (buffers[i].start);
00635 break;
00636 }
00637
00638 if (currentFrame != NULL)
00639 {
00640 if (currentFrame->data != NULL)
00641 free(currentFrame->data);
00642 if (currentFrame->lumData != NULL)
00643 free(currentFrame->lumData);
00644 free(currentFrame);
00645 }
00646
00647 free (buffers);
00648 }
00649
00650 void init_read(unsigned int buffer_size)
00651 {
00652 buffers = (struct buffer*)calloc (1, sizeof (*buffers));
00653
00654 if (!buffers) {
00655 fprintf (stderr, "Out of memory\n");
00656 exit (EXIT_FAILURE);
00657 }
00658
00659 buffers[0].length = buffer_size;
00660 buffers[0].start = malloc (buffer_size);
00661
00662 if (!buffers[0].start) {
00663 fprintf (stderr, "Out of memory\n");
00664 exit (EXIT_FAILURE);
00665 }
00666 }
00667
00668 void init_mmap(void)
00669 {
00670 struct v4l2_requestbuffers req;
00671
00672 CLEAR (req);
00673
00674 req.count = 1;
00675 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00676 req.memory = V4L2_MEMORY_MMAP;
00677
00678 if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req)) {
00679 if (EINVAL == errno) {
00680 fprintf (stderr, "%s does not support "
00681 "memory mapping\n", dev_name);
00682 exit (EXIT_FAILURE);
00683 } else {
00684 errno_exit ("VIDIOC_REQBUFS");
00685 }
00686 }
00687
00688 if (req.count < 2) {
00689 fprintf (stderr, "Insufficient buffer memory on %s\n",
00690 dev_name);
00691 exit (EXIT_FAILURE);
00692 }
00693
00694 buffers = (struct buffer*)calloc (req.count, sizeof (*buffers));
00695
00696 if (!buffers) {
00697 fprintf (stderr, "Out of memory\n");
00698 exit (EXIT_FAILURE);
00699 }
00700
00701 for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
00702 struct v4l2_buffer buf;
00703
00704 CLEAR (buf);
00705
00706 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00707 buf.memory = V4L2_MEMORY_MMAP;
00708 buf.index = n_buffers;
00709
00710 if (-1 == xioctl (fd, VIDIOC_QUERYBUF, &buf))
00711 errno_exit ("VIDIOC_QUERYBUF");
00712
00713 buffers[n_buffers].length = buf.length;
00714 buffers[n_buffers].start =
00715 mmap (NULL ,
00716 buf.length,
00717 PROT_READ | PROT_WRITE ,
00718 MAP_SHARED ,
00719 fd, buf.m.offset);
00720
00721 if (MAP_FAILED == buffers[n_buffers].start)
00722 errno_exit ("mmap");
00723 }
00724 }
00725
00726 void init_userp(unsigned int buffer_size)
00727 {
00728 struct v4l2_requestbuffers req;
00729
00730 CLEAR (req);
00731
00732 req.count = 4;
00733 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00734 req.memory = V4L2_MEMORY_USERPTR;
00735
00736 if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req)) {
00737 if (EINVAL == errno) {
00738 fprintf (stderr, "%s does not support "
00739 "user pointer i/o\n", dev_name);
00740 exit (EXIT_FAILURE);
00741 } else {
00742 errno_exit ("VIDIOC_REQBUFS");
00743 }
00744 }
00745
00746 buffers = (struct buffer*)calloc (4, sizeof (*buffers));
00747
00748 if (!buffers) {
00749 fprintf (stderr, "Out of memory\n");
00750 exit (EXIT_FAILURE);
00751 }
00752
00753 for (n_buffers = 0; n_buffers < 4; ++n_buffers) {
00754 buffers[n_buffers].length = buffer_size;
00755 buffers[n_buffers].start = malloc (buffer_size);
00756
00757 if (!buffers[n_buffers].start) {
00758 fprintf (stderr, "Out of memory\n");
00759 exit (EXIT_FAILURE);
00760 }
00761 }
00762 }
00763
00764 void init_device(int pix_fmt)
00765 {
00766 struct v4l2_capability cap;
00767 struct v4l2_cropcap cropcap;
00768 struct v4l2_crop crop;
00769 struct v4l2_format fmt;
00770 unsigned int min;
00771
00772 colorspace_init();
00773
00774 printf("Settting to pixformat %i\n", pix_fmt);
00775 if (-1 == xioctl (fd, VIDIOC_QUERYCAP, &cap)) {
00776 if (EINVAL == errno) {
00777 fprintf (stderr, "%s is no V4L2 device\n",
00778 dev_name);
00779 exit (EXIT_FAILURE);
00780 } else {
00781 errno_exit ("VIDIOC_QUERYCAP");
00782 }
00783 }
00784
00785 printf("V4L2 kernel driver: %s\n", cap.driver);
00786 printf("FrameGrabber board name is: %s\n", cap.card);
00787 printf("FrameGrabber board bus info: %s\n", cap.bus_info);
00788 if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)
00789 printf(" > Supports video capture\n");
00790 else printf("Not a video capture device.\n");
00791 if (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)
00792 printf(" > Supports video output\n");
00793 if (cap.capabilities & V4L2_CAP_VIDEO_OVERLAY)
00794 printf(" > Supports video overlay\n");
00795 if (cap.capabilities & V4L2_CAP_VBI_CAPTURE)
00796 printf(" > Supports raw VBI capture\n");
00797 if (cap.capabilities & V4L2_CAP_VBI_OUTPUT)
00798 printf(" > Supports raw VBI output\n");
00799
00800
00801 #ifdef V4L2_CAP_SLICED_VBI_CAPTURE
00802 if (cap.capabilities & V4L2_CAP_SLICED_VBI_CAPTURE)
00803 printf(" > Supports sliced VBI capture\n");
00804 #endif
00805 #ifdef V4L2_CAP_SLICED_VBI_OUTPUT
00806 if (cap.capabilities & V4L2_CAP_SLICED_VBI_OUTPUT)
00807 printf(" > Supports sliced VBI_OUTPUT\n");
00808 #endif
00809 if (cap.capabilities & V4L2_CAP_RDS_CAPTURE)
00810 printf(" > Supports RDS capture\n");
00811 if (cap.capabilities & V4L2_CAP_TUNER)
00812 printf(" > Has an RF tuner and/or modulator\n");
00813 if (cap.capabilities & V4L2_CAP_AUDIO)
00814 printf(" > Supports audio input and/or output\n");
00815 if (cap.capabilities & V4L2_CAP_READWRITE)
00816 printf(" > Supports read/write I/O method\n");
00817 if (cap.capabilities & V4L2_CAP_ASYNCIO)
00818 printf(" > Supports asynchronous I/O method\n");
00819 if (cap.capabilities & V4L2_CAP_STREAMING)
00820 printf(" > Supports streaming I/O (MMAP) method\n");
00821
00822
00823
00824
00825 struct v4l2_queryctrl ctrl;
00826 int cid;
00827 for (cid = V4L2_CID_BASE; cid < V4L2_CID_LASTP1; cid ++)
00828 {
00829 memset(&ctrl, 0, sizeof(ctrl));
00830 ctrl.id = cid;
00831
00832
00833 if (xioctl(fd, VIDIOC_QUERYCTRL, &ctrl) == 0 &&
00834 ctrl.type != 0)
00835 {
00836
00837
00838 struct v4l2_control control; control.id = cid;
00839 switch(cid)
00840 {
00841 case V4L2_CID_BRIGHTNESS:
00842 control.value = 64;
00843 if (xioctl(fd, VIDIOC_S_CTRL, &control) == -1)
00844 printf("Failed to set brightness to %d (VIDIOC_S_CTRL)\n",
00845 control.value);
00846 break;
00847 case V4L2_CID_CONTRAST:
00848 control.value = 0;
00849 if (xioctl(fd, VIDIOC_S_CTRL, &control) == -1)
00850 printf("Failed to set contrast to %d (VIDIOC_S_CTRL)\n",
00851 control.value);
00852 break;
00853 case V4L2_CID_WHITENESS:
00854
00855
00856
00857
00858
00859
00860 break;
00861 case V4L2_CID_SATURATION:
00862 control.value = 0;
00863 if (xioctl(fd, VIDIOC_S_CTRL, &control) == -1)
00864 printf("Failed to set saturation to %d (VIDIOC_S_CTRL)\n",
00865 control.value);
00866 break;
00867 case V4L2_CID_HUE:
00868 control.value = 32768;
00869 if (xioctl(fd, VIDIOC_S_CTRL, &control) == -1)
00870 printf("Failed to set hue to %d (VIDIOC_S_CTRL)\n",
00871 control.value);
00872 break;
00873
00874 default: break;
00875 }
00876
00877
00878 int val = -1;
00879 if (xioctl(fd, VIDIOC_G_CTRL, &control) == 0)
00880 val = control.value;
00881
00882 switch(ctrl.type)
00883 {
00884 case V4L2_CTRL_TYPE_INTEGER:
00885 printf("CONTROL: %s=%d (Def=%d, Rng=[%d .. %d])%s\n",
00886 ctrl.name, val, ctrl.default_value,
00887 ctrl.minimum, ctrl.maximum,
00888 ctrl.flags & V4L2_CTRL_FLAG_DISABLED ?
00889 " (DISABLED)" : "");
00890 break;
00891
00892 case V4L2_CTRL_TYPE_BOOLEAN:
00893 printf("CONTROL: %s=%s (Def=%s)%s\n",
00894 ctrl.name, val ? "true" : "false",
00895 ctrl.default_value ? "true" : "false",
00896 ctrl.flags & V4L2_CTRL_FLAG_DISABLED ?
00897 " (DISABLED)" : "");
00898 break;
00899
00900 case V4L2_CTRL_TYPE_MENU:
00901 printf("CONTROL: %s=[menu type not yet implemented]%s\n",
00902 ctrl.name,
00903 ctrl.flags & V4L2_CTRL_FLAG_DISABLED ?
00904 " (DISABLED)" : "");
00905 break;
00906 case V4L2_CTRL_TYPE_BUTTON:
00907 printf("CONTROL: %s=[button]%s\n",
00908 ctrl.name,
00909 ctrl.flags & V4L2_CTRL_FLAG_DISABLED ?
00910 " (DISABLED)" : "");
00911 break;
00912
00913 default: break;
00914 }
00915 }
00916 }
00917
00918
00919 int i;
00920 for (i = 0; ; i++)
00921 {
00922 struct v4l2_input inp;
00923 memset(&inp, 0, sizeof(inp));
00924 inp.index = i;
00925 if (xioctl(fd, VIDIOC_ENUMINPUT, &inp) != 0) break;
00926 printf("Video input %d is '%s'\n", i, inp.name);
00927 }
00928
00929
00930
00931
00932
00933 if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
00934 fprintf (stderr, "%s is no video capture device\n",
00935 dev_name);
00936 exit (EXIT_FAILURE);
00937 }
00938
00939 switch (io) {
00940 case IO_METHOD_READ:
00941 if (!(cap.capabilities & V4L2_CAP_READWRITE)) {
00942 fprintf (stderr, "%s does not support read i/o\n",
00943 dev_name);
00944 exit (EXIT_FAILURE);
00945 }
00946
00947 break;
00948
00949 case IO_METHOD_MMAP:
00950 case IO_METHOD_USERPTR:
00951 if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
00952 fprintf (stderr, "%s does not support streaming i/o\n",
00953 dev_name);
00954 exit (EXIT_FAILURE);
00955 }
00956
00957 break;
00958 }
00959
00960
00961
00962 int channel = 0;
00963 if (xioctl(fd, VIDIOC_S_INPUT, &channel) < 0)
00964 printf("Cannot select video input %d\n", channel);
00965 else
00966 printf("Selected video input %d\n", channel);
00967
00968
00969
00970
00971
00972
00973
00974
00975 CLEAR (cropcap);
00976 cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00977
00978 if (0 == xioctl (fd, VIDIOC_CROPCAP, &cropcap)) {
00979 printf("Video capture bounds: (%d, %d) -> (%d, %d)\n",
00980 cropcap.bounds.left, cropcap.bounds.top,
00981 cropcap.bounds.left + cropcap.bounds.width - 1,
00982 cropcap.bounds.top + cropcap.bounds.height - 1);
00983 printf("Video default capture rectangle: (%d, %d) -> (%d, %d)\n",
00984 cropcap.defrect.left, cropcap.defrect.top,
00985 cropcap.defrect.left + cropcap.defrect.width - 1,
00986 cropcap.defrect.top + cropcap.defrect.height - 1);
00987
00988 } else {
00989 printf("Failed to get cropping capabilities -- IGNORED.\n");
00990 }
00991
00992 memset (&crop, 0, sizeof(crop));
00993 crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00994 crop.c = cropcap.defrect;
00995 if (xioctl(fd, VIDIOC_S_CROP, &crop) == -1)
00996 printf("Failed to reset cropping settings -- IGNORED.\n");
00997
00998
00999
01000
01001
01002 CLEAR (fmt);
01003 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
01004 fmt.fmt.pix.width = width;
01005 fmt.fmt.pix.height = height;
01006 fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
01007 int fmt_to_use = -1;
01008
01009 for (i = 0; ; i ++)
01010 {
01011 struct v4l2_fmtdesc fdesc;
01012 memset(&fdesc, 0, sizeof(fdesc));
01013 fdesc.index = i;
01014 fdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
01015 if (xioctl(fd, VIDIOC_ENUM_FMT, &fdesc) != 0) break;
01016 unsigned int f;
01017 for (f = 0; f < (unsigned int)IROBOT_VIDFMT_AUTO; f ++)
01018 if (v4l2format[f] == fdesc.pixelformat) break;
01019
01020
01021 fmt.fmt.pix.pixelformat = fdesc.pixelformat;
01022 int worked = 0;
01023 if (xioctl(fd, VIDIOC_TRY_FMT, &fmt) == 0)
01024 {
01025 worked = 1;
01026 if (fmt_to_use == -1) fmt_to_use = fdesc.pixelformat;
01027 }
01028 printf("Video Format: Use '%i index %i' for '%s (Fourcc: %c%c%c%c)'%s%s\n",
01029 f == IROBOT_VIDFMT_AUTO ? -1 : f,
01030 fdesc.index,
01031 fdesc.description,
01032 ((char*)(&fdesc.pixelformat))[0],
01033 ((char*)(&fdesc.pixelformat))[1],
01034 ((char*)(&fdesc.pixelformat))[2],
01035 ((char*)(&fdesc.pixelformat))[3],
01036 fdesc.flags & V4L2_FMT_FLAG_COMPRESSED ? " (COMPRESSED)" : "",
01037 worked ? " [OK]" : " [FAILED TO SET]");
01038 }
01039 printf("Using format %i\n", fmt_to_use);
01040
01041
01042 struct v4l2_streamparm sparm;
01043 memset(&sparm, 0, sizeof(sparm));
01044 sparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
01045 if (xioctl(fd, VIDIOC_G_PARM, &sparm) == -1)
01046 {
01047 printf("Cannot get video standard params - ASSUMING NTSC\n");
01048 }
01049 else
01050 printf("Capture at %.2f fps\n",
01051 (float)sparm.parm.capture.timeperframe.numerator/
01052 (float)sparm.parm.capture.timeperframe.denominator);
01053
01054
01055 fmt.fmt.pix.pixelformat = v4l2format[11];
01056
01057 if (xioctl(fd, VIDIOC_S_FMT, &fmt) == -1)
01058 printf("Cannot set requested video mode/resolution %i [%dx%d], probably unsupported by hardware.",
01059 fmt_to_use, width, height);
01060
01061 if (xioctl(fd, VIDIOC_G_FMT, &fmt) == 0)
01062 printf("Video mode/resolution set to %i [%dx%d]\n",
01063 fmt_to_use,
01064 fmt.fmt.pix.width, fmt.fmt.pix.height);
01065
01066 if ((int)fmt.fmt.pix.width != width ||
01067 (int)fmt.fmt.pix.height != height)
01068 printf("Hardware suggests changing input dims to %dx%d instead of "
01069 "requested %dx%d\n",
01070 fmt.fmt.pix.width, fmt.fmt.pix.height,
01071 width, height);
01072
01073 width = fmt.fmt.pix.width;
01074 height = fmt.fmt.pix.height;
01075
01076
01077
01078
01079 switch (io) {
01080 case IO_METHOD_READ:
01081 init_read (fmt.fmt.pix.sizeimage);
01082 break;
01083
01084 case IO_METHOD_MMAP:
01085 printf("Using MMap\n");
01086 init_mmap ();
01087 break;
01088
01089 case IO_METHOD_USERPTR:
01090 init_userp (fmt.fmt.pix.sizeimage);
01091 break;
01092 }
01093 }
01094
01095 void close_device(void)
01096 {
01097 if (-1 == close (fd))
01098 errno_exit ("close");
01099
01100 fd = -1;
01101 }
01102
01103 void open_device(void)
01104 {
01105 struct stat st;
01106
01107 if (-1 == stat (dev_name, &st)) {
01108 fprintf (stderr, "Cannot identify '%s': %d, %s\n",
01109 dev_name, errno, strerror (errno));
01110 exit (EXIT_FAILURE);
01111 }
01112
01113 if (!S_ISCHR (st.st_mode)) {
01114 fprintf (stderr, "%s is no device\n", dev_name);
01115 exit (EXIT_FAILURE);
01116 }
01117
01118 fd = open (dev_name, O_RDWR | O_NONBLOCK, 0);
01119
01120 if (-1 == fd) {
01121 fprintf (stderr, "Cannot open '%s': %d, %s\n",
01122 dev_name, errno, strerror (errno));
01123 exit (EXIT_FAILURE);
01124 }
01125 }