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