Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1195)

Unified Diff: media/capture/video/linux/v4l2_capture_delegate_unittest.cc

Issue 2479413002: Image Capture v4l2: reset all user controls to default values when closing device fd (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: media/capture/video/linux/v4l2_capture_delegate_unittest.cc
diff --git a/media/capture/video/linux/v4l2_capture_delegate_unittest.cc b/media/capture/video/linux/v4l2_capture_delegate_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..d11d55854e9bf896c43b84d0968ea647b7e706cd
--- /dev/null
+++ b/media/capture/video/linux/v4l2_capture_delegate_unittest.cc
@@ -0,0 +1,311 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <sys/fcntl.h>
+#include <sys/ioctl.h>
+
+#include "base/files/file_enumerator.h"
+#include "base/run_loop.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "media/capture/video/linux/v4l2_capture_delegate.h"
+#include "media/capture/video/video_capture_device.h"
+#include "media/capture/video/video_capture_device_descriptor.h"
+#include "media/capture/video_capture_types.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+
+namespace media {
+
+namespace {
+
+ACTION_P(RunClosure, closure) {
+ closure.Run();
+}
+
+bool IsSpecialControl(int control_id) {
+ if (control_id == V4L2_CID_AUTO_WHITE_BALANCE)
emircan 2016/12/07 21:45:31 switch statement?
mcasas 2016/12/08 23:46:52 Done.
+ return true;
+ else if (control_id == V4L2_CID_EXPOSURE_AUTO)
+ return true;
+ else if (control_id == V4L2_CID_EXPOSURE_AUTO_PRIORITY)
+ return true;
+ else if (control_id == V4L2_CID_FOCUS_AUTO)
+ return true;
+ return false;
+}
+
+void SetControlsToMaxValues(int device_fd) {
+ // Set V4L2_CID_AUTO_WHITE_BALANCE to false first.
+ v4l2_control auto_white_balance = {};
+ auto_white_balance.id = V4L2_CID_AUTO_WHITE_BALANCE;
+ auto_white_balance.value = false;
+ if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_S_CTRL, &auto_white_balance)) < 0)
+ DPLOG(ERROR) << "VIDIOC_S_CTRL";
+
+ std::vector<struct v4l2_ext_control> user_controls;
+ for (int control_id = V4L2_CID_USER_BASE; control_id < V4L2_CID_LASTP1;
+ ++control_id) {
+ if (IsSpecialControl(control_id))
+ continue;
+ v4l2_queryctrl range = {};
+ range.id = control_id;
+ if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_QUERYCTRL, &range)) < 0)
+ continue;
+ DVLOG(1) << __func__ << ", " << range.name << " - " << range.maximum;
+
+ struct v4l2_ext_control ext_control = {};
+ ext_control.id = control_id;
+ ext_control.value = range.maximum;
+ user_controls.push_back(ext_control);
+ }
+
+ if (!user_controls.empty()) {
+ struct v4l2_ext_controls ext_controls = {};
+ ext_controls.ctrl_class = V4L2_CTRL_CLASS_USER;
+ ext_controls.count = user_controls.size();
+ ext_controls.controls = user_controls.data();
+ if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_S_EXT_CTRLS, &ext_controls)) < 0)
+ DPLOG(ERROR) << "VIDIOC_S_EXT_CTRLS " << user_controls.size();
+ }
+
+ for (int control_id = V4L2_CID_USER_BASE; control_id < V4L2_CID_LASTP1;
+ ++control_id) {
+ if (IsSpecialControl(control_id))
+ continue;
+ v4l2_queryctrl range = {};
+ range.id = control_id;
+ if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_QUERYCTRL, &range)) < 0)
+ continue;
+ v4l2_control readback = {};
+ readback.id = control_id;
+ if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_G_CTRL, &readback)) < 0)
+ DPLOG(ERROR) << range.name << ", failed to be read.";
+ EXPECT_EQ(range.maximum, readback.value)
+ << " control didnt get set correctly" << range.name;
+ }
+
+ std::vector<struct v4l2_ext_control> special_camera_controls;
+ // Set V4L2_CID_EXPOSURE_AUTO to V4L2_EXPOSURE_MANUAL.
+ v4l2_ext_control auto_exposure = {};
+ auto_exposure.id = V4L2_CID_EXPOSURE_AUTO;
+ auto_exposure.value = V4L2_EXPOSURE_MANUAL;
+ special_camera_controls.push_back(auto_exposure);
+ // Set V4L2_CID_EXPOSURE_AUTO_PRIORITY to false.
+ v4l2_ext_control priority_auto_exposure = {};
+ priority_auto_exposure.id = V4L2_CID_EXPOSURE_AUTO_PRIORITY;
+ priority_auto_exposure.value = false;
+ special_camera_controls.push_back(priority_auto_exposure);
+ // Set V4L2_CID_FOCUS_AUTO to false.
+ v4l2_ext_control auto_focus = {};
+ auto_focus.id = V4L2_CID_FOCUS_AUTO;
+ auto_focus.value = false;
+ special_camera_controls.push_back(auto_focus);
+
+ struct v4l2_ext_controls ext_controls = {};
+ ext_controls.ctrl_class = V4L2_CID_CAMERA_CLASS;
+ ext_controls.count = special_camera_controls.size();
+ ext_controls.controls = special_camera_controls.data();
+ if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_S_EXT_CTRLS, &ext_controls)) < 0)
+ DPLOG(ERROR) << "VIDIOC_S_EXT_CTRLS";
+
+ std::vector<struct v4l2_ext_control> camera_controls;
+ for (int control_id = V4L2_CID_CAMERA_CLASS_BASE;
+ control_id < V4L2_CID_CAMERA_CLASS_BASE + 32; ++control_id) {
+ if (IsSpecialControl(control_id))
+ continue;
+ v4l2_queryctrl range = {};
+ range.id = control_id;
+ if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_QUERYCTRL, &range)) < 0)
+ continue;
+ DVLOG(1) << __func__ << ", " << range.name << " - " << range.maximum;
+
+ struct v4l2_ext_control ext_control = {};
+ ext_control.id = control_id;
+ ext_control.value = range.maximum; // Set to its maximum !!!!
+ camera_controls.push_back(ext_control);
+ }
+
+ if (!camera_controls.empty()) {
+ struct v4l2_ext_controls ext_controls = {};
+ ext_controls.ctrl_class = V4L2_CID_CAMERA_CLASS;
+ ext_controls.count = camera_controls.size();
+ ext_controls.controls = camera_controls.data();
+ if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_S_EXT_CTRLS, &ext_controls)) < 0)
+ DPLOG(ERROR) << "VIDIOC_S_EXT_CTRLS";
+ }
+
+ for (int control_id = V4L2_CID_CAMERA_CLASS_BASE;
+ control_id < V4L2_CID_CAMERA_CLASS_BASE + 32; ++control_id) {
+ if (IsSpecialControl(control_id))
+ continue;
+ v4l2_queryctrl range = {};
+ range.id = control_id;
+ if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_QUERYCTRL, &range)) < 0)
+ continue;
+ v4l2_control readback = {};
+ readback.id = control_id;
+ if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_G_CTRL, &readback)) < 0)
+ DPLOG(ERROR) << range.name << ", failed to be read.";
+ EXPECT_EQ(range.maximum, readback.value) << " control didnt reset, "
+ << range.name;
+ }
+}
+
+void VerifyUserControlsAreSetToDefaultValues(int device_fd) {
+ for (int control_id = V4L2_CID_USER_BASE; control_id < V4L2_CID_LASTP1;
+ ++control_id) {
+ if (IsSpecialControl(control_id))
+ continue;
+
+ v4l2_queryctrl range = {};
+ range.id = control_id;
+ if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_QUERYCTRL, &range)) < 0)
+ continue;
+ if (range.flags & V4L2_CTRL_FLAG_DISABLED)
+ continue;
+
+ DVLOG(1) << __func__ << ", " << range.name << ": " << range.minimum << "-"
+ << range.maximum << ", default: " << range.default_value;
+
+ v4l2_control current = {};
+ current.id = control_id;
+ if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_G_CTRL, &current)) < 0)
+ DPLOG(ERROR) << "control " << range.name << ", " << current.value;
+
+ EXPECT_EQ(range.default_value, current.value);
+ }
+
+ for (int control_id = V4L2_CID_CAMERA_CLASS_BASE;
+ control_id < V4L2_CID_CAMERA_CLASS_BASE + 32; ++control_id) {
+ if (IsSpecialControl(control_id))
+ continue;
+
+ v4l2_queryctrl range = {};
+ range.id = control_id;
+ if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_QUERYCTRL, &range)) < 0)
+ continue;
+ if (range.flags & V4L2_CTRL_FLAG_DISABLED)
+ continue;
+
+ DVLOG(1) << __func__ << ", " << range.name << ": " << range.minimum << "-"
+ << range.maximum << ", default: " << range.default_value;
+
+ v4l2_control current = {};
+ current.id = control_id;
+ if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_G_CTRL, &current)) < 0)
+ DPLOG(ERROR) << "control " << range.name << ", " << current.value;
+
+ EXPECT_EQ(range.default_value, current.value);
+ }
+}
+
+class MockVideoCaptureDeviceClient : public VideoCaptureDevice::Client {
+ public:
+ MOCK_METHOD7(OnIncomingCapturedData,
+ void(const uint8_t*,
+ int,
+ const VideoCaptureFormat&,
+ int,
+ base::TimeTicks,
+ base::TimeDelta,
+ int));
+ MOCK_METHOD4(ReserveOutputBuffer,
+ std::unique_ptr<Buffer>(const gfx::Size&,
+ media::VideoPixelFormat,
+ media::VideoPixelStorage,
+ int));
+ void OnIncomingCapturedBuffer(std::unique_ptr<Buffer> buffer,
+ const VideoCaptureFormat& frame_format,
+ base::TimeTicks reference_time,
+ base::TimeDelta timestamp) override {
+ DoOnIncomingCapturedBuffer();
+ }
+ MOCK_METHOD0(DoOnIncomingCapturedBuffer, void(void));
+ void OnIncomingCapturedVideoFrame(
+ std::unique_ptr<Buffer> buffer,
+ scoped_refptr<media::VideoFrame> frame) override {
+ DoOnIncomingCapturedVideoFrame();
+ }
+ MOCK_METHOD0(DoOnIncomingCapturedVideoFrame, void(void));
+ MOCK_METHOD4(ResurrectLastOutputBuffer,
+ std::unique_ptr<Buffer>(const gfx::Size&,
+ VideoPixelFormat,
+ VideoPixelStorage,
+ int));
+ MOCK_METHOD2(OnError,
+ void(const tracked_objects::Location& from_here,
+ const std::string& reason));
+ MOCK_CONST_METHOD0(GetBufferPoolUtilization, double(void));
+};
+
+class V4L2CaptureDelegateTest : public ::testing::Test {
+ public:
+ V4L2CaptureDelegateTest()
+ : device_descriptor_("Device 0", "/dev/video0"),
+ delegate_(new V4L2CaptureDelegate(device_descriptor_,
+ base::ThreadTaskRunnerHandle::Get(),
+ 50)) {}
+ ~V4L2CaptureDelegateTest() override = default;
+
+ base::MessageLoop loop_;
+ VideoCaptureDeviceDescriptor device_descriptor_;
+ scoped_refptr<V4L2CaptureDelegate> delegate_;
+};
+
+} // anonymous namespace
+
+TEST_F(V4L2CaptureDelegateTest, CreateAndDestroyAndVerifyControls) {
+ // Check that there is at least a video device, otherwise bail.
+ const base::FilePath path("/dev/");
+ base::FileEnumerator enumerator(path, false, base::FileEnumerator::FILES,
+ "video*");
+ if (enumerator.Next().empty()) {
+ DLOG(INFO) << " No devices found, skipping test";
+ return;
+ }
+
+ // Open device, manipulate user and camera controls, and close it.
+ {
+ base::ScopedFD device_fd(
+ HANDLE_EINTR(open(device_descriptor_.device_id.c_str(), O_RDWR)));
+ ASSERT_TRUE(device_fd.is_valid());
+
+ SetControlsToMaxValues(device_fd.get());
+
+ base::RunLoop().RunUntilIdle();
+ }
+
+ // Start and stop capturing, triggering the resetting of user and camera
+ // control values.
+ {
+ std::unique_ptr<MockVideoCaptureDeviceClient> client(
+ new MockVideoCaptureDeviceClient());
+ MockVideoCaptureDeviceClient* client_ptr = client.get();
+ delegate_->AllocateAndStart(320 /* width */, 240 /* height */,
+ 10.0 /* frame_rate */, std::move(client));
+
+ base::RunLoop run_loop;
+ base::Closure quit_closure = run_loop.QuitClosure();
+ EXPECT_CALL(*client_ptr, OnIncomingCapturedData(_, _, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(RunClosure(quit_closure));
+ run_loop.Run();
+
+ delegate_->StopAndDeAllocate();
+ base::RunLoop().RunUntilIdle();
+ }
+
+ // Reopen the device and verify all user and camera controls should be back to
+ // their |default_value|s.
+ {
+ base::ScopedFD device_fd(
+ HANDLE_EINTR(open(device_descriptor_.device_id.c_str(), O_RDWR)));
+ ASSERT_TRUE(device_fd.is_valid());
+ VerifyUserControlsAreSetToDefaultValues(device_fd.get());
+ }
+}
+
+}; // namespace media

Powered by Google App Engine
This is Rietveld 408576698