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

Side by Side Diff: media/capture/video/linux/v4l2_capture_delegate.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
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/capture/video/linux/v4l2_capture_delegate.h" 5 #include "media/capture/video/linux/v4l2_capture_delegate.h"
6 6
7 #include <linux/version.h> 7 #include <linux/version.h>
8 #include <linux/videodev2.h>
8 #include <poll.h> 9 #include <poll.h>
9 #include <sys/fcntl.h> 10 #include <sys/fcntl.h>
10 #include <sys/ioctl.h> 11 #include <sys/ioctl.h>
11 #include <sys/mman.h> 12 #include <sys/mman.h>
12 #include <utility> 13 #include <utility>
13 14
14 #include "base/bind.h" 15 #include "base/bind.h"
15 #include "base/files/file_enumerator.h" 16 #include "base/files/file_enumerator.h"
16 #include "base/posix/eintr_wrapper.h" 17 #include "base/posix/eintr_wrapper.h"
17 #include "base/strings/stringprintf.h" 18 #include "base/strings/stringprintf.h"
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
70 // decode. However, it is needed for large resolutions due to USB bandwidth 71 // decode. However, it is needed for large resolutions due to USB bandwidth
71 // limitations, so GetListOfUsableFourCcs() can duplicate it on top, see 72 // limitations, so GetListOfUsableFourCcs() can duplicate it on top, see
72 // that method. 73 // that method.
73 {V4L2_PIX_FMT_MJPEG, PIXEL_FORMAT_MJPEG, 1}, 74 {V4L2_PIX_FMT_MJPEG, PIXEL_FORMAT_MJPEG, 1},
74 // JPEG works as MJPEG on some gspca webcams from field reports, see 75 // JPEG works as MJPEG on some gspca webcams from field reports, see
75 // https://code.google.com/p/webrtc/issues/detail?id=529, put it as the 76 // https://code.google.com/p/webrtc/issues/detail?id=529, put it as the
76 // least preferred format. 77 // least preferred format.
77 {V4L2_PIX_FMT_JPEG, PIXEL_FORMAT_MJPEG, 1}, 78 {V4L2_PIX_FMT_JPEG, PIXEL_FORMAT_MJPEG, 1},
78 }; 79 };
79 80
81 // Maximum number of ioctl retries before giving up trying to reset controls.
82 const int kMaxIOCtrlRetries = 5;
83
84 // Base id and class identifier for Controls to be reset.
85 static struct {
86 uint32_t control_base;
87 uint32_t class_id;
88 } const kControls[] = {{V4L2_CID_USER_BASE, V4L2_CID_USER_CLASS},
89 {V4L2_CID_CAMERA_CLASS_BASE, V4L2_CID_CAMERA_CLASS}};
90
80 // Fill in |format| with the given parameters. 91 // Fill in |format| with the given parameters.
81 static void FillV4L2Format(v4l2_format* format, 92 static void FillV4L2Format(v4l2_format* format,
82 uint32_t width, 93 uint32_t width,
83 uint32_t height, 94 uint32_t height,
84 uint32_t pixelformat_fourcc) { 95 uint32_t pixelformat_fourcc) {
85 memset(format, 0, sizeof(*format)); 96 memset(format, 0, sizeof(*format));
86 format->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 97 format->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
87 format->fmt.pix.width = width; 98 format->fmt.pix.width = width;
88 format->fmt.pix.height = height; 99 format->fmt.pix.height = height;
89 format->fmt.pix.pixelformat = pixelformat_fourcc; 100 format->fmt.pix.pixelformat = pixelformat_fourcc;
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
127 138
128 v4l2_control current = {}; 139 v4l2_control current = {};
129 current.id = control_id; 140 current.id = control_id;
130 if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_G_CTRL, &current)) < 0) 141 if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_G_CTRL, &current)) < 0)
131 return mojom::Range::New(); 142 return mojom::Range::New();
132 capability->current = current.value; 143 capability->current = current.value;
133 144
134 return capability; 145 return capability;
135 } 146 }
136 147
148 // Determines if |control_id| is special, i.e. controls another one's state.
149 static bool IsSpecialControl(int control_id) {
150 switch (control_id) {
151 case V4L2_CID_AUTO_WHITE_BALANCE:
152 case V4L2_CID_EXPOSURE_AUTO:
153 case V4L2_CID_EXPOSURE_AUTO_PRIORITY:
154 case V4L2_CID_FOCUS_AUTO:
155 return true;
156 }
157 return false;
158 }
159
160 // Sets all user control to their default. Some controls are enabled by another
161 // flag, usually having the word "auto" in the name, see IsSpecialControl().
162 // These flags are preset beforehand, then set to their defaults individually
163 // afterwards.
164 static void ResetUserAndCameraControlsToDefault(int device_fd) {
165 // Set V4L2_CID_AUTO_WHITE_BALANCE to false first.
166 v4l2_control auto_white_balance = {};
167 auto_white_balance.id = V4L2_CID_AUTO_WHITE_BALANCE;
168 auto_white_balance.value = false;
169 int num_retries = 0;
170 // Setting up the first control right after stopping streaming seems
171 // not to the work the first time, so retry a few times.
172 for (; num_retries < kMaxIOCtrlRetries &&
173 HANDLE_EINTR(ioctl(device_fd, VIDIOC_S_CTRL, &auto_white_balance)) < 0;
174 ++num_retries) {
175 DPLOG(WARNING) << "VIDIOC_S_CTRL";
176 }
177 if (num_retries == kMaxIOCtrlRetries) {
178 DLOG(ERROR) << "Cannot access device controls";
179 return;
180 }
181
182 std::vector<struct v4l2_ext_control> special_camera_controls;
183 // Set V4L2_CID_EXPOSURE_AUTO to V4L2_EXPOSURE_MANUAL.
184 v4l2_ext_control auto_exposure = {};
185 auto_exposure.id = V4L2_CID_EXPOSURE_AUTO;
186 auto_exposure.value = V4L2_EXPOSURE_MANUAL;
187 special_camera_controls.push_back(auto_exposure);
188 // Set V4L2_CID_EXPOSURE_AUTO_PRIORITY to false.
189 v4l2_ext_control priority_auto_exposure = {};
190 priority_auto_exposure.id = V4L2_CID_EXPOSURE_AUTO_PRIORITY;
191 priority_auto_exposure.value = false;
192 special_camera_controls.push_back(priority_auto_exposure);
193 // Set V4L2_CID_FOCUS_AUTO to false.
194 v4l2_ext_control auto_focus = {};
195 auto_focus.id = V4L2_CID_FOCUS_AUTO;
196 auto_focus.value = false;
197 special_camera_controls.push_back(auto_focus);
198
199 struct v4l2_ext_controls ext_controls = {};
200 ext_controls.ctrl_class = V4L2_CID_CAMERA_CLASS;
201 ext_controls.count = special_camera_controls.size();
202 ext_controls.controls = special_camera_controls.data();
203 if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_S_EXT_CTRLS, &ext_controls)) < 0)
204 DPLOG(ERROR) << "VIDIOC_S_EXT_CTRLS";
205
206 std::vector<struct v4l2_ext_control> camera_controls;
207 for (const auto& control : kControls) {
208 std::vector<struct v4l2_ext_control> camera_controls;
209
210 v4l2_queryctrl range = {};
211 range.id = control.control_base | V4L2_CTRL_FLAG_NEXT_CTRL;
212 while (0 == HANDLE_EINTR(ioctl(device_fd, VIDIOC_QUERYCTRL, &range))) {
213 if (V4L2_CTRL_ID2CLASS(range.id) != V4L2_CTRL_ID2CLASS(control.class_id))
214 break;
215 range.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
216
217 if (IsSpecialControl(range.id & ~V4L2_CTRL_FLAG_NEXT_CTRL))
218 continue;
219
220 struct v4l2_ext_control ext_control = {};
221 ext_control.id = range.id & ~V4L2_CTRL_FLAG_NEXT_CTRL;
222 ext_control.value = range.default_value;
223 camera_controls.push_back(ext_control);
224 }
225
226 if (!camera_controls.empty()) {
227 struct v4l2_ext_controls ext_controls = {};
228 ext_controls.ctrl_class = control.class_id;
229 ext_controls.count = camera_controls.size();
230 ext_controls.controls = camera_controls.data();
231 if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_S_EXT_CTRLS, &ext_controls)) < 0)
232 DPLOG(ERROR) << "VIDIOC_S_EXT_CTRLS";
233 }
234 }
235
236 // Now set the special flags to the default values
237 v4l2_queryctrl range = {};
238 range.id = V4L2_CID_AUTO_WHITE_BALANCE;
239 HANDLE_EINTR(ioctl(device_fd, VIDIOC_QUERYCTRL, &range));
240 auto_white_balance.value = range.default_value;
241 HANDLE_EINTR(ioctl(device_fd, VIDIOC_S_CTRL, &auto_white_balance));
242
243 special_camera_controls.clear();
244 memset(&range, 0, sizeof(struct v4l2_queryctrl));
245 range.id = V4L2_CID_EXPOSURE_AUTO;
246 HANDLE_EINTR(ioctl(device_fd, VIDIOC_QUERYCTRL, &range));
247 auto_exposure.value = range.default_value;
248 special_camera_controls.push_back(auto_exposure);
249
250 memset(&range, 0, sizeof(struct v4l2_queryctrl));
251 range.id = V4L2_CID_EXPOSURE_AUTO_PRIORITY;
252 HANDLE_EINTR(ioctl(device_fd, VIDIOC_QUERYCTRL, &range));
253 priority_auto_exposure.value = range.default_value;
254 special_camera_controls.push_back(priority_auto_exposure);
255
256 memset(&range, 0, sizeof(struct v4l2_queryctrl));
257 range.id = V4L2_CID_FOCUS_AUTO;
258 HANDLE_EINTR(ioctl(device_fd, VIDIOC_QUERYCTRL, &range));
259 auto_focus.value = range.default_value;
260 special_camera_controls.push_back(auto_focus);
261
262 memset(&ext_controls, 0, sizeof(struct v4l2_ext_controls));
263 ext_controls.ctrl_class = V4L2_CID_CAMERA_CLASS;
264 ext_controls.count = special_camera_controls.size();
265 ext_controls.controls = special_camera_controls.data();
266 if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_S_EXT_CTRLS, &ext_controls)) < 0)
267 DPLOG(ERROR) << "VIDIOC_S_EXT_CTRLS";
268 }
269
137 // Class keeping track of a SPLANE V4L2 buffer, mmap()ed on construction and 270 // Class keeping track of a SPLANE V4L2 buffer, mmap()ed on construction and
138 // munmap()ed on destruction. 271 // munmap()ed on destruction.
139 class V4L2CaptureDelegate::BufferTracker 272 class V4L2CaptureDelegate::BufferTracker
140 : public base::RefCounted<BufferTracker> { 273 : public base::RefCounted<BufferTracker> {
141 public: 274 public:
142 BufferTracker(); 275 BufferTracker();
143 // Abstract method to mmap() given |fd| according to |buffer|. 276 // Abstract method to mmap() given |fd| according to |buffer|.
144 bool Init(int fd, const v4l2_buffer& buffer); 277 bool Init(int fd, const v4l2_buffer& buffer);
145 278
146 const uint8_t* start() const { return start_; } 279 const uint8_t* start() const { return start_; }
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after
348 return; 481 return;
349 } 482 }
350 483
351 buffer_tracker_pool_.clear(); 484 buffer_tracker_pool_.clear();
352 485
353 v4l2_requestbuffers r_buffer; 486 v4l2_requestbuffers r_buffer;
354 FillV4L2RequestBuffer(&r_buffer, 0); 487 FillV4L2RequestBuffer(&r_buffer, 0);
355 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_REQBUFS, &r_buffer)) < 0) 488 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_REQBUFS, &r_buffer)) < 0)
356 SetErrorState(FROM_HERE, "Failed to VIDIOC_REQBUFS with count = 0"); 489 SetErrorState(FROM_HERE, "Failed to VIDIOC_REQBUFS with count = 0");
357 490
491 ResetUserAndCameraControlsToDefault(device_fd_.get());
358 // At this point we can close the device. 492 // At this point we can close the device.
359 // This is also needed for correctly changing settings later via VIDIOC_S_FMT. 493 // This is also needed for correctly changing settings later via VIDIOC_S_FMT.
360 device_fd_.reset(); 494 device_fd_.reset();
361 is_capturing_ = false; 495 is_capturing_ = false;
362 client_.reset(); 496 client_.reset();
363 } 497 }
364 498
365 void V4L2CaptureDelegate::TakePhoto( 499 void V4L2CaptureDelegate::TakePhoto(
366 VideoCaptureDevice::TakePhotoCallback callback) { 500 VideoCaptureDevice::TakePhotoCallback callback) {
367 DCHECK(v4l2_task_runner_->BelongsToCurrentThread()); 501 DCHECK(v4l2_task_runner_->BelongsToCurrentThread());
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after
646 DLOG(ERROR) << "Error mmap()ing a V4L2 buffer into userspace"; 780 DLOG(ERROR) << "Error mmap()ing a V4L2 buffer into userspace";
647 return false; 781 return false;
648 } 782 }
649 start_ = static_cast<uint8_t*>(start); 783 start_ = static_cast<uint8_t*>(start);
650 length_ = buffer.length; 784 length_ = buffer.length;
651 payload_size_ = 0; 785 payload_size_ = 0;
652 return true; 786 return true;
653 } 787 }
654 788
655 } // namespace media 789 } // namespace media
OLDNEW
« no previous file with comments | « media/capture/video/linux/v4l2_capture_delegate.h ('k') | media/capture/video/linux/v4l2_capture_delegate_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698