From e43bc88fc37d04fbb4fcf5436ca568b0987944b4 Mon Sep 17 00:00:00 2001 From: Maksim Shabunin Date: Fri, 7 Jul 2023 17:25:49 +0300 Subject: [PATCH] videoio: test for V4L using virtual device --- modules/videoio/src/cap_v4l.cpp | 8 +- modules/videoio/test/test_precomp.hpp | 8 ++ modules/videoio/test/test_v4l2.cpp | 116 ++++++++++++++++++++++++++ 3 files changed, 130 insertions(+), 2 deletions(-) create mode 100644 modules/videoio/test/test_v4l2.cpp diff --git a/modules/videoio/src/cap_v4l.cpp b/modules/videoio/src/cap_v4l.cpp index a5d8561c6b..2f8b8b3745 100644 --- a/modules/videoio/src/cap_v4l.cpp +++ b/modules/videoio/src/cap_v4l.cpp @@ -1854,8 +1854,12 @@ static inline cv::String capPropertyName(int prop) return "auto wb"; case CAP_PROP_WB_TEMPERATURE: return "wb temperature"; + case CAP_PROP_ORIENTATION_META: + return "orientation meta"; + case CAP_PROP_ORIENTATION_AUTO: + return "orientation auto"; default: - return "unknown"; + return cv::format("unknown (%d)", prop); } } @@ -1970,7 +1974,7 @@ bool CvCaptureCAM_V4L::controlInfo(int property_id, __u32 &_v4l2id, cv::Range &r v4l2_queryctrl queryctrl = v4l2_queryctrl(); queryctrl.id = __u32(v4l2id); if (v4l2id == -1 || !tryIoctl(VIDIOC_QUERYCTRL, &queryctrl)) { - CV_LOG_INFO(NULL, "VIDEOIO(V4L2:" << deviceName << "): property " << capPropertyName(property_id) << " is not supported"); + CV_LOG_INFO(NULL, "VIDEOIO(V4L2:" << deviceName << "): property '" << capPropertyName(property_id) << "' is not supported"); return false; } _v4l2id = __u32(v4l2id); diff --git a/modules/videoio/test/test_precomp.hpp b/modules/videoio/test/test_precomp.hpp index e9ac63d999..c39dc7da13 100644 --- a/modules/videoio/test/test_precomp.hpp +++ b/modules/videoio/test/test_precomp.hpp @@ -5,6 +5,7 @@ #define __OPENCV_TEST_PRECOMP_HPP__ #include +#include #include "opencv2/ts.hpp" #include "opencv2/ts/ocl_test.hpp" @@ -56,6 +57,13 @@ inline std::string fourccToString(int fourcc) return cv::format("%c%c%c%c", fourcc & 255, (fourcc >> 8) & 255, (fourcc >> 16) & 255, (fourcc >> 24) & 255); } +inline std::string fourccToStringSafe(int fourcc) +{ + std::string res = fourccToString(fourcc); + std::replace_if(res.begin(), res.end(), [](uint8_t c){ return c < '0' || c > 'z'; }, '_'); + return res; +} + inline int fourccFromString(const std::string &fourcc) { if (fourcc.size() != 4) return 0; diff --git a/modules/videoio/test/test_v4l2.cpp b/modules/videoio/test/test_v4l2.cpp new file mode 100644 index 0000000000..010013c3a9 --- /dev/null +++ b/modules/videoio/test/test_v4l2.cpp @@ -0,0 +1,116 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +// Reference: https://www.kernel.org/doc/html/v4.8/media/v4l-drivers/vivid.html + +// create 1 virtual device of type CAP (0x1) at /dev/video10 +// sudo modprobe vivid ndevs=1 node_types=0x1 vid_cap_nr=10 +// make sure user have read/write access (e.g. via group 'video') +// $ ls -l /dev/video10 +// crw-rw----+ 1 root video ... /dev/video10 +// set environment variable: +// export OPENCV_TEST_V4L2_VIVID_DEVICE=/dev/video10 +// run v4l2 tests: +// opencv_test_videoio --gtest_filter=*videoio_v4l2* + + +#ifdef HAVE_CAMV4L2 + +#include "test_precomp.hpp" +#include +#include + +using namespace cv; + +namespace opencv_test { namespace { + +struct Format_Channels_Depth +{ + uint32_t pixel_format; + uint8_t channels; + uint8_t depth; + float mul_width; + float mul_height; +}; + +typedef testing::TestWithParam videoio_v4l2; + +TEST_P(videoio_v4l2, formats) +{ + utils::Paths devs = utils::getConfigurationParameterPaths("OPENCV_TEST_V4L2_VIVID_DEVICE"); + if (devs.size() != 1) + { + throw SkipTestException("OPENCV_TEST_V4L2_VIVID_DEVICE is not set"); + } + const string device = devs[0]; + const Size sz(640, 480); + const Format_Channels_Depth params = GetParam(); + + { + // Case with RAW output + VideoCapture cap; + ASSERT_TRUE(cap.open(device, CAP_V4L2)); + // VideoCapture will set device's format automatically, vivid device will accept it + ASSERT_TRUE(cap.set(CAP_PROP_FOURCC, params.pixel_format)); + ASSERT_TRUE(cap.set(CAP_PROP_CONVERT_RGB, false)); + for (size_t idx = 0; idx < 3; ++idx) + { + Mat img; + EXPECT_TRUE(cap.grab()); + EXPECT_TRUE(cap.retrieve(img)); + EXPECT_EQ(Size(sz.width * params.mul_width, sz.height * params.mul_height), img.size()); + EXPECT_EQ(params.channels, img.channels()); + EXPECT_EQ(params.depth, img.depth()); + } + } + { + // case with BGR output + VideoCapture cap; + ASSERT_TRUE(cap.open(device, CAP_V4L2)); + // VideoCapture will set device's format automatically, vivid device will accept it + ASSERT_TRUE(cap.set(CAP_PROP_FOURCC, params.pixel_format)); + for (size_t idx = 0; idx < 3; ++idx) + { + Mat img; + EXPECT_TRUE(cap.grab()); + EXPECT_TRUE(cap.retrieve(img)); + EXPECT_EQ(sz, img.size()); + EXPECT_EQ(3, img.channels()); + EXPECT_EQ(CV_8U, img.depth()); + } + } +} + +vector all_params = { + { V4L2_PIX_FMT_YVU420, 1, CV_8U, 1.f, 1.5f }, + { V4L2_PIX_FMT_YUV420, 1, CV_8U, 1.f, 1.5f }, + { V4L2_PIX_FMT_NV12, 1, CV_8U, 1.f, 1.5f }, + { V4L2_PIX_FMT_NV21, 1, CV_8U, 1.f, 1.5f }, + { V4L2_PIX_FMT_YUV411P, 3, CV_8U, 1.f, 1.f }, +// { V4L2_PIX_FMT_MJPEG, 1, CV_8U, 1.f, 1.f }, +// { V4L2_PIX_FMT_JPEG, 1, CV_8U, 1.f, 1.f }, + { V4L2_PIX_FMT_YUYV, 2, CV_8U, 1.f, 1.f }, + { V4L2_PIX_FMT_UYVY, 2, CV_8U, 1.f, 1.f }, +// { V4L2_PIX_FMT_SBGGR8, 1, CV_8U, 1.f, 1.f }, +// { V4L2_PIX_FMT_SN9C10X, 3, CV_8U, 1.f, 1.f }, +// { V4L2_PIX_FMT_SGBRG8, 1, CV_8U, 1.f, 1.f }, + { V4L2_PIX_FMT_RGB24, 3, CV_8U, 1.f, 1.f }, + { V4L2_PIX_FMT_Y16, 1, CV_16U, 1.f, 1.f }, + { V4L2_PIX_FMT_Y10, 1, CV_16U, 1.f, 1.f }, + { V4L2_PIX_FMT_GREY, 1, CV_8U, 1.f, 1.f }, + { V4L2_PIX_FMT_BGR24, 3, CV_8U, 1.f, 1.f }, + { V4L2_PIX_FMT_XBGR32, 3, CV_8U, 1.f, 1.f }, + { V4L2_PIX_FMT_ABGR32, 3, CV_8U, 1.f, 1.f }, +}; + +inline static std::string param_printer(const testing::TestParamInfo& info) +{ + return fourccToStringSafe(info.param.pixel_format); +} + +INSTANTIATE_TEST_CASE_P(/*videoio_v4l2*/, videoio_v4l2, ValuesIn(all_params), param_printer); + +}} // opencv_test:::: + +#endif // HAVE_CAMV4L2