xref: /openbsd/regress/sys/dev/video/videotest.c (revision b7041c07)
1 /*	$OpenBSD: videotest.c,v 1.6 2021/10/24 21:24:20 deraadt 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
main(void)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);
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
test_ioctl_querycap(int fd)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
test_ioctl_g_fmt(int fd)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
test_ioctl_enum_fmt(int fd)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
test_ioctl_enum_fsizes(int fd,uint32_t pixelformat,int index)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
test_capture(char * dev_name,char * dev_full,int access,int use_poll)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);
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
test_capture_read(int fd,char * buf,int buf_size,int use_poll)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
test_capture_mmap(int fd,char * buf,int buf_size,int use_poll)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
jpeg_insert_dht(uint8_t * src,int src_len,uint8_t * dst,int * dst_len)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 *
print_pixelformat(uint32_t pixelformat,int lowercase)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