int testEnumFormats(struct node *node) { static const __u32 buftype2cap[] = { 0, V4L2_CAP_VIDEO_CAPTURE, V4L2_CAP_VIDEO_OUTPUT, V4L2_CAP_VIDEO_OVERLAY, V4L2_CAP_VBI_CAPTURE, V4L2_CAP_VBI_OUTPUT, V4L2_CAP_SLICED_VBI_CAPTURE, V4L2_CAP_SLICED_VBI_OUTPUT, V4L2_CAP_VIDEO_OUTPUT_OVERLAY, V4L2_CAP_VIDEO_CAPTURE_MPLANE, V4L2_CAP_VIDEO_OUTPUT_MPLANE, }; int type; int ret; for (type = 0; type <= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; type++) { ret = testEnumFormatsType(node, (enum v4l2_buf_type)type); if (ret > 0) return ret; switch (type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: case V4L2_BUF_TYPE_VIDEO_OVERLAY: case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: if (ret < 0 && (node->caps & buftype2cap[type])) return fail("%s cap set, but no %s formats defined\n", buftype2s(type).c_str(), buftype2s(type).c_str()); if (!ret && !(node->caps & buftype2cap[type])) return fail("%s cap not set, but %s formats defined\n", buftype2s(type).c_str(), buftype2s(type).c_str()); break; default: if (!ret) return fail("Buffer type %s not allowed!\n", buftype2s(type).c_str()); break; } } ret = testEnumFormatsType(node, V4L2_BUF_TYPE_PRIVATE); if (ret > 0) return ret; if (!ret) warn("Buffer type PRIVATE allowed!\n"); ret = testEnumFrameSizes(node, 0x20202020); if (ret >= 0) return fail("Accepted framesize for invalid format\n"); ret = testEnumFrameIntervals(node, 0x20202020, 640, 480, false); if (ret >= 0) return fail("Accepted frameinterval for invalid format\n"); return 0; }
int testEnumFormats(struct node *node) { bool supported = false; unsigned type; int ret; for (type = 0; type <= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; type++) { ret = testEnumFormatsType(node, type); if (ret && ret != ENOTTY) return ret; if (!ret) supported = true; switch (type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: case V4L2_BUF_TYPE_VIDEO_OVERLAY: case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: if (ret && (node->caps & buftype2cap[type])) return fail("%s cap set, but no %s formats defined\n", buftype2s(type).c_str(), buftype2s(type).c_str()); if (!ret && !(node->caps & buftype2cap[type])) return fail("%s cap not set, but %s formats defined\n", buftype2s(type).c_str(), buftype2s(type).c_str()); break; default: if (!ret) return fail("Buffer type %s not allowed!\n", buftype2s(type).c_str()); break; } } ret = testEnumFormatsType(node, V4L2_BUF_TYPE_PRIVATE); if (ret && ret != ENOTTY) return ret; if (!ret) { supported = true; warn("Buffer type PRIVATE allowed!\n"); } ret = testEnumFrameSizes(node, 0x20202020); if (ret != ENOTTY) return fail("Accepted framesize for invalid format\n"); ret = testEnumFrameIntervals(node, 0x20202020, 640, 480, false); if (ret != ENOTTY) return fail("Accepted frameinterval for invalid format\n"); return supported ? 0 : ENOTTY; }
static int testEnumFrameSizes(struct node *node, __u32 pixfmt) { struct v4l2_frmsizeenum frmsize; struct v4l2_frmsize_stepwise *sw = &frmsize.stepwise; bool found_stepwise = false; unsigned f = 0; int ret; for (;;) { memset(&frmsize, 0xff, sizeof(frmsize)); frmsize.index = f; frmsize.pixel_format = pixfmt; ret = doioctl(node, VIDIOC_ENUM_FRAMESIZES, &frmsize); if (ret == ENOTTY) return ret; if (f == 0 && ret == EINVAL) return ENOTTY; if (ret == EINVAL) break; if (ret) return fail("expected EINVAL, but got %d when enumerating framesize %d\n", ret, f); ret = check_0(frmsize.reserved, sizeof(frmsize.reserved)); if (ret) return fail("frmsize.reserved not zeroed\n"); if (frmsize.pixel_format != pixfmt || frmsize.index != f) return fail("frmsize.pixel_format or index changed\n"); switch (frmsize.type) { case V4L2_FRMSIZE_TYPE_DISCRETE: if (frmsize.discrete.width == 0 || frmsize.discrete.height == 0) return fail("invalid width/height for discrete framesize\n"); if (found_stepwise) return fail("mixing discrete and stepwise is not allowed\n"); ret = testEnumFrameIntervals(node, pixfmt, frmsize.discrete.width, frmsize.discrete.height, true); if (ret && ret != ENOTTY) return ret; ret = testEnumFrameIntervals(node, pixfmt, frmsize.discrete.width + 1, frmsize.discrete.height, false); if (ret && ret != ENOTTY) return ret; break; case V4L2_FRMSIZE_TYPE_CONTINUOUS: if (frmsize.stepwise.step_width != 1 || frmsize.stepwise.step_height != 1) return fail("invalid step_width/height for continuous framesize\n"); /* fallthrough */ case V4L2_FRMSIZE_TYPE_STEPWISE: if (frmsize.index) return fail("index must be 0 for stepwise/continuous framesizes\n"); found_stepwise = true; if (!sw->min_width || !sw->min_height || !sw->step_width || !sw->step_height) return fail("0 for min_width/height or step_width/height\n"); if (sw->min_width > sw->max_width || sw->min_height > sw->max_height) return fail("min_width/height > max_width/height\n"); if (sw->step_width > sw->max_width - sw->min_width || sw->step_height > sw->max_height - sw->min_height) return fail("step > max - min for width or height\n"); ret = testEnumFrameIntervals(node, pixfmt, sw->min_width, sw->min_height, true); if (ret && ret != ENOTTY) return ret; ret = testEnumFrameIntervals(node, pixfmt, sw->max_width, sw->max_height, true); if (ret && ret != ENOTTY) return ret; ret = testEnumFrameIntervals(node, pixfmt, sw->min_width - 1, sw->min_height, false); if (ret && ret != ENOTTY) return ret; ret = testEnumFrameIntervals(node, pixfmt, sw->max_width, sw->max_height + 1, false); if (ret && ret != ENOTTY) return ret; break; default: return fail("frmsize.type is invalid\n"); } f++; } info("found %d framesizes for pixel format %08x\n", f, pixfmt); return 0; }