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