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