1 .. SPDX-License-Identifier: GFDL-1.1-no-invari 1 .. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later 2 2 3 file: media/v4l/capture.c 3 file: media/v4l/capture.c 4 ========================= 4 ========================= 5 5 6 .. code-block:: c 6 .. code-block:: c 7 7 8 /* 8 /* 9 * V4L2 video capture example 9 * V4L2 video capture example 10 * 10 * 11 * This program can be used and distribut 11 * This program can be used and distributed without restrictions. 12 * 12 * 13 * This program is provided with the 13 * This program is provided with the V4L2 API 14 * see https://linuxtv.org/docs.php for mo 14 * see https://linuxtv.org/docs.php for more information 15 */ 15 */ 16 16 17 #include <stdio.h> 17 #include <stdio.h> 18 #include <stdlib.h> 18 #include <stdlib.h> 19 #include <string.h> 19 #include <string.h> 20 #include <assert.h> 20 #include <assert.h> 21 21 22 #include <getopt.h> /* getopt_ 22 #include <getopt.h> /* getopt_long() */ 23 23 24 #include <fcntl.h> /* low-lev 24 #include <fcntl.h> /* low-level i/o */ 25 #include <unistd.h> 25 #include <unistd.h> 26 #include <errno.h> 26 #include <errno.h> 27 #include <sys/stat.h> 27 #include <sys/stat.h> 28 #include <sys/types.h> 28 #include <sys/types.h> 29 #include <sys/time.h> 29 #include <sys/time.h> 30 #include <sys/mman.h> 30 #include <sys/mman.h> 31 #include <sys/ioctl.h> 31 #include <sys/ioctl.h> 32 32 33 #include <linux/videodev2.h> 33 #include <linux/videodev2.h> 34 34 35 #define CLEAR(x) memset(&(x), 0, sizeof(x) 35 #define CLEAR(x) memset(&(x), 0, sizeof(x)) 36 36 37 enum io_method { 37 enum io_method { 38 IO_METHOD_READ, 38 IO_METHOD_READ, 39 IO_METHOD_MMAP, 39 IO_METHOD_MMAP, 40 IO_METHOD_USERPTR, 40 IO_METHOD_USERPTR, 41 }; 41 }; 42 42 43 struct buffer { 43 struct buffer { 44 void *start; 44 void *start; 45 size_t length; 45 size_t length; 46 }; 46 }; 47 47 48 static char *dev_name; 48 static char *dev_name; 49 static enum io_method io = IO_METHOD_MMA 49 static enum io_method io = IO_METHOD_MMAP; 50 static int fd = -1; 50 static int fd = -1; 51 struct buffer *buffers; 51 struct buffer *buffers; 52 static unsigned int n_buffers; 52 static unsigned int n_buffers; 53 static int out_buf; 53 static int out_buf; 54 static int force_format; 54 static int force_format; 55 static int frame_count = 70; 55 static int frame_count = 70; 56 56 57 static void errno_exit(const char *s) 57 static void errno_exit(const char *s) 58 { 58 { 59 fprintf(stderr, "%s error %d, %s\n 59 fprintf(stderr, "%s error %d, %s\n", s, errno, strerror(errno)); 60 exit(EXIT_FAILURE); 60 exit(EXIT_FAILURE); 61 } 61 } 62 62 63 static int xioctl(int fh, int request, voi 63 static int xioctl(int fh, int request, void *arg) 64 { 64 { 65 int r; 65 int r; 66 66 67 do { 67 do { 68 r = ioctl(fh, request, arg 68 r = ioctl(fh, request, arg); 69 } while (-1 == r && EINTR == errno 69 } while (-1 == r && EINTR == errno); 70 70 71 return r; 71 return r; 72 } 72 } 73 73 74 static void process_image(const void *p, i 74 static void process_image(const void *p, int size) 75 { 75 { 76 if (out_buf) 76 if (out_buf) 77 fwrite(p, size, 1, stdout) 77 fwrite(p, size, 1, stdout); 78 78 79 fflush(stderr); 79 fflush(stderr); 80 fprintf(stderr, "."); 80 fprintf(stderr, "."); 81 fflush(stdout); 81 fflush(stdout); 82 } 82 } 83 83 84 static int read_frame(void) 84 static int read_frame(void) 85 { 85 { 86 struct v4l2_buffer buf; 86 struct v4l2_buffer buf; 87 unsigned int i; 87 unsigned int i; 88 88 89 switch (io) { 89 switch (io) { 90 case IO_METHOD_READ: 90 case IO_METHOD_READ: 91 if (-1 == read(fd, buffers 91 if (-1 == read(fd, buffers[0].start, buffers[0].length)) { 92 switch (errno) { 92 switch (errno) { 93 case EAGAIN: 93 case EAGAIN: 94 return 0; 94 return 0; 95 95 96 case EIO: 96 case EIO: 97 /* Could i 97 /* Could ignore EIO, see spec. */ 98 98 99 /* fall th 99 /* fall through */ 100 100 101 default: 101 default: 102 errno_exit 102 errno_exit("read"); 103 } 103 } 104 } 104 } 105 105 106 process_image(buffers[0].s 106 process_image(buffers[0].start, buffers[0].length); 107 break; 107 break; 108 108 109 case IO_METHOD_MMAP: 109 case IO_METHOD_MMAP: 110 CLEAR(buf); 110 CLEAR(buf); 111 111 112 buf.type = V4L2_BUF_TYPE_V 112 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 113 buf.memory = V4L2_MEMORY_M 113 buf.memory = V4L2_MEMORY_MMAP; 114 114 115 if (-1 == xioctl(fd, VIDIO 115 if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) { 116 switch (errno) { 116 switch (errno) { 117 case EAGAIN: 117 case EAGAIN: 118 return 0; 118 return 0; 119 119 120 case EIO: 120 case EIO: 121 /* Could i 121 /* Could ignore EIO, see spec. */ 122 122 123 /* fall th 123 /* fall through */ 124 124 125 default: 125 default: 126 errno_exit 126 errno_exit("VIDIOC_DQBUF"); 127 } 127 } 128 } 128 } 129 129 130 assert(buf.index < n_buffe 130 assert(buf.index < n_buffers); 131 131 132 process_image(buffers[buf. 132 process_image(buffers[buf.index].start, buf.bytesused); 133 133 134 if (-1 == xioctl(fd, VIDIO 134 if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) 135 errno_exit("VIDIOC 135 errno_exit("VIDIOC_QBUF"); 136 break; 136 break; 137 137 138 case IO_METHOD_USERPTR: 138 case IO_METHOD_USERPTR: 139 CLEAR(buf); 139 CLEAR(buf); 140 140 141 buf.type = V4L2_BUF_TYPE_V 141 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 142 buf.memory = V4L2_MEMORY_U 142 buf.memory = V4L2_MEMORY_USERPTR; 143 143 144 if (-1 == xioctl(fd, VIDIO 144 if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) { 145 switch (errno) { 145 switch (errno) { 146 case EAGAIN: 146 case EAGAIN: 147 return 0; 147 return 0; 148 148 149 case EIO: 149 case EIO: 150 /* Could i 150 /* Could ignore EIO, see spec. */ 151 151 152 /* fall th 152 /* fall through */ 153 153 154 default: 154 default: 155 errno_exit 155 errno_exit("VIDIOC_DQBUF"); 156 } 156 } 157 } 157 } 158 158 159 for (i = 0; i < n_buffers; 159 for (i = 0; i < n_buffers; ++i) 160 if (buf.m.userptr 160 if (buf.m.userptr == (unsigned long)buffers[i].start 161 && buf.length 161 && buf.length == buffers[i].length) 162 break; 162 break; 163 163 164 assert(i < n_buffers); 164 assert(i < n_buffers); 165 165 166 process_image((void *)buf. 166 process_image((void *)buf.m.userptr, buf.bytesused); 167 167 168 if (-1 == xioctl(fd, VIDIO 168 if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) 169 errno_exit("VIDIOC 169 errno_exit("VIDIOC_QBUF"); 170 break; 170 break; 171 } 171 } 172 172 173 return 1; 173 return 1; 174 } 174 } 175 175 176 static void mainloop(void) 176 static void mainloop(void) 177 { 177 { 178 unsigned int count; 178 unsigned int count; 179 179 180 count = frame_count; 180 count = frame_count; 181 181 182 while (count-- > 0) { 182 while (count-- > 0) { 183 for (;;) { 183 for (;;) { 184 fd_set fds; 184 fd_set fds; 185 struct timeval tv; 185 struct timeval tv; 186 int r; 186 int r; 187 187 188 FD_ZERO(&fds); 188 FD_ZERO(&fds); 189 FD_SET(fd, &fds); 189 FD_SET(fd, &fds); 190 190 191 /* Timeout. */ 191 /* Timeout. */ 192 tv.tv_sec = 2; 192 tv.tv_sec = 2; 193 tv.tv_usec = 0; 193 tv.tv_usec = 0; 194 194 195 r = select(fd + 1, 195 r = select(fd + 1, &fds, NULL, NULL, &tv); 196 196 197 if (-1 == r) { 197 if (-1 == r) { 198 if (EINTR 198 if (EINTR == errno) 199 co 199 continue; 200 errno_exit 200 errno_exit("select"); 201 } 201 } 202 202 203 if (0 == r) { 203 if (0 == r) { 204 fprintf(st 204 fprintf(stderr, "select timeout\n"); 205 exit(EXIT_ 205 exit(EXIT_FAILURE); 206 } 206 } 207 207 208 if (read_frame()) 208 if (read_frame()) 209 break; 209 break; 210 /* EAGAIN - contin 210 /* EAGAIN - continue select loop. */ 211 } 211 } 212 } 212 } 213 } 213 } 214 214 215 static void stop_capturing(void) 215 static void stop_capturing(void) 216 { 216 { 217 enum v4l2_buf_type type; 217 enum v4l2_buf_type type; 218 218 219 switch (io) { 219 switch (io) { 220 case IO_METHOD_READ: 220 case IO_METHOD_READ: 221 /* Nothing to do. */ 221 /* Nothing to do. */ 222 break; 222 break; 223 223 224 case IO_METHOD_MMAP: 224 case IO_METHOD_MMAP: 225 case IO_METHOD_USERPTR: 225 case IO_METHOD_USERPTR: 226 type = V4L2_BUF_TYPE_VIDEO 226 type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 227 if (-1 == xioctl(fd, VIDIO 227 if (-1 == xioctl(fd, VIDIOC_STREAMOFF, &type)) 228 errno_exit("VIDIOC 228 errno_exit("VIDIOC_STREAMOFF"); 229 break; 229 break; 230 } 230 } 231 } 231 } 232 232 233 static void start_capturing(void) 233 static void start_capturing(void) 234 { 234 { 235 unsigned int i; 235 unsigned int i; 236 enum v4l2_buf_type type; 236 enum v4l2_buf_type type; 237 237 238 switch (io) { 238 switch (io) { 239 case IO_METHOD_READ: 239 case IO_METHOD_READ: 240 /* Nothing to do. */ 240 /* Nothing to do. */ 241 break; 241 break; 242 242 243 case IO_METHOD_MMAP: 243 case IO_METHOD_MMAP: 244 for (i = 0; i < n_buffers; 244 for (i = 0; i < n_buffers; ++i) { 245 struct v4l2_buffer 245 struct v4l2_buffer buf; 246 246 247 CLEAR(buf); 247 CLEAR(buf); 248 buf.type = V4L2_BU 248 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 249 buf.memory = V4L2_ 249 buf.memory = V4L2_MEMORY_MMAP; 250 buf.index = i; 250 buf.index = i; 251 251 252 if (-1 == xioctl(f 252 if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) 253 errno_exit 253 errno_exit("VIDIOC_QBUF"); 254 } 254 } 255 type = V4L2_BUF_TYPE_VIDEO 255 type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 256 if (-1 == xioctl(fd, VIDIO 256 if (-1 == xioctl(fd, VIDIOC_STREAMON, &type)) 257 errno_exit("VIDIOC 257 errno_exit("VIDIOC_STREAMON"); 258 break; 258 break; 259 259 260 case IO_METHOD_USERPTR: 260 case IO_METHOD_USERPTR: 261 for (i = 0; i < n_buffers; 261 for (i = 0; i < n_buffers; ++i) { 262 struct v4l2_buffer 262 struct v4l2_buffer buf; 263 263 264 CLEAR(buf); 264 CLEAR(buf); 265 buf.type = V4L2_BU 265 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 266 buf.memory = V4L2_ 266 buf.memory = V4L2_MEMORY_USERPTR; 267 buf.index = i; 267 buf.index = i; 268 buf.m.userptr = (u 268 buf.m.userptr = (unsigned long)buffers[i].start; 269 buf.length = buffe 269 buf.length = buffers[i].length; 270 270 271 if (-1 == xioctl(f 271 if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) 272 errno_exit 272 errno_exit("VIDIOC_QBUF"); 273 } 273 } 274 type = V4L2_BUF_TYPE_VIDEO 274 type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 275 if (-1 == xioctl(fd, VIDIO 275 if (-1 == xioctl(fd, VIDIOC_STREAMON, &type)) 276 errno_exit("VIDIOC 276 errno_exit("VIDIOC_STREAMON"); 277 break; 277 break; 278 } 278 } 279 } 279 } 280 280 281 static void uninit_device(void) 281 static void uninit_device(void) 282 { 282 { 283 unsigned int i; 283 unsigned int i; 284 284 285 switch (io) { 285 switch (io) { 286 case IO_METHOD_READ: 286 case IO_METHOD_READ: 287 free(buffers[0].start); 287 free(buffers[0].start); 288 break; 288 break; 289 289 290 case IO_METHOD_MMAP: 290 case IO_METHOD_MMAP: 291 for (i = 0; i < n_buffers; 291 for (i = 0; i < n_buffers; ++i) 292 if (-1 == munmap(b 292 if (-1 == munmap(buffers[i].start, buffers[i].length)) 293 errno_exit 293 errno_exit("munmap"); 294 break; 294 break; 295 295 296 case IO_METHOD_USERPTR: 296 case IO_METHOD_USERPTR: 297 for (i = 0; i < n_buffers; 297 for (i = 0; i < n_buffers; ++i) 298 free(buffers[i].st 298 free(buffers[i].start); 299 break; 299 break; 300 } 300 } 301 301 302 free(buffers); 302 free(buffers); 303 } 303 } 304 304 305 static void init_read(unsigned int buffer_ 305 static void init_read(unsigned int buffer_size) 306 { 306 { 307 buffers = calloc(1, sizeof(*buffer 307 buffers = calloc(1, sizeof(*buffers)); 308 308 309 if (!buffers) { 309 if (!buffers) { 310 fprintf(stderr, "Out of me 310 fprintf(stderr, "Out of memory\n"); 311 exit(EXIT_FAILURE); 311 exit(EXIT_FAILURE); 312 } 312 } 313 313 314 buffers[0].length = buffer_size; 314 buffers[0].length = buffer_size; 315 buffers[0].start = malloc(buffer_s 315 buffers[0].start = malloc(buffer_size); 316 316 317 if (!buffers[0].start) { 317 if (!buffers[0].start) { 318 fprintf(stderr, "Out of me 318 fprintf(stderr, "Out of memory\n"); 319 exit(EXIT_FAILURE); 319 exit(EXIT_FAILURE); 320 } 320 } 321 } 321 } 322 322 323 static void init_mmap(void) 323 static void init_mmap(void) 324 { 324 { 325 struct v4l2_requestbuffers req; 325 struct v4l2_requestbuffers req; 326 326 327 CLEAR(req); 327 CLEAR(req); 328 328 329 req.count = 4; 329 req.count = 4; 330 req.type = V4L2_BUF_TYPE_VIDEO_CAP 330 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 331 req.memory = V4L2_MEMORY_MMAP; 331 req.memory = V4L2_MEMORY_MMAP; 332 332 333 if (-1 == xioctl(fd, VIDIOC_REQBUF 333 if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) { 334 if (EINVAL == errno) { 334 if (EINVAL == errno) { 335 fprintf(stderr, "% 335 fprintf(stderr, "%s does not support " 336 "memory m 336 "memory mapping\n", dev_name); 337 exit(EXIT_FAILURE) 337 exit(EXIT_FAILURE); 338 } else { 338 } else { 339 errno_exit("VIDIOC 339 errno_exit("VIDIOC_REQBUFS"); 340 } 340 } 341 } 341 } 342 342 343 if (req.count < 2) { 343 if (req.count < 2) { 344 fprintf(stderr, "Insuffici 344 fprintf(stderr, "Insufficient buffer memory on %s\n", 345 dev_name); 345 dev_name); 346 exit(EXIT_FAILURE); 346 exit(EXIT_FAILURE); 347 } 347 } 348 348 349 buffers = calloc(req.count, sizeof 349 buffers = calloc(req.count, sizeof(*buffers)); 350 350 351 if (!buffers) { 351 if (!buffers) { 352 fprintf(stderr, "Out of me 352 fprintf(stderr, "Out of memory\n"); 353 exit(EXIT_FAILURE); 353 exit(EXIT_FAILURE); 354 } 354 } 355 355 356 for (n_buffers = 0; n_buffers < re 356 for (n_buffers = 0; n_buffers < req.count; ++n_buffers) { 357 struct v4l2_buffer buf; 357 struct v4l2_buffer buf; 358 358 359 CLEAR(buf); 359 CLEAR(buf); 360 360 361 buf.type = V4L2_BUF 361 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 362 buf.memory = V4L2_MEM 362 buf.memory = V4L2_MEMORY_MMAP; 363 buf.index = n_buffer 363 buf.index = n_buffers; 364 364 365 if (-1 == xioctl(fd, VIDIO 365 if (-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf)) 366 errno_exit("VIDIOC 366 errno_exit("VIDIOC_QUERYBUF"); 367 367 368 buffers[n_buffers].length 368 buffers[n_buffers].length = buf.length; 369 buffers[n_buffers].start = 369 buffers[n_buffers].start = 370 mmap(NULL /* start 370 mmap(NULL /* start anywhere */, 371 buf.length, 371 buf.length, 372 PROT_READ | 372 PROT_READ | PROT_WRITE /* required */, 373 MAP_SHARED / 373 MAP_SHARED /* recommended */, 374 fd, buf.m.of 374 fd, buf.m.offset); 375 375 376 if (MAP_FAILED == buffers[ 376 if (MAP_FAILED == buffers[n_buffers].start) 377 errno_exit("mmap") 377 errno_exit("mmap"); 378 } 378 } 379 } 379 } 380 380 381 static void init_userp(unsigned int buffer 381 static void init_userp(unsigned int buffer_size) 382 { 382 { 383 struct v4l2_requestbuffers req; 383 struct v4l2_requestbuffers req; 384 384 385 CLEAR(req); 385 CLEAR(req); 386 386 387 req.count = 4; 387 req.count = 4; 388 req.type = V4L2_BUF_TYPE_VIDEO_C 388 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 389 req.memory = V4L2_MEMORY_USERPTR; 389 req.memory = V4L2_MEMORY_USERPTR; 390 390 391 if (-1 == xioctl(fd, VIDIOC_REQBUF 391 if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) { 392 if (EINVAL == errno) { 392 if (EINVAL == errno) { 393 fprintf(stderr, "% 393 fprintf(stderr, "%s does not support " 394 "user poi 394 "user pointer i/o\n", dev_name); 395 exit(EXIT_FAILURE) 395 exit(EXIT_FAILURE); 396 } else { 396 } else { 397 errno_exit("VIDIOC 397 errno_exit("VIDIOC_REQBUFS"); 398 } 398 } 399 } 399 } 400 400 401 buffers = calloc(4, sizeof(*buffer 401 buffers = calloc(4, sizeof(*buffers)); 402 402 403 if (!buffers) { 403 if (!buffers) { 404 fprintf(stderr, "Out of me 404 fprintf(stderr, "Out of memory\n"); 405 exit(EXIT_FAILURE); 405 exit(EXIT_FAILURE); 406 } 406 } 407 407 408 for (n_buffers = 0; n_buffers < 4; 408 for (n_buffers = 0; n_buffers < 4; ++n_buffers) { 409 buffers[n_buffers].length 409 buffers[n_buffers].length = buffer_size; 410 buffers[n_buffers].start = 410 buffers[n_buffers].start = malloc(buffer_size); 411 411 412 if (!buffers[n_buffers].st 412 if (!buffers[n_buffers].start) { 413 fprintf(stderr, "O 413 fprintf(stderr, "Out of memory\n"); 414 exit(EXIT_FAILURE) 414 exit(EXIT_FAILURE); 415 } 415 } 416 } 416 } 417 } 417 } 418 418 419 static void init_device(void) 419 static void init_device(void) 420 { 420 { 421 struct v4l2_capability cap; 421 struct v4l2_capability cap; 422 struct v4l2_cropcap cropcap; 422 struct v4l2_cropcap cropcap; 423 struct v4l2_crop crop; 423 struct v4l2_crop crop; 424 struct v4l2_format fmt; 424 struct v4l2_format fmt; 425 unsigned int min; 425 unsigned int min; 426 426 427 if (-1 == xioctl(fd, VIDIOC_QUERYC 427 if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &cap)) { 428 if (EINVAL == errno) { 428 if (EINVAL == errno) { 429 fprintf(stderr, "% 429 fprintf(stderr, "%s is no V4L2 device\n", 430 dev_name) 430 dev_name); 431 exit(EXIT_FAILURE) 431 exit(EXIT_FAILURE); 432 } else { 432 } else { 433 errno_exit("VIDIOC 433 errno_exit("VIDIOC_QUERYCAP"); 434 } 434 } 435 } 435 } 436 436 437 if (!(cap.capabilities & V4L2_CAP_ 437 if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { 438 fprintf(stderr, "%s is no 438 fprintf(stderr, "%s is no video capture device\n", 439 dev_name); 439 dev_name); 440 exit(EXIT_FAILURE); 440 exit(EXIT_FAILURE); 441 } 441 } 442 442 443 switch (io) { 443 switch (io) { 444 case IO_METHOD_READ: 444 case IO_METHOD_READ: 445 if (!(cap.capabilities & V 445 if (!(cap.capabilities & V4L2_CAP_READWRITE)) { 446 fprintf(stderr, "% 446 fprintf(stderr, "%s does not support read i/o\n", 447 dev_name) 447 dev_name); 448 exit(EXIT_FAILURE) 448 exit(EXIT_FAILURE); 449 } 449 } 450 break; 450 break; 451 451 452 case IO_METHOD_MMAP: 452 case IO_METHOD_MMAP: 453 case IO_METHOD_USERPTR: 453 case IO_METHOD_USERPTR: 454 if (!(cap.capabilities & V 454 if (!(cap.capabilities & V4L2_CAP_STREAMING)) { 455 fprintf(stderr, "% 455 fprintf(stderr, "%s does not support streaming i/o\n", 456 dev_name) 456 dev_name); 457 exit(EXIT_FAILURE) 457 exit(EXIT_FAILURE); 458 } 458 } 459 break; 459 break; 460 } 460 } 461 461 462 462 463 /* Select video input, video stand 463 /* Select video input, video standard and tune here. */ 464 464 465 465 466 CLEAR(cropcap); 466 CLEAR(cropcap); 467 467 468 cropcap.type = V4L2_BUF_TYPE_VIDEO 468 cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 469 469 470 if (0 == xioctl(fd, VIDIOC_CROPCAP 470 if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap)) { 471 crop.type = V4L2_BUF_TYPE_ 471 crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 472 crop.c = cropcap.defrect; 472 crop.c = cropcap.defrect; /* reset to default */ 473 473 474 if (-1 == xioctl(fd, VIDIO 474 if (-1 == xioctl(fd, VIDIOC_S_CROP, &crop)) { 475 switch (errno) { 475 switch (errno) { 476 case EINVAL: 476 case EINVAL: 477 /* Croppin 477 /* Cropping not supported. */ 478 break; 478 break; 479 default: 479 default: 480 /* Errors 480 /* Errors ignored. */ 481 break; 481 break; 482 } 482 } 483 } 483 } 484 } else { 484 } else { 485 /* Errors ignored. */ 485 /* Errors ignored. */ 486 } 486 } 487 487 488 488 489 CLEAR(fmt); 489 CLEAR(fmt); 490 490 491 fmt.type = V4L2_BUF_TYPE_VIDEO_CAP 491 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 492 if (force_format) { 492 if (force_format) { 493 fmt.fmt.pix.width = 493 fmt.fmt.pix.width = 640; 494 fmt.fmt.pix.height = 494 fmt.fmt.pix.height = 480; 495 fmt.fmt.pix.pixelformat = 495 fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; 496 fmt.fmt.pix.field = 496 fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; 497 497 498 if (-1 == xioctl(fd, VIDIO 498 if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt)) 499 errno_exit("VIDIOC 499 errno_exit("VIDIOC_S_FMT"); 500 500 501 /* Note VIDIOC_S_FMT may c 501 /* Note VIDIOC_S_FMT may change width and height. */ 502 } else { 502 } else { 503 /* Preserve original setti 503 /* Preserve original settings as set by v4l2-ctl for example */ 504 if (-1 == xioctl(fd, VIDIO 504 if (-1 == xioctl(fd, VIDIOC_G_FMT, &fmt)) 505 errno_exit("VIDIOC 505 errno_exit("VIDIOC_G_FMT"); 506 } 506 } 507 507 508 /* Buggy driver paranoia. */ 508 /* Buggy driver paranoia. */ 509 min = fmt.fmt.pix.width * 2; 509 min = fmt.fmt.pix.width * 2; 510 if (fmt.fmt.pix.bytesperline < min 510 if (fmt.fmt.pix.bytesperline < min) 511 fmt.fmt.pix.bytesperline = 511 fmt.fmt.pix.bytesperline = min; 512 min = fmt.fmt.pix.bytesperline * f 512 min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height; 513 if (fmt.fmt.pix.sizeimage < min) 513 if (fmt.fmt.pix.sizeimage < min) 514 fmt.fmt.pix.sizeimage = mi 514 fmt.fmt.pix.sizeimage = min; 515 515 516 switch (io) { 516 switch (io) { 517 case IO_METHOD_READ: 517 case IO_METHOD_READ: 518 init_read(fmt.fmt.pix.size 518 init_read(fmt.fmt.pix.sizeimage); 519 break; 519 break; 520 520 521 case IO_METHOD_MMAP: 521 case IO_METHOD_MMAP: 522 init_mmap(); 522 init_mmap(); 523 break; 523 break; 524 524 525 case IO_METHOD_USERPTR: 525 case IO_METHOD_USERPTR: 526 init_userp(fmt.fmt.pix.siz 526 init_userp(fmt.fmt.pix.sizeimage); 527 break; 527 break; 528 } 528 } 529 } 529 } 530 530 531 static void close_device(void) 531 static void close_device(void) 532 { 532 { 533 if (-1 == close(fd)) 533 if (-1 == close(fd)) 534 errno_exit("close"); 534 errno_exit("close"); 535 535 536 fd = -1; 536 fd = -1; 537 } 537 } 538 538 539 static void open_device(void) 539 static void open_device(void) 540 { 540 { 541 struct stat st; 541 struct stat st; 542 542 543 if (-1 == stat(dev_name, &st)) { 543 if (-1 == stat(dev_name, &st)) { 544 fprintf(stderr, "Cannot id 544 fprintf(stderr, "Cannot identify '%s': %d, %s\n", 545 dev_name, errno, 545 dev_name, errno, strerror(errno)); 546 exit(EXIT_FAILURE); 546 exit(EXIT_FAILURE); 547 } 547 } 548 548 549 if (!S_ISCHR(st.st_mode)) { 549 if (!S_ISCHR(st.st_mode)) { 550 fprintf(stderr, "%s is no 550 fprintf(stderr, "%s is no device\n", dev_name); 551 exit(EXIT_FAILURE); 551 exit(EXIT_FAILURE); 552 } 552 } 553 553 554 fd = open(dev_name, O_RDWR /* requ 554 fd = open(dev_name, O_RDWR /* required */ | O_NONBLOCK, 0); 555 555 556 if (-1 == fd) { 556 if (-1 == fd) { 557 fprintf(stderr, "Cannot op 557 fprintf(stderr, "Cannot open '%s': %d, %s\n", 558 dev_name, errno, 558 dev_name, errno, strerror(errno)); 559 exit(EXIT_FAILURE); 559 exit(EXIT_FAILURE); 560 } 560 } 561 } 561 } 562 562 563 static void usage(FILE *fp, int argc, char 563 static void usage(FILE *fp, int argc, char **argv) 564 { 564 { 565 fprintf(fp, 565 fprintf(fp, 566 "Usage: %s [options]\n\n" 566 "Usage: %s [options]\n\n" 567 "Version 1.3\n" 567 "Version 1.3\n" 568 "Options:\n" 568 "Options:\n" 569 "-d | --device name Vid 569 "-d | --device name Video device name [%s]\n" 570 "-h | --help Pri 570 "-h | --help Print this message\n" 571 "-m | --mmap Use 571 "-m | --mmap Use memory mapped buffers [default]\n" 572 "-r | --read Use 572 "-r | --read Use read() calls\n" 573 "-u | --userp Use 573 "-u | --userp Use application allocated buffers\n" 574 "-o | --output Out 574 "-o | --output Outputs stream to stdout\n" 575 "-f | --format For 575 "-f | --format Force format to 640x480 YUYV\n" 576 "-c | --count Num 576 "-c | --count Number of frames to grab [%i]\n" 577 "", 577 "", 578 argv[0], dev_name, frame_ 578 argv[0], dev_name, frame_count); 579 } 579 } 580 580 581 static const char short_options[] = "d:hmr 581 static const char short_options[] = "d:hmruofc:"; 582 582 583 static const struct option 583 static const struct option 584 long_options[] = { 584 long_options[] = { 585 { "device", required_argument, NUL 585 { "device", required_argument, NULL, 'd' }, 586 { "help", no_argument, NUL 586 { "help", no_argument, NULL, 'h' }, 587 { "mmap", no_argument, NUL 587 { "mmap", no_argument, NULL, 'm' }, 588 { "read", no_argument, NUL 588 { "read", no_argument, NULL, 'r' }, 589 { "userp", no_argument, NUL 589 { "userp", no_argument, NULL, 'u' }, 590 { "output", no_argument, NUL 590 { "output", no_argument, NULL, 'o' }, 591 { "format", no_argument, NUL 591 { "format", no_argument, NULL, 'f' }, 592 { "count", required_argument, NUL 592 { "count", required_argument, NULL, 'c' }, 593 { 0, 0, 0, 0 } 593 { 0, 0, 0, 0 } 594 }; 594 }; 595 595 596 int main(int argc, char **argv) 596 int main(int argc, char **argv) 597 { 597 { 598 dev_name = "/dev/video0"; 598 dev_name = "/dev/video0"; 599 599 600 for (;;) { 600 for (;;) { 601 int idx; 601 int idx; 602 int c; 602 int c; 603 603 604 c = getopt_long(argc, argv 604 c = getopt_long(argc, argv, 605 short_opti 605 short_options, long_options, &idx); 606 606 607 if (-1 == c) 607 if (-1 == c) 608 break; 608 break; 609 609 610 switch (c) { 610 switch (c) { 611 case 0: /* getopt_long() f 611 case 0: /* getopt_long() flag */ 612 break; 612 break; 613 613 614 case 'd': 614 case 'd': 615 dev_name = optarg; 615 dev_name = optarg; 616 break; 616 break; 617 617 618 case 'h': 618 case 'h': 619 usage(stdout, argc 619 usage(stdout, argc, argv); 620 exit(EXIT_SUCCESS) 620 exit(EXIT_SUCCESS); 621 621 622 case 'm': 622 case 'm': 623 io = IO_METHOD_MMA 623 io = IO_METHOD_MMAP; 624 break; 624 break; 625 625 626 case 'r': 626 case 'r': 627 io = IO_METHOD_REA 627 io = IO_METHOD_READ; 628 break; 628 break; 629 629 630 case 'u': 630 case 'u': 631 io = IO_METHOD_USE 631 io = IO_METHOD_USERPTR; 632 break; 632 break; 633 633 634 case 'o': 634 case 'o': 635 out_buf++; 635 out_buf++; 636 break; 636 break; 637 637 638 case 'f': 638 case 'f': 639 force_format++; 639 force_format++; 640 break; 640 break; 641 641 642 case 'c': 642 case 'c': 643 errno = 0; 643 errno = 0; 644 frame_count = strt 644 frame_count = strtol(optarg, NULL, 0); 645 if (errno) 645 if (errno) 646 errno_exit 646 errno_exit(optarg); 647 break; 647 break; 648 648 649 default: 649 default: 650 usage(stderr, argc 650 usage(stderr, argc, argv); 651 exit(EXIT_FAILURE) 651 exit(EXIT_FAILURE); 652 } 652 } 653 } 653 } 654 654 655 open_device(); 655 open_device(); 656 init_device(); 656 init_device(); 657 start_capturing(); 657 start_capturing(); 658 mainloop(); 658 mainloop(); 659 stop_capturing(); 659 stop_capturing(); 660 uninit_device(); 660 uninit_device(); 661 close_device(); 661 close_device(); 662 fprintf(stderr, "\n"); 662 fprintf(stderr, "\n"); 663 return 0; 663 return 0; 664 } 664 }
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.