00001 /* 00002 * V4L2 video capture example 00003 * 00004 * This program can be used and distributed without restrictions. 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 //io_method io = IO_METHOD_READ; 00020 int fd = -1; 00021 buffer* buffers = NULL; 00022 unsigned int n_buffers = 0; 00023 //int width = 160, height = 120; 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; // Y range = [16,235] 00048 const int VIDEOYUV_UV_OFFSET = 128; 00049 const int VIDEOYUV_UV_RANGE = 224; // UV range = [16,240] 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 // so that we get proper rounding in fixed-point integer arithmetic: 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 // FIXME should probably have -0.5 instead of +0.5 here and 00081 // flip the sign of G_U_tab and G_V_tab: 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 // we have 2 luminance pixels per chroma pair 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 // first luminance pixel: 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 // second luminance pixel: 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 // no unsigned charswap 00128 for ( j = 0; j < h; ++j) 00129 for ( i = 0; i < w; i += 2) 00130 { 00131 // we have 2 luminance pixels per chroma pair 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 // first luminance pixel: 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 // second luminance pixel: 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) { /* flip image? */ 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, // dst_stride , 00276 (const unsigned char*)p, 00277 (const unsigned char*)p + width*height, 00278 (const unsigned char*)p + width*height + w2*h2, 00279 width, // y_stride , 00280 w2, // uv_stride , 00281 width, // image width , 00282 height); // image 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 /* Could ignore EIO, see spec. */ 00301 00302 /* fall through */ 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 // wait until buffer 'itsCurrentFrame' has been fully captured: 00320 if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) { 00321 switch (errno) { 00322 case EAGAIN: 00323 return 0; 00324 00325 case EIO: 00326 /* Could ignore EIO, see spec. */ 00327 00328 /* fall through */ 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 // get ready for capture of that frame again (for later): 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 /* Could ignore EIO, see spec. */ 00358 00359 /* fall through */ 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 /* Could ignore EIO, see spec. */ 00398 00399 /* fall through */ 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 // wait until buffer 'itsCurrentFrame' has been fully captured: 00417 if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) { 00418 switch (errno) { 00419 case EAGAIN: 00420 return 0; 00421 00422 case EIO: 00423 /* Could ignore EIO, see spec. */ 00424 return 0; 00425 00426 /* fall through */ 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 // get ready for capture of that frame again (for later): 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 /* Could ignore EIO, see spec. */ 00456 00457 /* fall through */ 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 /* Timeout. */ 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 /* EAGAIN - continue select loop. */ 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 /* Nothing to do. */ 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 /* Nothing to do. */ 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 /* start anywhere */, 00700 buf.length, 00701 PROT_READ | PROT_WRITE /* required */, 00702 MAP_SHARED /* recommended */, 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 // NOTE: older versions of V4L2 don't know about sliced VBI: 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 // List available controls and their current settings: 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 // is that control supported? 00817 if (xioctl(fd, VIDIOC_QUERYCTRL, &ctrl) == 0 && 00818 ctrl.type != 0) 00819 { 00820 // first of all, if we have a ModelParam for it, let's 00821 // attempt to set the current value: 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: // NOTE this is = V4L2_CID_GAMMA 00838 // NOTE: bttv driver supports saturation but not whiteness 00839 // NOTE: macbook supports gamma 00840 /*control.value = 50; 00841 if (xioctl(fd, VIDIOC_S_CTRL, &control) == -1) 00842 printf("Failed to set whiteness to %d (VIDIOC_S_CTRL)\n", 00843 control.value);*/ 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; // Ignore other controls 00859 } 00860 00861 // ok, now get the current value, silently ignoring errors: 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 // list available channels: 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 /* Select video input, video standard and tune here. */ 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 // Reset cropping parameters and get resolution capabilities. NOTE: 00955 // just open()'ing the device does not reset it, according to the 00956 // unix toolchain philosophy. Hence, although here we do not provide 00957 // support for cropping, we still need to ensure that it is properly 00958 // reset: 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 // list available video formats and see which ones would work with 00985 // the requested resolution: 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; // in case user selected "auto" format 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 // try to see whether that would work with our given image dims: 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 // Get the frame time, according to current video standard: 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 //fmt.fmt.pix.pixelformat = fmt_to_use; 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 /* Note VIDIOC_S_FMT may change width and height. */ 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 /* required */ | 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 }