1 /*
2 V4L2 API format ioctl tests.
3
4 Copyright (C) 2011 Hans Verkuil <hans.verkuil@cisco.com>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
19 */
20
21 #include <unistd.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <inttypes.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29 #include <ctype.h>
30 #include <errno.h>
31 #include <sys/ioctl.h>
32 #include <assert.h>
33
34 #include <sys/cdefs.h>
35 #include "v4l2-compliance.h"
36
37 static const uint32_t buftype2cap[] = {
38 0,
39 V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_M2M,
40 V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_M2M,
41 V4L2_CAP_VIDEO_OVERLAY,
42 V4L2_CAP_VBI_CAPTURE,
43 V4L2_CAP_VBI_OUTPUT,
44 V4L2_CAP_SLICED_VBI_CAPTURE,
45 V4L2_CAP_SLICED_VBI_OUTPUT,
46 V4L2_CAP_VIDEO_OUTPUT_OVERLAY,
47 V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_M2M_MPLANE,
48 V4L2_CAP_VIDEO_OUTPUT_MPLANE | V4L2_CAP_VIDEO_M2M_MPLANE,
49 V4L2_CAP_SDR_CAPTURE,
50 V4L2_CAP_SDR_OUTPUT,
51 V4L2_CAP_META_CAPTURE,
52 V4L2_CAP_META_OUTPUT,
53 };
54
testEnumFrameIntervals(struct node * node,uint32_t pixfmt,uint32_t w,uint32_t h,uint32_t type)55 static int testEnumFrameIntervals(struct node *node, uint32_t pixfmt,
56 uint32_t w, uint32_t h, uint32_t type)
57 {
58 struct v4l2_frmivalenum frmival;
59 struct v4l2_frmival_stepwise *sw = &frmival.stepwise;
60 bool found_stepwise = false;
61 unsigned f = 0;
62 int ret;
63
64 for (;;) {
65 memset(&frmival, 0xff, sizeof(frmival));
66 frmival.index = f;
67 frmival.pixel_format = pixfmt;
68 frmival.width = w;
69 frmival.height = h;
70
71 ret = doioctl(node, VIDIOC_ENUM_FRAMEINTERVALS, &frmival);
72 if (ret == ENOTTY)
73 return ret;
74 if (f == 0 && ret == EINVAL) {
75 if (type == V4L2_FRMSIZE_TYPE_DISCRETE)
76 warn("found framesize %dx%d, but no frame intervals\n", w, h);
77 return ENOTTY;
78 }
79 if (ret == EINVAL)
80 break;
81 if (ret)
82 return fail("expected EINVAL, but got %d when enumerating frameinterval %d\n", ret, f);
83 ret = check_0(frmival.reserved, sizeof(frmival.reserved));
84 if (ret)
85 return fail("frmival.reserved not zeroed\n");
86 if (frmival.pixel_format != pixfmt || frmival.index != f ||
87 frmival.width != w || frmival.height != h)
88 return fail("frmival.pixel_format, index, width or height changed\n");
89 switch (frmival.type) {
90 case V4L2_FRMIVAL_TYPE_DISCRETE:
91 ret = check_fract(&frmival.discrete);
92 if (ret)
93 return fail("invalid frameinterval %d (%d/%d)\n", f,
94 frmival.discrete.numerator,
95 frmival.discrete.denominator);
96 if (found_stepwise)
97 return fail("mixing discrete and stepwise is not allowed\n");
98 break;
99 case V4L2_FRMIVAL_TYPE_CONTINUOUS:
100 if (sw->step.numerator != 1 || sw->step.denominator != 1)
101 return fail("invalid step for continuous frameinterval\n");
102 ;
103 case V4L2_FRMIVAL_TYPE_STEPWISE:
104 if (frmival.index)
105 return fail("index must be 0 for stepwise/continuous frameintervals\n");
106 found_stepwise = true;
107 ret = check_fract(&sw->min);
108 if (ret == 0)
109 ret = check_fract(&sw->max);
110 if (ret == 0)
111 ret = check_fract(&sw->step);
112 if (ret)
113 return fail("invalid min, max or step for frameinterval %d\n", f);
114 if (fract2f(&sw->min) > fract2f(&sw->max))
115 return fail("min > max\n");
116 if (frmival.type == V4L2_FRMIVAL_TYPE_STEPWISE &&
117 fract2f(&sw->step) > fract2f(&sw->max) - fract2f(&sw->min))
118 return fail("step > (max - min)\n");
119 break;
120 default:
121 return fail("frmival.type is invalid\n");
122 }
123
124 f++;
125 node->has_frmintervals = true;
126 }
127 if (type == 0)
128 return fail("found frame intervals for invalid size %dx%d\n", w, h);
129 info("found %d frameintervals for pixel format %08x (%s) and size %dx%d\n",
130 f, pixfmt, fcc2s(pixfmt).c_str(), w, h);
131 return 0;
132 }
133
testEnumFrameSizes(struct node * node,uint32_t pixfmt)134 static int testEnumFrameSizes(struct node *node, uint32_t pixfmt)
135 {
136 struct v4l2_frmsizeenum frmsize;
137 struct v4l2_frmsize_stepwise *sw = &frmsize.stepwise;
138 bool found_stepwise = false;
139 uint64_t cookie;
140 unsigned f = 0;
141 unsigned count = 0;
142 int ret;
143
144 for (;;) {
145 memset(&frmsize, 0xff, sizeof(frmsize));
146 frmsize.index = f;
147 frmsize.pixel_format = pixfmt;
148
149 ret = doioctl(node, VIDIOC_ENUM_FRAMESIZES, &frmsize);
150 if (ret == ENOTTY)
151 return ret;
152 if (f == 0 && ret == EINVAL)
153 return ENOTTY;
154 if (ret == EINVAL)
155 break;
156 if (ret)
157 return fail("expected EINVAL, but got %d when enumerating framesize %d\n", ret, f);
158 ret = check_0(frmsize.reserved, sizeof(frmsize.reserved));
159 if (ret)
160 return fail("frmsize.reserved not zeroed\n");
161 if (frmsize.pixel_format != pixfmt || frmsize.index != f)
162 return fail("frmsize.pixel_format or index changed\n");
163 switch (frmsize.type) {
164 case V4L2_FRMSIZE_TYPE_DISCRETE:
165 if (frmsize.discrete.width == 0 || frmsize.discrete.height == 0)
166 return fail("invalid width/height for discrete framesize\n");
167 if (found_stepwise)
168 return fail("mixing discrete and stepwise is not allowed\n");
169 ret = testEnumFrameIntervals(node, pixfmt,
170 frmsize.discrete.width, frmsize.discrete.height, frmsize.type);
171 if (ret && ret != ENOTTY)
172 return ret;
173 ret = testEnumFrameIntervals(node, pixfmt,
174 frmsize.discrete.width + 1, frmsize.discrete.height, 0);
175 if (ret && ret != ENOTTY)
176 return ret;
177 if (ret == 0 && !(node->g_caps() & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_CAPTURE_MPLANE)))
178 return fail("found discrete framesizes when no video capture is supported\n");
179 cookie = (static_cast<uint64_t>(pixfmt) << 32) |
180 (frmsize.discrete.width << 16) |
181 frmsize.discrete.height;
182 node->frmsizes.insert(cookie);
183 count++;
184 break;
185 case V4L2_FRMSIZE_TYPE_CONTINUOUS:
186 if (frmsize.stepwise.step_width != 1 || frmsize.stepwise.step_height != 1)
187 return fail("invalid step_width/height for continuous framesize\n");
188 ;
189 case V4L2_FRMSIZE_TYPE_STEPWISE:
190 if (frmsize.index)
191 return fail("index must be 0 for stepwise/continuous framesizes\n");
192 found_stepwise = true;
193 if (!sw->min_width || !sw->min_height || !sw->step_width || !sw->step_height)
194 return fail("0 for min_width/height or step_width/height\n");
195 if (sw->min_width > sw->max_width || sw->min_height > sw->max_height)
196 return fail("min_width/height > max_width/height\n");
197 if (sw->step_width > sw->max_width - sw->min_width ||
198 sw->step_height > sw->max_height - sw->min_height)
199 return fail("step > max - min for width or height\n");
200 ret = testEnumFrameIntervals(node, pixfmt,
201 sw->min_width, sw->min_height, frmsize.type);
202 if (ret && ret != ENOTTY)
203 return ret;
204 ret = testEnumFrameIntervals(node, pixfmt,
205 sw->max_width, sw->max_height, frmsize.type);
206 if (ret && ret != ENOTTY)
207 return ret;
208 ret = testEnumFrameIntervals(node, pixfmt,
209 sw->min_width - 1, sw->min_height, 0);
210 if (ret && ret != ENOTTY)
211 return ret;
212 ret = testEnumFrameIntervals(node, pixfmt,
213 sw->max_width, sw->max_height + 1, 0);
214 if (ret && ret != ENOTTY)
215 return ret;
216 break;
217 default:
218 return fail("frmsize.type is invalid\n");
219 }
220
221 f++;
222 }
223 node->frmsizes_count[pixfmt] = count;
224 info("found %d framesizes for pixel format %08x (%s)\n",
225 f, pixfmt, fcc2s(pixfmt).c_str());
226 return 0;
227 }
228
testEnumFormatsType(struct node * node,unsigned type)229 static int testEnumFormatsType(struct node *node, unsigned type)
230 {
231 pixfmt_map &map = node->buftype_pixfmts[type];
232 struct v4l2_fmtdesc fmtdesc;
233 unsigned f = 0;
234 int ret;
235
236 for (;;) {
237 memset(&fmtdesc, 0xff, sizeof(fmtdesc));
238 fmtdesc.type = type;
239 fmtdesc.index = f;
240 fmtdesc.mbus_code = 0;
241
242 ret = doioctl(node, VIDIOC_ENUM_FMT, &fmtdesc);
243 if (ret == ENOTTY)
244 return ret;
245 if (f == 0 && ret == EINVAL)
246 return ENOTTY;
247 if (ret == EINVAL)
248 break;
249 if (ret)
250 return fail("expected EINVAL, but got %d when enumerating buftype %d\n", ret, type);
251 ret = check_0(fmtdesc.reserved, sizeof(fmtdesc.reserved));
252 if (ret)
253 return fail("fmtdesc.reserved not zeroed\n");
254 if (fmtdesc.index != f)
255 return fail("fmtdesc.index was modified\n");
256 if (fmtdesc.type != type)
257 return fail("fmtdesc.type was modified\n");
258 ret = check_ustring(fmtdesc.description, sizeof(fmtdesc.description));
259 if (ret)
260 return fail("fmtdesc.description not set\n");
261 if (!fmtdesc.pixelformat)
262 return fail("fmtdesc.pixelformat not set\n");
263 if (node->g_direct() && (fmtdesc.flags & V4L2_FMT_FLAG_EMULATED))
264 return fail("drivers must never set the emulated flag\n");
265 if (fmtdesc.flags & ~(V4L2_FMT_FLAG_COMPRESSED | V4L2_FMT_FLAG_EMULATED |
266 V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM |
267 V4L2_FMT_FLAG_DYN_RESOLUTION))
268 return fail("unknown flag %08x returned\n", fmtdesc.flags);
269 if (!(fmtdesc.flags & V4L2_FMT_FLAG_COMPRESSED))
270 fail_on_test(fmtdesc.flags & (V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM |
271 V4L2_FMT_FLAG_DYN_RESOLUTION));
272 ret = testEnumFrameSizes(node, fmtdesc.pixelformat);
273 if (ret)
274 fail_on_test(node->codec_mask & STATEFUL_ENCODER);
275 if (ret && ret != ENOTTY)
276 return ret;
277 f++;
278 if (type == V4L2_BUF_TYPE_PRIVATE)
279 continue;
280 // Update define in v4l2-compliance.h if new buffer types are added
281 assert(type <= V4L2_BUF_TYPE_LAST);
282 if (map.find(fmtdesc.pixelformat) != map.end())
283 return fail("duplicate format %08x (%s)\n",
284 fmtdesc.pixelformat, fcc2s(fmtdesc.pixelformat).c_str());
285 map[fmtdesc.pixelformat] = fmtdesc.flags;
286 }
287 info("found %d formats for buftype %d\n", f, type);
288 return 0;
289 }
290
testEnumFormats(struct node * node)291 int testEnumFormats(struct node *node)
292 {
293 bool supported = false;
294 unsigned type;
295 int ret;
296
297 for (type = 0; type <= V4L2_BUF_TYPE_LAST; type++) {
298 ret = testEnumFormatsType(node, type);
299 if (ret && ret != ENOTTY)
300 return ret;
301 if (!ret)
302 supported = true;
303 switch (type) {
304 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
305 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
306 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
307 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
308 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
309 case V4L2_BUF_TYPE_SDR_CAPTURE:
310 case V4L2_BUF_TYPE_SDR_OUTPUT:
311 if (ret && (node->g_caps() & buftype2cap[type]))
312 return fail("%s cap set, but no %s formats defined\n",
313 buftype2s(type).c_str(), buftype2s(type).c_str());
314 if (!ret && !(node->g_caps() & buftype2cap[type]))
315 return fail("%s cap not set, but %s formats defined\n",
316 buftype2s(type).c_str(), buftype2s(type).c_str());
317 break;
318 case V4L2_BUF_TYPE_META_CAPTURE:
319 case V4L2_BUF_TYPE_META_OUTPUT:
320 /* Metadata formats need not be present for the current input/output */
321 break;
322 default:
323 if (!ret)
324 return fail("Buffer type %s not allowed!\n", buftype2s(type).c_str());
325 break;
326 }
327 }
328
329 ret = testEnumFormatsType(node, V4L2_BUF_TYPE_PRIVATE);
330 if (ret != ENOTTY && ret != EINVAL)
331 return fail("Buffer type PRIVATE allowed!\n");
332
333 ret = testEnumFrameSizes(node, 0x20202020);
334 if (ret != ENOTTY)
335 return fail("Accepted framesize for invalid format\n");
336 ret = testEnumFrameIntervals(node, 0x20202020, 640, 480, 0);
337 if (ret != ENOTTY)
338 return fail("Accepted frameinterval for invalid format\n");
339 return supported ? 0 : ENOTTY;
340 }
341
testColorspace(bool non_zero_colorspace,uint32_t pixelformat,uint32_t colorspace,uint32_t ycbcr_enc,uint32_t quantization)342 static int testColorspace(bool non_zero_colorspace,
343 uint32_t pixelformat, uint32_t colorspace, uint32_t ycbcr_enc, uint32_t quantization)
344 {
345 if (non_zero_colorspace)
346 fail_on_test(!colorspace);
347 fail_on_test(colorspace == V4L2_COLORSPACE_BT878);
348 fail_on_test(pixelformat != V4L2_PIX_FMT_JPEG &&
349 pixelformat != V4L2_PIX_FMT_MJPEG &&
350 colorspace == V4L2_COLORSPACE_JPEG);
351 fail_on_test(colorspace >= 0xff);
352 fail_on_test(ycbcr_enc >= 0xff);
353 fail_on_test(quantization >= 0xff);
354 return 0;
355 }
356
testFBuf(struct node * node)357 int testFBuf(struct node *node)
358 {
359 struct v4l2_framebuffer fbuf;
360 uint32_t caps;
361 uint32_t flags;
362 int ret;
363
364 memset(&fbuf, 0xff, sizeof(fbuf));
365 fbuf.fmt.priv = 0;
366 ret = doioctl(node, VIDIOC_G_FBUF, &fbuf);
367 fail_on_test(ret == 0 && !(node->g_caps() & (V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_VIDEO_OUTPUT_OVERLAY)));
368 fail_on_test(ret == ENOTTY && (node->g_caps() & (V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_VIDEO_OUTPUT_OVERLAY)));
369 if (ret == ENOTTY)
370 return ret;
371 if (ret && ret != EINVAL)
372 return fail("expected EINVAL, but got %d when getting framebuffer format\n", ret);
373 node->fbuf_caps = caps = fbuf.capability;
374 flags = fbuf.flags;
375 if (node->g_caps() & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)
376 fail_on_test(!fbuf.base);
377 if (flags & V4L2_FBUF_FLAG_CHROMAKEY)
378 fail_on_test(!(caps & V4L2_FBUF_CAP_CHROMAKEY));
379 if (flags & V4L2_FBUF_FLAG_LOCAL_ALPHA)
380 fail_on_test(!(caps & V4L2_FBUF_CAP_LOCAL_ALPHA));
381 if (flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA)
382 fail_on_test(!(caps & V4L2_FBUF_CAP_GLOBAL_ALPHA));
383 if (flags & V4L2_FBUF_FLAG_LOCAL_INV_ALPHA)
384 fail_on_test(!(caps & V4L2_FBUF_CAP_LOCAL_INV_ALPHA));
385 if (flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY)
386 fail_on_test(!(caps & V4L2_FBUF_CAP_SRC_CHROMAKEY));
387 fail_on_test(!fbuf.fmt.width || !fbuf.fmt.height);
388 if (fbuf.fmt.priv)
389 warn("fbuf.fmt.priv is non-zero\n");
390 /* Not yet: unclear what EXTERNOVERLAY means in a output overlay context
391 if (caps & V4L2_FBUF_CAP_EXTERNOVERLAY) {
392 fail_on_test(fbuf.fmt.bytesperline);
393 fail_on_test(fbuf.fmt.sizeimage);
394 fail_on_test(fbuf.base);
395 }*/
396 fail_on_test(fbuf.fmt.bytesperline && fbuf.fmt.bytesperline < fbuf.fmt.width);
397 fail_on_test(fbuf.fmt.sizeimage && fbuf.fmt.sizeimage < fbuf.fmt.bytesperline * fbuf.fmt.height);
398 fail_on_test(testColorspace(true, fbuf.fmt.pixelformat, fbuf.fmt.colorspace, 0, 0));
399 return 0;
400 }
401
createInvalidFmt(struct v4l2_format & fmt,struct v4l2_clip & clip,unsigned type)402 static void createInvalidFmt(struct v4l2_format &fmt, struct v4l2_clip &clip, unsigned type)
403 {
404 memset(&fmt, 0xff, sizeof(fmt));
405 fmt.type = type;
406 fmt.fmt.pix.field = V4L2_FIELD_ANY;
407 if (type == V4L2_BUF_TYPE_VIDEO_OVERLAY ||
408 type == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY) {
409 memset(&clip, 0xff, sizeof(clip));
410 clip.next = (struct v4l2_clip *)0x0eadbeef;
411 fmt.fmt.win.clipcount = 1;
412 fmt.fmt.win.clips = &clip;
413 fmt.fmt.win.bitmap = NULL;
414 }
415 }
416
testFormatsType(struct node * node,int ret,unsigned type,struct v4l2_format & fmt,bool have_clip=false)417 static int testFormatsType(struct node *node, int ret, unsigned type, struct v4l2_format &fmt, bool have_clip = false)
418 {
419 pixfmt_map &map = node->buftype_pixfmts[type];
420 pixfmt_map *map_splane;
421 struct v4l2_pix_format &pix = fmt.fmt.pix;
422 struct v4l2_pix_format_mplane &pix_mp = fmt.fmt.pix_mp;
423 struct v4l2_window &win = fmt.fmt.win;
424 struct v4l2_vbi_format &vbi = fmt.fmt.vbi;
425 struct v4l2_sliced_vbi_format &sliced = fmt.fmt.sliced;
426 struct v4l2_sdr_format &sdr = fmt.fmt.sdr;
427 struct v4l2_meta_format &meta = fmt.fmt.meta;
428 unsigned min_data_samples;
429 unsigned min_sampling_rate;
430 v4l2_std_id std;
431 uint32_t service_set = 0;
432 unsigned tot_bytesperline = 0;
433 unsigned cnt = 0;
434
435 if (ret == ENOTTY)
436 return ret;
437 if (ret == EINVAL)
438 return ENOTTY;
439 if (ret)
440 return fail("expected EINVAL, but got %d when getting format for buftype %d\n", ret, type);
441 fail_on_test(fmt.type != type);
442
443 switch (type) {
444 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
445 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
446 fail_on_test(!pix.width || !pix.height);
447 if (map.find(pix.pixelformat) == map.end())
448 return fail("pixelformat %08x (%s) for buftype %d not reported by ENUM_FMT\n",
449 pix.pixelformat, fcc2s(pix.pixelformat).c_str(), type);
450 fail_on_test(pix.bytesperline && pix.bytesperline < pix.width);
451 fail_on_test(!pix.sizeimage);
452 if (!node->is_m2m)
453 fail_on_test(testColorspace(!node->is_io_mc,
454 pix.pixelformat, pix.colorspace,
455 pix.ycbcr_enc, pix.quantization));
456 fail_on_test(pix.field == V4L2_FIELD_ANY);
457 if (pix.priv && pix.priv != V4L2_PIX_FMT_PRIV_MAGIC)
458 return fail("priv is non-zero and non-magic!\n");
459 break;
460 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
461 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
462 fail_on_test(!pix_mp.width || !pix_mp.height);
463 map_splane = &node->buftype_pixfmts[type - 8];
464 if (map.find(pix_mp.pixelformat) == map.end() &&
465 map_splane->find(pix_mp.pixelformat) == map_splane->end())
466 return fail("pixelformat %08x (%s) for buftype %d not reported by ENUM_FMT\n",
467 pix_mp.pixelformat, fcc2s(pix_mp.pixelformat).c_str(), type);
468 if (!node->is_m2m)
469 fail_on_test(testColorspace(!node->is_io_mc,
470 pix_mp.pixelformat, pix_mp.colorspace,
471 pix_mp.ycbcr_enc, pix_mp.quantization));
472 fail_on_test(pix_mp.field == V4L2_FIELD_ANY);
473 ret = check_0(pix_mp.reserved, sizeof(pix_mp.reserved));
474 if (ret)
475 return fail("pix_mp.reserved not zeroed\n");
476 fail_on_test(pix_mp.num_planes == 0 || pix_mp.num_planes >= VIDEO_MAX_PLANES);
477 for (int i = 0; i < pix_mp.num_planes; i++) {
478 struct v4l2_plane_pix_format &pfmt = pix_mp.plane_fmt[i];
479
480 ret = check_0(pfmt.reserved, sizeof(pfmt.reserved));
481 if (ret)
482 return fail("pix_mp.plane_fmt[%d].reserved not zeroed\n", i);
483 fail_on_test(!pfmt.sizeimage);
484 tot_bytesperline += pfmt.bytesperline;
485 }
486 fail_on_test(tot_bytesperline && tot_bytesperline < pix_mp.width);
487 break;
488 case V4L2_BUF_TYPE_VBI_CAPTURE:
489 case V4L2_BUF_TYPE_VBI_OUTPUT:
490 // Currently VBI assumes that you have G_STD as well.
491 fail_on_test(doioctl(node, VIDIOC_G_STD, &std));
492 if (std & V4L2_STD_625_50) {
493 min_sampling_rate = 6937500;
494 // the number of databits for PAL teletext is 18 (clock run in) +
495 // 6 (framing code) + 42 * 8 (data).
496 min_data_samples = (vbi.sampling_rate * (18 + 6 + 42 * 8)) / min_sampling_rate;
497 } else {
498 min_sampling_rate = 5727272;
499 // the number of databits for NTSC teletext is 18 (clock run in) +
500 // 6 (framing code) + 34 * 8 (data).
501 min_data_samples = (vbi.sampling_rate * (18 + 6 + 34 * 8)) / min_sampling_rate;
502 }
503 fail_on_test(vbi.sampling_rate < min_sampling_rate);
504 fail_on_test(!vbi.samples_per_line);
505 fail_on_test(vbi.sample_format != V4L2_PIX_FMT_GREY);
506 fail_on_test(vbi.offset > vbi.samples_per_line);
507 ret = check_0(vbi.reserved, sizeof(vbi.reserved));
508 if (ret)
509 return fail("vbi.reserved not zeroed\n");
510 // Check that offset leaves enough room for the maximum required
511 // amount of data.
512 fail_on_test(min_data_samples > vbi.samples_per_line - vbi.offset);
513 fail_on_test(!vbi.count[0] || !vbi.count[1]);
514 fail_on_test(vbi.flags & ~(V4L2_VBI_UNSYNC | V4L2_VBI_INTERLACED));
515 if (vbi.flags & V4L2_VBI_INTERLACED)
516 fail_on_test(vbi.count[0] != vbi.count[1]);
517 break;
518 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
519 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
520 ret = check_0(sliced.reserved, sizeof(sliced.reserved));
521 if (ret)
522 return fail("sliced.reserved not zeroed\n");
523 fail_on_test(sliced.service_lines[0][0] || sliced.service_lines[1][0]);
524 for (int f = 0; f < 2; f++) {
525 for (int i = 0; i < 24; i++) {
526 if (sliced.service_lines[f][i])
527 cnt++;
528 service_set |= sliced.service_lines[f][i];
529 }
530 }
531 fail_on_test(sliced.io_size < sizeof(struct v4l2_sliced_vbi_data) * cnt);
532 fail_on_test(sliced.service_set != service_set);
533 break;
534 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
535 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
536 fail_on_test(win.clipcount && !(node->fbuf_caps & V4L2_FBUF_CAP_LIST_CLIPPING));
537 if (have_clip)
538 fail_on_test(!win.clipcount && (node->fbuf_caps & V4L2_FBUF_CAP_LIST_CLIPPING));
539 if (win.clipcount) {
540 struct v4l2_rect *r = &win.clips->c;
541 struct v4l2_framebuffer fb;
542
543 fail_on_test(doioctl(node, VIDIOC_G_FBUF, &fb));
544 fail_on_test(!win.clips);
545 fail_on_test(win.clips->next != (void *)0x0eadbeef);
546 fail_on_test(win.clipcount != 1);
547 fail_on_test(r->left < 0 || r->top < 0);
548 fail_on_test((unsigned)r->left >= fb.fmt.width || (unsigned)r->top >= fb.fmt.height);
549 fail_on_test(r->width == 0 || r->height == 0);
550 fail_on_test(r->left + r->width > fb.fmt.width || r->top + r->height > fb.fmt.height);
551 }
552 fail_on_test(win.chromakey && !(node->fbuf_caps & (V4L2_FBUF_CAP_CHROMAKEY | V4L2_FBUF_CAP_SRC_CHROMAKEY)));
553 if (!(node->fbuf_caps & V4L2_FBUF_CAP_BITMAP_CLIPPING))
554 fail_on_test(win.bitmap);
555 fail_on_test(win.global_alpha && !(node->fbuf_caps & V4L2_FBUF_CAP_GLOBAL_ALPHA));
556 break;
557 case V4L2_BUF_TYPE_SDR_CAPTURE:
558 case V4L2_BUF_TYPE_SDR_OUTPUT:
559 if (map.find(sdr.pixelformat) == map.end())
560 return fail("pixelformat %08x (%s) for buftype %d not reported by ENUM_FMT\n",
561 sdr.pixelformat, fcc2s(sdr.pixelformat).c_str(), type);
562 fail_on_test(sdr.buffersize == 0);
563 fail_on_test(check_0(sdr.reserved, sizeof(sdr.reserved)));
564 break;
565 case V4L2_BUF_TYPE_META_CAPTURE:
566 case V4L2_BUF_TYPE_META_OUTPUT:
567 if (map.find(meta.dataformat) == map.end())
568 return fail("dataformat %08x (%s) for buftype %d not reported by ENUM_FMT\n",
569 meta.dataformat, fcc2s(meta.dataformat).c_str(), type);
570 fail_on_test(meta.buffersize == 0);
571 break;
572 case V4L2_BUF_TYPE_PRIVATE:
573 break;
574 }
575 return 0;
576 }
577
testGetFormats(struct node * node)578 int testGetFormats(struct node *node)
579 {
580 struct v4l2_clip clip;
581 struct v4l2_format fmt;
582 bool supported = false;
583 int type;
584 int ret;
585
586 for (type = 0; type <= V4L2_BUF_TYPE_LAST; type++) {
587 createInvalidFmt(fmt, clip, type);
588 ret = doioctl(node, VIDIOC_G_FMT, &fmt);
589 if (!ret)
590 node->valid_buftypes |= 1 << type;
591
592 ret = testFormatsType(node, ret, type, fmt);
593
594 if (ret && ret != ENOTTY)
595 return ret;
596 if (!ret)
597 supported = true;
598
599 switch (type) {
600 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
601 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
602 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
603 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
604 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
605 case V4L2_BUF_TYPE_SDR_CAPTURE:
606 case V4L2_BUF_TYPE_SDR_OUTPUT:
607 if (ret && (node->g_caps() & buftype2cap[type]))
608 return fail("%s cap set, but no %s formats defined\n",
609 buftype2s(type).c_str(), buftype2s(type).c_str());
610 if (!ret && !(node->g_caps() & buftype2cap[type]))
611 return fail("%s cap not set, but %s formats defined\n",
612 buftype2s(type).c_str(), buftype2s(type).c_str());
613 break;
614 case V4L2_BUF_TYPE_META_CAPTURE:
615 case V4L2_BUF_TYPE_META_OUTPUT:
616 if (ret && !node->buftype_pixfmts[type].empty())
617 return fail("%s G_FMT failed, but %s formats defined\n",
618 buftype2s(type).c_str(), buftype2s(type).c_str());
619 if (!ret && node->buftype_pixfmts[type].empty())
620 return fail("%s G_FMT success, but no %s formats defined\n",
621 buftype2s(type).c_str(), buftype2s(type).c_str());
622 break;
623 default:
624 /* ENUMFMT doesn't support other buftypes */
625 break;
626 }
627 }
628
629 memset(&fmt, 0, sizeof(fmt));
630 fmt.type = V4L2_BUF_TYPE_PRIVATE;
631 ret = doioctl(node, VIDIOC_G_FMT, &fmt);
632 if (ret != ENOTTY && ret != EINVAL)
633 return fail("Buffer type PRIVATE allowed!\n");
634 return supported ? 0 : ENOTTY;
635 }
636
matchFormats(const struct v4l2_format & f1,const struct v4l2_format & f2)637 static bool matchFormats(const struct v4l2_format &f1, const struct v4l2_format &f2)
638 {
639 const struct v4l2_pix_format &pix1 = f1.fmt.pix;
640 const struct v4l2_pix_format &pix2 = f2.fmt.pix;
641 const struct v4l2_window &win1 = f1.fmt.win;
642 const struct v4l2_window &win2 = f2.fmt.win;
643
644 if (f1.type != f2.type)
645 return false;
646 switch (f1.type) {
647 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
648 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
649 if (!memcmp(&f1.fmt.pix, &f2.fmt.pix, sizeof(f1.fmt.pix)))
650 return true;
651 printf("\t\tG_FMT: %dx%d, %s, %d, %d, %d, %d, %d, %d, %x\n",
652 pix1.width, pix1.height, fcc2s(pix1.pixelformat).c_str(), pix1.field, pix1.bytesperline,
653 pix1.sizeimage, pix1.colorspace, pix1.ycbcr_enc, pix1.quantization, pix1.priv);
654 printf("\t\tTRY/S_FMT: %dx%d, %s, %d, %d, %d, %d, %d, %d, %x\n",
655 pix2.width, pix2.height, fcc2s(pix2.pixelformat).c_str(), pix2.field, pix2.bytesperline,
656 pix2.sizeimage, pix2.colorspace, pix2.ycbcr_enc, pix2.quantization, pix2.priv);
657 return false;
658 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
659 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
660 if (!memcmp(&f1.fmt.win, &f2.fmt.win, sizeof(f1.fmt.win)))
661 return true;
662 printf("\t\tG_FMT: %dx%d@%dx%d, %d, %x, %p, %d, %p, %x\n",
663 win1.w.width, win1.w.height, win1.w.left, win1.w.top, win1.field,
664 win1.chromakey, (void *)win1.clips, win1.clipcount, win1.bitmap, win1.global_alpha);
665 printf("\t\tTRY/S_FMT: %dx%d@%dx%d, %d, %x, %p, %d, %p, %x\n",
666 win2.w.width, win2.w.height, win2.w.left, win2.w.top, win2.field,
667 win2.chromakey, (void *)win2.clips, win2.clipcount, win2.bitmap, win2.global_alpha);
668 return false;
669 case V4L2_BUF_TYPE_VBI_CAPTURE:
670 case V4L2_BUF_TYPE_VBI_OUTPUT:
671 return !memcmp(&f1.fmt.vbi, &f2.fmt.vbi, sizeof(f1.fmt.vbi));
672 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
673 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
674 return !memcmp(&f1.fmt.sliced, &f2.fmt.sliced, sizeof(f1.fmt.sliced));
675 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
676 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
677 return !memcmp(&f1.fmt.pix_mp, &f2.fmt.pix_mp, sizeof(f1.fmt.pix_mp));
678 case V4L2_BUF_TYPE_SDR_CAPTURE:
679 case V4L2_BUF_TYPE_SDR_OUTPUT:
680 return !memcmp(&f1.fmt.sdr, &f2.fmt.sdr, sizeof(f1.fmt.sdr));
681 case V4L2_BUF_TYPE_META_CAPTURE:
682 case V4L2_BUF_TYPE_META_OUTPUT:
683 return !memcmp(&f1.fmt.meta, &f2.fmt.meta, sizeof(f1.fmt.meta));
684
685 }
686 return false;
687 }
688
testTryFormats(struct node * node)689 int testTryFormats(struct node *node)
690 {
691 struct v4l2_clip clip;
692 struct v4l2_format fmt, fmt_try;
693 int result = 0;
694 int type;
695 int ret;
696
697 for (type = 0; type <= V4L2_BUF_TYPE_LAST; type++) {
698 if (!(node->valid_buftypes & (1 << type)))
699 continue;
700
701 switch (type) {
702 case V4L2_BUF_TYPE_VBI_CAPTURE:
703 case V4L2_BUF_TYPE_VBI_OUTPUT:
704 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
705 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
706 if (!(node->cur_io_caps & V4L2_IN_CAP_STD))
707 continue;
708 break;
709 }
710
711 createInvalidFmt(fmt, clip, type);
712 doioctl(node, VIDIOC_G_FMT, &fmt);
713 fmt_try = fmt;
714 ret = doioctl(node, VIDIOC_TRY_FMT, &fmt_try);
715 if (ret)
716 return fail("%s is valid, but no TRY_FMT was implemented\n",
717 buftype2s(type).c_str());
718 ret = testFormatsType(node, ret, type, fmt_try);
719 if (ret)
720 return ret;
721 if (!matchFormats(fmt, fmt_try))
722 result = fail("%s: TRY_FMT(G_FMT) != G_FMT\n",
723 buftype2s(type).c_str());
724 }
725
726 for (type = 0; type <= V4L2_BUF_TYPE_LAST; type++) {
727 if (!(node->valid_buftypes & (1 << type)))
728 continue;
729
730 switch (type) {
731 case V4L2_BUF_TYPE_VBI_CAPTURE:
732 case V4L2_BUF_TYPE_VBI_OUTPUT:
733 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
734 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
735 if (!(node->cur_io_caps & V4L2_IN_CAP_STD))
736 continue;
737 break;
738 }
739
740 createInvalidFmt(fmt, clip, type);
741 ret = doioctl(node, VIDIOC_TRY_FMT, &fmt);
742 if (ret == EINVAL) {
743 uint32_t pixelformat;
744 bool is_mplane = false;
745
746 /* In case of failure obtain a valid pixelformat and insert
747 * that in the next attempt to call TRY_FMT. */
748 doioctl(node, VIDIOC_G_FMT, &fmt);
749
750 switch (type) {
751 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
752 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
753 pixelformat = fmt.fmt.pix.pixelformat;
754 break;
755 case V4L2_BUF_TYPE_SDR_CAPTURE:
756 case V4L2_BUF_TYPE_SDR_OUTPUT:
757 pixelformat = fmt.fmt.sdr.pixelformat;
758 break;
759 case V4L2_BUF_TYPE_META_CAPTURE:
760 case V4L2_BUF_TYPE_META_OUTPUT:
761 pixelformat = fmt.fmt.meta.dataformat;
762 break;
763 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
764 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
765 pixelformat = fmt.fmt.pix_mp.pixelformat;
766 is_mplane = true;
767 break;
768 default:
769 /* for other formats returning EINVAL is certainly wrong */
770 return fail("TRY_FMT cannot handle an invalid format\n");
771 }
772 warn_once("TRY_FMT cannot handle an invalid pixelformat.\n");
773 warn_once("This may or may not be a problem. For more information see:\n");
774 warn_once("http://www.mail-archive.com/linux-media@vger.kernel.org/msg56550.html\n");
775
776 /* Now try again, but pass a valid pixelformat. */
777 createInvalidFmt(fmt, clip, type);
778 if (node->is_sdr)
779 fmt.fmt.sdr.pixelformat = pixelformat;
780 else if (node->is_meta)
781 fmt.fmt.meta.dataformat = pixelformat;
782 else if (is_mplane)
783 fmt.fmt.pix_mp.pixelformat = pixelformat;
784 else
785 fmt.fmt.pix.pixelformat = pixelformat;
786 ret = doioctl(node, VIDIOC_TRY_FMT, &fmt);
787 if (ret == EINVAL)
788 return fail("TRY_FMT cannot handle an invalid format\n");
789 }
790 ret = testFormatsType(node, ret, type, fmt, true);
791 if (ret)
792 return ret;
793 }
794
795 memset(&fmt, 0, sizeof(fmt));
796 fmt.type = V4L2_BUF_TYPE_PRIVATE;
797 ret = doioctl(node, VIDIOC_TRY_FMT, &fmt);
798 if (ret != ENOTTY && ret != EINVAL)
799 return fail("Buffer type PRIVATE allowed!\n");
800 return node->valid_buftypes ? result : ENOTTY;
801 }
802
testM2MFormats(struct node * node)803 static int testM2MFormats(struct node *node)
804 {
805 cv4l_fmt fmt_out;
806 cv4l_fmt fmt;
807 cv4l_fmt fmt_cap;
808 uint32_t cap_type = node->g_type();
809 uint32_t out_type = v4l_type_invert(cap_type);
810 uint32_t col, ycbcr_enc, quant, xfer_func;
811
812 fail_on_test(node->g_fmt(fmt_out, out_type));
813 node->g_fmt(fmt_cap, cap_type);
814 fail_on_test(fmt_cap.g_colorspace() != fmt_out.g_colorspace());
815 fail_on_test(fmt_cap.g_ycbcr_enc() != fmt_out.g_ycbcr_enc());
816 fail_on_test(fmt_cap.g_quantization() != fmt_out.g_quantization());
817 fail_on_test(fmt_cap.g_xfer_func() != fmt_out.g_xfer_func());
818 col = fmt_out.g_colorspace() == V4L2_COLORSPACE_SMPTE170M ?
819 V4L2_COLORSPACE_REC709 : V4L2_COLORSPACE_SMPTE170M;
820 ycbcr_enc = fmt_out.g_ycbcr_enc() == V4L2_YCBCR_ENC_601 ?
821 V4L2_YCBCR_ENC_709 : V4L2_YCBCR_ENC_601;
822 quant = fmt_out.g_quantization() == V4L2_QUANTIZATION_LIM_RANGE ?
823 V4L2_QUANTIZATION_FULL_RANGE : V4L2_QUANTIZATION_LIM_RANGE;
824 xfer_func = fmt_out.g_xfer_func() == V4L2_XFER_FUNC_SRGB ?
825 V4L2_XFER_FUNC_709 : V4L2_XFER_FUNC_SRGB;
826 fmt_out.s_colorspace(col);
827 fmt_out.s_xfer_func(xfer_func);
828 fmt_out.s_ycbcr_enc(ycbcr_enc);
829 fmt_out.s_quantization(quant);
830 node->s_fmt(fmt_out);
831 fail_on_test(fmt_out.g_colorspace() != col);
832 fail_on_test(fmt_out.g_xfer_func() != xfer_func);
833 fail_on_test(fmt_out.g_ycbcr_enc() != ycbcr_enc);
834 fail_on_test(fmt_out.g_quantization() != quant);
835 node->g_fmt(fmt_cap);
836 fail_on_test(fmt_cap.g_colorspace() != col);
837 fail_on_test(fmt_cap.g_xfer_func() != xfer_func);
838 fail_on_test(fmt_cap.g_ycbcr_enc() != ycbcr_enc);
839 fail_on_test(fmt_cap.g_quantization() != quant);
840
841 if (!(node->codec_mask & STATEFUL_ENCODER))
842 return 0;
843
844 fmt = fmt_out;
845 unsigned w = (fmt.g_width() & ~7) - 4;
846 unsigned h = (fmt.g_height() & ~7) - 4;
847 fmt.s_width(w);
848 fmt.s_height(h);
849 node->s_fmt(fmt);
850 fail_on_test(fmt.g_width() < w || fmt.g_width() > fmt_out.g_width());
851 fail_on_test(fmt.g_height() < h || fmt.g_height() > fmt_out.g_height());
852 node->g_fmt(fmt_cap);
853 fail_on_test(fmt_cap.g_width() < fmt.g_width());
854 fail_on_test(fmt_cap.g_height() < fmt.g_height());
855
856 v4l2_selection sel = {
857 .type = fmt.g_type(),
858 .target = V4L2_SEL_TGT_CROP,
859 };
860 if (node->g_selection(sel) == ENOTTY) {
861 fail_on_test(fmt_cap.g_width() != fmt.g_width());
862 fail_on_test(fmt_cap.g_height() != fmt.g_height());
863 return 0;
864 }
865 fail_on_test(sel.r.top || sel.r.left);
866 fail_on_test(sel.r.width != fmt.g_width());
867 fail_on_test(sel.r.height != fmt.g_height());
868 sel.r.width = w;
869 sel.r.height = h;
870 node->s_selection(sel);
871 node->g_selection(sel);
872 fail_on_test(sel.r.top || sel.r.left);
873 fail_on_test(sel.r.width != w);
874 fail_on_test(sel.r.height != h);
875 sel.target = V4L2_SEL_TGT_CROP_BOUNDS;
876 node->g_selection(sel);
877 fail_on_test(sel.r.top || sel.r.left);
878 fail_on_test(sel.r.width != fmt.g_width());
879 fail_on_test(sel.r.height != fmt.g_height());
880 sel.target = V4L2_SEL_TGT_CROP_DEFAULT;
881 node->g_selection(sel);
882 fail_on_test(sel.r.top || sel.r.left);
883 fail_on_test(sel.r.width != fmt.g_width());
884 fail_on_test(sel.r.height != fmt.g_height());
885
886 // It is unlikely that an encoder supports composition,
887 // so warn if this is detected. Should we get encoders
888 // that can actually do this, then this test needs to
889 // be refined.
890 sel.target = V4L2_SEL_TGT_COMPOSE;
891 if (!node->g_selection(sel))
892 warn("The stateful encoder unexpectedly supports composition\n");
893
894 sel.type = fmt_cap.g_type();
895 fail_on_test(!node->g_selection(sel));
896 sel.target = V4L2_SEL_TGT_CROP;
897 fail_on_test(!node->g_selection(sel));
898
899 node->s_fmt(fmt_out);
900
901 return 0;
902 }
903
testGlobalFormat(struct node * node,int type)904 static int testGlobalFormat(struct node *node, int type)
905 {
906 struct v4l2_fmtdesc fdesc;
907 struct v4l2_frmsizeenum fsize;
908 struct v4l2_format fmt1, fmt2;
909 struct v4l2_pix_format *p1 = &fmt1.fmt.pix;
910 struct v4l2_pix_format *p2 = &fmt2.fmt.pix;
911 struct v4l2_pix_format_mplane *mp1 = &fmt1.fmt.pix_mp;
912 struct v4l2_pix_format_mplane *mp2 = &fmt2.fmt.pix_mp;
913 struct v4l2_sdr_format *sdr1 = &fmt1.fmt.sdr;
914 struct v4l2_sdr_format *sdr2 = &fmt2.fmt.sdr;
915 uint32_t pixfmt1, pixfmt2;
916 uint32_t w1 = 0, w2 = 0, h1 = 0, h2 = 0;
917
918 memset(&fmt1, 0, sizeof(fmt1));
919 memset(&fmt2, 0, sizeof(fmt2));
920 fmt1.type = fmt2.type = type;
921 fdesc.index = 1;
922 fdesc.type = type;
923 memset(&fsize, 0, sizeof(fsize));
924
925 if (!doioctl(node, VIDIOC_ENUM_FMT, &fdesc)) {
926 // We found at least two different formats.
927 pixfmt2 = fdesc.pixelformat;
928 fdesc.index = 0;
929 doioctl(node, VIDIOC_ENUM_FMT, &fdesc);
930 pixfmt1 = fdesc.pixelformat;
931 } else {
932 fdesc.index = 0;
933 doioctl(node, VIDIOC_ENUM_FMT, &fdesc);
934 fsize.pixel_format = fdesc.pixelformat;
935 if (doioctl(node, VIDIOC_ENUM_FRAMESIZES, &fsize))
936 return 0;
937 pixfmt1 = pixfmt2 = fdesc.pixelformat;
938 switch (fsize.type) {
939 case V4L2_FRMSIZE_TYPE_CONTINUOUS:
940 case V4L2_FRMSIZE_TYPE_STEPWISE:
941 w1 = fsize.stepwise.min_width;
942 w2 = fsize.stepwise.max_width;
943 h1 = fsize.stepwise.min_height;
944 h2 = fsize.stepwise.max_height;
945 break;
946 case V4L2_FRMSIZE_TYPE_DISCRETE:
947 w1 = fsize.discrete.width;
948 h1 = fsize.discrete.height;
949 fsize.index = 1;
950 doioctl(node, VIDIOC_ENUM_FRAMESIZES, &fsize);
951 w2 = fsize.discrete.width;
952 h2 = fsize.discrete.height;
953 break;
954 }
955 }
956 // Check if we have found different formats, otherwise this
957 // test is pointless.
958 // This test will also never succeed if we are using the libv4l2
959 // wrapper.
960 if (!node->g_direct() || (pixfmt1 == pixfmt2 && w1 == w2 && h1 == h2))
961 return 0;
962
963 if (type == V4L2_BUF_TYPE_SDR_CAPTURE ||
964 type == V4L2_BUF_TYPE_SDR_OUTPUT) {
965 sdr1->pixelformat = pixfmt1;
966 sdr2->pixelformat = pixfmt2;
967 } else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ||
968 type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
969 mp1->pixelformat = pixfmt1;
970 mp1->width = w1;
971 mp1->height = h1;
972 mp2->pixelformat = pixfmt2;
973 mp2->width = w2;
974 mp2->height = h2;
975 } else {
976 p1->pixelformat = pixfmt1;
977 p1->width = w1;
978 p1->height = h1;
979 p2->pixelformat = pixfmt2;
980 p2->width = w2;
981 p2->height = h2;
982 }
983 if (doioctl(node, VIDIOC_S_FMT, &fmt1)) {
984 warn("Could not set fmt1\n");
985 return 0;
986 }
987 if (doioctl(node->node2, VIDIOC_S_FMT, &fmt2)) {
988 warn("Could not set fmt2\n");
989 return 0;
990 }
991 if (type == V4L2_BUF_TYPE_SDR_CAPTURE ||
992 type == V4L2_BUF_TYPE_SDR_OUTPUT) {
993 if (sdr1->pixelformat == sdr2->pixelformat) {
994 // This compliance test only succeeds if the two formats
995 // are really different after S_FMT
996 info("Could not perform global format test\n");
997 return 0;
998 }
999 } else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ||
1000 type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
1001 if (mp1->pixelformat == mp2->pixelformat &&
1002 mp1->width == mp2->width && mp1->height == mp2->height) {
1003 // This compliance test only succeeds if the two formats
1004 // are really different after S_FMT
1005 info("Could not perform global format test\n");
1006 return 0;
1007 }
1008 } else {
1009 if (p1->pixelformat == p2->pixelformat &&
1010 p1->width == p2->width && p1->height == p2->height) {
1011 // This compliance test only succeeds if the two formats
1012 // are really different after S_FMT
1013 info("Could not perform global format test\n");
1014 return 0;
1015 }
1016 }
1017 doioctl(node, VIDIOC_G_FMT, &fmt1);
1018 if (type == V4L2_BUF_TYPE_SDR_CAPTURE ||
1019 type == V4L2_BUF_TYPE_SDR_OUTPUT) {
1020 pixfmt1 = sdr1->pixelformat;
1021 pixfmt2 = sdr2->pixelformat;
1022 } else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ||
1023 type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
1024 pixfmt1 = mp1->pixelformat;
1025 w1 = mp1->width;
1026 h1 = mp1->height;
1027 pixfmt2 = mp2->pixelformat;
1028 w2 = mp2->width;
1029 h2 = mp2->height;
1030 } else {
1031 pixfmt1 = p1->pixelformat;
1032 w1 = p1->width;
1033 h1 = p1->height;
1034 pixfmt2 = p2->pixelformat;
1035 w2 = p2->width;
1036 h2 = p2->height;
1037 }
1038 if (pixfmt1 != pixfmt2 || w1 != w2 || h1 != h2)
1039 return fail("Global format mismatch: %08x(%s)/%dx%d vs %08x(%s)/%dx%d\n",
1040 pixfmt1, fcc2s(pixfmt1).c_str(), w1, h1,
1041 pixfmt2, fcc2s(pixfmt2).c_str(), w2, h2);
1042 info("Global format check succeeded for type %d\n", type);
1043 return 0;
1044 }
1045
testSetFormats(struct node * node)1046 int testSetFormats(struct node *node)
1047 {
1048 struct v4l2_clip clip, clip_set;
1049 struct v4l2_format fmt, fmt_set;
1050 struct v4l2_format initial_fmts[V4L2_BUF_TYPE_LAST + 1];
1051 int type;
1052 int ret;
1053
1054 for (type = 0; type <= V4L2_BUF_TYPE_LAST; type++) {
1055 if (!(node->valid_buftypes & (1 << type)))
1056 continue;
1057
1058 createInvalidFmt(fmt, clip, type);
1059 doioctl(node, VIDIOC_G_FMT, &fmt);
1060
1061 initial_fmts[type] = fmt;
1062 createInvalidFmt(fmt_set, clip_set, type);
1063 ret = doioctl(node, VIDIOC_S_FMT, &fmt_set);
1064 if (ret == EINVAL) {
1065 uint32_t pixelformat;
1066 bool is_mplane = false;
1067
1068 /* In case of failure obtain a valid pixelformat and insert
1069 * that in the next attempt to call TRY_FMT. */
1070 doioctl(node, VIDIOC_G_FMT, &fmt_set);
1071
1072 switch (type) {
1073 case V4L2_BUF_TYPE_META_CAPTURE:
1074 case V4L2_BUF_TYPE_META_OUTPUT:
1075 pixelformat = fmt_set.fmt.meta.dataformat;
1076 break;
1077 case V4L2_BUF_TYPE_SDR_CAPTURE:
1078 case V4L2_BUF_TYPE_SDR_OUTPUT:
1079 pixelformat = fmt_set.fmt.sdr.pixelformat;
1080 break;
1081 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
1082 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
1083 pixelformat = fmt_set.fmt.pix.pixelformat;
1084 break;
1085 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
1086 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
1087 pixelformat = fmt_set.fmt.pix_mp.pixelformat;
1088 is_mplane = true;
1089 break;
1090 case V4L2_BUF_TYPE_VBI_CAPTURE:
1091 case V4L2_BUF_TYPE_VBI_OUTPUT:
1092 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
1093 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
1094 continue;
1095 default:
1096 /* for other formats returning EINVAL is certainly wrong */
1097 return fail("TRY_FMT cannot handle an invalid format\n");
1098 }
1099 warn_once("S_FMT cannot handle an invalid pixelformat.\n");
1100 warn_once("This may or may not be a problem. For more information see:\n");
1101 warn_once("http://www.mail-archive.com/linux-media@vger.kernel.org/msg56550.html\n");
1102
1103 /* Now try again, but pass a valid pixelformat. */
1104 createInvalidFmt(fmt_set, clip_set, type);
1105 if (node->is_sdr)
1106 fmt_set.fmt.sdr.pixelformat = pixelformat;
1107 else if (node->is_meta)
1108 fmt_set.fmt.meta.dataformat = pixelformat;
1109 else if (is_mplane)
1110 fmt_set.fmt.pix_mp.pixelformat = pixelformat;
1111 else
1112 fmt_set.fmt.pix.pixelformat = pixelformat;
1113 ret = doioctl(node, VIDIOC_S_FMT, &fmt_set);
1114 if (ret == EINVAL)
1115 return fail("S_FMT cannot handle an invalid format\n");
1116 }
1117 ret = testFormatsType(node, ret, type, fmt_set, true);
1118 if (ret)
1119 return ret;
1120
1121 fmt_set = fmt;
1122 ret = doioctl(node, VIDIOC_S_FMT, &fmt_set);
1123 ret = testFormatsType(node, ret, type, fmt_set);
1124 if (ret)
1125 return ret;
1126 if (!matchFormats(fmt, fmt_set))
1127 return fail("%s: S_FMT(G_FMT) != G_FMT\n",
1128 buftype2s(type).c_str());
1129 }
1130 memset(&fmt, 0, sizeof(fmt));
1131 fmt.type = V4L2_BUF_TYPE_PRIVATE;
1132 ret = doioctl(node, VIDIOC_S_FMT, &fmt);
1133 if (ret != ENOTTY && ret != EINVAL)
1134 return fail("Buffer type PRIVATE allowed!\n");
1135 if (!node->valid_buftypes)
1136 return ENOTTY;
1137
1138 // Test if setting a format on one fh will set the format for all
1139 // filehandles.
1140 if (node->node2 == NULL)
1141 return 0;
1142
1143 // m2m devices are special in that the format is often per-filehandle.
1144 // But colorspace information should be passed from output to capture,
1145 // so test that.
1146 if (node->is_m2m)
1147 return testM2MFormats(node);
1148
1149 for (type = 0; type <= V4L2_BUF_TYPE_LAST; type++) {
1150 switch (type) {
1151 case V4L2_BUF_TYPE_SDR_CAPTURE:
1152 case V4L2_BUF_TYPE_SDR_OUTPUT:
1153 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
1154 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
1155 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
1156 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
1157 if (!(node->valid_buftypes & (1 << type)))
1158 continue;
1159
1160 ret = testGlobalFormat(node, type);
1161 if (ret)
1162 return ret;
1163 break;
1164
1165 default:
1166 break;
1167 }
1168 }
1169
1170 /* Restore initial format */
1171 for (type = 0; type <= V4L2_BUF_TYPE_LAST; type++) {
1172 if (!(node->valid_buftypes & (1 << type)))
1173 continue;
1174
1175 doioctl(node, VIDIOC_S_FMT, &initial_fmts[type]);
1176 }
1177 return 0;
1178 }
1179
testSlicedVBICapType(struct node * node,unsigned type)1180 static int testSlicedVBICapType(struct node *node, unsigned type)
1181 {
1182 struct v4l2_sliced_vbi_cap cap;
1183 bool sliced_type = (type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ||
1184 type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT);
1185 uint32_t service_set = 0;
1186 int ret;
1187
1188 memset(&cap, 0xff, sizeof(cap));
1189 memset(&cap.reserved, 0, sizeof(cap.reserved));
1190 cap.type = type;
1191 ret = doioctl(node, VIDIOC_G_SLICED_VBI_CAP, &cap);
1192 if (ret == ENOTTY || ret == EINVAL) {
1193 if (node->cur_io_caps & V4L2_IN_CAP_STD)
1194 fail_on_test(sliced_type && (node->g_caps() & buftype2cap[type]));
1195 return ret == ENOTTY ? ret : 0;
1196 }
1197 fail_on_test(ret);
1198 fail_on_test(check_0(cap.reserved, sizeof(cap.reserved)));
1199 fail_on_test(cap.type != type);
1200 fail_on_test(!sliced_type || !(node->g_caps() & buftype2cap[type]));
1201
1202 for (int f = 0; f < 2; f++)
1203 for (int i = 0; i < 24; i++)
1204 service_set |= cap.service_lines[f][i];
1205 fail_on_test(cap.service_set != service_set);
1206 fail_on_test(cap.service_lines[0][0] || cap.service_lines[1][0]);
1207 return 0;
1208 }
1209
testSlicedVBICap(struct node * node)1210 int testSlicedVBICap(struct node *node)
1211 {
1212 int ret;
1213
1214 ret = testSlicedVBICapType(node, V4L2_BUF_TYPE_SLICED_VBI_CAPTURE);
1215 if (ret)
1216 return ret;
1217 ret = testSlicedVBICapType(node, V4L2_BUF_TYPE_SLICED_VBI_OUTPUT);
1218 if (ret)
1219 return ret;
1220 return testSlicedVBICapType(node, V4L2_BUF_TYPE_VIDEO_CAPTURE);
1221 }
1222
testParmStruct(struct node * node,struct v4l2_streamparm & parm)1223 static int testParmStruct(struct node *node, struct v4l2_streamparm &parm)
1224 {
1225 struct v4l2_captureparm *cap = &parm.parm.capture;
1226 struct v4l2_outputparm *out = &parm.parm.output;
1227 int ret;
1228
1229 switch (parm.type) {
1230 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
1231 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
1232 ret = check_0(cap->reserved, sizeof(cap->reserved));
1233 if (ret)
1234 return fail("reserved not zeroed\n");
1235 fail_on_test(cap->readbuffers > VIDEO_MAX_FRAME);
1236 if (!(node->g_caps() & V4L2_CAP_READWRITE))
1237 fail_on_test(cap->readbuffers);
1238 else if (node->g_caps() & V4L2_CAP_STREAMING)
1239 fail_on_test(!cap->readbuffers);
1240 fail_on_test(cap->capability & ~V4L2_CAP_TIMEPERFRAME);
1241 fail_on_test(node->has_frmintervals && !cap->capability);
1242 fail_on_test(cap->capturemode & ~V4L2_MODE_HIGHQUALITY);
1243 if (cap->capturemode & V4L2_MODE_HIGHQUALITY)
1244 warn("V4L2_MODE_HIGHQUALITY is poorly defined\n");
1245 fail_on_test(cap->extendedmode);
1246 if (cap->capability & V4L2_CAP_TIMEPERFRAME)
1247 fail_on_test(cap->timeperframe.numerator == 0 || cap->timeperframe.denominator == 0);
1248 break;
1249 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
1250 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
1251 ret = check_0(out->reserved, sizeof(out->reserved));
1252 if (ret)
1253 return fail("reserved not zeroed\n");
1254 fail_on_test(out->writebuffers > VIDEO_MAX_FRAME);
1255 if (!(node->g_caps() & V4L2_CAP_READWRITE))
1256 fail_on_test(out->writebuffers);
1257 else if (node->g_caps() & V4L2_CAP_STREAMING)
1258 fail_on_test(!out->writebuffers);
1259 fail_on_test(out->capability & ~V4L2_CAP_TIMEPERFRAME);
1260 fail_on_test(out->outputmode);
1261 fail_on_test(out->extendedmode);
1262 if (out->capability & V4L2_CAP_TIMEPERFRAME)
1263 fail_on_test(out->timeperframe.numerator == 0 || out->timeperframe.denominator == 0);
1264 break;
1265 default:
1266 break;
1267 }
1268 return 0;
1269 }
1270
testParmType(struct node * node,unsigned type)1271 static int testParmType(struct node *node, unsigned type)
1272 {
1273 struct v4l2_streamparm parm;
1274 int ret;
1275
1276 memset(&parm, 0, sizeof(parm));
1277 parm.type = type;
1278 if (V4L2_TYPE_IS_OUTPUT(type))
1279 memset(parm.parm.output.reserved, 0xff,
1280 sizeof(parm.parm.output.reserved));
1281 else
1282 memset(parm.parm.capture.reserved, 0xff,
1283 sizeof(parm.parm.capture.reserved));
1284
1285 ret = doioctl(node, VIDIOC_G_PARM, &parm);
1286 switch (type) {
1287 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
1288 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
1289 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
1290 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
1291 if (type && (node->g_caps() & buftype2cap[type]))
1292 fail_on_test(ret && node->has_frmintervals);
1293 if (ret)
1294 break;
1295 break;
1296 default:
1297 fail_on_test(ret == 0);
1298 memset(&parm, 0, sizeof(parm));
1299 parm.type = type;
1300 fail_on_test(!doioctl(node, VIDIOC_S_PARM, &parm));
1301 break;
1302 }
1303 if (ret == ENOTTY)
1304 return ret;
1305 if (ret == EINVAL)
1306 return ENOTTY;
1307 if (ret)
1308 return fail("expected EINVAL, but got %d when getting parms for buftype %d\n", ret, type);
1309 fail_on_test(parm.type != type);
1310 ret = testParmStruct(node, parm);
1311 if (ret)
1312 return ret;
1313
1314 memset(&parm, 0, sizeof(parm));
1315 parm.type = type;
1316 if (V4L2_TYPE_IS_OUTPUT(type))
1317 memset(parm.parm.output.reserved, 0xff,
1318 sizeof(parm.parm.output.reserved));
1319 else
1320 memset(parm.parm.capture.reserved, 0xff,
1321 sizeof(parm.parm.capture.reserved));
1322 ret = doioctl(node, VIDIOC_S_PARM, &parm);
1323
1324 uint32_t cap;
1325
1326 if (V4L2_TYPE_IS_OUTPUT(type))
1327 cap = parm.parm.output.capability;
1328 else
1329 cap = parm.parm.capture.capability;
1330 fail_on_test(ret && node->has_frmintervals);
1331 if (!ret && (cap & V4L2_CAP_TIMEPERFRAME) && !node->has_frmintervals)
1332 warn("S_PARM is supported for buftype %d, but not for ENUM_FRAMEINTERVALS\n", type);
1333 if (ret == ENOTTY)
1334 return 0;
1335 if (ret)
1336 return fail("got error %d when setting parms for buftype %d\n", ret, type);
1337 fail_on_test(parm.type != type);
1338 if (!(parm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME))
1339 warn("S_PARM is supported but doesn't report V4L2_CAP_TIMEPERFRAME\n");
1340 ret = testParmStruct(node, parm);
1341 if (ret)
1342 return ret;
1343 if (V4L2_TYPE_IS_OUTPUT(type)) {
1344 parm.parm.output.timeperframe.numerator = 0;
1345 parm.parm.output.timeperframe.denominator = 1;
1346 } else {
1347 parm.parm.capture.timeperframe.numerator = 0;
1348 parm.parm.capture.timeperframe.denominator = 1;
1349 }
1350 fail_on_test(doioctl(node, VIDIOC_S_PARM, &parm));
1351 ret = testParmStruct(node, parm);
1352 if (ret)
1353 return ret;
1354 if (V4L2_TYPE_IS_OUTPUT(type)) {
1355 parm.parm.output.timeperframe.numerator = 1;
1356 parm.parm.output.timeperframe.denominator = 0;
1357 } else {
1358 parm.parm.capture.timeperframe.numerator = 1;
1359 parm.parm.capture.timeperframe.denominator = 0;
1360 }
1361 fail_on_test(doioctl(node, VIDIOC_S_PARM, &parm));
1362 return testParmStruct(node, parm);
1363 }
1364
testParm(struct node * node)1365 int testParm(struct node *node)
1366 {
1367 bool supported = false;
1368 int type;
1369 int ret;
1370
1371 for (type = 0; type <= V4L2_BUF_TYPE_LAST; type++) {
1372 ret = testParmType(node, type);
1373
1374 if (ret && ret != ENOTTY)
1375 return ret;
1376 if (!ret) {
1377 supported = true;
1378 if (V4L2_TYPE_IS_OUTPUT(type)) {
1379 if (!node->has_vid_out())
1380 return fail("video output caps not set, but G/S_PARM worked\n");
1381 } else if (!node->has_vid_cap()) {
1382 return fail("video capture caps not set, but G/S_PARM worked\n");
1383 }
1384 }
1385 }
1386
1387 ret = testParmType(node, V4L2_BUF_TYPE_PRIVATE);
1388 if (ret != ENOTTY && ret != EINVAL)
1389 return fail("Buffer type PRIVATE allowed!\n");
1390 return supported ? 0 : ENOTTY;
1391 }
1392
rect_is_inside(const struct v4l2_rect * r1,const struct v4l2_rect * r2)1393 static bool rect_is_inside(const struct v4l2_rect *r1, const struct v4l2_rect *r2)
1394 {
1395 return r1->left >= r2->left && r1->top >= r2->top &&
1396 r1->left + r1->width <= r2->left + r2->width &&
1397 r1->top + r1->height <= r2->top + r2->height;
1398 }
1399
testBasicSelection(struct node * node,unsigned type,unsigned target)1400 static int testBasicSelection(struct node *node, unsigned type, unsigned target)
1401 {
1402 struct v4l2_selection sel = {
1403 type,
1404 target,
1405 };
1406 int ret;
1407 v4l2_format fmt;
1408
1409 memset(sel.reserved, 0xff, sizeof(sel.reserved));
1410 ret = doioctl(node, VIDIOC_G_SELECTION, &sel);
1411 if (ret == ENOTTY || ret == EINVAL || ret == ENODATA) {
1412 fail_on_test(!doioctl(node, VIDIOC_S_SELECTION, &sel));
1413 return ENOTTY;
1414 }
1415 fail_on_test(ret);
1416 fail_on_test(check_0(sel.reserved, sizeof(sel.reserved)));
1417
1418 // selection is not supported (for now) if there is more than one
1419 // discrete frame size.
1420 if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1421 v4l_format_init(&fmt, node->is_planar ?
1422 V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
1423 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1424 else
1425 v4l_format_init(&fmt, node->is_planar ?
1426 V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE :
1427 V4L2_BUF_TYPE_VIDEO_OUTPUT);
1428 fail_on_test(doioctl(node, VIDIOC_G_FMT, &fmt));
1429 uint32_t pixfmt = v4l_format_g_pixelformat(&fmt);
1430 if (node->frmsizes_count.find(pixfmt) != node->frmsizes_count.end())
1431 fail_on_test(node->frmsizes_count[pixfmt] > 1);
1432
1433 // Check handling of invalid type.
1434 sel.type = 0xff;
1435 fail_on_test(doioctl(node, VIDIOC_G_SELECTION, &sel) != EINVAL);
1436 // Check handling of invalid target.
1437 sel.type = type;
1438 sel.target = 0xffff;
1439 fail_on_test(doioctl(node, VIDIOC_G_SELECTION, &sel) != EINVAL);
1440 return 0;
1441 }
1442
testBasicCrop(struct node * node,unsigned type)1443 static int testBasicCrop(struct node *node, unsigned type)
1444 {
1445 struct v4l2_selection sel_crop = {
1446 type,
1447 V4L2_SEL_TGT_CROP,
1448 };
1449 struct v4l2_selection sel_def;
1450 struct v4l2_selection sel_bounds;
1451
1452 fail_on_test(doioctl(node, VIDIOC_G_SELECTION, &sel_crop));
1453 fail_on_test(!sel_crop.r.width || !sel_crop.r.height);
1454 sel_def = sel_crop;
1455 sel_def.target = V4L2_SEL_TGT_CROP_DEFAULT;
1456 fail_on_test(doioctl(node, VIDIOC_G_SELECTION, &sel_def));
1457 fail_on_test(!sel_def.r.width || !sel_def.r.height);
1458 if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
1459 fail_on_test(sel_def.r.left || sel_def.r.top);
1460 sel_bounds = sel_crop;
1461 sel_bounds.target = V4L2_SEL_TGT_CROP_BOUNDS;
1462 fail_on_test(doioctl(node, VIDIOC_G_SELECTION, &sel_bounds));
1463 fail_on_test(!sel_bounds.r.width || !sel_bounds.r.height);
1464 if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
1465 fail_on_test(sel_bounds.r.left || sel_bounds.r.top);
1466 fail_on_test(!rect_is_inside(&sel_crop.r, &sel_bounds.r));
1467 fail_on_test(!rect_is_inside(&sel_def.r, &sel_bounds.r));
1468
1469 sel_crop.type = type;
1470 sel_crop.target = V4L2_SEL_TGT_CROP;
1471 fail_on_test(doioctl(node, VIDIOC_G_SELECTION, &sel_crop));
1472
1473 // Check handling of invalid type.
1474 sel_crop.type = 0xff;
1475 int s_sel_ret = doioctl(node, VIDIOC_S_SELECTION, &sel_crop);
1476 fail_on_test(s_sel_ret != EINVAL && s_sel_ret != ENOTTY);
1477 // Check handling of invalid target.
1478 sel_crop.type = type;
1479 sel_crop.target = 0xffff;
1480 fail_on_test(doioctl(node, VIDIOC_S_SELECTION, &sel_crop) != s_sel_ret);
1481 // Check handling of read-only targets.
1482 sel_crop.target = V4L2_SEL_TGT_CROP_DEFAULT;
1483 fail_on_test(doioctl(node, VIDIOC_S_SELECTION, &sel_crop) != s_sel_ret);
1484 sel_crop.target = V4L2_SEL_TGT_CROP_BOUNDS;
1485 fail_on_test(doioctl(node, VIDIOC_S_SELECTION, &sel_crop) != s_sel_ret);
1486 return 0;
1487 }
1488
testLegacyCrop(struct node * node)1489 static int testLegacyCrop(struct node *node)
1490 {
1491 struct v4l2_cropcap cap = {
1492 node->g_selection_type()
1493 };
1494 struct v4l2_crop crop = {
1495 node->g_selection_type()
1496 };
1497 struct v4l2_selection sel = {
1498 node->g_selection_type()
1499 };
1500
1501 sel.target = node->can_capture ? V4L2_SEL_TGT_CROP_DEFAULT :
1502 V4L2_SEL_TGT_COMPOSE_DEFAULT;
1503 /*
1504 * If either CROPCAP or G_CROP works, then G_SELECTION should
1505 * work as well.
1506 * If neither CROPCAP nor G_CROP work, then G_SELECTION shouldn't
1507 * work either.
1508 */
1509 if (!doioctl(node, VIDIOC_CROPCAP, &cap)) {
1510 fail_on_test(doioctl(node, VIDIOC_G_SELECTION, &sel));
1511
1512 // Checks for mplane types
1513 switch (cap.type) {
1514 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
1515 cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1516 break;
1517 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
1518 cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1519 break;
1520 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
1521 cap.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1522 break;
1523 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
1524 cap.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1525 break;
1526 }
1527 // Replace with fail_on_test once kernel is fixed for this.
1528 warn_on_test(doioctl(node, VIDIOC_CROPCAP, &cap));
1529 cap.type = 0xff;
1530 fail_on_test(doioctl(node, VIDIOC_CROPCAP, &cap) != EINVAL);
1531 } else {
1532 fail_on_test(!doioctl(node, VIDIOC_G_SELECTION, &sel));
1533 }
1534 sel.target = node->can_capture ? V4L2_SEL_TGT_CROP :
1535 V4L2_SEL_TGT_COMPOSE;
1536 if (!doioctl(node, VIDIOC_G_CROP, &crop))
1537 fail_on_test(doioctl(node, VIDIOC_G_SELECTION, &sel));
1538 else
1539 fail_on_test(!doioctl(node, VIDIOC_G_SELECTION, &sel));
1540 return 0;
1541 }
1542
testCropping(struct node * node)1543 int testCropping(struct node *node)
1544 {
1545 int ret_cap, ret_out;
1546
1547 ret_cap = ENOTTY;
1548 ret_out = ENOTTY;
1549
1550 fail_on_test(testLegacyCrop(node));
1551 if (node->can_capture && node->is_video)
1552 ret_cap = testBasicSelection(node, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_SEL_TGT_CROP);
1553 if (node->can_output && node->is_video)
1554 ret_out = testBasicSelection(node, V4L2_BUF_TYPE_VIDEO_OUTPUT, V4L2_SEL_TGT_CROP);
1555 if ((!node->can_capture && !node->can_output) || !node->is_video) {
1556 struct v4l2_selection sel = {
1557 V4L2_BUF_TYPE_VIDEO_CAPTURE,
1558 V4L2_SEL_TGT_CROP
1559 };
1560
1561 if (node->can_output)
1562 sel.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1563 fail_on_test(doioctl(node, VIDIOC_G_SELECTION, &sel) != ENOTTY);
1564 fail_on_test(doioctl(node, VIDIOC_S_SELECTION, &sel) != ENOTTY);
1565 }
1566 if (ret_cap && ret_out)
1567 return ret_cap;
1568
1569 if (!ret_cap) {
1570 fail_on_test(IS_ENCODER(node));
1571 fail_on_test(testBasicCrop(node, V4L2_BUF_TYPE_VIDEO_CAPTURE));
1572 }
1573 if (!ret_out) {
1574 fail_on_test(IS_DECODER(node));
1575 fail_on_test(testBasicCrop(node, V4L2_BUF_TYPE_VIDEO_OUTPUT));
1576 }
1577
1578 return 0;
1579 }
1580
testBasicCompose(struct node * node,unsigned type)1581 static int testBasicCompose(struct node *node, unsigned type)
1582 {
1583 struct v4l2_selection sel_compose = {
1584 type,
1585 V4L2_SEL_TGT_COMPOSE,
1586 };
1587 struct v4l2_selection sel_def;
1588 struct v4l2_selection sel_bounds;
1589 struct v4l2_selection sel_padded;
1590 int ret;
1591
1592 fail_on_test(doioctl(node, VIDIOC_G_SELECTION, &sel_compose));
1593 fail_on_test(!sel_compose.r.width || !sel_compose.r.height);
1594 sel_def = sel_compose;
1595 sel_def.target = V4L2_SEL_TGT_COMPOSE_DEFAULT;
1596 fail_on_test(doioctl(node, VIDIOC_G_SELECTION, &sel_def));
1597 fail_on_test(!sel_def.r.width || !sel_def.r.height);
1598 if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1599 fail_on_test(sel_def.r.left || sel_def.r.top);
1600 sel_bounds = sel_compose;
1601 sel_bounds.target = V4L2_SEL_TGT_COMPOSE_BOUNDS;
1602 fail_on_test(doioctl(node, VIDIOC_G_SELECTION, &sel_bounds));
1603 fail_on_test(!sel_bounds.r.width || !sel_bounds.r.height);
1604 if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1605 fail_on_test(sel_bounds.r.left || sel_bounds.r.top);
1606 fail_on_test(!rect_is_inside(&sel_compose.r, &sel_bounds.r));
1607 fail_on_test(!rect_is_inside(&sel_def.r, &sel_bounds.r));
1608 sel_padded = sel_compose;
1609 sel_padded.target = V4L2_SEL_TGT_COMPOSE_PADDED;
1610 ret = doioctl(node, VIDIOC_G_SELECTION, &sel_padded);
1611 fail_on_test(ret && ret != EINVAL);
1612 if (!ret) {
1613 fail_on_test(!rect_is_inside(&sel_padded.r, &sel_bounds.r));
1614 fail_on_test(!sel_padded.r.width || !sel_padded.r.height);
1615 }
1616
1617 sel_compose.type = type;
1618 sel_compose.target = V4L2_SEL_TGT_COMPOSE;
1619 fail_on_test(doioctl(node, VIDIOC_G_SELECTION, &sel_compose));
1620
1621 // Check handling of invalid type.
1622 sel_compose.type = 0xff;
1623 int s_sel_ret = doioctl(node, VIDIOC_S_SELECTION, &sel_compose);
1624 fail_on_test(s_sel_ret != EINVAL && s_sel_ret != ENOTTY);
1625 // Check handling of invalid target.
1626 sel_compose.type = type;
1627 sel_compose.target = 0xffff;
1628 fail_on_test(doioctl(node, VIDIOC_S_SELECTION, &sel_compose) != s_sel_ret);
1629 // Check handling of read-only targets.
1630 sel_compose.target = V4L2_SEL_TGT_COMPOSE_DEFAULT;
1631 fail_on_test(doioctl(node, VIDIOC_S_SELECTION, &sel_compose) != s_sel_ret);
1632 sel_compose.target = V4L2_SEL_TGT_COMPOSE_BOUNDS;
1633 fail_on_test(doioctl(node, VIDIOC_S_SELECTION, &sel_compose) != s_sel_ret);
1634 sel_compose.target = V4L2_SEL_TGT_COMPOSE_PADDED;
1635 fail_on_test(doioctl(node, VIDIOC_S_SELECTION, &sel_compose) != s_sel_ret);
1636 return 0;
1637 }
1638
testComposing(struct node * node)1639 int testComposing(struct node *node)
1640 {
1641 int ret_cap, ret_out;
1642
1643 ret_cap = ENOTTY;
1644 ret_out = ENOTTY;
1645
1646 if (node->can_capture && node->is_video)
1647 ret_cap = testBasicSelection(node, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_SEL_TGT_COMPOSE);
1648 if (node->can_output && node->is_video)
1649 ret_out = testBasicSelection(node, V4L2_BUF_TYPE_VIDEO_OUTPUT, V4L2_SEL_TGT_COMPOSE);
1650 if ((!node->can_capture && !node->can_output) || !node->is_video) {
1651 struct v4l2_selection sel = {
1652 V4L2_BUF_TYPE_VIDEO_OUTPUT,
1653 V4L2_SEL_TGT_COMPOSE
1654 };
1655
1656 if (node->can_output)
1657 sel.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1658 fail_on_test(doioctl(node, VIDIOC_G_SELECTION, &sel) != ENOTTY);
1659 fail_on_test(doioctl(node, VIDIOC_S_SELECTION, &sel) != ENOTTY);
1660 }
1661 if (ret_cap && ret_out)
1662 return ret_cap;
1663
1664 if (!ret_cap) {
1665 fail_on_test(IS_ENCODER(node));
1666 fail_on_test(testBasicCompose(node, V4L2_BUF_TYPE_VIDEO_CAPTURE));
1667 }
1668 if (!ret_out) {
1669 fail_on_test(IS_DECODER(node));
1670 fail_on_test(testBasicCompose(node, V4L2_BUF_TYPE_VIDEO_OUTPUT));
1671 }
1672
1673 return 0;
1674 }
1675
testBasicScaling(struct node * node,const struct v4l2_format & cur)1676 static int testBasicScaling(struct node *node, const struct v4l2_format &cur)
1677 {
1678 struct v4l2_selection sel_crop = {
1679 V4L2_BUF_TYPE_VIDEO_CAPTURE,
1680 V4L2_SEL_TGT_CROP,
1681 0,
1682 { 1, 1, 0, 0 }
1683 };
1684 struct v4l2_selection sel_compose = {
1685 V4L2_BUF_TYPE_VIDEO_CAPTURE,
1686 V4L2_SEL_TGT_COMPOSE,
1687 0,
1688 { 1, 1, 0, 0 }
1689 };
1690 unsigned compose_w = 0, compose_h = 0;
1691 unsigned crop_w = 0, crop_h = 0;
1692 struct v4l2_format fmt = cur;
1693 bool have_crop = false;
1694 bool crop_is_fmt = false;
1695 bool crop_is_const = false;
1696 bool have_compose = false;
1697 bool compose_is_fmt = false;
1698 bool compose_is_const = false;
1699 bool compose_is_crop = false;
1700 uint64_t cookie;
1701 int ret;
1702
1703 if (node->can_output) {
1704 sel_crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1705 sel_compose.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1706 }
1707 doioctl(node, VIDIOC_S_SELECTION, &sel_crop);
1708 doioctl(node, VIDIOC_S_SELECTION, &sel_compose);
1709 v4l_format_s_width(&fmt, 1);
1710 v4l_format_s_height(&fmt, 1);
1711 v4l_format_s_field(&fmt, V4L2_FIELD_ANY);
1712 fail_on_test(doioctl(node, VIDIOC_S_FMT, &fmt));
1713 ret = doioctl(node, VIDIOC_G_SELECTION, &sel_crop);
1714 have_crop = ret == 0;
1715 if (ret == 0) {
1716 crop_is_fmt = sel_crop.r.width == v4l_format_g_width(&fmt) &&
1717 sel_crop.r.height == v4l_format_g_height(&fmt);
1718 crop_w = sel_crop.r.width;
1719 crop_h = sel_crop.r.height;
1720 }
1721 ret = doioctl(node, VIDIOC_G_SELECTION, &sel_compose);
1722 have_compose = ret == 0;
1723 if (ret == 0) {
1724 compose_is_fmt = sel_compose.r.width == v4l_format_g_width(&fmt) &&
1725 sel_compose.r.height == v4l_format_g_height(&fmt);
1726 compose_w = sel_compose.r.width;
1727 compose_h = sel_compose.r.height;
1728 }
1729 if (have_crop && have_compose)
1730 compose_is_crop = compose_w == crop_w &&
1731 compose_h == crop_h;
1732
1733 cookie = (static_cast<uint64_t>(v4l_format_g_pixelformat(&fmt)) << 32) |
1734 (v4l_format_g_width(&fmt) << 16) |
1735 v4l_format_g_height(&fmt);
1736 if (node->can_output) {
1737 if (node->frmsizes.find(cookie) == node->frmsizes.end() && !compose_is_fmt &&
1738 (v4l_format_g_width(&fmt) != v4l_format_g_width(&cur) ||
1739 v4l_format_g_height(&fmt) != v4l_format_g_height(&cur)))
1740 node->can_scale = true;
1741 } else {
1742 if (node->frmsizes.find(cookie) == node->frmsizes.end() && !crop_is_fmt &&
1743 (v4l_format_g_width(&fmt) != v4l_format_g_width(&cur) ||
1744 v4l_format_g_height(&fmt) != v4l_format_g_height(&cur)))
1745 node->can_scale = true;
1746 }
1747 sel_crop.r.width = sel_compose.r.width = 0x4000;
1748 sel_crop.r.height = sel_compose.r.height = 0x4000;
1749 v4l_format_s_width(&fmt, 0x4000);
1750 v4l_format_s_height(&fmt, 0x4000);
1751 v4l_format_s_field(&fmt, V4L2_FIELD_ANY);
1752 fail_on_test(doioctl(node, VIDIOC_S_FMT, &fmt));
1753 doioctl(node, VIDIOC_S_SELECTION, &sel_crop);
1754 doioctl(node, VIDIOC_S_SELECTION, &sel_compose);
1755 crop_is_fmt = false;
1756 ret = doioctl(node, VIDIOC_G_SELECTION, &sel_crop);
1757 if (ret == 0) {
1758 crop_is_fmt = sel_crop.r.width == v4l_format_g_width(&fmt) &&
1759 sel_crop.r.height == v4l_format_g_height(&fmt);
1760 crop_is_const = sel_crop.r.width == crop_w &&
1761 sel_crop.r.height == crop_h;
1762 }
1763 ret = doioctl(node, VIDIOC_G_SELECTION, &sel_compose);
1764 if (ret == 0) {
1765 compose_is_fmt = sel_compose.r.width == v4l_format_g_width(&fmt) &&
1766 sel_compose.r.height == v4l_format_g_height(&fmt);
1767 compose_is_const = sel_compose.r.width == compose_w &&
1768 sel_compose.r.height == compose_h;
1769 }
1770 if (compose_is_crop)
1771 compose_is_crop = sel_compose.r.width == sel_crop.r.width &&
1772 sel_compose.r.height == sel_crop.r.height;
1773 cookie = (static_cast<uint64_t>(v4l_format_g_pixelformat(&fmt)) << 32) |
1774 (v4l_format_g_width(&fmt) << 16) |
1775 v4l_format_g_height(&fmt);
1776 if (node->can_output) {
1777 if (node->frmsizes.find(cookie) == node->frmsizes.end() && !compose_is_fmt &&
1778 (v4l_format_g_width(&fmt) != v4l_format_g_width(&cur) ||
1779 v4l_format_g_height(&fmt) != v4l_format_g_height(&cur)))
1780 node->can_scale = true;
1781 if (crop_is_const || compose_is_crop)
1782 node->can_scale = false;
1783 } else {
1784 if (node->frmsizes.find(cookie) == node->frmsizes.end() && !crop_is_fmt &&
1785 (v4l_format_g_width(&fmt) != v4l_format_g_width(&cur) ||
1786 v4l_format_g_height(&fmt) != v4l_format_g_height(&cur)))
1787 node->can_scale = true;
1788 if (compose_is_const || compose_is_crop)
1789 node->can_scale = false;
1790 }
1791 fail_on_test(node->can_scale &&
1792 node->frmsizes_count[v4l_format_g_pixelformat(&cur)]);
1793 return 0;
1794 }
1795
testM2MScaling(struct node * node)1796 static int testM2MScaling(struct node *node)
1797 {
1798 struct v4l2_selection sel_compose = {
1799 V4L2_BUF_TYPE_VIDEO_CAPTURE,
1800 V4L2_SEL_TGT_COMPOSE,
1801 0,
1802 { 1, 1, 0, 0 }
1803 };
1804 uint32_t cap_type = node->g_type();
1805 uint32_t out_type = v4l_type_invert(cap_type);
1806 cv4l_fmt out_fmt, cap_fmt, fmt;
1807
1808 fail_on_test(node->g_fmt(out_fmt, out_type));
1809 out_fmt.s_width(1);
1810 out_fmt.s_height(1);
1811 fail_on_test(node->s_fmt(out_fmt, out_type));
1812
1813 fail_on_test(node->g_fmt(cap_fmt, cap_type));
1814 cap_fmt.s_width(out_fmt.g_width());
1815 cap_fmt.s_height(out_fmt.g_height());
1816 fail_on_test(node->s_fmt(cap_fmt, cap_type));
1817 fmt = cap_fmt;
1818 fmt.s_width(0x4000);
1819 fmt.s_height(0x4000);
1820 fail_on_test(node->s_fmt(fmt, cap_type));
1821 if (!doioctl(node, VIDIOC_G_SELECTION, &sel_compose)) {
1822 sel_compose.r.width = fmt.g_width();
1823 sel_compose.r.height = fmt.g_height();
1824 doioctl(node, VIDIOC_S_SELECTION, &sel_compose);
1825 doioctl(node, VIDIOC_G_SELECTION, &sel_compose);
1826 if (sel_compose.r.width > cap_fmt.g_width() ||
1827 sel_compose.r.height > cap_fmt.g_height())
1828 node->can_scale = true;
1829 } else {
1830 if (fmt.g_width() > cap_fmt.g_width() ||
1831 fmt.g_height() > cap_fmt.g_height())
1832 node->can_scale = true;
1833 }
1834 return node->can_scale ? 0 : ENOTTY;
1835 }
1836
testScaling(struct node * node)1837 int testScaling(struct node *node)
1838 {
1839 struct v4l2_format fmt;
1840
1841 if (!node->is_video)
1842 return ENOTTY;
1843 node->can_scale = false;
1844
1845 /*
1846 * Encoders do not have a scaler. Decoders might, but it is
1847 * very hard to detect this for any decoder but JPEG.
1848 */
1849 if (node->codec_mask && node->codec_mask != JPEG_DECODER)
1850 return ENOTTY;
1851
1852 if (node->is_m2m)
1853 return testM2MScaling(node);
1854
1855 if (node->can_capture) {
1856 v4l_format_init(&fmt, node->is_planar ?
1857 V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
1858 V4L2_BUF_TYPE_VIDEO_CAPTURE);
1859 fail_on_test(doioctl(node, VIDIOC_G_FMT, &fmt));
1860 testBasicScaling(node, fmt);
1861 fail_on_test(doioctl(node, VIDIOC_S_FMT, &fmt));
1862 }
1863 if (node->can_output) {
1864 v4l_format_init(&fmt, node->is_planar ?
1865 V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE :
1866 V4L2_BUF_TYPE_VIDEO_OUTPUT);
1867 fail_on_test(doioctl(node, VIDIOC_G_FMT, &fmt));
1868 testBasicScaling(node, fmt);
1869 fail_on_test(doioctl(node, VIDIOC_S_FMT, &fmt));
1870 }
1871 return node->can_scale ? 0 : ENOTTY;
1872 }
1873