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

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
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 bool IsSpecialControl(int control_id) {
29 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.
30 return true;
31 else if (control_id == V4L2_CID_EXPOSURE_AUTO)
32 return true;
33 else if (control_id == V4L2_CID_EXPOSURE_AUTO_PRIORITY)
34 return true;
35 else if (control_id == V4L2_CID_FOCUS_AUTO)
36 return true;
37 return false;
38 }
39
40 void SetControlsToMaxValues(int device_fd) {
41 // Set V4L2_CID_AUTO_WHITE_BALANCE to false first.
42 v4l2_control auto_white_balance = {};
43 auto_white_balance.id = V4L2_CID_AUTO_WHITE_BALANCE;
44 auto_white_balance.value = false;
45 if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_S_CTRL, &auto_white_balance)) < 0)
46 DPLOG(ERROR) << "VIDIOC_S_CTRL";
47
48 std::vector<struct v4l2_ext_control> user_controls;
49 for (int control_id = V4L2_CID_USER_BASE; control_id < V4L2_CID_LASTP1;
50 ++control_id) {
51 if (IsSpecialControl(control_id))
52 continue;
53 v4l2_queryctrl range = {};
54 range.id = control_id;
55 if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_QUERYCTRL, &range)) < 0)
56 continue;
57 DVLOG(1) << __func__ << ", " << range.name << " - " << range.maximum;
58
59 struct v4l2_ext_control ext_control = {};
60 ext_control.id = control_id;
61 ext_control.value = range.maximum;
62 user_controls.push_back(ext_control);
63 }
64
65 if (!user_controls.empty()) {
66 struct v4l2_ext_controls ext_controls = {};
67 ext_controls.ctrl_class = V4L2_CTRL_CLASS_USER;
68 ext_controls.count = user_controls.size();
69 ext_controls.controls = user_controls.data();
70 if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_S_EXT_CTRLS, &ext_controls)) < 0)
71 DPLOG(ERROR) << "VIDIOC_S_EXT_CTRLS " << user_controls.size();
72 }
73
74 for (int control_id = V4L2_CID_USER_BASE; control_id < V4L2_CID_LASTP1;
75 ++control_id) {
76 if (IsSpecialControl(control_id))
77 continue;
78 v4l2_queryctrl range = {};
79 range.id = control_id;
80 if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_QUERYCTRL, &range)) < 0)
81 continue;
82 v4l2_control readback = {};
83 readback.id = control_id;
84 if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_G_CTRL, &readback)) < 0)
85 DPLOG(ERROR) << range.name << ", failed to be read.";
86 EXPECT_EQ(range.maximum, readback.value)
87 << " control didnt get set correctly" << range.name;
88 }
89
90 std::vector<struct v4l2_ext_control> special_camera_controls;
91 // Set V4L2_CID_EXPOSURE_AUTO to V4L2_EXPOSURE_MANUAL.
92 v4l2_ext_control auto_exposure = {};
93 auto_exposure.id = V4L2_CID_EXPOSURE_AUTO;
94 auto_exposure.value = V4L2_EXPOSURE_MANUAL;
95 special_camera_controls.push_back(auto_exposure);
96 // Set V4L2_CID_EXPOSURE_AUTO_PRIORITY to false.
97 v4l2_ext_control priority_auto_exposure = {};
98 priority_auto_exposure.id = V4L2_CID_EXPOSURE_AUTO_PRIORITY;
99 priority_auto_exposure.value = false;
100 special_camera_controls.push_back(priority_auto_exposure);
101 // Set V4L2_CID_FOCUS_AUTO to false.
102 v4l2_ext_control auto_focus = {};
103 auto_focus.id = V4L2_CID_FOCUS_AUTO;
104 auto_focus.value = false;
105 special_camera_controls.push_back(auto_focus);
106
107 struct v4l2_ext_controls ext_controls = {};
108 ext_controls.ctrl_class = V4L2_CID_CAMERA_CLASS;
109 ext_controls.count = special_camera_controls.size();
110 ext_controls.controls = special_camera_controls.data();
111 if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_S_EXT_CTRLS, &ext_controls)) < 0)
112 DPLOG(ERROR) << "VIDIOC_S_EXT_CTRLS";
113
114 std::vector<struct v4l2_ext_control> camera_controls;
115 for (int control_id = V4L2_CID_CAMERA_CLASS_BASE;
116 control_id < V4L2_CID_CAMERA_CLASS_BASE + 32; ++control_id) {
117 if (IsSpecialControl(control_id))
118 continue;
119 v4l2_queryctrl range = {};
120 range.id = control_id;
121 if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_QUERYCTRL, &range)) < 0)
122 continue;
123 DVLOG(1) << __func__ << ", " << range.name << " - " << range.maximum;
124
125 struct v4l2_ext_control ext_control = {};
126 ext_control.id = control_id;
127 ext_control.value = range.maximum; // Set to its maximum !!!!
128 camera_controls.push_back(ext_control);
129 }
130
131 if (!camera_controls.empty()) {
132 struct v4l2_ext_controls ext_controls = {};
133 ext_controls.ctrl_class = V4L2_CID_CAMERA_CLASS;
134 ext_controls.count = camera_controls.size();
135 ext_controls.controls = camera_controls.data();
136 if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_S_EXT_CTRLS, &ext_controls)) < 0)
137 DPLOG(ERROR) << "VIDIOC_S_EXT_CTRLS";
138 }
139
140 for (int control_id = V4L2_CID_CAMERA_CLASS_BASE;
141 control_id < V4L2_CID_CAMERA_CLASS_BASE + 32; ++control_id) {
142 if (IsSpecialControl(control_id))
143 continue;
144 v4l2_queryctrl range = {};
145 range.id = control_id;
146 if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_QUERYCTRL, &range)) < 0)
147 continue;
148 v4l2_control readback = {};
149 readback.id = control_id;
150 if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_G_CTRL, &readback)) < 0)
151 DPLOG(ERROR) << range.name << ", failed to be read.";
152 EXPECT_EQ(range.maximum, readback.value) << " control didnt reset, "
153 << range.name;
154 }
155 }
156
157 void VerifyUserControlsAreSetToDefaultValues(int device_fd) {
158 for (int control_id = V4L2_CID_USER_BASE; control_id < V4L2_CID_LASTP1;
159 ++control_id) {
160 if (IsSpecialControl(control_id))
161 continue;
162
163 v4l2_queryctrl range = {};
164 range.id = control_id;
165 if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_QUERYCTRL, &range)) < 0)
166 continue;
167 if (range.flags & V4L2_CTRL_FLAG_DISABLED)
168 continue;
169
170 DVLOG(1) << __func__ << ", " << range.name << ": " << range.minimum << "-"
171 << range.maximum << ", default: " << range.default_value;
172
173 v4l2_control current = {};
174 current.id = control_id;
175 if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_G_CTRL, &current)) < 0)
176 DPLOG(ERROR) << "control " << range.name << ", " << current.value;
177
178 EXPECT_EQ(range.default_value, current.value);
179 }
180
181 for (int control_id = V4L2_CID_CAMERA_CLASS_BASE;
182 control_id < V4L2_CID_CAMERA_CLASS_BASE + 32; ++control_id) {
183 if (IsSpecialControl(control_id))
184 continue;
185
186 v4l2_queryctrl range = {};
187 range.id = control_id;
188 if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_QUERYCTRL, &range)) < 0)
189 continue;
190 if (range.flags & V4L2_CTRL_FLAG_DISABLED)
191 continue;
192
193 DVLOG(1) << __func__ << ", " << range.name << ": " << range.minimum << "-"
194 << range.maximum << ", default: " << range.default_value;
195
196 v4l2_control current = {};
197 current.id = control_id;
198 if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_G_CTRL, &current)) < 0)
199 DPLOG(ERROR) << "control " << range.name << ", " << current.value;
200
201 EXPECT_EQ(range.default_value, current.value);
202 }
203 }
204
205 class MockVideoCaptureDeviceClient : public VideoCaptureDevice::Client {
206 public:
207 MOCK_METHOD7(OnIncomingCapturedData,
208 void(const uint8_t*,
209 int,
210 const VideoCaptureFormat&,
211 int,
212 base::TimeTicks,
213 base::TimeDelta,
214 int));
215 MOCK_METHOD4(ReserveOutputBuffer,
216 std::unique_ptr<Buffer>(const gfx::Size&,
217 media::VideoPixelFormat,
218 media::VideoPixelStorage,
219 int));
220 void OnIncomingCapturedBuffer(std::unique_ptr<Buffer> buffer,
221 const VideoCaptureFormat& frame_format,
222 base::TimeTicks reference_time,
223 base::TimeDelta timestamp) override {
224 DoOnIncomingCapturedBuffer();
225 }
226 MOCK_METHOD0(DoOnIncomingCapturedBuffer, void(void));
227 void OnIncomingCapturedVideoFrame(
228 std::unique_ptr<Buffer> buffer,
229 scoped_refptr<media::VideoFrame> frame) override {
230 DoOnIncomingCapturedVideoFrame();
231 }
232 MOCK_METHOD0(DoOnIncomingCapturedVideoFrame, void(void));
233 MOCK_METHOD4(ResurrectLastOutputBuffer,
234 std::unique_ptr<Buffer>(const gfx::Size&,
235 VideoPixelFormat,
236 VideoPixelStorage,
237 int));
238 MOCK_METHOD2(OnError,
239 void(const tracked_objects::Location& from_here,
240 const std::string& reason));
241 MOCK_CONST_METHOD0(GetBufferPoolUtilization, double(void));
242 };
243
244 class V4L2CaptureDelegateTest : public ::testing::Test {
245 public:
246 V4L2CaptureDelegateTest()
247 : device_descriptor_("Device 0", "/dev/video0"),
248 delegate_(new V4L2CaptureDelegate(device_descriptor_,
249 base::ThreadTaskRunnerHandle::Get(),
250 50)) {}
251 ~V4L2CaptureDelegateTest() override = default;
252
253 base::MessageLoop loop_;
254 VideoCaptureDeviceDescriptor device_descriptor_;
255 scoped_refptr<V4L2CaptureDelegate> delegate_;
256 };
257
258 } // anonymous namespace
259
260 TEST_F(V4L2CaptureDelegateTest, CreateAndDestroyAndVerifyControls) {
261 // Check that there is at least a video device, otherwise bail.
262 const base::FilePath path("/dev/");
263 base::FileEnumerator enumerator(path, false, base::FileEnumerator::FILES,
264 "video*");
265 if (enumerator.Next().empty()) {
266 DLOG(INFO) << " No devices found, skipping test";
267 return;
268 }
269
270 // Open device, manipulate user and camera controls, and close it.
271 {
272 base::ScopedFD device_fd(
273 HANDLE_EINTR(open(device_descriptor_.device_id.c_str(), O_RDWR)));
274 ASSERT_TRUE(device_fd.is_valid());
275
276 SetControlsToMaxValues(device_fd.get());
277
278 base::RunLoop().RunUntilIdle();
279 }
280
281 // Start and stop capturing, triggering the resetting of user and camera
282 // control values.
283 {
284 std::unique_ptr<MockVideoCaptureDeviceClient> client(
285 new MockVideoCaptureDeviceClient());
286 MockVideoCaptureDeviceClient* client_ptr = client.get();
287 delegate_->AllocateAndStart(320 /* width */, 240 /* height */,
288 10.0 /* frame_rate */, std::move(client));
289
290 base::RunLoop run_loop;
291 base::Closure quit_closure = run_loop.QuitClosure();
292 EXPECT_CALL(*client_ptr, OnIncomingCapturedData(_, _, _, _, _, _, _))
293 .Times(1)
294 .WillOnce(RunClosure(quit_closure));
295 run_loop.Run();
296
297 delegate_->StopAndDeAllocate();
298 base::RunLoop().RunUntilIdle();
299 }
300
301 // Reopen the device and verify all user and camera controls should be back to
302 // their |default_value|s.
303 {
304 base::ScopedFD device_fd(
305 HANDLE_EINTR(open(device_descriptor_.device_id.c_str(), O_RDWR)));
306 ASSERT_TRUE(device_fd.is_valid());
307 VerifyUserControlsAreSetToDefaultValues(device_fd.get());
308 }
309 }
310
311 }; // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698