OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright (c) 2012 Intel Corporation. All Rights Reserved. |
| 3 * |
| 4 * Permission is hereby granted, free of charge, to any person obtaining a |
| 5 * copy of this software and associated documentation files (the |
| 6 * "Software"), to deal in the Software without restriction, including |
| 7 * without limitation the rights to use, copy, modify, merge, publish, |
| 8 * distribute, sub license, and/or sell copies of the Software, and to |
| 9 * permit persons to whom the Software is furnished to do so, subject to |
| 10 * the following conditions: |
| 11 * |
| 12 * The above copyright notice and this permission notice (including the |
| 13 * next paragraph) shall be included in all copies or substantial portions |
| 14 * of the Software. |
| 15 * |
| 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| 17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
| 18 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
| 19 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
| 20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
| 21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
| 22 * USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 23 */ |
| 24 |
| 25 /* |
| 26 * This example is based on: http://linuxtv.org/downloads/v4l-dvb-apis/capture-e
xample.html |
| 27 * V4L2 video capture example |
| 28 * This program is provided with the V4L2 API |
| 29 * see http://linuxtv.org/docs.php for more information |
| 30 */ |
| 31 |
| 32 #include <cstdlib> /* EXIT_FAILURE, EXIT_SUCCESS */ |
| 33 #include <string> |
| 34 #include <cstring> /* strerror() */ |
| 35 #include <cassert> |
| 36 #include <getopt.h> /* getopt_long() */ |
| 37 #include <fcntl.h> /* low-level i/o */ |
| 38 #include <errno.h> |
| 39 #include <unistd.h> |
| 40 #include <malloc.h> |
| 41 #include <sys/stat.h> |
| 42 #include <sys/mman.h> |
| 43 #include <sys/ioctl.h> |
| 44 #include <csignal> |
| 45 |
| 46 #include <iostream> |
| 47 #include <linux/videodev2.h> |
| 48 |
| 49 using std::string; |
| 50 |
| 51 #include "TCPSocketClient.h" |
| 52 |
| 53 |
| 54 extern bool g_Force_P_Only; |
| 55 extern bool g_ShowNumber; |
| 56 extern bool g_LiveView; |
| 57 char device_settings_buffer[255]; |
| 58 char *device_settings = NULL; |
| 59 int g_Debug = 0; |
| 60 int g_Numerator = 0; |
| 61 int g_FrameRate = 0; |
| 62 TCPSocketClient *sock_ptr = NULL; |
| 63 std::string ip_name = "localhost"; |
| 64 int ip_port = 8888; |
| 65 extern int g_PX; |
| 66 extern int g_PY; |
| 67 extern int win2_width; |
| 68 extern int win2_height; |
| 69 |
| 70 |
| 71 |
| 72 |
| 73 int encoder_init(int width, int height); |
| 74 int encode_frame(unsigned char *inbuf); |
| 75 void encoder_close(); |
| 76 |
| 77 #define CLEAR(x) memset (&(x), 0, sizeof (x)) |
| 78 |
| 79 typedef enum { |
| 80 IO_METHOD_READ, |
| 81 IO_METHOD_MMAP, |
| 82 IO_METHOD_USERPTR, |
| 83 } io_method; |
| 84 |
| 85 struct buffer { |
| 86 void * start; |
| 87 size_t length; |
| 88 }; |
| 89 |
| 90 static char * dev_name = NULL; |
| 91 static io_method io = IO_METHOD_MMAP; |
| 92 static int fd = -1; |
| 93 struct buffer * buffers = NULL; |
| 94 static unsigned int n_buffers = 0; |
| 95 static unsigned int width = 176; |
| 96 static unsigned int height = 144; |
| 97 static unsigned int pixelformat = V4L2_PIX_FMT_YUYV; |
| 98 |
| 99 static int time_to_quit = 0; |
| 100 static void SignalHandler(int a_Signal) |
| 101 { |
| 102 time_to_quit = 1; |
| 103 signal(SIGINT, SIG_DFL); |
| 104 } |
| 105 |
| 106 static void |
| 107 errno_exit (const char * s) |
| 108 { |
| 109 std::cerr << s << " error " << errno << ", " << strerror(errno) << '\n'; |
| 110 exit (EXIT_FAILURE); |
| 111 } |
| 112 |
| 113 static int xioctl (int fd, int request, void * arg) |
| 114 { |
| 115 int r; |
| 116 do r = ioctl (fd, request, arg); |
| 117 while (-1 == r && EINTR == errno); |
| 118 return r; |
| 119 } |
| 120 |
| 121 |
| 122 static void |
| 123 process_image (const void * p, ssize_t size) |
| 124 { |
| 125 const size_t src_frame_size = (width*height) + height*(width >> 1) + height*
(width >> 1); |
| 126 if (size != src_frame_size){ |
| 127 std::cerr << "wrong buffer size: " << size << "; expect: " << src_frame_
size << '\n'; |
| 128 return; |
| 129 } |
| 130 if (!encode_frame((unsigned char *)p)) |
| 131 time_to_quit = 1; |
| 132 } |
| 133 |
| 134 static int |
| 135 read_frame (void) |
| 136 { |
| 137 struct v4l2_buffer buf; |
| 138 unsigned int i; |
| 139 switch (io) { |
| 140 case IO_METHOD_READ: |
| 141 if (-1 == read (fd, buffers[0].start, buffers[0].length)) { |
| 142 switch (errno) { |
| 143 case EAGAIN: |
| 144 return 0; |
| 145 case EIO: |
| 146 /* Could ignore EIO, see spec. */ |
| 147 /* fall through */ |
| 148 default: |
| 149 errno_exit ("read"); |
| 150 } |
| 151 } |
| 152 process_image (buffers[0].start, buffers[0].length); |
| 153 break; |
| 154 |
| 155 case IO_METHOD_MMAP: |
| 156 CLEAR (buf); |
| 157 |
| 158 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 159 buf.memory = V4L2_MEMORY_MMAP; |
| 160 |
| 161 if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) { |
| 162 switch (errno) { |
| 163 case EAGAIN: |
| 164 return 0; |
| 165 |
| 166 case EIO: |
| 167 /* Could ignore EIO, see spec. */ |
| 168 /* fall through */ |
| 169 default: |
| 170 errno_exit ("VIDIOC_DQBUF"); |
| 171 } |
| 172 } |
| 173 |
| 174 assert (buf.index < n_buffers); |
| 175 |
| 176 process_image (buffers[buf.index].start, buf.length); |
| 177 |
| 178 if (-1 == xioctl (fd, VIDIOC_QBUF, &buf)) |
| 179 errno_exit ("VIDIOC_QBUF"); |
| 180 |
| 181 break; |
| 182 |
| 183 case IO_METHOD_USERPTR: |
| 184 CLEAR (buf); |
| 185 |
| 186 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 187 buf.memory = V4L2_MEMORY_USERPTR; |
| 188 |
| 189 if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) { |
| 190 switch (errno) { |
| 191 case EAGAIN: |
| 192 return 0; |
| 193 |
| 194 case EIO: |
| 195 /* Could ignore EIO, see spec. */ |
| 196 /* fall through */ |
| 197 default: |
| 198 errno_exit ("VIDIOC_DQBUF"); |
| 199 } |
| 200 } |
| 201 |
| 202 for (i = 0; i < n_buffers; ++i) |
| 203 if (buf.m.userptr == (unsigned long) buffers[i].start && buf.length
== buffers[i].length) |
| 204 break; |
| 205 |
| 206 assert (i < n_buffers); |
| 207 process_image ((void *) buf.m.userptr, buf.length); |
| 208 if (-1 == xioctl (fd, VIDIOC_QBUF, &buf)) |
| 209 errno_exit ("VIDIOC_QBUF"); |
| 210 |
| 211 break; |
| 212 } |
| 213 |
| 214 return 1; |
| 215 } |
| 216 |
| 217 static void |
| 218 mainloop (void) |
| 219 { |
| 220 while (!time_to_quit) { |
| 221 for (;;) { |
| 222 fd_set fds; |
| 223 struct timeval tv; |
| 224 int r; |
| 225 |
| 226 FD_ZERO (&fds); |
| 227 FD_SET (fd, &fds); |
| 228 |
| 229 /* Timeout. */ |
| 230 tv.tv_sec = 5; |
| 231 tv.tv_usec = 0; |
| 232 |
| 233 r = select (fd + 1, &fds, NULL, NULL, &tv); |
| 234 |
| 235 if (-1 == r) { |
| 236 if (EINTR == errno) |
| 237 continue; |
| 238 |
| 239 errno_exit ("select"); |
| 240 } |
| 241 |
| 242 if (0 == r) { |
| 243 std::cerr << "select timeout\n"; |
| 244 exit (EXIT_FAILURE); |
| 245 } |
| 246 |
| 247 if (read_frame ()) |
| 248 break; |
| 249 |
| 250 /* EAGAIN - continue select loop. */ |
| 251 } |
| 252 } |
| 253 } |
| 254 |
| 255 static void |
| 256 stop_capturing (void) |
| 257 { |
| 258 enum v4l2_buf_type type; |
| 259 |
| 260 switch (io) { |
| 261 case IO_METHOD_READ: |
| 262 /* Nothing to do. */ |
| 263 break; |
| 264 |
| 265 case IO_METHOD_MMAP: |
| 266 case IO_METHOD_USERPTR: |
| 267 type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 268 |
| 269 if (-1 == xioctl (fd, VIDIOC_STREAMOFF, &type)) |
| 270 errno_exit ("VIDIOC_STREAMOFF"); |
| 271 |
| 272 break; |
| 273 } |
| 274 } |
| 275 |
| 276 static void |
| 277 start_capturing (void) |
| 278 { |
| 279 unsigned int i; |
| 280 enum v4l2_buf_type type; |
| 281 |
| 282 switch (io) { |
| 283 case IO_METHOD_READ: |
| 284 /* Nothing to do. */ |
| 285 break; |
| 286 |
| 287 case IO_METHOD_MMAP: |
| 288 for (i = 0; i < n_buffers; ++i) { |
| 289 struct v4l2_buffer buf; |
| 290 |
| 291 CLEAR (buf); |
| 292 |
| 293 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 294 buf.memory = V4L2_MEMORY_MMAP; |
| 295 buf.index = i; |
| 296 |
| 297 if (-1 == xioctl (fd, VIDIOC_QBUF, &buf)) |
| 298 errno_exit ("VIDIOC_QBUF"); |
| 299 } |
| 300 |
| 301 type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 302 |
| 303 if (-1 == xioctl (fd, VIDIOC_STREAMON, &type)) |
| 304 errno_exit ("VIDIOC_STREAMON"); |
| 305 |
| 306 break; |
| 307 |
| 308 case IO_METHOD_USERPTR: |
| 309 for (i = 0; i < n_buffers; ++i) { |
| 310 struct v4l2_buffer buf; |
| 311 |
| 312 CLEAR (buf); |
| 313 |
| 314 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 315 buf.memory = V4L2_MEMORY_USERPTR; |
| 316 buf.index = i; |
| 317 buf.m.userptr = (unsigned long) buffers[i].start; |
| 318 buf.length = buffers[i].length; |
| 319 |
| 320 if (-1 == xioctl (fd, VIDIOC_QBUF, &buf)) |
| 321 errno_exit ("VIDIOC_QBUF"); |
| 322 } |
| 323 |
| 324 type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 325 |
| 326 if (-1 == xioctl (fd, VIDIOC_STREAMON, &type)) |
| 327 errno_exit ("VIDIOC_STREAMON"); |
| 328 |
| 329 break; |
| 330 } |
| 331 } |
| 332 |
| 333 static void uninit_device (void) |
| 334 { |
| 335 unsigned int i; |
| 336 |
| 337 switch (io) { |
| 338 case IO_METHOD_READ: |
| 339 free (buffers[0].start); |
| 340 break; |
| 341 |
| 342 case IO_METHOD_MMAP: |
| 343 for (i = 0; i < n_buffers; ++i) |
| 344 if (-1 == munmap (buffers[i].start, buffers[i].length)) |
| 345 errno_exit ("munmap"); |
| 346 break; |
| 347 |
| 348 case IO_METHOD_USERPTR: |
| 349 for (i = 0; i < n_buffers; ++i) |
| 350 free (buffers[i].start); |
| 351 break; |
| 352 } |
| 353 |
| 354 free (buffers); |
| 355 } |
| 356 |
| 357 static void init_read (unsigned int buffer_size) |
| 358 { |
| 359 buffers = (buffer*)calloc (1, sizeof (*buffers)); |
| 360 |
| 361 if (!buffers) { |
| 362 std::cerr << "Out of memory\n"; |
| 363 exit (EXIT_FAILURE); |
| 364 } |
| 365 |
| 366 buffers[0].length = buffer_size; |
| 367 buffers[0].start = malloc (buffer_size); |
| 368 |
| 369 if (!buffers[0].start) { |
| 370 std::cerr << "Out of memory\n"; |
| 371 exit (EXIT_FAILURE); |
| 372 } |
| 373 } |
| 374 |
| 375 static void init_mmap (void) |
| 376 { |
| 377 struct v4l2_requestbuffers req; |
| 378 |
| 379 CLEAR (req); |
| 380 |
| 381 req.count = 4; |
| 382 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 383 req.memory = V4L2_MEMORY_MMAP; |
| 384 |
| 385 if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req)) { |
| 386 if (EINVAL == errno) { |
| 387 std::cerr << dev_name << " does not support " |
| 388 << "memory mapping\n"; |
| 389 exit (EXIT_FAILURE); |
| 390 } else { |
| 391 errno_exit ("VIDIOC_REQBUFS"); |
| 392 } |
| 393 } |
| 394 |
| 395 if (req.count < 2) { |
| 396 std::cerr << "Insufficient buffer memory on " << dev_name << '\n'; |
| 397 exit (EXIT_FAILURE); |
| 398 } |
| 399 |
| 400 buffers = (buffer*)calloc (req.count, sizeof (*buffers)); |
| 401 |
| 402 if (!buffers) { |
| 403 std::cerr << "Out of memory\n"; |
| 404 exit (EXIT_FAILURE); |
| 405 } |
| 406 |
| 407 for (n_buffers = 0; n_buffers < req.count; ++n_buffers) { |
| 408 struct v4l2_buffer buf; |
| 409 CLEAR (buf); |
| 410 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 411 buf.memory = V4L2_MEMORY_MMAP; |
| 412 buf.index = n_buffers; |
| 413 if (-1 == xioctl (fd, VIDIOC_QUERYBUF, &buf)) |
| 414 errno_exit ("VIDIOC_QUERYBUF"); |
| 415 buffers[n_buffers].length = buf.length; |
| 416 buffers[n_buffers].start = |
| 417 mmap (NULL /* start anywhere */, |
| 418 buf.length, |
| 419 PROT_READ | PROT_WRITE /* required */, |
| 420 MAP_SHARED /* recommended */, |
| 421 fd, buf.m.offset); |
| 422 |
| 423 if (MAP_FAILED == buffers[n_buffers].start) |
| 424 errno_exit ("mmap"); |
| 425 } |
| 426 } |
| 427 |
| 428 static void init_userp (unsigned int buffer_size) |
| 429 { |
| 430 struct v4l2_requestbuffers req; |
| 431 unsigned int page_size; |
| 432 page_size = getpagesize (); |
| 433 buffer_size = (buffer_size + page_size - 1) & ~(page_size - 1); |
| 434 CLEAR (req); |
| 435 req.count = 4; |
| 436 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 437 req.memory = V4L2_MEMORY_USERPTR; |
| 438 if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req)) { |
| 439 if (EINVAL == errno) { |
| 440 std::cerr << dev_name << " does not support " |
| 441 << "user pointer i/o\n"; |
| 442 exit (EXIT_FAILURE); |
| 443 } else { |
| 444 errno_exit ("VIDIOC_REQBUFS"); |
| 445 } |
| 446 } |
| 447 buffers = (buffer*) calloc (4, sizeof (*buffers)); |
| 448 if (!buffers) { |
| 449 std::cerr << "Out of memory\n"; |
| 450 exit (EXIT_FAILURE); |
| 451 } |
| 452 for (n_buffers = 0; n_buffers < 4; ++n_buffers) { |
| 453 buffers[n_buffers].length = buffer_size; |
| 454 buffers[n_buffers].start = memalign (/* boundary */ page_size, |
| 455 buffer_size); |
| 456 |
| 457 if (!buffers[n_buffers].start) { |
| 458 std::cerr << "Out of memory\n"; |
| 459 exit (EXIT_FAILURE); |
| 460 } |
| 461 } |
| 462 } |
| 463 |
| 464 static void init_device (void) |
| 465 { |
| 466 struct v4l2_capability cap; |
| 467 struct v4l2_cropcap cropcap; |
| 468 struct v4l2_crop crop; |
| 469 struct v4l2_format fmt; |
| 470 unsigned int min; |
| 471 if (-1 == xioctl (fd, VIDIOC_QUERYCAP, &cap)) { |
| 472 if (EINVAL == errno) { |
| 473 std::cerr << dev_name << " is no V4L2 device\n"; |
| 474 exit (EXIT_FAILURE); |
| 475 } else { |
| 476 errno_exit ("VIDIOC_QUERYCAP"); |
| 477 } |
| 478 } |
| 479 |
| 480 if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { |
| 481 std::cerr << dev_name << " is no video capture device\n"; |
| 482 exit (EXIT_FAILURE); |
| 483 } |
| 484 |
| 485 switch (io) { |
| 486 case IO_METHOD_READ: |
| 487 if (!(cap.capabilities & V4L2_CAP_READWRITE)) { |
| 488 std::cerr << dev_name << " does not support read i/o\n"; |
| 489 exit (EXIT_FAILURE); |
| 490 } |
| 491 |
| 492 break; |
| 493 case IO_METHOD_MMAP: |
| 494 case IO_METHOD_USERPTR: |
| 495 if (!(cap.capabilities & V4L2_CAP_STREAMING)) { |
| 496 std::cerr << dev_name << " does not support streaming i/o\n"; |
| 497 exit (EXIT_FAILURE); |
| 498 } |
| 499 break; |
| 500 } |
| 501 /* Select video input, video standard and tune here. */ |
| 502 CLEAR (cropcap); |
| 503 cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 504 if (0 == xioctl (fd, VIDIOC_CROPCAP, &cropcap)) { |
| 505 crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 506 crop.c = cropcap.defrect; /* reset to default */ |
| 507 if (-1 == xioctl (fd, VIDIOC_S_CROP, &crop)) { |
| 508 switch (errno) { |
| 509 case EINVAL: |
| 510 /* Cropping not supported. */ |
| 511 break; |
| 512 default: |
| 513 /* Errors ignored. */ |
| 514 break; |
| 515 } |
| 516 } |
| 517 } else { |
| 518 /* Errors ignored. */ |
| 519 } |
| 520 struct v4l2_fmtdesc fmtdesc; |
| 521 printf("video capture\n"); |
| 522 for (int i = 0;; i++) { |
| 523 memset(&fmtdesc,0,sizeof(fmtdesc)); |
| 524 fmtdesc.index = i; |
| 525 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 526 if (-1 == xioctl (fd, VIDIOC_ENUM_FMT,&fmtdesc)) |
| 527 break; |
| 528 printf(" VIDIOC_ENUM_FMT(%d,VIDEO_CAPTURE)\n",i); |
| 529 printf("pfmt: 0x%x %s\n",fmtdesc.pixelformat,fmtdesc.description); |
| 530 if (fmtdesc.pixelformat != 0x56595559) { |
| 531 printf(" => don't list not supported format\n"); |
| 532 continue; |
| 533 } |
| 534 for (int k = 0;; k++) { |
| 535 struct v4l2_frmsizeenum frmsize; |
| 536 memset(&frmsize,0,sizeof(frmsize)); |
| 537 frmsize.index = k; |
| 538 frmsize.pixel_format = fmtdesc.pixelformat; |
| 539 if (-1 == xioctl (fd, VIDIOC_ENUM_FRAMESIZES,&frmsize)) |
| 540 break; |
| 541 if (frmsize.type== V4L2_FRMSIZE_TYPE_DISCRETE) { |
| 542 printf(" VIDIOC_ENUM_FRAMESIZES(%d,0x%x) %dx%d @",k, frms
ize.type, frmsize.discrete.width, frmsize.discrete.height); |
| 543 for (int l = 0;; l++) { |
| 544 struct v4l2_frmivalenum frmrate; |
| 545 memset(&frmrate, 0, sizeof(frmrate)); |
| 546 frmrate.index = l; |
| 547 frmrate.pixel_format = fmtdesc.pixelformat; |
| 548 frmrate.width = frmsize.discrete.width; |
| 549 frmrate.height = frmsize.discrete.height; |
| 550 if (-1 == xioctl (fd, VIDIOC_ENUM_FRAMEINTERVALS,&frmrate)) |
| 551 break; |
| 552 if (frmrate.type == V4L2_FRMIVAL_TYPE_DISCRETE) { |
| 553 printf(" %u/%u ", frmrate.discrete.numerator, frmrate.di
screte.denominator); |
| 554 } |
| 555 } |
| 556 printf("\n"); |
| 557 } |
| 558 } |
| 559 } |
| 560 CLEAR (fmt); |
| 561 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 562 if (-1 == xioctl (fd, VIDIOC_G_FMT, &fmt)) |
| 563 errno_exit ("VIDIOC_G_FMT"); |
| 564 printf("video: %dx%d; fourcc:0x%x\n", fmt.fmt.pix.width, fmt.fmt.pix.height,
fmt.fmt.pix.pixelformat); |
| 565 if (fmt.fmt.pix.width != width || fmt.fmt.pix.height != height || (fmt.fmt.p
ix.pixelformat != pixelformat)){ |
| 566 struct v4l2_pix_format def_format; |
| 567 memcpy(&def_format, &fmt.fmt.pix, sizeof(struct v4l2_pix_format)); |
| 568 fmt.fmt.pix.width = width; |
| 569 fmt.fmt.pix.height = height; |
| 570 fmt.fmt.pix.pixelformat = pixelformat; |
| 571 if (-1 == xioctl (fd, VIDIOC_S_FMT, &fmt)){ |
| 572 std::cerr << "failed to set resolution " << fmt.fmt.pix.width << "x"
<< fmt.fmt.pix.height << '\n'; |
| 573 errno_exit ("VIDIOC_S_FMT"); |
| 574 } |
| 575 } |
| 576 if (-1 == xioctl (fd, VIDIOC_S_FMT, &fmt)) |
| 577 errno_exit ("VIDIOC_S_FMT"); |
| 578 |
| 579 CLEAR (fmt); |
| 580 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 581 if (-1 == xioctl (fd, VIDIOC_G_FMT, &fmt)) |
| 582 errno_exit ("VIDIOC_G_FMT"); |
| 583 printf("video: %dx%d; fourcc:0x%x\n", fmt.fmt.pix.width, fmt.fmt.pix.height,
fmt.fmt.pix.pixelformat); |
| 584 if (fmt.fmt.pix.width != width || fmt.fmt.pix.height != height || fmt.fmt.pix.
pixelformat != pixelformat){ |
| 585 errno_exit ("VIDIOC_S_FMT not set !"); |
| 586 } |
| 587 |
| 588 /* Buggy driver paranoia. */ |
| 589 min = fmt.fmt.pix.width * 2; |
| 590 if (fmt.fmt.pix.bytesperline < min) |
| 591 fmt.fmt.pix.bytesperline = min; |
| 592 min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height; |
| 593 if (fmt.fmt.pix.sizeimage < min) |
| 594 fmt.fmt.pix.sizeimage = min; |
| 595 struct v4l2_streamparm capp; |
| 596 CLEAR(capp); |
| 597 capp.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 598 if (g_FrameRate) { |
| 599 if (-1 == xioctl (fd, VIDIOC_G_PARM, &capp) == -1) { |
| 600 errno_exit ("VIDIOC_G_PARM"); |
| 601 } |
| 602 printf("vidioc_s_parm called frate=%d/%d\n", capp.parm.capture.timeperfr
ame.numerator, capp.parm.capture.timeperframe.denominator); |
| 603 capp.parm.capture.timeperframe.numerator = g_Numerator; |
| 604 capp.parm.capture.timeperframe.denominator = g_FrameRate; |
| 605 printf("vidioc_s_parm set: frate=%d/%d\n", capp.parm.capture.timeperfram
e.numerator, capp.parm.capture.timeperframe.denominator); |
| 606 if (-1 == xioctl (fd, VIDIOC_S_PARM, &capp) == -1) { |
| 607 errno_exit ("VIDIOC_S_PARM"); |
| 608 } |
| 609 if (-1 == xioctl (fd, VIDIOC_G_PARM, &capp) == -1) { |
| 610 errno_exit ("VIDIOC_G_PARM"); |
| 611 } |
| 612 if ((capp.parm.capture.timeperframe.numerator != g_Numerator) || ( |
| 613 capp.parm.capture.timeperframe.denominator != g_FrameRate)) { |
| 614 errno_exit ("VIDIOC_S_PARM NOT SET"); |
| 615 } |
| 616 } else { |
| 617 if (-1 == xioctl (fd, VIDIOC_G_PARM, &capp) == -1) { |
| 618 errno_exit ("VIDIOC_G_PARM"); |
| 619 } |
| 620 } |
| 621 sprintf(device_settings_buffer,"%dx%d@%d/%d", width, height, capp.parm.captu
re.timeperframe.numerator, capp.parm.capture.timeperframe.denominator); |
| 622 device_settings = &device_settings_buffer[0]; |
| 623 printf("INFO: %s\n", device_settings); |
| 624 |
| 625 |
| 626 switch (io) { |
| 627 case IO_METHOD_READ: |
| 628 init_read (fmt.fmt.pix.sizeimage); |
| 629 break; |
| 630 |
| 631 case IO_METHOD_MMAP: |
| 632 init_mmap (); |
| 633 break; |
| 634 |
| 635 case IO_METHOD_USERPTR: |
| 636 init_userp (fmt.fmt.pix.sizeimage); |
| 637 break; |
| 638 } |
| 639 } |
| 640 |
| 641 static void |
| 642 close_device (void) |
| 643 { |
| 644 if (-1 == close (fd)) |
| 645 errno_exit ("close"); |
| 646 |
| 647 fd = -1; |
| 648 } |
| 649 |
| 650 static void open_device (void) |
| 651 { |
| 652 struct stat st; |
| 653 |
| 654 if (-1 == stat (dev_name, &st)) { |
| 655 std::cerr << "Cannot identify '" << dev_name << "': " << errno << ", " <
< strerror(errno) << '\n'; |
| 656 exit (EXIT_FAILURE); |
| 657 } |
| 658 |
| 659 if (!S_ISCHR (st.st_mode)) { |
| 660 std::cerr << dev_name << " is no device\n"; |
| 661 exit (EXIT_FAILURE); |
| 662 } |
| 663 |
| 664 fd = open (dev_name, O_RDWR /* required */ | O_NONBLOCK, 0); |
| 665 |
| 666 if (-1 == fd) { |
| 667 std::cerr << "Cannot open '" << dev_name << "': " << errno << ", " << st
rerror(errno) << '\n'; |
| 668 exit (EXIT_FAILURE); |
| 669 } |
| 670 } |
| 671 |
| 672 static void usage (std::ostream &o, int argc, char ** argv) |
| 673 { |
| 674 o << "Usage: " << argv[0] << " [options]\n" |
| 675 "\n" |
| 676 "Options:\n" |
| 677 "-?, --help Print this message\n" |
| 678 "-d, --device=NAME Video device name ["<< dev_name<< "]\n" |
| 679 "-i, --ip=IP Target ip [localhost]\n" |
| 680 "-p, --port=PORT Target port [" << ip_port << "]\n" |
| 681 "-m, --mmap Use memory mapped buffers\n" |
| 682 "-r, --read Use read() calls\n" |
| 683 "-u, --userp Use application allocated buffers\n" |
| 684 "-N, --no-number Disable OSD\n" |
| 685 "-P, --progressive Force P frames only\n" |
| 686 "-l, --liveview-off Live View off\n" |
| 687 "-f, --framerate=FPS Framerate [no limit]\n" |
| 688 "-w, --width=WIDTH Window width [" << win2_width << "]\n" |
| 689 "-h, --height=HEIGHT Window height [" << win2_height << "]\n" |
| 690 "-x, --posx=POS_X X position [WM handles placement]\n" |
| 691 "-y, --posy=POS_Y Y position [WM handles placement]\n" |
| 692 "-n, --numerator=NUM Numerator [no limit]\n" |
| 693 "-W, --dev-width=WIDTH Device width ["<< width << "]\n" |
| 694 "-H, --dev-height=HEIGHT Device height [" << height << "]\n" |
| 695 "-D, --debug=LEVEL Debug level [" << g_Debug << "]\n" |
| 696 "\n"; |
| 697 } |
| 698 |
| 699 void InitSock() |
| 700 { |
| 701 printf("Using: %s:%d\n", ip_name.c_str(), ip_port); |
| 702 try { |
| 703 sock_ptr = new TCPSocketClient(ip_name, ip_port); |
| 704 } |
| 705 catch (const std::exception& e) |
| 706 { |
| 707 printf("%s\n", e.what()); |
| 708 exit(1); |
| 709 } |
| 710 } |
| 711 |
| 712 |
| 713 static const char short_options [] = "d:i:p:?mruNPlf:w:h:x:y:n:W:H:D:"; |
| 714 |
| 715 static const struct option |
| 716 long_options [] = { |
| 717 { "device", required_argument, NULL, 'd' }, |
| 718 { "ip", required_argument, NULL, 'i' }, |
| 719 { "port", required_argument, NULL, 'p' }, |
| 720 { "help", no_argument, NULL, '?' }, |
| 721 { "mmap", no_argument, NULL, 'm' }, |
| 722 { "read", no_argument, NULL, 'r' }, |
| 723 { "userp", no_argument, NULL, 'u' }, |
| 724 { "no-number", no_argument, NULL, 'N' }, |
| 725 { "progressive", no_argument, NULL, 'P' }, |
| 726 { "liveview-off", no_argument, NULL, 'l' }, |
| 727 { "framerate", required_argument, NULL, 'f' }, |
| 728 { "width", required_argument, NULL, 'w' }, |
| 729 { "height", required_argument, NULL, 'h' }, |
| 730 { "posx", required_argument, NULL, 'x' }, |
| 731 { "posy", required_argument, NULL, 'y' }, |
| 732 { "numerator", required_argument, NULL, 'n' }, |
| 733 { "dev-width", required_argument, NULL, 'W' }, |
| 734 { "dev-height", required_argument, NULL, 'H' }, |
| 735 { "debug", required_argument, NULL, 'D' }, |
| 736 { 0, 0, 0, 0 } |
| 737 }; |
| 738 |
| 739 int |
| 740 main (int argc, char ** argv) |
| 741 { |
| 742 width = 640; |
| 743 height = 480; |
| 744 dev_name = (char*)"/dev/video0"; |
| 745 |
| 746 for (;;) { |
| 747 int index; |
| 748 int c; |
| 749 |
| 750 c = getopt_long (argc, argv, |
| 751 short_options, long_options, |
| 752 &index); |
| 753 |
| 754 if (-1 == c) |
| 755 break; |
| 756 |
| 757 switch (c) { |
| 758 case 0: /* getopt_long() flag */ |
| 759 break; |
| 760 |
| 761 case 'd': |
| 762 dev_name = optarg; |
| 763 break; |
| 764 case 'i': |
| 765 ip_name = optarg; |
| 766 break; |
| 767 case 'p': |
| 768 ip_port = atoi(optarg); |
| 769 break; |
| 770 case '?': |
| 771 usage (std::cout, argc, argv); |
| 772 exit (EXIT_SUCCESS); |
| 773 case 'm': |
| 774 io = IO_METHOD_MMAP; |
| 775 break; |
| 776 case 'r': |
| 777 io = IO_METHOD_READ; |
| 778 break; |
| 779 case 'u': |
| 780 io = IO_METHOD_USERPTR; |
| 781 break; |
| 782 case 'N': |
| 783 g_ShowNumber = false; |
| 784 break; |
| 785 case 'P': |
| 786 g_Force_P_Only = true; |
| 787 break; |
| 788 case 'l': |
| 789 g_LiveView = false; |
| 790 break; |
| 791 case 'f': |
| 792 g_FrameRate = atoi(optarg); |
| 793 if (!g_Numerator) g_Numerator = 1; |
| 794 break; |
| 795 case 'w': |
| 796 win2_width = atoi(optarg); |
| 797 break; |
| 798 case 'h': |
| 799 win2_height = atoi(optarg); |
| 800 break; |
| 801 case 'x': |
| 802 g_PX = atoi(optarg); |
| 803 break; |
| 804 case 'y': |
| 805 g_PY = atoi(optarg); |
| 806 break; |
| 807 case 'n': |
| 808 g_Numerator = atoi(optarg); |
| 809 break; |
| 810 case 'W': |
| 811 width = atoi(optarg); |
| 812 break; |
| 813 case 'H': |
| 814 height = atoi(optarg); |
| 815 break; |
| 816 case 'D': |
| 817 g_Debug = atoi(optarg); |
| 818 break; |
| 819 default: |
| 820 usage (std::cerr, argc, argv); |
| 821 exit (EXIT_FAILURE); |
| 822 } |
| 823 } |
| 824 if (g_Debug) { |
| 825 printf("Capture: %dx%d %d/%d\n", width, height, g_Numerator, g_FrameRate
); |
| 826 printf("Win: %dx%d (%d,%d)\n", win2_width, win2_height, g_PX, g_PY); |
| 827 } |
| 828 |
| 829 if(signal(SIGINT, SignalHandler) == SIG_ERR){ |
| 830 printf("signal() failed\n"); |
| 831 time_to_quit = 1; |
| 832 } |
| 833 InitSock(); |
| 834 open_device(); |
| 835 pixelformat = V4L2_PIX_FMT_YUYV; |
| 836 init_device (); |
| 837 printf("negotiated frame resolution: %dx%d\n", width, height); |
| 838 |
| 839 if (!encoder_init(width, height)) { |
| 840 start_capturing (); |
| 841 mainloop (); |
| 842 stop_capturing (); |
| 843 encoder_close(); |
| 844 } else { |
| 845 printf("Error: encoder init !\n"); |
| 846 } |
| 847 uninit_device (); |
| 848 close_device (); |
| 849 delete sock_ptr; |
| 850 return 0; |
| 851 } |
OLD | NEW |