2
V4L2 API format ioctl tests.
4
Copyright (C) 2011 Hans Verkuil <hans.verkuil@cisco.com>
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.
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.
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
26
#include <sys/types.h>
31
#include <sys/ioctl.h>
33
#include "v4l2-compliance.h"
35
static const __u32 buftype2cap[] = {
37
V4L2_CAP_VIDEO_CAPTURE,
38
V4L2_CAP_VIDEO_OUTPUT,
39
V4L2_CAP_VIDEO_OVERLAY,
42
V4L2_CAP_SLICED_VBI_CAPTURE,
43
V4L2_CAP_SLICED_VBI_OUTPUT,
44
V4L2_CAP_VIDEO_OUTPUT_OVERLAY,
46
V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_CAPTURE,
47
V4L2_CAP_VIDEO_OUTPUT_MPLANE | V4L2_CAP_VIDEO_OUTPUT,
50
static int testEnumFrameIntervals(struct node *node, __u32 pixfmt, __u32 w, __u32 h, bool valid)
52
struct v4l2_frmivalenum frmival;
53
struct v4l2_frmival_stepwise *sw = &frmival.stepwise;
54
bool found_stepwise = false;
59
memset(&frmival, 0xff, sizeof(frmival));
61
frmival.pixel_format = pixfmt;
65
ret = doioctl(node, VIDIOC_ENUM_FRAMEINTERVALS, &frmival);
66
if (f == 0 && ret == EINVAL) {
68
warn("found framesize %dx%d, but no frame intervals\n", w, h);
74
return fail("expected EINVAL, but got %d when enumerating frameinterval %d\n", ret, f);
75
ret = check_0(frmival.reserved, sizeof(frmival.reserved));
77
return fail("frmival.reserved not zeroed\n");
78
if (frmival.pixel_format != pixfmt || frmival.index != f ||
79
frmival.width != w || frmival.height != h)
80
return fail("frmival.pixel_format, index, width or height changed\n");
81
switch (frmival.type) {
82
case V4L2_FRMIVAL_TYPE_DISCRETE:
83
ret = check_fract(&frmival.discrete);
85
return fail("mixing discrete and stepwise is not allowed\n");
87
case V4L2_FRMIVAL_TYPE_CONTINUOUS:
88
if (sw->step.numerator != 1 || sw->step.denominator != 1)
89
return fail("invalid step for continuous frameinterval\n");
91
case V4L2_FRMIVAL_TYPE_STEPWISE:
93
return fail("index must be 0 for stepwise/continuous frameintervals\n");
94
found_stepwise = true;
95
ret = check_fract(&sw->min);
97
ret = check_fract(&sw->max);
99
ret = check_fract(&sw->step);
101
return fail("invalid min, max or step for frameinterval %d\n", f);
102
if (fract2f(&sw->min) > fract2f(&sw->max))
103
return fail("min > max\n");
104
if (fract2f(&sw->step) > fract2f(&sw->max) - fract2f(&sw->min))
105
return fail("step > (max - min)\n");
108
return fail("frmival.type is invalid\n");
114
return fail("found frame intervals for invalid size %dx%d\n", w, h);
115
info("found %d frameintervals for pixel format %08x and size %dx%d\n", f, pixfmt, w, h);
119
static int testEnumFrameSizes(struct node *node, __u32 pixfmt)
121
struct v4l2_frmsizeenum frmsize;
122
struct v4l2_frmsize_stepwise *sw = &frmsize.stepwise;
123
bool found_stepwise = false;
128
memset(&frmsize, 0xff, sizeof(frmsize));
130
frmsize.pixel_format = pixfmt;
132
ret = doioctl(node, VIDIOC_ENUM_FRAMESIZES, &frmsize);
133
if (f == 0 && ret == EINVAL)
138
return fail("expected EINVAL, but got %d when enumerating framesize %d\n", ret, f);
139
ret = check_0(frmsize.reserved, sizeof(frmsize.reserved));
141
return fail("frmsize.reserved not zeroed\n");
142
if (frmsize.pixel_format != pixfmt || frmsize.index != f)
143
return fail("frmsize.pixel_format or index changed\n");
144
switch (frmsize.type) {
145
case V4L2_FRMSIZE_TYPE_DISCRETE:
146
if (frmsize.discrete.width == 0 || frmsize.discrete.height == 0)
147
return fail("invalid width/height for discrete framesize\n");
149
return fail("mixing discrete and stepwise is not allowed\n");
150
ret = testEnumFrameIntervals(node, pixfmt,
151
frmsize.discrete.width, frmsize.discrete.height, true);
154
ret = testEnumFrameIntervals(node, pixfmt,
155
frmsize.discrete.width + 1, frmsize.discrete.height, false);
159
case V4L2_FRMSIZE_TYPE_CONTINUOUS:
160
if (frmsize.stepwise.step_width != 1 || frmsize.stepwise.step_height != 1)
161
return fail("invalid step_width/height for continuous framesize\n");
163
case V4L2_FRMSIZE_TYPE_STEPWISE:
165
return fail("index must be 0 for stepwise/continuous framesizes\n");
166
found_stepwise = true;
167
if (!sw->min_width || !sw->min_height || !sw->step_width || !sw->step_height)
168
return fail("0 for min_width/height or step_width/height\n");
169
if (sw->min_width > sw->max_width || sw->min_height > sw->max_height)
170
return fail("min_width/height > max_width/height\n");
171
if (sw->step_width > sw->max_width - sw->min_width ||
172
sw->step_height > sw->max_height - sw->min_height)
173
return fail("step > max - min for width or height\n");
174
ret = testEnumFrameIntervals(node, pixfmt,
175
sw->min_width, sw->min_height, true);
178
ret = testEnumFrameIntervals(node, pixfmt,
179
sw->max_width, sw->max_height, true);
182
ret = testEnumFrameIntervals(node, pixfmt,
183
sw->min_width - 1, sw->min_height, false);
186
ret = testEnumFrameIntervals(node, pixfmt,
187
sw->max_width, sw->max_height + 1, false);
192
return fail("frmsize.type is invalid\n");
197
info("found %d framesizes for pixel format %08x\n", f, pixfmt);
201
static int testEnumFormatsType(struct node *node, enum v4l2_buf_type type)
203
pixfmt_set &set = node->buftype_pixfmts[type];
204
struct v4l2_fmtdesc fmtdesc;
209
memset(&fmtdesc, 0xff, sizeof(fmtdesc));
213
ret = doioctl(node, VIDIOC_ENUM_FMT, &fmtdesc);
214
if (f == 0 && ret == EINVAL)
219
return fail("expected EINVAL, but got %d when enumerating buftype %d\n", ret, type);
220
ret = check_0(fmtdesc.reserved, sizeof(fmtdesc.reserved));
222
return fail("fmtdesc.reserved not zeroed\n");
223
if (fmtdesc.index != f)
224
return fail("fmtdesc.index was modified\n");
225
if (fmtdesc.type != type)
226
return fail("fmtdesc.type was modified\n");
227
ret = check_ustring(fmtdesc.description, sizeof(fmtdesc.description));
229
return fail("fmtdesc.description not set\n");
230
if (!fmtdesc.pixelformat)
231
return fail("fmtdesc.pixelformat not set\n");
232
if (!wrapper && (fmtdesc.flags & V4L2_FMT_FLAG_EMULATED))
233
return fail("drivers must never set the emulated flag\n");
234
if (fmtdesc.flags & ~(V4L2_FMT_FLAG_COMPRESSED | V4L2_FMT_FLAG_EMULATED))
235
return fail("unknown flag %08x returned\n", fmtdesc.flags);
236
ret = testEnumFrameSizes(node, fmtdesc.pixelformat);
239
if (ret == 0 && !(node->caps & (V4L2_CAP_VIDEO_CAPTURE | V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)))
240
return fail("found framesizes when no video capture is supported\n");
242
if (type == V4L2_BUF_TYPE_PRIVATE)
244
// Update array in v4l2-compliance.h if new buffer types are added
245
assert(type <= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
246
if (set.find(fmtdesc.pixelformat) != set.end())
247
return fail("duplicate format %08x\n", fmtdesc.pixelformat);
248
set.insert(fmtdesc.pixelformat);
250
info("found %d formats for buftype %d\n", f, type);
254
int testEnumFormats(struct node *node)
256
static const __u32 buftype2cap[] = {
258
V4L2_CAP_VIDEO_CAPTURE,
259
V4L2_CAP_VIDEO_OUTPUT,
260
V4L2_CAP_VIDEO_OVERLAY,
261
V4L2_CAP_VBI_CAPTURE,
263
V4L2_CAP_SLICED_VBI_CAPTURE,
264
V4L2_CAP_SLICED_VBI_OUTPUT,
265
V4L2_CAP_VIDEO_OUTPUT_OVERLAY,
266
V4L2_CAP_VIDEO_CAPTURE_MPLANE,
267
V4L2_CAP_VIDEO_OUTPUT_MPLANE,
272
for (type = 0; type <= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; type++) {
273
ret = testEnumFormatsType(node, (enum v4l2_buf_type)type);
277
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
278
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
279
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
280
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
281
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
282
if (ret < 0 && (node->caps & buftype2cap[type]))
283
return fail("%s cap set, but no %s formats defined\n",
284
buftype2s(type).c_str(), buftype2s(type).c_str());
285
if (!ret && !(node->caps & buftype2cap[type]))
286
return fail("%s cap not set, but %s formats defined\n",
287
buftype2s(type).c_str(), buftype2s(type).c_str());
291
return fail("Buffer type %s not allowed!\n", buftype2s(type).c_str());
296
ret = testEnumFormatsType(node, V4L2_BUF_TYPE_PRIVATE);
300
warn("Buffer type PRIVATE allowed!\n");
302
ret = testEnumFrameSizes(node, 0x20202020);
304
return fail("Accepted framesize for invalid format\n");
305
ret = testEnumFrameIntervals(node, 0x20202020, 640, 480, false);
307
return fail("Accepted frameinterval for invalid format\n");
311
int testFBuf(struct node *node)
313
struct v4l2_framebuffer fbuf;
314
struct v4l2_pix_format &fmt = fbuf.fmt;
319
memset(&fbuf, 0xff, sizeof(fbuf));
321
ret = doioctl(node, VIDIOC_G_FBUF, &fbuf);
322
fail_on_test(ret == 0 && !(node->caps & (V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_VIDEO_OUTPUT_OVERLAY)));
323
fail_on_test(ret == EINVAL && (node->caps & (V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_VIDEO_OUTPUT_OVERLAY)));
327
return fail("expected EINVAL, but got %d when getting framebuffer format\n", ret);
328
node->fbuf_caps = caps = fbuf.capability;
330
if (node->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)
331
fail_on_test(!fbuf.base);
332
if (flags & V4L2_FBUF_FLAG_CHROMAKEY)
333
fail_on_test(!(caps & V4L2_FBUF_CAP_CHROMAKEY));
334
if (flags & V4L2_FBUF_FLAG_LOCAL_ALPHA)
335
fail_on_test(!(caps & V4L2_FBUF_CAP_LOCAL_ALPHA));
336
if (flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA)
337
fail_on_test(!(caps & V4L2_FBUF_CAP_GLOBAL_ALPHA));
338
if (flags & V4L2_FBUF_FLAG_LOCAL_INV_ALPHA)
339
fail_on_test(!(caps & V4L2_FBUF_CAP_LOCAL_INV_ALPHA));
340
if (flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY)
341
fail_on_test(!(caps & V4L2_FBUF_CAP_SRC_CHROMAKEY));
342
fail_on_test(!fmt.width || !fmt.height);
344
warn("fbuf.fmt.priv is non-zero\n");
345
/* Not yet: unclear what EXTERNOVERLAY means in a output overlay context
346
if (caps & V4L2_FBUF_CAP_EXTERNOVERLAY) {
347
fail_on_test(fmt.bytesperline);
348
fail_on_test(fmt.sizeimage);
349
fail_on_test(fbuf.base);
351
fail_on_test(fmt.bytesperline && fmt.bytesperline < fmt.width);
352
fail_on_test(fmt.sizeimage && fmt.sizeimage < fmt.bytesperline * fmt.height);
353
fail_on_test(!fmt.colorspace);
357
static int testFormatsType(struct node *node, enum v4l2_buf_type type)
359
pixfmt_set &set = node->buftype_pixfmts[type];
360
pixfmt_set *set_splane;
361
struct v4l2_format fmt;
362
struct v4l2_pix_format &pix = fmt.fmt.pix;
363
struct v4l2_pix_format_mplane &pix_mp = fmt.fmt.pix_mp;
364
struct v4l2_window &win = fmt.fmt.win;
365
struct v4l2_vbi_format &vbi = fmt.fmt.vbi;
366
struct v4l2_sliced_vbi_format &sliced = fmt.fmt.sliced;
367
__u32 service_set = 0;
371
memset(&fmt, 0xff, sizeof(fmt));
373
ret = doioctl(node, VIDIOC_G_FMT, &fmt);
377
return fail("expected EINVAL, but got %d when getting format for buftype %d\n", ret, type);
378
fail_on_test(fmt.type != type);
381
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
382
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
383
fail_on_test(!pix.width || !pix.height);
384
if (set.find(pix.pixelformat) == set.end())
385
return fail("unknown pixelformat %08x for buftype %d\n",
386
pix.pixelformat, type);
387
fail_on_test(pix.bytesperline && pix.bytesperline < pix.width);
388
fail_on_test(!pix.sizeimage);
389
fail_on_test(!pix.colorspace);
391
warn("priv is non-zero!\n");
393
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
394
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
395
fail_on_test(!pix_mp.width || !pix_mp.height);
396
set_splane = &node->buftype_pixfmts[type - 8];
397
if (set.find(pix_mp.pixelformat) == set.end() &&
398
set_splane->find(pix_mp.pixelformat) == set_splane->end())
399
return fail("unknown pixelformat %08x for buftype %d\n",
400
pix_mp.pixelformat, type);
401
fail_on_test(!pix_mp.colorspace);
402
ret = check_0(pix_mp.reserved, sizeof(pix_mp.reserved));
404
return fail("pix_mp.reserved not zeroed\n");
405
fail_on_test(pix_mp.num_planes == 0 || pix_mp.num_planes >= VIDEO_MAX_PLANES);
406
for (int i = 0; i < pix_mp.num_planes; i++) {
407
struct v4l2_plane_pix_format &pfmt = pix_mp.plane_fmt[i];
409
ret = check_0(pfmt.reserved, sizeof(pfmt.reserved));
411
return fail("pix_mp.plane_fmt[%d].reserved not zeroed\n", i);
412
fail_on_test(!pfmt.sizeimage);
413
fail_on_test(pfmt.bytesperline && pfmt.bytesperline < pix_mp.width);
416
case V4L2_BUF_TYPE_VBI_CAPTURE:
417
case V4L2_BUF_TYPE_VBI_OUTPUT:
418
fail_on_test(!vbi.sampling_rate);
419
fail_on_test(!vbi.samples_per_line);
420
fail_on_test(vbi.sample_format != V4L2_PIX_FMT_GREY);
421
fail_on_test(vbi.offset > vbi.samples_per_line);
422
ret = check_0(vbi.reserved, sizeof(vbi.reserved));
424
return fail("vbi.reserved not zeroed\n");
425
fail_on_test(!vbi.count[0] || !vbi.count[1]);
426
fail_on_test(vbi.flags & ~(V4L2_VBI_UNSYNC | V4L2_VBI_INTERLACED));
427
if (vbi.flags & V4L2_VBI_INTERLACED)
428
fail_on_test(vbi.count[0] != vbi.count[1]);
430
case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
431
case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
432
ret = check_0(sliced.reserved, sizeof(sliced.reserved));
434
return fail("sliced.reserved not zeroed\n");
435
fail_on_test(sliced.service_lines[0][0] || sliced.service_lines[1][0]);
436
for (int f = 0; f < 2; f++) {
437
for (int i = 0; i < 24; i++) {
438
if (sliced.service_lines[f][i])
440
service_set |= sliced.service_lines[f][i];
443
fail_on_test(sliced.io_size < sizeof(struct v4l2_sliced_vbi_data) * cnt);
444
fail_on_test(sliced.service_set != service_set);
446
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
447
case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
448
fail_on_test(win.field != V4L2_FIELD_ANY &&
449
win.field != V4L2_FIELD_TOP &&
450
win.field != V4L2_FIELD_BOTTOM &&
451
win.field != V4L2_FIELD_INTERLACED);
452
fail_on_test(win.clipcount && !(node->fbuf_caps & V4L2_FBUF_CAP_LIST_CLIPPING));
453
for (struct v4l2_clip *clip = win.clips; clip; win.clipcount--) {
454
fail_on_test(clip == NULL);
457
fail_on_test(win.clipcount);
458
fail_on_test(win.chromakey && !(node->fbuf_caps & (V4L2_FBUF_CAP_CHROMAKEY | V4L2_FBUF_CAP_SRC_CHROMAKEY)));
459
if (!(node->fbuf_caps & V4L2_FBUF_CAP_BITMAP_CLIPPING))
460
fail_on_test(win.bitmap);
461
fail_on_test(win.global_alpha && !(node->fbuf_caps & V4L2_FBUF_CAP_GLOBAL_ALPHA));
463
case V4L2_BUF_TYPE_PRIVATE:
469
int testFormats(struct node *node)
474
for (type = 0; type <= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; type++) {
475
ret = testFormatsType(node, (enum v4l2_buf_type)type);
479
if (ret && (node->caps & buftype2cap[type]))
480
return fail("%s cap set, but no %s formats defined\n",
481
buftype2s(type).c_str(), buftype2s(type).c_str());
482
if (!ret && !(node->caps & buftype2cap[type]))
483
return fail("%s cap not set, but %s formats defined\n",
484
buftype2s(type).c_str(), buftype2s(type).c_str());
487
ret = testFormatsType(node, V4L2_BUF_TYPE_PRIVATE);
491
warn("Buffer type PRIVATE allowed!\n");
495
static int testSlicedVBICapType(struct node *node, enum v4l2_buf_type type)
497
struct v4l2_sliced_vbi_cap cap;
498
bool sliced_type = (type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ||
499
type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT);
500
__u32 service_set = 0;
503
memset(&cap, 0xff, sizeof(cap));
504
memset(&cap.reserved, 0, sizeof(cap.reserved));
506
ret = doioctl(node, VIDIOC_G_SLICED_VBI_CAP, &cap);
507
fail_on_test(check_0(cap.reserved, sizeof(cap.reserved)));
508
fail_on_test(cap.type != type);
509
fail_on_test(ret && ret != EINVAL && sliced_type);
511
fail_on_test(sliced_type && (node->caps & buftype2cap[type]));
512
if (node->caps & (V4L2_CAP_SLICED_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT))
517
return fail("expected EINVAL, but got %d when getting sliced VBI caps buftype %d\n", ret, type);
518
fail_on_test(!(node->caps & buftype2cap[type]));
520
for (int f = 0; f < 2; f++)
521
for (int i = 0; i < 24; i++)
522
service_set |= cap.service_lines[f][i];
523
fail_on_test(cap.service_set != service_set);
524
fail_on_test(cap.service_lines[0][0] || cap.service_lines[1][0]);
528
int testSlicedVBICap(struct node *node)
532
ret = testSlicedVBICapType(node, V4L2_BUF_TYPE_SLICED_VBI_CAPTURE);
535
ret = testSlicedVBICapType(node, V4L2_BUF_TYPE_SLICED_VBI_OUTPUT);
538
return testSlicedVBICapType(node, V4L2_BUF_TYPE_VIDEO_CAPTURE);