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

Side by Side 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 unified diff | Download patch
« no previous file with comments | « media/capture/video/linux/v4l2_capture_delegate.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <sys/fcntl.h>
6 #include <sys/ioctl.h>
7
8 #include "base/files/file_enumerator.h"
9 #include "base/run_loop.h"
10 #include "base/threading/thread_task_runner_handle.h"
11 #include "media/capture/video/linux/v4l2_capture_delegate.h"
12 #include "media/capture/video/video_capture_device.h"
13 #include "media/capture/video/video_capture_device_descriptor.h"
14 #include "media/capture/video_capture_types.h"
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 using ::testing::_;
19
20 namespace media {
21
22 namespace {
23
24 ACTION_P(RunClosure, closure) {
25 closure.Run();
26 }
27
28 // Base id and class identifiers for Controls to be modified and later tested
29 // agains default values.
30 static struct {
31 uint32_t control_base;
32 uint32_t class_id;
33 } const kControls[] = {{V4L2_CID_USER_BASE, V4L2_CID_USER_CLASS},
34 {V4L2_CID_CAMERA_CLASS_BASE, V4L2_CID_CAMERA_CLASS}};
35
36 // Determines if |control_id| is special, i.e. controls another one's state.
37 static bool IsSpecialControl(int control_id) {
38 switch (control_id) {
39 case V4L2_CID_AUTO_WHITE_BALANCE:
40 case V4L2_CID_EXPOSURE_AUTO:
41 case V4L2_CID_EXPOSURE_AUTO_PRIORITY:
42 case V4L2_CID_FOCUS_AUTO:
43 return true;
44 }
45 return false;
46 }
47
48 static void SetControlsToMaxValues(int device_fd) {
49 // Set V4L2_CID_AUTO_WHITE_BALANCE to false first.
50 v4l2_control auto_white_balance = {};
51 auto_white_balance.id = V4L2_CID_AUTO_WHITE_BALANCE;
52 auto_white_balance.value = false;
53 if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_S_CTRL, &auto_white_balance)) < 0)
54 DPLOG(ERROR) << "VIDIOC_S_CTRL";
55
56 std::vector<struct v4l2_ext_control> special_camera_controls;
57 // Set V4L2_CID_EXPOSURE_AUTO to V4L2_EXPOSURE_MANUAL.
58 v4l2_ext_control auto_exposure = {};
59 auto_exposure.id = V4L2_CID_EXPOSURE_AUTO;
60 auto_exposure.value = V4L2_EXPOSURE_MANUAL;
61 special_camera_controls.push_back(auto_exposure);
62 // Set V4L2_CID_EXPOSURE_AUTO_PRIORITY to false.
63 v4l2_ext_control priority_auto_exposure = {};
64 priority_auto_exposure.id = V4L2_CID_EXPOSURE_AUTO_PRIORITY;
65 priority_auto_exposure.value = false;
66 special_camera_controls.push_back(priority_auto_exposure);
67 // Set V4L2_CID_FOCUS_AUTO to false.
68 v4l2_ext_control auto_focus = {};
69 auto_focus.id = V4L2_CID_FOCUS_AUTO;
70 auto_focus.value = false;
71 special_camera_controls.push_back(auto_focus);
72
73 struct v4l2_ext_controls ext_controls = {};
74 ext_controls.ctrl_class = V4L2_CID_CAMERA_CLASS;
75 ext_controls.count = special_camera_controls.size();
76 ext_controls.controls = special_camera_controls.data();
77 if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_S_EXT_CTRLS, &ext_controls)) < 0)
78 DPLOG(ERROR) << "VIDIOC_S_EXT_CTRLS";
79
80 for (const auto& control : kControls) {
81 std::vector<struct v4l2_ext_control> camera_controls;
82
83 v4l2_queryctrl range = {};
84 range.id = control.control_base | V4L2_CTRL_FLAG_NEXT_CTRL;
85 while (0 == HANDLE_EINTR(ioctl(device_fd, VIDIOC_QUERYCTRL, &range))) {
86 if (V4L2_CTRL_ID2CLASS(range.id) != V4L2_CTRL_ID2CLASS(control.class_id))
87 break;
88 range.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
89
90 if (IsSpecialControl(range.id & ~V4L2_CTRL_FLAG_NEXT_CTRL))
91 continue;
92 DVLOG(1) << __func__ << " " << range.name << " set to " << range.maximum;
93
94 struct v4l2_ext_control ext_control = {};
95 ext_control.id = range.id & ~V4L2_CTRL_FLAG_NEXT_CTRL;
96 ext_control.value = range.maximum;
97 camera_controls.push_back(ext_control);
98 }
99
100 if (!camera_controls.empty()) {
101 struct v4l2_ext_controls ext_controls = {};
102 ext_controls.ctrl_class = control.class_id;
103 ext_controls.count = camera_controls.size();
104 ext_controls.controls = camera_controls.data();
105 if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_S_EXT_CTRLS, &ext_controls)) < 0)
106 DPLOG(ERROR) << "VIDIOC_S_EXT_CTRLS";
107 }
108
109 range.id = control.control_base | V4L2_CTRL_FLAG_NEXT_CTRL;
110 while (0 == HANDLE_EINTR(ioctl(device_fd, VIDIOC_QUERYCTRL, &range))) {
111 if (V4L2_CTRL_ID2CLASS(range.id) != V4L2_CTRL_ID2CLASS(control.class_id))
112 break;
113 range.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
114
115 if (IsSpecialControl(range.id & ~V4L2_CTRL_FLAG_NEXT_CTRL))
116 continue;
117 DVLOG(1) << __func__ << " " << range.name << " set to " << range.maximum;
118
119 v4l2_control readback = {};
120 readback.id = range.id & ~V4L2_CTRL_FLAG_NEXT_CTRL;
121 if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_G_CTRL, &readback)) < 0)
122 DPLOG(ERROR) << range.name << ", failed to be read.";
123 EXPECT_EQ(range.maximum, readback.value) << " control " << range.name
124 << " didnt set correctly";
125 }
126 }
127 }
128
129 static void VerifyUserControlsAreSetToDefaultValues(int device_fd) {
130 for (const auto& control : kControls) {
131 v4l2_queryctrl range = {};
132 range.id = control.control_base | V4L2_CTRL_FLAG_NEXT_CTRL;
133 while (0 == HANDLE_EINTR(ioctl(device_fd, VIDIOC_QUERYCTRL, &range))) {
134 if (V4L2_CTRL_ID2CLASS(range.id) != V4L2_CTRL_ID2CLASS(control.class_id))
135 break;
136 range.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
137
138 DVLOG(1) << __func__ << " " << range.name << ": " << range.minimum << "-"
139 << range.maximum << ", default: " << range.default_value;
140
141 v4l2_control current = {};
142 current.id = range.id & ~V4L2_CTRL_FLAG_NEXT_CTRL;
143 if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_G_CTRL, &current)) < 0)
144 DPLOG(ERROR) << "control " << range.name;
145
146 EXPECT_EQ(range.default_value, current.value);
147 }
148 }
149 }
150
151 class MockVideoCaptureDeviceClient : public VideoCaptureDevice::Client {
152 public:
153 MOCK_METHOD7(OnIncomingCapturedData,
154 void(const uint8_t*,
155 int,
156 const VideoCaptureFormat&,
157 int,
158 base::TimeTicks,
159 base::TimeDelta,
160 int));
161 MOCK_METHOD4(ReserveOutputBuffer,
162 std::unique_ptr<Buffer>(const gfx::Size&,
163 media::VideoPixelFormat,
164 media::VideoPixelStorage,
165 int));
166 void OnIncomingCapturedBuffer(std::unique_ptr<Buffer> buffer,
167 const VideoCaptureFormat& frame_format,
168 base::TimeTicks reference_time,
169 base::TimeDelta timestamp) override {
170 DoOnIncomingCapturedBuffer();
171 }
172 MOCK_METHOD0(DoOnIncomingCapturedBuffer, void(void));
173 void OnIncomingCapturedVideoFrame(
174 std::unique_ptr<Buffer> buffer,
175 scoped_refptr<media::VideoFrame> frame) override {
176 DoOnIncomingCapturedVideoFrame();
177 }
178 MOCK_METHOD0(DoOnIncomingCapturedVideoFrame, void(void));
179 MOCK_METHOD4(ResurrectLastOutputBuffer,
180 std::unique_ptr<Buffer>(const gfx::Size&,
181 VideoPixelFormat,
182 VideoPixelStorage,
183 int));
184 MOCK_METHOD2(OnError,
185 void(const tracked_objects::Location& from_here,
186 const std::string& reason));
187 MOCK_CONST_METHOD0(GetBufferPoolUtilization, double(void));
188 };
189
190 class V4L2CaptureDelegateTest : public ::testing::Test {
191 public:
192 V4L2CaptureDelegateTest()
193 : device_descriptor_("Device 0", "/dev/video0"),
194 delegate_(new V4L2CaptureDelegate(device_descriptor_,
195 base::ThreadTaskRunnerHandle::Get(),
196 50)) {}
197 ~V4L2CaptureDelegateTest() override = default;
198
199 base::MessageLoop loop_;
200 VideoCaptureDeviceDescriptor device_descriptor_;
201 scoped_refptr<V4L2CaptureDelegate> delegate_;
202 };
203
204 } // anonymous namespace
205
206 TEST_F(V4L2CaptureDelegateTest, CreateAndDestroyAndVerifyControls) {
207 // Check that there is at least a video device, otherwise bail.
208 const base::FilePath path("/dev/");
209 base::FileEnumerator enumerator(path, false, base::FileEnumerator::FILES,
210 "video*");
211 if (enumerator.Next().empty()) {
212 DLOG(INFO) << " No devices found, skipping test";
213 return;
214 }
215
216 // Open device, manipulate user and camera controls, and close it.
217 {
218 base::ScopedFD device_fd(
219 HANDLE_EINTR(open(device_descriptor_.device_id.c_str(), O_RDWR)));
220 ASSERT_TRUE(device_fd.is_valid());
221
222 SetControlsToMaxValues(device_fd.get());
223
224 base::RunLoop().RunUntilIdle();
225 }
226
227 // Start and stop capturing, triggering the resetting of user and camera
228 // control values.
229 {
230 std::unique_ptr<MockVideoCaptureDeviceClient> client(
231 new MockVideoCaptureDeviceClient());
232 MockVideoCaptureDeviceClient* client_ptr = client.get();
233 delegate_->AllocateAndStart(320 /* width */, 240 /* height */,
234 10.0 /* frame_rate */, std::move(client));
235
236 base::RunLoop run_loop;
237 base::Closure quit_closure = run_loop.QuitClosure();
238 EXPECT_CALL(*client_ptr, OnIncomingCapturedData(_, _, _, _, _, _, _))
239 .Times(1)
240 .WillOnce(RunClosure(quit_closure));
241 run_loop.Run();
242
243 delegate_->StopAndDeAllocate();
244 base::RunLoop().RunUntilIdle();
245 }
246
247 // Reopen the device and verify all user and camera controls should be back to
248 // their |default_value|s.
249 {
250 base::ScopedFD device_fd(
251 HANDLE_EINTR(open(device_descriptor_.device_id.c_str(), O_RDWR)));
252 ASSERT_TRUE(device_fd.is_valid());
253 VerifyUserControlsAreSetToDefaultValues(device_fd.get());
254 }
255 }
256
257 }; // namespace media
OLDNEW
« no previous file with comments | « media/capture/video/linux/v4l2_capture_delegate.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698