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

Side by Side Diff: media/capture/video/linux/v4l2_capture_delegate.cc

Issue 1418263006: Extend VideoCaptureDevice::Client::OnError() to have a tracked_objects::Location param. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 1 month 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 <poll.h> 7 #include <poll.h>
8 #include <sys/fcntl.h> 8 #include <sys/fcntl.h>
9 #include <sys/ioctl.h> 9 #include <sys/ioctl.h>
10 #include <sys/mman.h> 10 #include <sys/mman.h>
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
173 int height, 173 int height,
174 float frame_rate, 174 float frame_rate,
175 scoped_ptr<VideoCaptureDevice::Client> client) { 175 scoped_ptr<VideoCaptureDevice::Client> client) {
176 DCHECK(v4l2_task_runner_->BelongsToCurrentThread()); 176 DCHECK(v4l2_task_runner_->BelongsToCurrentThread());
177 DCHECK(client); 177 DCHECK(client);
178 client_ = client.Pass(); 178 client_ = client.Pass();
179 179
180 // Need to open camera with O_RDWR after Linux kernel 3.3. 180 // Need to open camera with O_RDWR after Linux kernel 3.3.
181 device_fd_.reset(HANDLE_EINTR(open(device_name_.id().c_str(), O_RDWR))); 181 device_fd_.reset(HANDLE_EINTR(open(device_name_.id().c_str(), O_RDWR)));
182 if (!device_fd_.is_valid()) { 182 if (!device_fd_.is_valid()) {
183 SetErrorState("Failed to open V4L2 device driver file."); 183 SetErrorState(FROM_HERE, "Failed to open V4L2 device driver file.");
184 return; 184 return;
185 } 185 }
186 186
187 v4l2_capability cap = {}; 187 v4l2_capability cap = {};
188 if (!((HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QUERYCAP, &cap)) == 0) && 188 if (!((HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QUERYCAP, &cap)) == 0) &&
189 ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE || 189 ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE ||
190 cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE) && 190 cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE) &&
191 !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) && 191 !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) &&
192 !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT_MPLANE)))) { 192 !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT_MPLANE)))) {
193 device_fd_.reset(); 193 device_fd_.reset();
194 SetErrorState("This is not a V4L2 video capture device"); 194 SetErrorState(FROM_HERE, "This is not a V4L2 video capture device");
195 return; 195 return;
196 } 196 }
197 197
198 // Get supported video formats in preferred order. 198 // Get supported video formats in preferred order.
199 // For large resolutions, favour mjpeg over raw formats. 199 // For large resolutions, favour mjpeg over raw formats.
200 const std::list<uint32_t>& desired_v4l2_formats = 200 const std::list<uint32_t>& desired_v4l2_formats =
201 GetListOfUsableFourCcs(width > kMjpegWidth || height > kMjpegHeight); 201 GetListOfUsableFourCcs(width > kMjpegWidth || height > kMjpegHeight);
202 std::list<uint32_t>::const_iterator best = desired_v4l2_formats.end(); 202 std::list<uint32_t>::const_iterator best = desired_v4l2_formats.end();
203 203
204 v4l2_fmtdesc fmtdesc = {}; 204 v4l2_fmtdesc fmtdesc = {};
205 fmtdesc.type = capture_type_; 205 fmtdesc.type = capture_type_;
206 for (; HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_ENUM_FMT, &fmtdesc)) == 0; 206 for (; HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_ENUM_FMT, &fmtdesc)) == 0;
207 ++fmtdesc.index) { 207 ++fmtdesc.index) {
208 best = std::find(desired_v4l2_formats.begin(), best, fmtdesc.pixelformat); 208 best = std::find(desired_v4l2_formats.begin(), best, fmtdesc.pixelformat);
209 } 209 }
210 if (best == desired_v4l2_formats.end()) { 210 if (best == desired_v4l2_formats.end()) {
211 SetErrorState("Failed to find a supported camera format."); 211 SetErrorState(FROM_HERE, "Failed to find a supported camera format.");
212 return; 212 return;
213 } 213 }
214 214
215 DVLOG(1) << "Chosen pixel format is " << FourccToString(*best); 215 DVLOG(1) << "Chosen pixel format is " << FourccToString(*best);
216 216
217 video_fmt_.type = capture_type_; 217 video_fmt_.type = capture_type_;
218 if (!FillV4L2Format(&video_fmt_, width, height, *best)) { 218 if (!FillV4L2Format(&video_fmt_, width, height, *best)) {
219 SetErrorState("Failed filling in V4L2 Format"); 219 SetErrorState(FROM_HERE, "Failed filling in V4L2 Format");
220 return; 220 return;
221 } 221 }
222 222
223 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_FMT, &video_fmt_)) < 0) { 223 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_FMT, &video_fmt_)) < 0) {
224 SetErrorState("Failed to set video capture format"); 224 SetErrorState(FROM_HERE, "Failed to set video capture format");
225 return; 225 return;
226 } 226 }
227 const VideoPixelFormat pixel_format = 227 const VideoPixelFormat pixel_format =
228 V4l2FourCcToChromiumPixelFormat(video_fmt_.fmt.pix.pixelformat); 228 V4l2FourCcToChromiumPixelFormat(video_fmt_.fmt.pix.pixelformat);
229 if (pixel_format == PIXEL_FORMAT_UNKNOWN) { 229 if (pixel_format == PIXEL_FORMAT_UNKNOWN) {
230 SetErrorState("Unsupported pixel format"); 230 SetErrorState(FROM_HERE, "Unsupported pixel format");
231 return; 231 return;
232 } 232 }
233 233
234 // Set capture framerate in the form of capture interval. 234 // Set capture framerate in the form of capture interval.
235 v4l2_streamparm streamparm = {}; 235 v4l2_streamparm streamparm = {};
236 streamparm.type = capture_type_; 236 streamparm.type = capture_type_;
237 // The following line checks that the driver knows about framerate get/set. 237 // The following line checks that the driver knows about framerate get/set.
238 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_G_PARM, &streamparm)) >= 0) { 238 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_G_PARM, &streamparm)) >= 0) {
239 // Now check if the device is able to accept a capture framerate set. 239 // Now check if the device is able to accept a capture framerate set.
240 if (streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) { 240 if (streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) {
241 // |frame_rate| is float, approximate by a fraction. 241 // |frame_rate| is float, approximate by a fraction.
242 streamparm.parm.capture.timeperframe.numerator = 242 streamparm.parm.capture.timeperframe.numerator =
243 media::kFrameRatePrecision; 243 media::kFrameRatePrecision;
244 streamparm.parm.capture.timeperframe.denominator = 244 streamparm.parm.capture.timeperframe.denominator =
245 (frame_rate) ? (frame_rate * media::kFrameRatePrecision) 245 (frame_rate) ? (frame_rate * media::kFrameRatePrecision)
246 : (kTypicalFramerate * media::kFrameRatePrecision); 246 : (kTypicalFramerate * media::kFrameRatePrecision);
247 247
248 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_PARM, &streamparm)) < 248 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_PARM, &streamparm)) <
249 0) { 249 0) {
250 SetErrorState("Failed to set camera framerate"); 250 SetErrorState(FROM_HERE, "Failed to set camera framerate");
251 return; 251 return;
252 } 252 }
253 DVLOG(2) << "Actual camera driverframerate: " 253 DVLOG(2) << "Actual camera driverframerate: "
254 << streamparm.parm.capture.timeperframe.denominator << "/" 254 << streamparm.parm.capture.timeperframe.denominator << "/"
255 << streamparm.parm.capture.timeperframe.numerator; 255 << streamparm.parm.capture.timeperframe.numerator;
256 } 256 }
257 } 257 }
258 // TODO(mcasas): what should be done if the camera driver does not allow 258 // TODO(mcasas): what should be done if the camera driver does not allow
259 // framerate configuration, or the actual one is different from the desired? 259 // framerate configuration, or the actual one is different from the desired?
260 260
(...skipping 14 matching lines...) Expand all
275 capture_format_.frame_size.SetSize(video_fmt_.fmt.pix.width, 275 capture_format_.frame_size.SetSize(video_fmt_.fmt.pix.width,
276 video_fmt_.fmt.pix.height); 276 video_fmt_.fmt.pix.height);
277 capture_format_.frame_rate = frame_rate; 277 capture_format_.frame_rate = frame_rate;
278 capture_format_.pixel_format = pixel_format; 278 capture_format_.pixel_format = pixel_format;
279 279
280 v4l2_requestbuffers r_buffer = {}; 280 v4l2_requestbuffers r_buffer = {};
281 r_buffer.type = capture_type_; 281 r_buffer.type = capture_type_;
282 r_buffer.memory = V4L2_MEMORY_MMAP; 282 r_buffer.memory = V4L2_MEMORY_MMAP;
283 r_buffer.count = kNumVideoBuffers; 283 r_buffer.count = kNumVideoBuffers;
284 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_REQBUFS, &r_buffer)) < 0) { 284 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_REQBUFS, &r_buffer)) < 0) {
285 SetErrorState("Error requesting MMAP buffers from V4L2"); 285 SetErrorState(FROM_HERE, "Error requesting MMAP buffers from V4L2");
286 return; 286 return;
287 } 287 }
288 for (unsigned int i = 0; i < r_buffer.count; ++i) { 288 for (unsigned int i = 0; i < r_buffer.count; ++i) {
289 if (!MapAndQueueBuffer(i)) { 289 if (!MapAndQueueBuffer(i)) {
290 SetErrorState("Allocate buffer failed"); 290 SetErrorState(FROM_HERE, "Allocate buffer failed");
291 return; 291 return;
292 } 292 }
293 } 293 }
294 294
295 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_STREAMON, &capture_type_)) < 295 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_STREAMON, &capture_type_)) <
296 0) { 296 0) {
297 SetErrorState("VIDIOC_STREAMON failed"); 297 SetErrorState(FROM_HERE, "VIDIOC_STREAMON failed");
298 return; 298 return;
299 } 299 }
300 300
301 is_capturing_ = true; 301 is_capturing_ = true;
302 // Post task to start fetching frames from v4l2. 302 // Post task to start fetching frames from v4l2.
303 v4l2_task_runner_->PostTask( 303 v4l2_task_runner_->PostTask(
304 FROM_HERE, base::Bind(&V4L2CaptureDelegate::DoCapture, this)); 304 FROM_HERE, base::Bind(&V4L2CaptureDelegate::DoCapture, this));
305 } 305 }
306 306
307 void V4L2CaptureDelegate::StopAndDeAllocate() { 307 void V4L2CaptureDelegate::StopAndDeAllocate() {
308 DCHECK(v4l2_task_runner_->BelongsToCurrentThread()); 308 DCHECK(v4l2_task_runner_->BelongsToCurrentThread());
309 // The order is important: stop streaming, clear |buffer_pool_|, 309 // The order is important: stop streaming, clear |buffer_pool_|,
310 // thus munmap()ing the v4l2_buffers, and then return them to the OS. 310 // thus munmap()ing the v4l2_buffers, and then return them to the OS.
311 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_STREAMOFF, &capture_type_)) < 311 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_STREAMOFF, &capture_type_)) <
312 0) { 312 0) {
313 SetErrorState("VIDIOC_STREAMOFF failed"); 313 SetErrorState(FROM_HERE, "VIDIOC_STREAMOFF failed");
314 return; 314 return;
315 } 315 }
316 316
317 buffer_tracker_pool_.clear(); 317 buffer_tracker_pool_.clear();
318 318
319 v4l2_requestbuffers r_buffer = {}; 319 v4l2_requestbuffers r_buffer = {};
320 r_buffer.type = capture_type_; 320 r_buffer.type = capture_type_;
321 r_buffer.memory = V4L2_MEMORY_MMAP; 321 r_buffer.memory = V4L2_MEMORY_MMAP;
322 r_buffer.count = 0; 322 r_buffer.count = 0;
323 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_REQBUFS, &r_buffer)) < 0) 323 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_REQBUFS, &r_buffer)) < 0)
324 SetErrorState("Failed to VIDIOC_REQBUFS with count = 0"); 324 SetErrorState(FROM_HERE, "Failed to VIDIOC_REQBUFS with count = 0");
325 325
326 // At this point we can close the device. 326 // At this point we can close the device.
327 // This is also needed for correctly changing settings later via VIDIOC_S_FMT. 327 // This is also needed for correctly changing settings later via VIDIOC_S_FMT.
328 device_fd_.reset(); 328 device_fd_.reset();
329 is_capturing_ = false; 329 is_capturing_ = false;
330 client_.reset(); 330 client_.reset();
331 } 331 }
332 332
333 void V4L2CaptureDelegate::SetRotation(int rotation) { 333 void V4L2CaptureDelegate::SetRotation(int rotation) {
334 DCHECK(v4l2_task_runner_->BelongsToCurrentThread()); 334 DCHECK(v4l2_task_runner_->BelongsToCurrentThread());
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
370 void V4L2CaptureDelegate::DoCapture() { 370 void V4L2CaptureDelegate::DoCapture() {
371 DCHECK(v4l2_task_runner_->BelongsToCurrentThread()); 371 DCHECK(v4l2_task_runner_->BelongsToCurrentThread());
372 if (!is_capturing_) 372 if (!is_capturing_)
373 return; 373 return;
374 374
375 pollfd device_pfd = {}; 375 pollfd device_pfd = {};
376 device_pfd.fd = device_fd_.get(); 376 device_pfd.fd = device_fd_.get();
377 device_pfd.events = POLLIN; 377 device_pfd.events = POLLIN;
378 const int result = HANDLE_EINTR(poll(&device_pfd, 1, kCaptureTimeoutMs)); 378 const int result = HANDLE_EINTR(poll(&device_pfd, 1, kCaptureTimeoutMs));
379 if (result < 0) { 379 if (result < 0) {
380 SetErrorState("Poll failed"); 380 SetErrorState(FROM_HERE, "Poll failed");
381 return; 381 return;
382 } 382 }
383 // Check if poll() timed out; track the amount of times it did in a row and 383 // Check if poll() timed out; track the amount of times it did in a row and
384 // throw an error if it times out too many times. 384 // throw an error if it times out too many times.
385 if (result == 0) { 385 if (result == 0) {
386 timeout_count_++; 386 timeout_count_++;
387 if (timeout_count_ >= kContinuousTimeoutLimit) { 387 if (timeout_count_ >= kContinuousTimeoutLimit) {
388 SetErrorState("Multiple continuous timeouts while read-polling."); 388 SetErrorState(FROM_HERE,
389 "Multiple continuous timeouts while read-polling.");
389 timeout_count_ = 0; 390 timeout_count_ = 0;
390 return; 391 return;
391 } 392 }
392 } else { 393 } else {
393 timeout_count_ = 0; 394 timeout_count_ = 0;
394 } 395 }
395 396
396 // Deenqueue, send and reenqueue a buffer if the driver has filled one in. 397 // Deenqueue, send and reenqueue a buffer if the driver has filled one in.
397 if (device_pfd.revents & POLLIN) { 398 if (device_pfd.revents & POLLIN) {
398 v4l2_buffer buffer; 399 v4l2_buffer buffer;
399 FillV4L2Buffer(&buffer, 0); 400 FillV4L2Buffer(&buffer, 0);
400 401
401 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_DQBUF, &buffer)) < 0) { 402 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_DQBUF, &buffer)) < 0) {
402 SetErrorState("Failed to dequeue capture buffer"); 403 SetErrorState(FROM_HERE, "Failed to dequeue capture buffer");
403 return; 404 return;
404 } 405 }
405 406
406 SetPayloadSize(buffer_tracker_pool_[buffer.index], buffer); 407 SetPayloadSize(buffer_tracker_pool_[buffer.index], buffer);
407 SendBuffer(buffer_tracker_pool_[buffer.index], video_fmt_); 408 SendBuffer(buffer_tracker_pool_[buffer.index], video_fmt_);
408 409
409 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QBUF, &buffer)) < 0) { 410 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QBUF, &buffer)) < 0) {
410 SetErrorState("Failed to enqueue capture buffer"); 411 SetErrorState(FROM_HERE, "Failed to enqueue capture buffer");
411 return; 412 return;
412 } 413 }
413 } 414 }
414 415
415 v4l2_task_runner_->PostTask( 416 v4l2_task_runner_->PostTask(
416 FROM_HERE, base::Bind(&V4L2CaptureDelegate::DoCapture, this)); 417 FROM_HERE, base::Bind(&V4L2CaptureDelegate::DoCapture, this));
417 } 418 }
418 419
419 void V4L2CaptureDelegate::SetErrorState(const std::string& reason) { 420 void V4L2CaptureDelegate::SetErrorState(
421 const tracked_objects::Location& from_here,
422 const std::string& reason) {
420 DCHECK(v4l2_task_runner_->BelongsToCurrentThread()); 423 DCHECK(v4l2_task_runner_->BelongsToCurrentThread());
421 is_capturing_ = false; 424 is_capturing_ = false;
422 client_->OnError(reason); 425 client_->OnError(from_here, reason);
423 } 426 }
424 427
425 } // namespace media 428 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698