camera_V4L2: Fix time per frame capability
V4L2_CAP_TIMEPERFRAME should be from v4l2_streamparm instead of
v4l2_capability.
BUG=chromium:718278
TEST=use an external camera which supports to adjust frame rate.
Change-Id: I44cc7ca281802bc135838f1ddb9accc8c6940f83
Reviewed-on: https://chromium-review.googlesource.com/501619
Commit-Ready: Heng-ruey Hsu <henryhsu@google.com>
Tested-by: Heng-ruey Hsu <henryhsu@google.com>
Reviewed-by: Heng-ruey Hsu <henryhsu@google.com>
diff --git a/client/site_tests/camera_V4L2/src/media_v4l2_device.cc b/client/site_tests/camera_V4L2/src/media_v4l2_device.cc
index 08bf5e2..aa110d8 100644
--- a/client/site_tests/camera_V4L2/src/media_v4l2_device.cc
+++ b/client/site_tests/camera_V4L2/src/media_v4l2_device.cc
@@ -99,13 +99,8 @@
}
v4l2_format fmt;
- memset(&fmt, 0, sizeof(fmt));
- fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- if (-1 == DoIoctl(VIDIOC_G_FMT, &fmt)) {
- printf("<<< Error: VIDIOC_G_FMT on %s.>>>\n", dev_name_);
+ if (!GetV4L2Format(&fmt))
return false;
- }
fmt.fmt.pix.width = width;
fmt.fmt.pix.height = height;
@@ -134,22 +129,24 @@
return false;
}
- if (cap.capabilities & V4L2_CAP_TIMEPERFRAME) {
- if (fps > 0)
+ v4l2_streamparm param;
+ if (!GetParam(¶m))
+ return false;
+
+ if (param.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) {
+ if (fps > 0) {
SetFrameRate(fps);
- fps = GetFrameRate();
- } else {
- // TODO(jiesun): probably we should derive this from VIDIOC_G_STD
- fps = 30.0;
+ } else {
+ printf("<<< Error: fps %f should be a positive number.>>>\n", fps);
+ return false;
+ }
}
+ float actual_fps = GetFrameRate();
printf("actual format for capture %dx%d %c%c%c%c picture at %.2f fps\n",
fmt.fmt.pix.width, fmt.fmt.pix.height,
(pixfmt >> 0) & 0xff, (pixfmt >> 8) & 0xff,
- (pixfmt >> 16) & 0xff, (pixfmt >> 24 ) & 0xff, fps);
- width_ = fmt.fmt.pix.width;
- height_ = fmt.fmt.pix.height;
- pixfmt_ = fmt;
+ (pixfmt >> 16) & 0xff, (pixfmt >> 24 ) & 0xff, actual_fps);
bool ret = false;
switch (io_) {
@@ -906,8 +903,6 @@
if (cap->capabilities & V4L2_CAP_STREAMING)
printf("<<< Info: %s support streaming i/o interface.>>>\n", dev_name_);
- if (cap->capabilities & V4L2_CAP_TIMEPERFRAME)
- printf("<<< Info: %s support flexible frame period.>>>\n", dev_name_);
}
return true;
@@ -954,6 +949,17 @@
param.parm.capture.timeperframe.numerator;
}
+bool V4L2Device::GetV4L2Format(v4l2_format* format) {
+ memset(format, 0, sizeof(v4l2_format));
+ format->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ if (-1 == DoIoctl(VIDIOC_G_FMT, format)) {
+ printf("<<< Error: VIDIOC_G_FMT on %s.>>>\n", dev_name_);
+ return false;
+ }
+ return true;
+}
+
uint64_t V4L2Device::Now() {
struct timespec ts;
int res = clock_gettime(CLOCK_MONOTONIC, &ts);
diff --git a/client/site_tests/camera_V4L2/src/media_v4l2_device.h b/client/site_tests/camera_V4L2/src/media_v4l2_device.h
index ce4eb19..50116a0 100644
--- a/client/site_tests/camera_V4L2/src/media_v4l2_device.h
+++ b/client/site_tests/camera_V4L2/src/media_v4l2_device.h
@@ -36,6 +36,10 @@
virtual bool OpenDevice();
virtual void CloseDevice();
+ // After this function is called, the driver may adjust the settings if they
+ // are unsupported. Caller can use GetV4L2Format() and GetFrameRate() to know
+ // the actual settings. If V4L2_CAP_TIMEPERFRAME is unsupported, fps will be
+ // ignored.
virtual bool InitDevice(IOMethod io,
uint32_t width,
uint32_t height,
@@ -73,21 +77,9 @@
uint32_t index, uint32_t pixfmt, uint32_t width, uint32_t height,
float* frame_rate);
float GetFrameRate();
+ bool GetV4L2Format(v4l2_format* format);
bool Stop();
- // Getter.
- int32_t GetActualWidth() {
- return width_;
- }
-
- int32_t GetActualHeight() {
- return height_;
- }
-
- v4l2_format& GetActualPixelFormat() {
- return pixfmt_;
- }
-
static uint32_t MapFourCC(const char* fourcc);
virtual void ProcessImage(const void* p);
@@ -109,9 +101,6 @@
uint32_t min_buffers_; // Minimum buffers requirement.
bool stopped_;
- // Valid only after |InitDevice()|.
- uint32_t width_, height_;
- v4l2_format pixfmt_;
// Sets to true when buffers are initialized.
bool initialized_;
};
diff --git a/client/site_tests/camera_V4L2/src/media_v4l2_test.cc b/client/site_tests/camera_V4L2/src/media_v4l2_test.cc
index 0b76e84..d5c1570 100644
--- a/client/site_tests/camera_V4L2/src/media_v4l2_test.cc
+++ b/client/site_tests/camera_V4L2/src/media_v4l2_test.cc
@@ -4,6 +4,8 @@
#include <getopt.h>
+#include <cmath>
+#include <limits>
#include <memory>
#include <string>
#include <unordered_map>
@@ -169,7 +171,7 @@
return true;
}
-// Test all required resolutions with all fps which are larger than 30.
+// Test all required resolutions with 30 fps.
bool TestResolutions(const std::string& dev_name,
bool check_1280x960,
bool check_1600x1200) {
@@ -189,16 +191,24 @@
}
SupportedFormat max_resolution = GetMaximumResolution(supported_formats);
+ const float kFrameRate = 30.0;
SupportedFormats required_resolutions;
- required_resolutions.push_back(SupportedFormat(320, 240, 0, 30.0));
- required_resolutions.push_back(SupportedFormat(640, 480, 0, 30.0));
- required_resolutions.push_back(SupportedFormat(1280, 720, 0, 30.0));
- required_resolutions.push_back(SupportedFormat(1920, 1080, 0, 30.0));
+ required_resolutions.push_back(SupportedFormat(320, 240, 0, kFrameRate));
+ required_resolutions.push_back(SupportedFormat(640, 480, 0, kFrameRate));
+ required_resolutions.push_back(SupportedFormat(1280, 720, 0, kFrameRate));
+ required_resolutions.push_back(SupportedFormat(1920, 1080, 0, kFrameRate));
if (check_1600x1200) {
- required_resolutions.push_back(SupportedFormat(1600, 1200, 0, 30.0));
+ required_resolutions.push_back(SupportedFormat(1600, 1200, 0, kFrameRate));
}
if (check_1280x960) {
- required_resolutions.push_back(SupportedFormat(1280, 960, 0, 30.0));
+ required_resolutions.push_back(SupportedFormat(1280, 960, 0, kFrameRate));
+ }
+
+ v4l2_streamparm param;
+ if (!device->GetParam(¶m)) {
+ printf("[Error] Can not get stream param on device '%s'\n",
+ dev_name.c_str());
+ return false;
}
for (const auto& test_resolution : required_resolutions) {
@@ -216,39 +226,45 @@
return false;
}
- bool frame_rate_tested = false;
+ bool frame_rate_30_supported = false;
for (const auto& frame_rate : test_format->frame_rates) {
- // If the fps is less than the fps that we want to test, skip it.
- if (frame_rate < test_resolution.frame_rates[0]) {
- continue;
- }
- frame_rate_tested = true;
- if (RunTest(device.get(), io, buffers, time_to_capture,
- test_format->width, test_format->height, test_format->fourcc,
- frame_rate)) {
- printf("[Error] Could not capture frames for %dx%d (%08X) %.2f fps in "
- "%s\n", test_format->width, test_format->height,
- test_format->fourcc, frame_rate, dev_name.c_str());
- return false;
- }
-
- // Make sure the driver didn't adjust the format.
- v4l2_format fmt = device->GetActualPixelFormat();
- if (test_format->width != fmt.fmt.pix.width ||
- test_format->height != fmt.fmt.pix.height ||
- test_format->fourcc != fmt.fmt.pix.pixelformat ||
- frame_rate != device->GetFrameRate()) {
- printf("[Error] Capture test %dx%d (%08X) %.2f fps failed in %s\n",
- test_format->width, test_format->height, test_format->fourcc,
- frame_rate, dev_name.c_str());
+ if (std::fabs(frame_rate - kFrameRate) <=
+ std::numeric_limits<float>::epsilon()) {
+ frame_rate_30_supported = true;
+ break;
}
}
- if (!frame_rate_tested) {
- printf("[Error] Cannot test frame rate for %dx%d (%08X) failed in %s\n",
+ if (!frame_rate_30_supported) {
+ printf("[Error] Cannot test 30 fps for %dx%d (%08X) failed in %s\n",
test_format->width, test_format->height, test_format->fourcc,
dev_name.c_str());
return false;
}
+
+ if (RunTest(device.get(), io, buffers, time_to_capture,
+ test_format->width, test_format->height, test_format->fourcc,
+ kFrameRate)) {
+ printf("[Error] Could not capture frames for %dx%d (%08X) %.2f fps in "
+ "%s\n", test_format->width, test_format->height,
+ test_format->fourcc, kFrameRate, dev_name.c_str());
+ return false;
+ }
+
+ // Make sure the driver didn't adjust the format.
+ v4l2_format fmt;
+ if (!device->GetV4L2Format(&fmt)) {
+ return false;
+ }
+ if (test_format->width != fmt.fmt.pix.width ||
+ test_format->height != fmt.fmt.pix.height ||
+ test_format->fourcc != fmt.fmt.pix.pixelformat ||
+ std::fabs(kFrameRate - device->GetFrameRate()) >
+ std::numeric_limits<float>::epsilon()) {
+ printf("[Error] Capture test %dx%d (%08X) %.2f fps failed in %s\n",
+ test_format->width, test_format->height, test_format->fourcc,
+ kFrameRate, dev_name.c_str());
+ return false;
+ }
}
device->CloseDevice();
diff --git a/client/site_tests/camera_V4L2/src/media_v4l2_unittest.cc b/client/site_tests/camera_V4L2/src/media_v4l2_unittest.cc
index fcfbebd..53931d5 100644
--- a/client/site_tests/camera_V4L2/src/media_v4l2_unittest.cc
+++ b/client/site_tests/camera_V4L2/src/media_v4l2_unittest.cc
@@ -218,50 +218,17 @@
if (!v4l2_dev.OpenDevice()) {
printf("[Error] Can not open device '%s'\n", dev_name);
}
- v4l2_capability caps;
- if (!v4l2_dev.ProbeCaps(&caps, true)) {
- printf("[Error] Can not probe caps on device '%s'\n", dev_name);
+ v4l2_streamparm param;
+ if (!v4l2_dev.GetParam(¶m)) {
+ printf("[Error] Can not get stream param on device '%s'\n", dev_name);
exit(EXIT_FAILURE);
}
// we only try to adjust frame rate when it claims can.
- if (caps.capabilities & V4L2_CAP_TIMEPERFRAME) {
- v4l2_streamparm param;
- if (!v4l2_dev.GetParam(¶m)) {
- printf("[Error] Can not get stream param on device '%s'\n", dev_name);
- exit(EXIT_FAILURE);
- }
+ if (param.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) {
if (!v4l2_dev.SetParam(¶m)) {
printf("[Error] Can not set stream param on device '%s'\n", dev_name);
exit(EXIT_FAILURE);
}
-
- if (!v4l2_dev.SetFrameRate(15)) {
- printf("[Error] SetFrameRate failed on '%s'\n", dev_name);
- exit(EXIT_FAILURE);
- }
- if (!v4l2_dev.GetParam(¶m)) {
- printf("[Error] Can not get stream param on device '%s'\n", dev_name);
- exit(EXIT_FAILURE);
- }
- if (param.parm.capture.timeperframe.denominator !=
- param.parm.capture.timeperframe.numerator * 15) {
- printf("[Error] Can not set frame rate to 15 on '%s'\n", dev_name);
- exit(EXIT_FAILURE);
- }
-
- if (!v4l2_dev.SetFrameRate(10)) {
- printf("[Error] SetFrameRate failed on '%s'\n", dev_name);
- exit(EXIT_FAILURE);
- }
- if (!v4l2_dev.GetParam(¶m)) {
- printf("[Error] Can not get stream param on device '%s'\n", dev_name);
- exit(EXIT_FAILURE);
- }
- if (param.parm.capture.timeperframe.denominator !=
- param.parm.capture.timeperframe.numerator * 10) {
- printf("[Error] Can not set frame rate to 10 on '%s'\n", dev_name);
- exit(EXIT_FAILURE);
- }
}
v4l2_dev.CloseDevice();