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

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 27 matching lines...) Expand all
45 // https://crbug.com/470717 46 // https://crbug.com/470717
46 const int kCaptureTimeoutMs = 1000; 47 const int kCaptureTimeoutMs = 1000;
47 // The number of continuous timeouts tolerated before treated as error. 48 // The number of continuous timeouts tolerated before treated as error.
48 const int kContinuousTimeoutLimit = 10; 49 const int kContinuousTimeoutLimit = 10;
49 // MJPEG is preferred if the requested width or height is larger than this. 50 // MJPEG is preferred if the requested width or height is larger than this.
50 const int kMjpegWidth = 640; 51 const int kMjpegWidth = 640;
51 const int kMjpegHeight = 480; 52 const int kMjpegHeight = 480;
52 // Typical framerate, in fps 53 // Typical framerate, in fps
53 const int kTypicalFramerate = 30; 54 const int kTypicalFramerate = 30;
54 55
56 const int kMaxIOCtrlRetries = 5;
emircan 2016/12/07 21:45:31 Add a comment for this here as well.
mcasas 2016/12/08 23:46:52 Done.
57
55 // V4L2 color formats supported by V4L2CaptureDelegate derived classes. 58 // V4L2 color formats supported by V4L2CaptureDelegate derived classes.
56 // This list is ordered by precedence of use -- but see caveats for MJPEG. 59 // This list is ordered by precedence of use -- but see caveats for MJPEG.
57 static struct { 60 static struct {
58 uint32_t fourcc; 61 uint32_t fourcc;
59 VideoPixelFormat pixel_format; 62 VideoPixelFormat pixel_format;
60 size_t num_planes; 63 size_t num_planes;
61 } const kSupportedFormatsAndPlanarity[] = { 64 } const kSupportedFormatsAndPlanarity[] = {
62 {V4L2_PIX_FMT_YUV420, PIXEL_FORMAT_I420, 1}, 65 {V4L2_PIX_FMT_YUV420, PIXEL_FORMAT_I420, 1},
63 {V4L2_PIX_FMT_Y16, PIXEL_FORMAT_Y16, 1}, 66 {V4L2_PIX_FMT_Y16, PIXEL_FORMAT_Y16, 1},
64 {V4L2_PIX_FMT_Z16, PIXEL_FORMAT_Y16, 1}, 67 {V4L2_PIX_FMT_Z16, PIXEL_FORMAT_Y16, 1},
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
127 130
128 v4l2_control current = {}; 131 v4l2_control current = {};
129 current.id = control_id; 132 current.id = control_id;
130 if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_G_CTRL, &current)) < 0) 133 if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_G_CTRL, &current)) < 0)
131 return mojom::Range::New(); 134 return mojom::Range::New();
132 capability->current = current.value; 135 capability->current = current.value;
133 136
134 return capability; 137 return capability;
135 } 138 }
136 139
140 // Determines if a |control_id| is special, i.e. controls another one's state.
141 static bool IsSpecialControl(int control_id) {
142 if (control_id == V4L2_CID_AUTO_WHITE_BALANCE)
emircan 2016/12/07 21:45:31 Can you regroup this into a switch statement?
mcasas 2016/12/08 23:46:52 Done.
143 return true;
144 else if (control_id == V4L2_CID_EXPOSURE_AUTO)
145 return true;
146 else if (control_id == V4L2_CID_EXPOSURE_AUTO_PRIORITY)
147 return true;
148 else if (control_id == V4L2_CID_FOCUS_AUTO)
149 return true;
150 return false;
151 }
152
153 // Sets all user control to their default. Some controls are enabled by another
154 // flag, usually having the word "auto" in the name, see ISpecialControl().
155 // These flags are preset beforehand.
156 static void ResetUserAndCameraControlsToDefault(int device_fd) {
157 // Set V4L2_CID_AUTO_WHITE_BALANCE to false first.
158 v4l2_control auto_white_balance = {};
159 auto_white_balance.id = V4L2_CID_AUTO_WHITE_BALANCE;
160 auto_white_balance.value = false;
161 int num_retries = 0;
162 // Setting up the first control right after stopping streaming seems
163 // not to the work the first time, so retry a few times.
164 for (; num_retries < kMaxIOCtrlRetries &&
165 HANDLE_EINTR(ioctl(device_fd, VIDIOC_S_CTRL, &auto_white_balance)) < 0;
emircan 2016/12/07 21:45:31 Would it help to log the return value here?
mcasas 2016/12/08 23:46:52 Not really, DPLOG() in l.167 will show what has ha
166 ++num_retries) {
167 DPLOG(WARNING) << "VIDIOC_S_CTRL";
168 }
169 if (num_retries == kMaxIOCtrlRetries) {
170 DLOG(ERROR) << "Cannot access device controls";
171 return;
172 }
173
174 std::vector<struct v4l2_ext_control> user_controls;
175 for (int control_id = V4L2_CID_USER_BASE; control_id < V4L2_CID_LASTP1;
176 ++control_id) {
177 if (IsSpecialControl(control_id))
emircan 2016/12/07 21:45:31 Can you refactor l.177-187 and l.226-236 into a st
mcasas 2016/12/08 23:46:52 I've rewritten the whole implementation so it's ho
178 continue;
179 v4l2_queryctrl range = {};
180 range.id = control_id;
181 if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_QUERYCTRL, &range)) < 0)
182 continue;
183
184 struct v4l2_ext_control ext_control = {};
185 ext_control.id = control_id;
186 ext_control.value = range.default_value;
187 user_controls.push_back(ext_control);
188 }
189
190 if (!user_controls.empty()) {
191 struct v4l2_ext_controls ext_controls = {};
192 ext_controls.ctrl_class = V4L2_CTRL_CLASS_USER;
193 ext_controls.count = user_controls.size();
194 ext_controls.controls = user_controls.data();
195 if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_S_EXT_CTRLS, &ext_controls)) < 0)
196 DPLOG(ERROR) << "VIDIOC_S_EXT_CTRLS";
197 }
198
199 std::vector<struct v4l2_ext_control> special_camera_controls;
200 // Set V4L2_CID_EXPOSURE_AUTO to V4L2_EXPOSURE_MANUAL.
201 v4l2_ext_control auto_exposure = {};
202 auto_exposure.id = V4L2_CID_EXPOSURE_AUTO;
203 auto_exposure.value = V4L2_EXPOSURE_MANUAL;
204 special_camera_controls.push_back(auto_exposure);
205 // Set V4L2_CID_EXPOSURE_AUTO_PRIORITY to false.
206 v4l2_ext_control priority_auto_exposure = {};
207 priority_auto_exposure.id = V4L2_CID_EXPOSURE_AUTO_PRIORITY;
208 priority_auto_exposure.value = false;
209 special_camera_controls.push_back(priority_auto_exposure);
210 // Set V4L2_CID_FOCUS_AUTO to false.
211 v4l2_ext_control auto_focus = {};
212 auto_focus.id = V4L2_CID_FOCUS_AUTO;
213 auto_focus.value = false;
214 special_camera_controls.push_back(auto_focus);
215
216 struct v4l2_ext_controls ext_controls = {};
217 ext_controls.ctrl_class = V4L2_CID_CAMERA_CLASS;
218 ext_controls.count = special_camera_controls.size();
219 ext_controls.controls = special_camera_controls.data();
220 if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_S_EXT_CTRLS, &ext_controls)) < 0)
221 DPLOG(ERROR) << "VIDIOC_S_EXT_CTRLS";
222
223 std::vector<struct v4l2_ext_control> camera_controls;
224 for (int control_id = V4L2_CID_CAMERA_CLASS_BASE;
225 control_id < V4L2_CID_CAMERA_CLASS_BASE + 32; ++control_id) {
emircan 2016/12/07 21:45:31 Where is this 32 coming from? I was doing a quick
mcasas 2016/12/08 23:46:52 In the latest kernel yes, but in the 3.13 that we
226 if (IsSpecialControl(control_id))
227 continue;
228 v4l2_queryctrl range = {};
229 range.id = control_id;
230 if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_QUERYCTRL, &range)) < 0)
231 continue;
232
233 struct v4l2_ext_control ext_control = {};
234 ext_control.id = control_id;
235 ext_control.value = range.default_value;
236 camera_controls.push_back(ext_control);
237 }
238
239 if (!camera_controls.empty()) {
240 struct v4l2_ext_controls ext_controls = {};
241 ext_controls.ctrl_class = V4L2_CID_CAMERA_CLASS;
242 ext_controls.count = camera_controls.size();
243 ext_controls.controls = camera_controls.data();
244 if (HANDLE_EINTR(ioctl(device_fd, VIDIOC_S_EXT_CTRLS, &ext_controls)) < 0)
245 DPLOG(ERROR) << "VIDIOC_S_EXT_CTRLS";
246 }
247 }
248
137 // Class keeping track of a SPLANE V4L2 buffer, mmap()ed on construction and 249 // Class keeping track of a SPLANE V4L2 buffer, mmap()ed on construction and
138 // munmap()ed on destruction. 250 // munmap()ed on destruction.
139 class V4L2CaptureDelegate::BufferTracker 251 class V4L2CaptureDelegate::BufferTracker
140 : public base::RefCounted<BufferTracker> { 252 : public base::RefCounted<BufferTracker> {
141 public: 253 public:
142 BufferTracker(); 254 BufferTracker();
143 // Abstract method to mmap() given |fd| according to |buffer|. 255 // Abstract method to mmap() given |fd| according to |buffer|.
144 bool Init(int fd, const v4l2_buffer& buffer); 256 bool Init(int fd, const v4l2_buffer& buffer);
145 257
146 const uint8_t* start() const { return start_; } 258 const uint8_t* start() const { return start_; }
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after
348 return; 460 return;
349 } 461 }
350 462
351 buffer_tracker_pool_.clear(); 463 buffer_tracker_pool_.clear();
352 464
353 v4l2_requestbuffers r_buffer; 465 v4l2_requestbuffers r_buffer;
354 FillV4L2RequestBuffer(&r_buffer, 0); 466 FillV4L2RequestBuffer(&r_buffer, 0);
355 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_REQBUFS, &r_buffer)) < 0) 467 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_REQBUFS, &r_buffer)) < 0)
356 SetErrorState(FROM_HERE, "Failed to VIDIOC_REQBUFS with count = 0"); 468 SetErrorState(FROM_HERE, "Failed to VIDIOC_REQBUFS with count = 0");
357 469
470 ResetUserAndCameraControlsToDefault(device_fd_.get());
358 // At this point we can close the device. 471 // At this point we can close the device.
359 // This is also needed for correctly changing settings later via VIDIOC_S_FMT. 472 // This is also needed for correctly changing settings later via VIDIOC_S_FMT.
360 device_fd_.reset(); 473 device_fd_.reset();
361 is_capturing_ = false; 474 is_capturing_ = false;
362 client_.reset(); 475 client_.reset();
363 } 476 }
364 477
365 void V4L2CaptureDelegate::TakePhoto( 478 void V4L2CaptureDelegate::TakePhoto(
366 VideoCaptureDevice::TakePhotoCallback callback) { 479 VideoCaptureDevice::TakePhotoCallback callback) {
367 DCHECK(v4l2_task_runner_->BelongsToCurrentThread()); 480 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"; 759 DLOG(ERROR) << "Error mmap()ing a V4L2 buffer into userspace";
647 return false; 760 return false;
648 } 761 }
649 start_ = static_cast<uint8_t*>(start); 762 start_ = static_cast<uint8_t*>(start);
650 length_ = buffer.length; 763 length_ = buffer.length;
651 payload_size_ = 0; 764 payload_size_ = 0;
652 return true; 765 return true;
653 } 766 }
654 767
655 } // namespace media 768 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698