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 00425 /* fall through */ 00426 00427 default: 00428 errno_exit ("VIDIOC_DQBUF"); 00429 } 00430 } 00431 00432 assert (buf.index < n_buffers); 00433 00434 return process_image (buffers[buf.index].start,buffers[buf.index].length ); 00435 00436 // get ready for capture of that frame again (for later): 00437 if (-1 == xioctl (fd, VIDIOC_QBUF, &buf)) 00438 errno_exit ("VIDIOC_QBUF"); 00439 00440 break; 00441 00442 case IO_METHOD_USERPTR: 00443 CLEAR (buf); 00444 00445 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 00446 buf.memory = V4L2_MEMORY_USERPTR; 00447 00448 if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) { 00449 switch (errno) { 00450 case EAGAIN: 00451 return 0; 00452 00453 case EIO: 00454 /* Could ignore EIO, see spec. */ 00455 00456 /* fall through */ 00457 00458 default: 00459 errno_exit ("VIDIOC_DQBUF"); 00460 } 00461 } 00462 00463 for (i = 0; i < n_buffers; ++i) 00464 if (buf.m.userptr == (unsigned long) buffers[i].start 00465 && buf.length == buffers[i].length) 00466 break; 00467 00468 assert (i < n_buffers); 00469 00470 return process_image ((void *) buf.m.userptr, 0); 00471 00472 if (-1 == xioctl (fd, VIDIOC_QBUF, &buf)) 00473 errno_exit ("VIDIOC_QBUF"); 00474 00475 break; 00476 } 00477 00478 return NULL; 00479 } 00480 00481 00482 void mainloop(void) 00483 { 00484 unsigned int count; 00485 00486 count = 100; 00487 00488 while (count-- > 0) { 00489 for (;;) { 00490 fd_set fds; 00491 struct timeval tv; 00492 int r; 00493 00494 FD_ZERO (&fds); 00495 FD_SET (fd, &fds); 00496 00497 /* Timeout. */ 00498 tv.tv_sec = 2; 00499 tv.tv_usec = 0; 00500 00501 r = select (fd + 1, &fds, NULL, NULL, &tv); 00502 00503 if (-1 == r) { 00504 if (EINTR == errno) 00505 continue; 00506 00507 errno_exit ("select"); 00508 } 00509 00510 if (0 == r) { 00511 fprintf (stderr, "select timeout\n"); 00512 exit (EXIT_FAILURE); 00513 } 00514 00515 if (read_frame ()) 00516 break; 00517 00518 /* EAGAIN - continue select loop. */ 00519 } 00520 } 00521 } 00522 00523 void stop_capturing(void) 00524 { 00525 enum v4l2_buf_type type; 00526 00527 switch (io) { 00528 case IO_METHOD_READ: 00529 /* Nothing to do. */ 00530 break; 00531 00532 case IO_METHOD_MMAP: 00533 case IO_METHOD_USERPTR: 00534 type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 00535 00536 if (-1 == xioctl (fd, VIDIOC_STREAMOFF, &type)) 00537 errno_exit ("VIDIOC_STREAMOFF"); 00538 00539 break; 00540 } 00541 } 00542 00543 void start_capturing(void) 00544 { 00545 unsigned int i; 00546 enum v4l2_buf_type type; 00547 00548 currentFrame = new frame; 00549 currentFrame->data = new unsigned char[width*height*3]; 00550 currentFrame->width = width; 00551 currentFrame->height = height; 00552 currentFrame->pixType=0; 00553 00554 00555 switch (io) { 00556 case IO_METHOD_READ: 00557 /* Nothing to do. */ 00558 break; 00559 00560 case IO_METHOD_MMAP: 00561 for (i = 0; i < n_buffers; ++i) { 00562 struct v4l2_buffer buf; 00563 00564 CLEAR (buf); 00565 00566 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 00567 buf.memory = V4L2_MEMORY_MMAP; 00568 buf.index = i; 00569 00570 if (-1 == xioctl (fd, VIDIOC_QBUF, &buf)) 00571 errno_exit ("VIDIOC_QBUF"); 00572 } 00573 00574 type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 00575 00576 if (-1 == xioctl (fd, VIDIOC_STREAMON, &type)) 00577 errno_exit ("VIDIOC_STREAMON"); 00578 00579 break; 00580 00581 case IO_METHOD_USERPTR: 00582 for (i = 0; i < n_buffers; ++i) { 00583 struct v4l2_buffer buf; 00584 00585 CLEAR (buf); 00586 00587 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 00588 buf.memory = V4L2_MEMORY_USERPTR; 00589 buf.index = i; 00590 buf.m.userptr = (unsigned long) buffers[i].start; 00591 buf.length = buffers[i].length; 00592 00593 if (-1 == xioctl (fd, VIDIOC_QBUF, &buf)) 00594 errno_exit ("VIDIOC_QBUF"); 00595 } 00596 00597 type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 00598 00599 if (-1 == xioctl (fd, VIDIOC_STREAMON, &type)) 00600 errno_exit ("VIDIOC_STREAMON"); 00601 00602 break; 00603 } 00604 } 00605 00606 void uninit_device(void) 00607 { 00608 unsigned int i; 00609 00610 switch (io) { 00611 case IO_METHOD_READ: 00612 free (buffers[0].start); 00613 break; 00614 00615 case IO_METHOD_MMAP: 00616 for (i = 0; i < n_buffers; ++i) 00617 if (-1 == munmap (buffers[i].start, buffers[i].length)) 00618 errno_exit ("munmap"); 00619 break; 00620 00621 case IO_METHOD_USERPTR: 00622 for (i = 0; i < n_buffers; ++i) 00623 free (buffers[i].start); 00624 break; 00625 } 00626 00627 if (currentFrame != NULL) 00628 if (currentFrame->data != NULL) 00629 free(currentFrame->data); 00630 free(currentFrame); 00631 00632 free (buffers); 00633 } 00634 00635 void init_read(unsigned int buffer_size) 00636 { 00637 buffers = (struct buffer*)calloc (1, sizeof (*buffers)); 00638 00639 if (!buffers) { 00640 fprintf (stderr, "Out of memory\n"); 00641 exit (EXIT_FAILURE); 00642 } 00643 00644 buffers[0].length = buffer_size; 00645 buffers[0].start = malloc (buffer_size); 00646 00647 if (!buffers[0].start) { 00648 fprintf (stderr, "Out of memory\n"); 00649 exit (EXIT_FAILURE); 00650 } 00651 } 00652 00653 void init_mmap(void) 00654 { 00655 struct v4l2_requestbuffers req; 00656 00657 CLEAR (req); 00658 00659 req.count = 1; 00660 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 00661 req.memory = V4L2_MEMORY_MMAP; 00662 00663 if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req)) { 00664 if (EINVAL == errno) { 00665 fprintf (stderr, "%s does not support " 00666 "memory mapping\n", dev_name); 00667 exit (EXIT_FAILURE); 00668 } else { 00669 errno_exit ("VIDIOC_REQBUFS"); 00670 } 00671 } 00672 00673 if (req.count < 2) { 00674 fprintf (stderr, "Insufficient buffer memory on %s\n", 00675 dev_name); 00676 exit (EXIT_FAILURE); 00677 } 00678 00679 buffers = (struct buffer*)calloc (req.count, sizeof (*buffers)); 00680 00681 if (!buffers) { 00682 fprintf (stderr, "Out of memory\n"); 00683 exit (EXIT_FAILURE); 00684 } 00685 00686 for (n_buffers = 0; n_buffers < req.count; ++n_buffers) { 00687 struct v4l2_buffer buf; 00688 00689 CLEAR (buf); 00690 00691 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 00692 buf.memory = V4L2_MEMORY_MMAP; 00693 buf.index = n_buffers; 00694 00695 if (-1 == xioctl (fd, VIDIOC_QUERYBUF, &buf)) 00696 errno_exit ("VIDIOC_QUERYBUF"); 00697 00698 buffers[n_buffers].length = buf.length; 00699 buffers[n_buffers].start = 00700 mmap (NULL /* start anywhere */, 00701 buf.length, 00702 PROT_READ | PROT_WRITE /* required */, 00703 MAP_SHARED /* recommended */, 00704 fd, buf.m.offset); 00705 00706 if (MAP_FAILED == buffers[n_buffers].start) 00707 errno_exit ("mmap"); 00708 } 00709 } 00710 00711 void init_userp(unsigned int buffer_size) 00712 { 00713 struct v4l2_requestbuffers req; 00714 00715 CLEAR (req); 00716 00717 req.count = 4; 00718 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 00719 req.memory = V4L2_MEMORY_USERPTR; 00720 00721 if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req)) { 00722 if (EINVAL == errno) { 00723 fprintf (stderr, "%s does not support " 00724 "user pointer i/o\n", dev_name); 00725 exit (EXIT_FAILURE); 00726 } else { 00727 errno_exit ("VIDIOC_REQBUFS"); 00728 } 00729 } 00730 00731 buffers = (struct buffer*)calloc (4, sizeof (*buffers)); 00732 00733 if (!buffers) { 00734 fprintf (stderr, "Out of memory\n"); 00735 exit (EXIT_FAILURE); 00736 } 00737 00738 for (n_buffers = 0; n_buffers < 4; ++n_buffers) { 00739 buffers[n_buffers].length = buffer_size; 00740 buffers[n_buffers].start = malloc (buffer_size); 00741 00742 if (!buffers[n_buffers].start) { 00743 fprintf (stderr, "Out of memory\n"); 00744 exit (EXIT_FAILURE); 00745 } 00746 } 00747 } 00748 00749 void init_device(int pix_fmt) 00750 { 00751 struct v4l2_capability cap; 00752 struct v4l2_cropcap cropcap; 00753 struct v4l2_crop crop; 00754 struct v4l2_format fmt; 00755 unsigned int min; 00756 00757 colorspace_init(); 00758 00759 printf("Settting to pixformat %i\n", pix_fmt); 00760 if (-1 == xioctl (fd, VIDIOC_QUERYCAP, &cap)) { 00761 if (EINVAL == errno) { 00762 fprintf (stderr, "%s is no V4L2 device\n", 00763 dev_name); 00764 exit (EXIT_FAILURE); 00765 } else { 00766 errno_exit ("VIDIOC_QUERYCAP"); 00767 } 00768 } 00769 00770 printf("V4L2 kernel driver: %s\n", cap.driver); 00771 printf("FrameGrabber board name is: %s\n", cap.card); 00772 printf("FrameGrabber board bus info: %s\n", cap.bus_info); 00773 if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) 00774 printf(" > Supports video capture\n"); 00775 else printf("Not a video capture device.\n"); 00776 if (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) 00777 printf(" > Supports video output\n"); 00778 if (cap.capabilities & V4L2_CAP_VIDEO_OVERLAY) 00779 printf(" > Supports video overlay\n"); 00780 if (cap.capabilities & V4L2_CAP_VBI_CAPTURE) 00781 printf(" > Supports raw VBI capture\n"); 00782 if (cap.capabilities & V4L2_CAP_VBI_OUTPUT) 00783 printf(" > Supports raw VBI output\n"); 00784 00785 // NOTE: older versions of V4L2 don't know about sliced VBI: 00786 #ifdef V4L2_CAP_SLICED_VBI_CAPTURE 00787 if (cap.capabilities & V4L2_CAP_SLICED_VBI_CAPTURE) 00788 printf(" > Supports sliced VBI capture\n"); 00789 #endif 00790 #ifdef V4L2_CAP_SLICED_VBI_OUTPUT 00791 if (cap.capabilities & V4L2_CAP_SLICED_VBI_OUTPUT) 00792 printf(" > Supports sliced VBI_OUTPUT\n"); 00793 #endif 00794 if (cap.capabilities & V4L2_CAP_RDS_CAPTURE) 00795 printf(" > Supports RDS capture\n"); 00796 if (cap.capabilities & V4L2_CAP_TUNER) 00797 printf(" > Has an RF tuner and/or modulator\n"); 00798 if (cap.capabilities & V4L2_CAP_AUDIO) 00799 printf(" > Supports audio input and/or output\n"); 00800 if (cap.capabilities & V4L2_CAP_READWRITE) 00801 printf(" > Supports read/write I/O method\n"); 00802 if (cap.capabilities & V4L2_CAP_ASYNCIO) 00803 printf(" > Supports asynchronous I/O method\n"); 00804 if (cap.capabilities & V4L2_CAP_STREAMING) 00805 printf(" > Supports streaming I/O (MMAP) method\n"); 00806 00807 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 00808 00809 // List available controls and their current settings: 00810 struct v4l2_queryctrl ctrl; 00811 int cid; 00812 for (cid = V4L2_CID_BASE; cid < V4L2_CID_LASTP1; cid ++) 00813 { 00814 memset(&ctrl, 0, sizeof(ctrl)); 00815 ctrl.id = cid; 00816 00817 // is that control supported? 00818 if (xioctl(fd, VIDIOC_QUERYCTRL, &ctrl) == 0 && 00819 ctrl.type != 0) 00820 { 00821 // first of all, if we have a ModelParam for it, let's 00822 // attempt to set the current value: 00823 struct v4l2_control control; control.id = cid; 00824 switch(cid) 00825 { 00826 case V4L2_CID_BRIGHTNESS: 00827 control.value = 127; 00828 if (xioctl(fd, VIDIOC_S_CTRL, &control) == -1) 00829 printf("Failed to set brightness to %d (VIDIOC_S_CTRL)\n", 00830 control.value); 00831 break; 00832 case V4L2_CID_CONTRAST: 00833 control.value = 32; 00834 if (xioctl(fd, VIDIOC_S_CTRL, &control) == -1) 00835 printf("Failed to set contrast to %d (VIDIOC_S_CTRL)\n", 00836 control.value); 00837 break; 00838 case V4L2_CID_WHITENESS: // NOTE this is = V4L2_CID_GAMMA 00839 // NOTE: bttv driver supports saturation but not whiteness 00840 // NOTE: macbook supports gamma 00841 /*control.value = 50; 00842 if (xioctl(fd, VIDIOC_S_CTRL, &control) == -1) 00843 printf("Failed to set whiteness to %d (VIDIOC_S_CTRL)\n", 00844 control.value);*/ 00845 break; 00846 case V4L2_CID_SATURATION: 00847 control.value = 39; 00848 if (xioctl(fd, VIDIOC_S_CTRL, &control) == -1) 00849 printf("Failed to set saturation to %d (VIDIOC_S_CTRL)\n", 00850 control.value); 00851 break; 00852 case V4L2_CID_HUE: 00853 control.value = 32768; 00854 if (xioctl(fd, VIDIOC_S_CTRL, &control) == -1) 00855 printf("Failed to set hue to %d (VIDIOC_S_CTRL)\n", 00856 control.value); 00857 break; 00858 00859 default: break; // Ignore other controls 00860 } 00861 00862 // ok, now get the current value, silently ignoring errors: 00863 int val = -1; 00864 if (xioctl(fd, VIDIOC_G_CTRL, &control) == 0) 00865 val = control.value; 00866 00867 switch(ctrl.type) 00868 { 00869 case V4L2_CTRL_TYPE_INTEGER: 00870 printf("CONTROL: %s=%d (Def=%d, Rng=[%d .. %d])%s\n", 00871 ctrl.name, val, ctrl.default_value, 00872 ctrl.minimum, ctrl.maximum, 00873 ctrl.flags & V4L2_CTRL_FLAG_DISABLED ? 00874 " (DISABLED)" : ""); 00875 break; 00876 00877 case V4L2_CTRL_TYPE_BOOLEAN: 00878 printf("CONTROL: %s=%s (Def=%s)%s\n", 00879 ctrl.name, val ? "true" : "false", 00880 ctrl.default_value ? "true" : "false", 00881 ctrl.flags & V4L2_CTRL_FLAG_DISABLED ? 00882 " (DISABLED)" : ""); 00883 break; 00884 00885 case V4L2_CTRL_TYPE_MENU: 00886 printf("CONTROL: %s=[menu type not yet implemented]%s\n", 00887 ctrl.name, 00888 ctrl.flags & V4L2_CTRL_FLAG_DISABLED ? 00889 " (DISABLED)" : ""); 00890 break; 00891 case V4L2_CTRL_TYPE_BUTTON: 00892 printf("CONTROL: %s=[button]%s\n", 00893 ctrl.name, 00894 ctrl.flags & V4L2_CTRL_FLAG_DISABLED ? 00895 " (DISABLED)" : ""); 00896 break; 00897 00898 default: break; 00899 } 00900 } 00901 } 00902 00903 // list available channels: 00904 int i; 00905 for (i = 0; ; i++) 00906 { 00907 struct v4l2_input inp; 00908 memset(&inp, 0, sizeof(inp)); 00909 inp.index = i; 00910 if (xioctl(fd, VIDIOC_ENUMINPUT, &inp) != 0) break; 00911 printf("Video input %d is '%s'\n", i, inp.name); 00912 } 00913 00914 00915 00916 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 00917 00918 if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { 00919 fprintf (stderr, "%s is no video capture device\n", 00920 dev_name); 00921 exit (EXIT_FAILURE); 00922 } 00923 00924 switch (io) { 00925 case IO_METHOD_READ: 00926 if (!(cap.capabilities & V4L2_CAP_READWRITE)) { 00927 fprintf (stderr, "%s does not support read i/o\n", 00928 dev_name); 00929 exit (EXIT_FAILURE); 00930 } 00931 00932 break; 00933 00934 case IO_METHOD_MMAP: 00935 case IO_METHOD_USERPTR: 00936 if (!(cap.capabilities & V4L2_CAP_STREAMING)) { 00937 fprintf (stderr, "%s does not support streaming i/o\n", 00938 dev_name); 00939 exit (EXIT_FAILURE); 00940 } 00941 00942 break; 00943 } 00944 00945 00946 /* Select video input, video standard and tune here. */ 00947 int channel = 0; 00948 if (xioctl(fd, VIDIOC_S_INPUT, &channel) < 0) 00949 printf("Cannot select video input %d\n", channel); 00950 else 00951 printf("Selected video input %d\n", channel); 00952 00953 00954 00955 // Reset cropping parameters and get resolution capabilities. NOTE: 00956 // just open()'ing the device does not reset it, according to the 00957 // unix toolchain philosophy. Hence, although here we do not provide 00958 // support for cropping, we still need to ensure that it is properly 00959 // reset: 00960 CLEAR (cropcap); 00961 cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 00962 00963 if (0 == xioctl (fd, VIDIOC_CROPCAP, &cropcap)) { 00964 printf("Video capture bounds: (%d, %d) -> (%d, %d)\n", 00965 cropcap.bounds.left, cropcap.bounds.top, 00966 cropcap.bounds.left + cropcap.bounds.width - 1, 00967 cropcap.bounds.top + cropcap.bounds.height - 1); 00968 printf("Video default capture rectangle: (%d, %d) -> (%d, %d)\n", 00969 cropcap.defrect.left, cropcap.defrect.top, 00970 cropcap.defrect.left + cropcap.defrect.width - 1, 00971 cropcap.defrect.top + cropcap.defrect.height - 1); 00972 00973 } else { 00974 printf("Failed to get cropping capabilities -- IGNORED.\n"); 00975 } 00976 00977 memset (&crop, 0, sizeof(crop)); 00978 crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 00979 crop.c = cropcap.defrect; 00980 if (xioctl(fd, VIDIOC_S_CROP, &crop) == -1) 00981 printf("Failed to reset cropping settings -- IGNORED.\n"); 00982 00983 00984 00985 // list available video formats and see which ones would work with 00986 // the requested resolution: 00987 CLEAR (fmt); 00988 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 00989 fmt.fmt.pix.width = width; 00990 fmt.fmt.pix.height = height; 00991 fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; 00992 int fmt_to_use = -1; // in case user selected "auto" format 00993 00994 for (i = 0; ; i ++) 00995 { 00996 struct v4l2_fmtdesc fdesc; 00997 memset(&fdesc, 0, sizeof(fdesc)); 00998 fdesc.index = i; 00999 fdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 01000 if (xioctl(fd, VIDIOC_ENUM_FMT, &fdesc) != 0) break; 01001 unsigned int f; 01002 for (f = 0; f < (unsigned int)SALGLASSES_VIDFMT_AUTO; f ++) 01003 if (v4l2format[f] == fdesc.pixelformat) break; 01004 01005 // try to see whether that would work with our given image dims: 01006 fmt.fmt.pix.pixelformat = fdesc.pixelformat; 01007 int worked = 0; 01008 if (xioctl(fd, VIDIOC_TRY_FMT, &fmt) == 0) 01009 { 01010 worked = 1; 01011 if (fmt_to_use == -1) fmt_to_use = fdesc.pixelformat; 01012 } 01013 printf("Video Format: Use '%i' for '%s (Fourcc: %c%c%c%c)'%s%s\n", 01014 f == SALGLASSES_VIDFMT_AUTO ? -1 : f, 01015 fdesc.description, 01016 ((char*)(&fdesc.pixelformat))[0], 01017 ((char*)(&fdesc.pixelformat))[1], 01018 ((char*)(&fdesc.pixelformat))[2], 01019 ((char*)(&fdesc.pixelformat))[3], 01020 fdesc.flags & V4L2_FMT_FLAG_COMPRESSED ? " (COMPRESSED)" : "", 01021 worked ? " [OK]" : " [FAILED TO SET]"); 01022 } 01023 printf("Using format %i\n", fmt_to_use); 01024 01025 // Get the frame time, according to current video standard: 01026 struct v4l2_streamparm sparm; 01027 memset(&sparm, 0, sizeof(sparm)); 01028 sparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 01029 if (xioctl(fd, VIDIOC_G_PARM, &sparm) == -1) 01030 { 01031 printf("Cannot get video standard params - ASSUMING NTSC\n"); 01032 } 01033 else 01034 printf("Capture at %.2f fps\n", 01035 (float)sparm.parm.capture.timeperframe.numerator/ 01036 (float)sparm.parm.capture.timeperframe.denominator); 01037 01038 //fmt.fmt.pix.pixelformat = fmt_to_use; 01039 fmt.fmt.pix.pixelformat = v4l2format[11]; 01040 01041 if (xioctl(fd, VIDIOC_S_FMT, &fmt) == -1) 01042 printf("Cannot set requested video mode/resolution %i [%dx%d], probably unsupported by hardware.", 01043 fmt_to_use, width, height); 01044 01045 if (xioctl(fd, VIDIOC_G_FMT, &fmt) == 0) 01046 printf("Video mode/resolution set to %i [%dx%d]\n", 01047 fmt_to_use, 01048 fmt.fmt.pix.width, fmt.fmt.pix.height); 01049 01050 if ((int)fmt.fmt.pix.width != width || 01051 (int)fmt.fmt.pix.height != height) 01052 printf("Hardware suggests changing input dims to %dx%d instead of " 01053 "requested %dx%d\n", 01054 fmt.fmt.pix.width, fmt.fmt.pix.height, 01055 width, height); 01056 01057 width = fmt.fmt.pix.width; 01058 height = fmt.fmt.pix.height; 01059 01060 01061 /* Note VIDIOC_S_FMT may change width and height. */ 01062 01063 switch (io) { 01064 case IO_METHOD_READ: 01065 init_read (fmt.fmt.pix.sizeimage); 01066 break; 01067 01068 case IO_METHOD_MMAP: 01069 printf("Using MMap\n"); 01070 init_mmap (); 01071 break; 01072 01073 case IO_METHOD_USERPTR: 01074 init_userp (fmt.fmt.pix.sizeimage); 01075 break; 01076 } 01077 } 01078 01079 void close_device(void) 01080 { 01081 if (-1 == close (fd)) 01082 errno_exit ("close"); 01083 01084 fd = -1; 01085 } 01086 01087 void open_device(void) 01088 { 01089 struct stat st; 01090 01091 if (-1 == stat (dev_name, &st)) { 01092 fprintf (stderr, "Cannot identify '%s': %d, %s\n", 01093 dev_name, errno, strerror (errno)); 01094 exit (EXIT_FAILURE); 01095 } 01096 01097 if (!S_ISCHR (st.st_mode)) { 01098 fprintf (stderr, "%s is no device\n", dev_name); 01099 exit (EXIT_FAILURE); 01100 } 01101 01102 fd = open (dev_name, O_RDWR /* required */ | O_NONBLOCK, 0); 01103 01104 if (-1 == fd) { 01105 fprintf (stderr, "Cannot open '%s': %d, %s\n", 01106 dev_name, errno, strerror (errno)); 01107 exit (EXIT_FAILURE); 01108 } 01109 }