1 /* $OpenBSD: videotest.c,v 1.5 2015/11/17 07:13:55 mmcc Exp $ */ 2 3 /* 4 * Copyright (c) 2010 Marcus Glocker <mglocker@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /* 20 * Regression test program for the video(4) interface. 21 * 22 * TODO: 23 * - Add test for VIDIOC_ENUM_FRAMEINTERVALS ioctl. 24 * - Add test for VIDIOC_ENUMINPUT ioctl. 25 * - Add test for VIDIOC_S_INPUT ioctl. 26 * - Add test for VIDIOC_TRY_FMT ioctl. 27 * - Add test for VIDIOC_QUERYCTRL ioctl. 28 * - Add test for VIDIOC_G_CTRL ioctl. 29 * - Add test for VIDIOC_S_CTRL ioctl. 30 */ 31 32 #include <sys/ioctl.h> 33 #include <sys/types.h> 34 #include <sys/mman.h> 35 #include <sys/videoio.h> 36 37 #include <err.h> 38 #include <errno.h> 39 #include <fcntl.h> 40 #include <poll.h> 41 #include <unistd.h> 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <string.h> 45 46 /* 47 * Defines. 48 */ 49 #define DEV_CHECK_NR 128 50 #define DEV_PATH "/dev/" 51 52 /* 53 * Some devices need a hell of time to initialize and stop (e.g. the 54 * Logitech Pro 9000). If we don't give them that time, they will stall 55 * at some point in the open / close cycle and will require a cold reset 56 * (detach / attach) to operate again. 57 */ 58 #define WAIT_INIT 5 /* seconds */ 59 #define WAIT_STOP 15 /* seconds */ 60 61 #define POLL_NO 0 62 #define POLL_YES 1 63 #define POLL_TIMEOUT 2000 /* milliseconds */ 64 65 #define ACCESS_READ 0 66 #define ACCESS_MMAP 1 67 68 #define MMAP_QUEUE_NR 4 69 70 /* 71 * Prototypes. 72 */ 73 int test_ioctl_querycap(int); 74 int test_ioctl_g_fmt(int); 75 int test_ioctl_enum_fmt(int); 76 int test_ioctl_enum_fsizes(int, uint32_t, int); 77 int test_capture(char *, char *, int, int); 78 int test_capture_read(int, char *, int, int); 79 int test_capture_mmap(int, char *, int, int); 80 void jpeg_insert_dht(uint8_t *, int, uint8_t *, int *); 81 char *print_pixelformat(uint32_t, int); 82 83 /* 84 * Structures. 85 */ 86 struct frame_buffer { 87 uint8_t *buf; 88 int len; 89 }; 90 91 struct sizes { 92 uint32_t width; 93 uint32_t height; 94 }; 95 96 /* 97 * Global variables. 98 */ 99 struct fmt_sizes { 100 uint32_t pixelformat; 101 struct sizes s[32]; 102 } dev_fmts[8]; 103 104 /* 105 * Main program. 106 */ 107 int 108 main(void) 109 { 110 int i, fd, r; 111 char dev_name[32], dev_full[32]; 112 113 for (i = 0; i < DEV_CHECK_NR; i++) { 114 /* assemble device name and path */ 115 snprintf(dev_name, sizeof(dev_name), "video%d", i); 116 snprintf(dev_full, sizeof(dev_full), "%s%s", 117 DEV_PATH, dev_name); 118 119 /* open video device */ 120 fd = open(dev_full, O_RDWR, 0); 121 if (fd == -1) { 122 warn("%s", dev_full); 123 break; 124 } 125 126 /* run some ioctl tests */ 127 r = test_ioctl_querycap(fd); 128 if (r == -1) 129 err(1, "ioctl_querycap"); 130 131 r = test_ioctl_g_fmt(fd); 132 if (r == -1) 133 err(1, "ioctl_g_fmt"); 134 135 r = test_ioctl_enum_fmt(fd); 136 if (r == -1) 137 err(1, "ioctl_enum_fmt"); 138 139 /* close video device */ 140 close(fd); 141 142 /* run frame capture tests */ 143 r = test_capture(dev_name, dev_full, ACCESS_READ, POLL_NO); 144 if (r == -1) 145 err(1, "test_capture"); 146 147 r = test_capture(dev_name, dev_full, ACCESS_READ, POLL_YES); 148 if (r == -1) 149 err(1, "test_capture"); 150 151 r = test_capture(dev_name, dev_full, ACCESS_MMAP, POLL_NO); 152 if (r == -1) 153 err(1, "test_capture"); 154 155 r = test_capture(dev_name, dev_full, ACCESS_MMAP, POLL_YES); 156 if (r == -1) 157 err(1, "test_capture"); 158 } 159 160 return (0); 161 } 162 163 int 164 test_ioctl_querycap(int fd) 165 { 166 int r; 167 struct v4l2_capability caps; 168 169 printf("[ Calling VIDIOC_QUERYCAP ioctl ]\n\n"); 170 171 memset(&caps, 0, sizeof(struct v4l2_capability)); 172 r = ioctl(fd, VIDIOC_QUERYCAP, &caps); 173 if (r == -1) 174 return (-1); 175 176 printf("Driver : %s\n", caps.driver); 177 printf("Card : %s\n", caps.card); 178 printf("Bus Info : %s\n", caps.bus_info); 179 printf("Version : %d\n", caps.version); 180 printf("Capabilities : "); 181 if (caps.capabilities & V4L2_CAP_VIDEO_CAPTURE) 182 printf("CAPTURE "); 183 if (caps.capabilities & V4L2_CAP_STREAMING) 184 printf("STREAMING "); 185 if (caps.capabilities & V4L2_CAP_READWRITE) 186 printf("READWRITE "); 187 printf("\n"); 188 189 printf("\n"); 190 191 return (0); 192 } 193 194 int 195 test_ioctl_g_fmt(int fd) 196 { 197 int r; 198 struct v4l2_format fmt; 199 200 printf("[ Calling VIDIOC_G_FMT ioctl ]\n\n"); 201 202 memset(&fmt, 0, sizeof(struct v4l2_format)); 203 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 204 r = ioctl(fd, VIDIOC_G_FMT, &fmt); 205 if (r == -1) 206 return (r); 207 208 printf("Current format : %s\n", 209 print_pixelformat(fmt.fmt.pix.pixelformat, 0)); 210 printf("Current width : %u pixels\n", fmt.fmt.pix.width); 211 printf("Current height : %u pixels\n", fmt.fmt.pix.height); 212 printf("Current max. framesize : %u bytes\n", fmt.fmt.pix.sizeimage); 213 214 printf("\n"); 215 216 return (0); 217 } 218 219 int 220 test_ioctl_enum_fmt(int fd) 221 { 222 int r; 223 struct v4l2_fmtdesc fmtdesc; 224 225 printf("[ Calling VIDIOC_ENUM_FMT|VIDIOC_ENUM_FRAMESIZES ioctl ]\n\n"); 226 227 memset(&fmtdesc, 0, sizeof(struct v4l2_fmtdesc)); 228 fmtdesc.index = 0; 229 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 230 while ((r = ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc)) == 0) { 231 printf("Pixelformat '%s' ", fmtdesc.description); 232 233 (void)test_ioctl_enum_fsizes(fd, fmtdesc.pixelformat, 234 fmtdesc.index); 235 236 fmtdesc.index++; 237 } 238 if (errno != EINVAL) 239 return (-1); 240 241 return (0); 242 } 243 244 int 245 test_ioctl_enum_fsizes(int fd, uint32_t pixelformat, int index) 246 { 247 int r; 248 struct v4l2_frmsizeenum fsizes; 249 250 printf("supports following sizes:\n"); 251 252 memset(&fsizes, 0, sizeof(struct v4l2_frmsizeenum)); 253 fsizes.index = 0; 254 fsizes.pixel_format = pixelformat; 255 while ((r = ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &fsizes)) == 0) { 256 if (fsizes.type == V4L2_FRMSIZE_TYPE_DISCRETE) { 257 printf("discrete width = %u, height = %u\n", 258 fsizes.discrete.width, 259 fsizes.discrete.height); 260 261 /* save format and sizes for later use */ 262 dev_fmts[index].pixelformat = pixelformat; 263 dev_fmts[index].s[fsizes.index].width = 264 fsizes.discrete.width; 265 dev_fmts[index].s[fsizes.index].height = 266 fsizes.discrete.height; 267 } 268 269 fsizes.index++; 270 } 271 if (errno != EINVAL) 272 return (-1); 273 274 printf("\n"); 275 276 return (0); 277 } 278 279 int 280 test_capture(char *dev_name, char *dev_full, int access, int use_poll) 281 { 282 ssize_t n1, n2; 283 int fd1, fd2; 284 int i, j, r; 285 int buf_size, img_size, img_len; 286 char filename[64]; 287 uint8_t *buf, *img; 288 uint32_t last_pixelformat; 289 struct v4l2_format fmt; 290 291 fd1 = last_pixelformat = n1 = 0; 292 img = buf = NULL; 293 294 printf("[ Testing %s access type %s]\n\n", 295 access == ACCESS_READ ? "READ" : "MMAP", 296 use_poll ? "with poll " : ""); 297 298 for (i = 0; i < 8; i++) { 299 /* did we reach end of formats? */ 300 if (dev_fmts[i].pixelformat == 0) 301 return (0); 302 303 /* some devices have duplicate format descriptors */ 304 if (last_pixelformat == dev_fmts[i].pixelformat) 305 continue; 306 else 307 last_pixelformat = dev_fmts[i].pixelformat; 308 309 for (j = 0; j < 32; j++) { 310 /* did we reach end of sizes? */ 311 if (dev_fmts[i].s[j].width == 0) { 312 free(buf); 313 buf = NULL; 314 free(img); 315 img = NULL; 316 break; 317 } 318 319 /* open device */ 320 fd1 = open(dev_full, O_RDWR, 0); 321 if (fd1 == -1) 322 err(1, "open"); 323 sleep(WAIT_INIT); /* let device initialize */ 324 325 /* set format */ 326 printf("Set format to %s-%ux%u ... ", 327 print_pixelformat(dev_fmts[i].pixelformat, 0), 328 dev_fmts[i].s[j].width, 329 dev_fmts[i].s[j].height); 330 331 memset(&fmt, 0, sizeof(struct v4l2_format)); 332 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 333 fmt.fmt.pix.width = dev_fmts[i].s[j].width; 334 fmt.fmt.pix.height = dev_fmts[i].s[j].height; 335 fmt.fmt.pix.pixelformat = dev_fmts[i].pixelformat; 336 fmt.fmt.pix.field = V4L2_FIELD_ANY; 337 r = ioctl(fd1, VIDIOC_S_FMT, &fmt); 338 if (r == -1) 339 goto error; 340 341 printf("results in %u bytes max. framesize.\n", 342 fmt.fmt.pix.sizeimage); 343 344 /* allocate frame and image buffer */ 345 free(buf); 346 buf = NULL; 347 free(img); 348 img = NULL; 349 350 buf_size = fmt.fmt.pix.sizeimage; 351 buf = calloc(1, buf_size); 352 if (buf == NULL) 353 goto error; 354 355 img_size = fmt.fmt.pix.sizeimage + 1024; 356 img = calloc(1, img_size); 357 if (img == NULL) 358 goto error; 359 360 /* get frame */ 361 if (access == ACCESS_READ) 362 n1 = test_capture_read(fd1, buf, buf_size, 363 use_poll); 364 else 365 n1 = test_capture_mmap(fd1, buf, buf_size, 366 use_poll); 367 if (n1 == -1) 368 goto error; 369 370 /* 371 * Convert frame to JPEG image. 372 * 373 * TODO: 374 * For now just MJPEG convertion is supported. 375 */ 376 snprintf(filename, sizeof(filename), 377 "%s_img_%s_%ux%u%s%s", 378 dev_name, 379 print_pixelformat(dev_fmts[i].pixelformat, 1), 380 fmt.fmt.pix.width, 381 fmt.fmt.pix.height, 382 access == ACCESS_READ ? "_read" : "_mmap", 383 use_poll ? "_poll" : ""); 384 385 switch (dev_fmts[i].pixelformat) { 386 case V4L2_PIX_FMT_MJPEG: 387 printf("Converting MJPEG to JPEG.\n"); 388 389 /* insert dynamic huffmann table to mjpeg */ 390 jpeg_insert_dht(buf, n1, img, &img_len); 391 392 strlcat(filename, ".jpg", sizeof(filename)); 393 break; 394 case V4L2_PIX_FMT_YUYV: 395 printf("Convertion for YUYV not supported!\n"); 396 397 img_len = n1; 398 memcpy(img, buf, img_len); 399 400 strlcat(filename, ".raw", sizeof(filename)); 401 break; 402 default: 403 break; 404 } 405 406 /* write image file */ 407 fd2 = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0644); 408 if (fd2 == -1) 409 goto error; 410 n2 = write(fd2, img, img_len); 411 if (n2 == -1) 412 goto error; 413 printf("Saving image to '%s'.\n\n", filename); 414 close(fd2); 415 416 /* shutdown device */ 417 close(fd1); 418 sleep(WAIT_STOP); /* let device stop */ 419 } 420 } 421 error: 422 free(buf); 423 buf = NULL; 424 free(img); 425 img = NULL; 426 close(fd1); 427 428 printf("\n"); 429 430 return (-1); 431 } 432 433 int 434 test_capture_read(int fd, char *buf, int buf_size, int use_poll) 435 { 436 ssize_t n1; 437 int i, r; 438 struct pollfd pfds[1]; 439 440 n1 = 0; 441 442 /* 443 * Read frame data. 444 * 445 * Some devices need a while until they start 446 * sending a sane image. Therefore skip the 447 * first few frames. 448 */ 449 printf("Reading frame data ... "); 450 451 for (i = 0; i < 3; i++) { 452 if (use_poll) { 453 pfds[0].fd = fd; 454 pfds[0].events = POLLIN; 455 456 r = poll(pfds, 1, POLL_TIMEOUT); 457 if (r == -1) 458 return (-1); 459 if (r == 0) { 460 printf("poll timeout (%d seconds)!\n", 461 POLL_TIMEOUT / 1000); 462 continue; 463 } 464 } 465 466 n1 = read(fd, buf, buf_size); 467 if (n1 == -1) 468 return (-1); 469 } 470 printf("%ld bytes read.\n", n1); 471 472 return (n1); 473 } 474 475 int 476 test_capture_mmap(int fd, char *buf, int buf_size, int use_poll) 477 { 478 int i, r, type; 479 struct v4l2_requestbuffers reqbufs; 480 struct v4l2_buffer buffer; 481 struct frame_buffer fbuffer[MMAP_QUEUE_NR]; 482 struct pollfd pfds[1]; 483 484 /* request buffers */ 485 memset(&reqbufs, 0, sizeof(struct v4l2_requestbuffers)); 486 reqbufs.count = MMAP_QUEUE_NR; 487 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 488 reqbufs.memory = V4L2_MEMORY_MMAP; 489 r = ioctl(fd, VIDIOC_REQBUFS, &reqbufs); 490 if (r == -1) 491 return (-1); 492 493 /* map the buffers */ 494 for (i = 0; i < MMAP_QUEUE_NR; i++) { 495 memset(&buffer, 0, sizeof(struct v4l2_buffer)); 496 buffer.index = i; 497 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 498 buffer.memory = V4L2_MEMORY_MMAP; 499 r = ioctl(fd, VIDIOC_QUERYBUF, &buffer); 500 if (r == -1) 501 return (-1); 502 503 fbuffer[i].buf = 504 mmap(0, buffer.length, PROT_READ, MAP_SHARED, fd, 505 buffer.m.offset); 506 if (fbuffer[i].buf == MAP_FAILED) 507 return (-1); 508 fbuffer[i].len = buffer.length; 509 } 510 511 /* queue the buffers */ 512 for (i = 0; i < MMAP_QUEUE_NR; i++) { 513 memset(&buffer, 0, sizeof(struct v4l2_buffer)); 514 buffer.index = i; 515 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 516 buffer.memory = V4L2_MEMORY_MMAP; 517 r = ioctl(fd, VIDIOC_QBUF, &buffer); 518 if (r == -1) 519 return (-1); 520 } 521 522 /* turn on stream */ 523 type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 524 r = ioctl(fd, VIDIOC_STREAMON, &type); 525 if (r == -1) 526 return (-1); 527 528 /* dequeue buffers */ 529 printf("Dequeue frame data ... "); 530 531 for (i = 0; i < MMAP_QUEUE_NR; i++) { 532 if (use_poll) { 533 pfds[0].fd = fd; 534 pfds[0].events = POLLIN; 535 536 r = poll(pfds, 1, POLL_TIMEOUT); 537 if (r == -1) 538 return (-1); 539 if (r == 0) { 540 printf("poll timeout (%d seconds)!\n", 541 POLL_TIMEOUT / 1000); 542 return (-1); 543 } 544 } 545 546 memset(&buffer, 0, sizeof(struct v4l2_buffer)); 547 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 548 buffer.memory = V4L2_MEMORY_MMAP; 549 r = ioctl(fd, VIDIOC_DQBUF, &buffer); 550 if (r == -1) 551 return (-1); 552 } 553 printf("%d bytes dequeued.\n", buffer.bytesused); 554 memcpy(buf, fbuffer[buffer.index].buf, buffer.bytesused); 555 556 /* turn off stream */ 557 type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 558 r = ioctl(fd, VIDIOC_STREAMOFF, &type); 559 if (r == -1) 560 return (-1); 561 562 /* unmap buffers */ 563 for (i = 0; i < MMAP_QUEUE_NR; i++) { 564 r = munmap(fbuffer[i].buf, fbuffer[i].len); 565 if (r == -1) 566 return (-1); 567 } 568 569 return (buffer.bytesused); 570 } 571 572 void 573 jpeg_insert_dht(uint8_t *src, int src_len, uint8_t *dst, int *dst_len) 574 { 575 int i; 576 uint8_t *p; 577 578 static unsigned char dht[] = { 579 0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 580 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 581 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 582 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 583 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, 584 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 585 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 586 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 587 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 588 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 589 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 590 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 591 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 592 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 593 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 594 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 595 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 596 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 597 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 598 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 599 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 600 0xf9, 0xfa, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 601 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 602 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 603 0x0b, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 604 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 605 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 606 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 607 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 608 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 609 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 610 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 611 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 612 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 613 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 614 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 615 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 616 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 617 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 618 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 619 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 620 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa 621 }; 622 623 p = src; 624 for (i = 0; i < src_len; i++, p++) { 625 if (*p != 0xff) 626 continue; 627 628 p++; 629 if (*p == 0xda) 630 break; 631 else 632 i++; 633 } 634 635 memcpy(dst, src, i); 636 dst += i; 637 memcpy(dst, dht, sizeof(dht)); 638 dst += sizeof(dht); 639 src += i; 640 memcpy(dst, src, src_len - i); 641 642 *dst_len = src_len + sizeof(dht); 643 } 644 645 char * 646 print_pixelformat(uint32_t pixelformat, int lowercase) 647 { 648 static char pformat[8]; 649 650 memset(pformat, 0, sizeof(pformat)); 651 652 switch (pixelformat) { 653 case V4L2_PIX_FMT_MJPEG: 654 if (lowercase) 655 memcpy(pformat, "mjpeg", 5); 656 else 657 memcpy(pformat, "MJPEG", 5); 658 break; 659 case V4L2_PIX_FMT_YUYV: 660 if (lowercase) 661 memcpy(pformat, "yuyv", 4); 662 else 663 memcpy(pformat, "YUYV", 4); 664 break; 665 default: 666 memcpy(pformat, "unknown", 7); 667 break; 668 } 669 670 return (pformat); 671 } 672