1 #include <unistd.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include <inttypes.h>
6 #include <getopt.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <fcntl.h>
10 #include <ctype.h>
11 #include <errno.h>
12 #include <sys/ioctl.h>
13 #include <sys/time.h>
14 #include <dirent.h>
15 #include <math.h>
16 #include <cstdlib>
17 #include <sys/endian.h>
18 
19 #include "v4l2-ctl.h"
20 
21 static struct v4l2_frmsizeenum frmsize; /* list frame sizes */
22 static struct v4l2_frmivalenum frmival; /* list frame intervals */
23 static unsigned set_fmts;
24 static uint32_t width, height, pixfmt, field, flags;
25 static uint32_t bytesperline[VIDEO_MAX_PLANES];
26 static uint32_t sizeimage[VIDEO_MAX_PLANES];
27 
vidcap_usage()28 void vidcap_usage()
29 {
30 	printf("\nVideo Capture Formats options:\n"
31 	       "  --list-formats     display supported video formats [VIDIOC_ENUM_FMT]\n"
32 	       "  --list-formats-ext display supported video formats including frame sizes\n"
33 	       "                     and intervals\n"
34 	       "  --list-framesizes <f>\n"
35 	       "                     list supported framesizes for pixelformat <f>\n"
36 	       "                     [VIDIOC_ENUM_FRAMESIZES]\n"
37 	       "                     pixelformat is the fourcc value as a string\n"
38 	       "  --list-frameintervals width=<w>,height=<h>,pixelformat=<f>\n"
39 	       "                     list supported frame intervals for pixelformat <f> and\n"
40 	       "                     the given width and height [VIDIOC_ENUM_FRAMEINTERVALS]\n"
41 	       "                     pixelformat is the fourcc value as a string\n"
42 	       "  --list-fields      list supported fields for the current format\n"
43 	       "  -V, --get-fmt-video\n"
44 	       "     		     query the video capture format [VIDIOC_G_FMT]\n"
45 	       "  -v, --set-fmt-video\n"
46 	       "  --try-fmt-video width=<w>,height=<h>,pixelformat=<pf>,field=<f>,colorspace=<c>,\n"
47 	       "                  xfer=<xf>,ycbcr=<y>,hsv=<hsv>,quantization=<q>,\n"
48 	       "                  premul-alpha,bytesperline=<bpl>,sizeimage=<sz>\n"
49 	       "                     set/try the video capture format [VIDIOC_S/TRY_FMT]\n"
50 	       "                     pixelformat is either the format index as reported by\n"
51 	       "                       --list-formats, or the fourcc value as a string.\n"
52 	       "                     The bytesperline and sizeimage options can be used multiple times,\n"
53 	       "                       once for each plane.\n"
54 	       "                     premul-alpha sets V4L2_PIX_FMT_FLAG_PREMUL_ALPHA.\n"
55 	       "                     <f> can be one of the following field layouts:\n"
56 	       "                       any, none, top, bottom, interlaced, seq_tb, seq_bt,\n"
57 	       "                       alternate, interlaced_tb, interlaced_bt\n"
58 	       "                     <c> can be one of the following colorspaces:\n"
59 	       "                       smpte170m, smpte240m, rec709, 470m, 470bg, jpeg, srgb,\n"
60 	       "                       oprgb, bt2020, dcip3\n"
61 	       "                     <xf> can be one of the following transfer functions:\n"
62 	       "                       default, 709, srgb, oprgb, smpte240m, smpte2084, dcip3, none\n"
63 	       "                     <y> can be one of the following Y'CbCr encodings:\n"
64 	       "                       default, 601, 709, xv601, xv709, bt2020, bt2020c, smpte240m\n"
65 	       "                     <hsv> can be one of the following HSV encodings:\n"
66 	       "                       default, 180, 256\n"
67 	       "                     <q> can be one of the following quantization methods:\n"
68 	       "                       default, full-range, lim-range\n"
69 	       );
70 }
71 
print_video_fields(int fd)72 static void print_video_fields(int fd)
73 {
74 	struct v4l2_format fmt;
75 	struct v4l2_format tmp;
76 
77 	memset(&fmt, 0, sizeof(fmt));
78 	fmt.fmt.pix.priv = priv_magic;
79 	fmt.type = vidcap_buftype;
80 	if (test_ioctl(fd, VIDIOC_G_FMT, &fmt) < 0)
81 		return;
82 
83 	printf("Supported Video Fields:\n");
84 	for (uint32_t f = V4L2_FIELD_NONE; f <= V4L2_FIELD_INTERLACED_BT; f++) {
85 		bool ok;
86 
87 		tmp = fmt;
88 		if (is_multiplanar)
89 			tmp.fmt.pix_mp.field = f;
90 		else
91 			tmp.fmt.pix.field = f;
92 		if (test_ioctl(fd, VIDIOC_TRY_FMT, &tmp) < 0)
93 			continue;
94 		if (is_multiplanar)
95 			ok = tmp.fmt.pix_mp.field == f;
96 		else
97 			ok = tmp.fmt.pix.field == f;
98 		if (ok)
99 			printf("\t%s\n", field2s(f).c_str());
100 	}
101 }
102 
vidcap_cmd(int ch,char * optarg)103 void vidcap_cmd(int ch, char *optarg)
104 {
105 	uint32_t colorspace, xfer_func, ycbcr, quantization;
106 	char *value, *subs;
107 	bool be_pixfmt;
108 
109 	switch (ch) {
110 	case OptSetVideoFormat:
111 	case OptTryVideoFormat:
112 		set_fmts = parse_fmt(optarg, width, height, pixfmt, field, colorspace,
113 				xfer_func, ycbcr, quantization, flags, bytesperline,
114 				sizeimage);
115 		if (!set_fmts ||
116 		    (set_fmts & (FmtColorspace | FmtYCbCr | FmtQuantization | FmtXferFunc))) {
117 			vidcap_usage();
118 			std::exit(EXIT_FAILURE);
119 		}
120 		break;
121 	case OptListFrameSizes:
122 		be_pixfmt = strlen(optarg) == 7 && !memcmp(optarg + 4, "-BE", 3);
123 		if (be_pixfmt || strlen(optarg) == 4) {
124 			frmsize.pixel_format = v4l2_fourcc(optarg[0], optarg[1],
125 							   optarg[2], optarg[3]);
126 			if (be_pixfmt)
127 				frmsize.pixel_format |= 1U << 31;
128 		} else if (isdigit(optarg[0])) {
129 			frmsize.pixel_format = strtol(optarg, 0L, 0);
130 		} else {
131 			fprintf(stderr, "The pixelformat '%s' is invalid\n", optarg);
132 			std::exit(EXIT_FAILURE);
133 		}
134 		break;
135 	case OptListFrameIntervals:
136 		subs = optarg;
137 		while (*subs != '\0') {
138 			static const char *const subopts[] = {
139 				"width",
140 				"height",
141 				"pixelformat",
142 				NULL
143 			};
144 
145 			switch (parse_subopt(&subs, subopts, &value)) {
146 			case 0:
147 				frmival.width = strtol(value, 0L, 0);
148 				break;
149 			case 1:
150 				frmival.height = strtol(value, 0L, 0);
151 				break;
152 			case 2:
153 				be_pixfmt = strlen(value) == 7 && !memcmp(value + 4, "-BE", 3);
154 				if (be_pixfmt || strlen(value) == 4) {
155 					frmival.pixel_format =
156 						v4l2_fourcc(value[0], value[1],
157 							    value[2], value[3]);
158 					if (be_pixfmt)
159 						frmival.pixel_format |= 1U << 31;
160 				} else if (isdigit(optarg[0])) {
161 					frmival.pixel_format = strtol(value, 0L, 0);
162 				} else {
163 					fprintf(stderr, "The pixelformat '%s' is invalid\n", optarg);
164 					std::exit(EXIT_FAILURE);
165 				}
166 				break;
167 			default:
168 				vidcap_usage();
169 				std::exit(EXIT_FAILURE);
170 			}
171 		}
172 		break;
173 	}
174 }
175 
vidcap_get_and_update_fmt(cv4l_fd & _fd,struct v4l2_format & vfmt)176 int vidcap_get_and_update_fmt(cv4l_fd &_fd, struct v4l2_format &vfmt)
177 {
178 	int fd = _fd.g_fd();
179 	int ret;
180 
181 	memset(&vfmt, 0, sizeof(vfmt));
182 	vfmt.fmt.pix.priv = priv_magic;
183 	vfmt.type = vidcap_buftype;
184 
185 	ret = doioctl(fd, VIDIOC_G_FMT, &vfmt);
186 	if (ret)
187 		return ret;
188 
189 	if (is_multiplanar) {
190 		if (set_fmts & FmtWidth)
191 			vfmt.fmt.pix_mp.width = width;
192 		if (set_fmts & FmtHeight)
193 			vfmt.fmt.pix_mp.height = height;
194 		if (set_fmts & FmtPixelFormat) {
195 			vfmt.fmt.pix_mp.pixelformat = pixfmt;
196 			if (vfmt.fmt.pix_mp.pixelformat < 256) {
197 				vfmt.fmt.pix_mp.pixelformat = pixfmt =
198 					find_pixel_format(fd, vfmt.fmt.pix_mp.pixelformat,
199 							  false, true);
200 			}
201 		}
202 		if (set_fmts & FmtField)
203 			vfmt.fmt.pix_mp.field = field;
204 		if (set_fmts & FmtFlags)
205 			vfmt.fmt.pix_mp.flags = flags;
206 		if (set_fmts & FmtBytesPerLine) {
207 			for (unsigned i = 0; i < VIDEO_MAX_PLANES; i++)
208 				vfmt.fmt.pix_mp.plane_fmt[i].bytesperline =
209 					bytesperline[i];
210 		} else {
211 			/*
212 			 * G_FMT might return bytesperline values > width,
213 			 * reset them to 0 to force the driver to update them
214 			 * to the closest value for the new width.
215 			 */
216 			for (unsigned i = 0; i < vfmt.fmt.pix_mp.num_planes; i++)
217 				vfmt.fmt.pix_mp.plane_fmt[i].bytesperline = 0;
218 		}
219 		if (set_fmts & FmtSizeImage) {
220 			for (unsigned i = 0; i < VIDEO_MAX_PLANES; i++)
221 				vfmt.fmt.pix_mp.plane_fmt[i].sizeimage =
222 					sizeimage[i];
223 		}
224 	} else {
225 		if (set_fmts & FmtWidth)
226 			vfmt.fmt.pix.width = width;
227 		if (set_fmts & FmtHeight)
228 			vfmt.fmt.pix.height = height;
229 		if (set_fmts & FmtPixelFormat) {
230 			vfmt.fmt.pix.pixelformat = pixfmt;
231 			if (vfmt.fmt.pix.pixelformat < 256) {
232 				vfmt.fmt.pix.pixelformat = pixfmt =
233 					find_pixel_format(fd, vfmt.fmt.pix.pixelformat,
234 							  false, false);
235 			}
236 		}
237 		if (set_fmts & FmtField)
238 			vfmt.fmt.pix.field = field;
239 		if (set_fmts & FmtFlags)
240 			vfmt.fmt.pix.flags = flags;
241 		if (set_fmts & FmtBytesPerLine) {
242 			vfmt.fmt.pix.bytesperline = bytesperline[0];
243 		} else {
244 			/*
245 			 * G_FMT might return a bytesperline value > width,
246 			 * reset this to 0 to force the driver to update it
247 			 * to the closest value for the new width.
248 			 */
249 			vfmt.fmt.pix.bytesperline = 0;
250 		}
251 		if (set_fmts & FmtSizeImage)
252 			vfmt.fmt.pix.sizeimage = sizeimage[0];
253 	}
254 
255 	if ((set_fmts & FmtPixelFormat) &&
256 	    !valid_pixel_format(fd, pixfmt, false, is_multiplanar)) {
257 		if (pixfmt)
258 			fprintf(stderr, "The pixelformat '%s' is invalid\n",
259 				fcc2s(pixfmt).c_str());
260 		else
261 			fprintf(stderr, "The pixelformat index was invalid\n");
262 		return -EINVAL;
263 	}
264 	return 0;
265 }
266 
vidcap_set(cv4l_fd & _fd)267 void vidcap_set(cv4l_fd &_fd)
268 {
269 	if (options[OptSetVideoFormat] || options[OptTryVideoFormat]) {
270 		int fd = _fd.g_fd();
271 		int ret;
272 		struct v4l2_format vfmt;
273 
274 		if (vidcap_get_and_update_fmt(_fd, vfmt) == 0) {
275 			if (options[OptSetVideoFormat])
276 				ret = doioctl(fd, VIDIOC_S_FMT, &vfmt);
277 			else
278 				ret = doioctl(fd, VIDIOC_TRY_FMT, &vfmt);
279 			if (ret == 0 && (verbose || options[OptTryVideoFormat]))
280 				printfmt(fd, vfmt);
281 		}
282 	}
283 }
284 
vidcap_get(cv4l_fd & fd)285 void vidcap_get(cv4l_fd &fd)
286 {
287 	if (options[OptGetVideoFormat]) {
288 		struct v4l2_format vfmt;
289 
290 		memset(&vfmt, 0, sizeof(vfmt));
291 		vfmt.fmt.pix.priv = priv_magic;
292 		vfmt.type = vidcap_buftype;
293 		if (doioctl(fd.g_fd(), VIDIOC_G_FMT, &vfmt) == 0)
294 			printfmt(fd.g_fd(), vfmt);
295 	}
296 }
297 
vidcap_list(cv4l_fd & fd)298 void vidcap_list(cv4l_fd &fd)
299 {
300 	if (options[OptListFormats]) {
301 		printf("ioctl: VIDIOC_ENUM_FMT\n");
302 		print_video_formats(fd, vidcap_buftype);
303 	}
304 
305 	if (options[OptListFormatsExt]) {
306 		printf("ioctl: VIDIOC_ENUM_FMT\n");
307 		print_video_formats_ext(fd, vidcap_buftype);
308 	}
309 
310 	if (options[OptListFields]) {
311 		print_video_fields(fd.g_fd());
312 	}
313 
314 	if (options[OptListFrameSizes]) {
315 		frmsize.index = 0;
316 		if (frmsize.pixel_format < 256) {
317 			frmsize.pixel_format =
318 				find_pixel_format(fd.g_fd(), frmsize.pixel_format,
319 						  false, is_multiplanar);
320 			if (!frmsize.pixel_format) {
321 				fprintf(stderr, "The pixelformat index was invalid\n");
322 				std::exit(EXIT_FAILURE);
323 			}
324 		}
325 		if (!valid_pixel_format(fd.g_fd(), frmsize.pixel_format, false, is_multiplanar) &&
326 		    !valid_pixel_format(fd.g_fd(), frmsize.pixel_format, true, is_multiplanar)) {
327 			fprintf(stderr, "The pixelformat '%s' is invalid\n",
328 				fcc2s(frmsize.pixel_format).c_str());
329 			std::exit(EXIT_FAILURE);
330 		}
331 
332 		printf("ioctl: VIDIOC_ENUM_FRAMESIZES\n");
333 		while (test_ioctl(fd.g_fd(), VIDIOC_ENUM_FRAMESIZES, &frmsize) >= 0) {
334 			print_frmsize(frmsize, "");
335 			frmsize.index++;
336 		}
337 	}
338 
339 	if (options[OptListFrameIntervals]) {
340 		frmival.index = 0;
341 		if (frmival.pixel_format < 256) {
342 			frmival.pixel_format =
343 				find_pixel_format(fd.g_fd(), frmival.pixel_format,
344 						  false, is_multiplanar);
345 			if (!frmival.pixel_format) {
346 				fprintf(stderr, "The pixelformat index was invalid\n");
347 				std::exit(EXIT_FAILURE);
348 			}
349 		}
350 		if (!valid_pixel_format(fd.g_fd(), frmival.pixel_format, false, is_multiplanar)) {
351 			fprintf(stderr, "The pixelformat '%s' is invalid\n",
352 				fcc2s(frmival.pixel_format).c_str());
353 			std::exit(EXIT_FAILURE);
354 		}
355 
356 		printf("ioctl: VIDIOC_ENUM_FRAMEINTERVALS\n");
357 		while (test_ioctl(fd.g_fd(), VIDIOC_ENUM_FRAMEINTERVALS, &frmival) >= 0) {
358 			print_frmival(frmival, "");
359 			frmival.index++;
360 		}
361 	}
362 }
363 
print_touch_buffer(FILE * f,cv4l_buffer & buf,cv4l_fmt & fmt,cv4l_queue & q)364 void print_touch_buffer(FILE *f, cv4l_buffer &buf, cv4l_fmt &fmt, cv4l_queue &q)
365 {
366 	static const char img[16] = {
367 		'.', ',', ':', ';', '!', '|', 'i', 'c',
368 		'n', 'o', 'm', 'I', 'C', 'N', 'O', 'M',
369 	};
370 	int16_t *vbuf = static_cast<int16_t *>(q.g_dataptr(buf.g_index(), 0));
371 	uint32_t x, y;
372 
373 	switch (fmt.g_pixelformat()) {
374 	case V4L2_TCH_FMT_DELTA_TD16:
375 		for (y = 0; y < fmt.g_height(); y++) {
376 			fprintf(f, "TD16: ");
377 
378 			for (x = 0; x < fmt.g_width(); x++, vbuf++) {
379 				int16_t v = static_cast<int16_t>(le16toh(*vbuf));
380 
381 				if (!options[OptConcise])
382 					fprintf(f, "% 4d", v);
383 				else if (v > 255)
384 					fprintf(f, "*");
385 				else if (v < -32)
386 					fprintf(f, "-");
387 				else if (v < 0)
388 					fprintf(f, "%c", img[0]);
389 				else
390 					fprintf(f, "%c", img[v / 16]);
391 			}
392 			fprintf(f, "\n");
393 		}
394 		break;
395 	}
396 }
397