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