Updating XTBs based on .GRDs from branch master
[chromium-blink-merge.git] / media / capture / video / linux / v4l2_capture_delegate.cc
blob8010193ded9a0c6474b7a11386b31722ab5fed9c
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
3 // found in the LICENSE file.
5 #include "media/capture/video/linux/v4l2_capture_delegate.h"
7 #include <poll.h>
8 #include <sys/fcntl.h>
9 #include <sys/ioctl.h>
10 #include <sys/mman.h>
12 #include "base/bind.h"
13 #include "base/files/file_enumerator.h"
14 #include "base/posix/eintr_wrapper.h"
15 #include "base/strings/stringprintf.h"
16 #include "media/base/bind_to_current_loop.h"
17 #include "media/capture/video/linux/v4l2_capture_delegate_multi_plane.h"
18 #include "media/capture/video/linux/v4l2_capture_delegate_single_plane.h"
19 #include "media/capture/video/linux/video_capture_device_linux.h"
21 namespace media {
23 // Desired number of video buffers to allocate. The actual number of allocated
24 // buffers by v4l2 driver can be higher or lower than this number.
25 // kNumVideoBuffers should not be too small, or Chrome may not return enough
26 // buffers back to driver in time.
27 const uint32 kNumVideoBuffers = 4;
28 // Timeout in milliseconds v4l2_thread_ blocks waiting for a frame from the hw.
29 const int kCaptureTimeoutMs = 200;
30 // The number of continuous timeouts tolerated before treated as error.
31 const int kContinuousTimeoutLimit = 10;
32 // MJPEG is preferred if the requested width or height is larger than this.
33 const int kMjpegWidth = 640;
34 const int kMjpegHeight = 480;
35 // Typical framerate, in fps
36 const int kTypicalFramerate = 30;
38 // V4L2 color formats supported by V4L2CaptureDelegate derived classes.
39 // This list is ordered by precedence of use -- but see caveats for MJPEG.
40 static struct {
41 uint32_t fourcc;
42 VideoCapturePixelFormat pixel_format;
43 size_t num_planes;
44 } const kSupportedFormatsAndPlanarity[] = {
45 {V4L2_PIX_FMT_YUV420, VIDEO_CAPTURE_PIXEL_FORMAT_I420, 1},
46 {V4L2_PIX_FMT_YUYV, VIDEO_CAPTURE_PIXEL_FORMAT_YUY2, 1},
47 {V4L2_PIX_FMT_UYVY, VIDEO_CAPTURE_PIXEL_FORMAT_UYVY, 1},
48 {V4L2_PIX_FMT_RGB24, VIDEO_CAPTURE_PIXEL_FORMAT_RGB24, 1},
49 #if !defined(OS_OPENBSD)
50 // TODO(mcasas): add V4L2_PIX_FMT_YVU420M when available in bots.
51 {V4L2_PIX_FMT_YUV420M, VIDEO_CAPTURE_PIXEL_FORMAT_I420, 3},
52 #endif
53 // MJPEG is usually sitting fairly low since we don't want to have to
54 // decode.
55 // However, is needed for large resolutions due to USB bandwidth
56 // limitations,
57 // so GetListOfUsableFourCcs() can duplicate it on top, see that method.
58 {V4L2_PIX_FMT_MJPEG, VIDEO_CAPTURE_PIXEL_FORMAT_MJPEG, 1},
59 // JPEG works as MJPEG on some gspca webcams from field reports, see
60 // https://code.google.com/p/webrtc/issues/detail?id=529, put it as the
61 // least
62 // preferred format.
63 {V4L2_PIX_FMT_JPEG, VIDEO_CAPTURE_PIXEL_FORMAT_MJPEG, 1},
66 // static
67 scoped_refptr<V4L2CaptureDelegate>
68 V4L2CaptureDelegate::CreateV4L2CaptureDelegate(
69 const VideoCaptureDevice::Name& device_name,
70 const scoped_refptr<base::SingleThreadTaskRunner>& v4l2_task_runner,
71 int power_line_frequency) {
72 switch (device_name.capture_api_type()) {
73 case VideoCaptureDevice::Name::V4L2_SINGLE_PLANE:
74 return make_scoped_refptr(new V4L2CaptureDelegateSinglePlane(
75 device_name, v4l2_task_runner, power_line_frequency));
76 case VideoCaptureDevice::Name::V4L2_MULTI_PLANE:
77 #if !defined(OS_OPENBSD)
78 return make_scoped_refptr(new V4L2CaptureDelegateMultiPlane(
79 device_name, v4l2_task_runner, power_line_frequency));
80 default:
81 #endif
82 NOTIMPLEMENTED() << "Unknown V4L2 capture API type";
83 return scoped_refptr<V4L2CaptureDelegate>();
87 // static
88 size_t V4L2CaptureDelegate::GetNumPlanesForFourCc(uint32_t fourcc) {
89 for (const auto& fourcc_and_pixel_format : kSupportedFormatsAndPlanarity) {
90 if (fourcc_and_pixel_format.fourcc == fourcc)
91 return fourcc_and_pixel_format.num_planes;
93 DVLOG(1) << "Unknown fourcc " << FourccToString(fourcc);
94 return 0;
97 // static
98 VideoCapturePixelFormat V4L2CaptureDelegate::V4l2FourCcToChromiumPixelFormat(
99 uint32_t v4l2_fourcc) {
100 for (const auto& fourcc_and_pixel_format : kSupportedFormatsAndPlanarity) {
101 if (fourcc_and_pixel_format.fourcc == v4l2_fourcc)
102 return fourcc_and_pixel_format.pixel_format;
104 // Not finding a pixel format is OK during device capabilities enumeration.
105 // Let the caller decide if VIDEO_CAPTURE_PIXEL_FORMAT_UNKNOWN is an error or
106 // not.
107 DVLOG(1) << "Unsupported pixel format: " << FourccToString(v4l2_fourcc);
108 return VIDEO_CAPTURE_PIXEL_FORMAT_UNKNOWN;
111 // static
112 std::list<uint32_t> V4L2CaptureDelegate::GetListOfUsableFourCcs(
113 bool prefer_mjpeg) {
114 std::list<uint32_t> supported_formats;
115 for (const auto& format : kSupportedFormatsAndPlanarity)
116 supported_formats.push_back(format.fourcc);
118 // Duplicate MJPEG on top of the list depending on |prefer_mjpeg|.
119 if (prefer_mjpeg)
120 supported_formats.push_front(V4L2_PIX_FMT_MJPEG);
122 return supported_formats;
125 // static
126 std::string V4L2CaptureDelegate::FourccToString(uint32_t fourcc) {
127 return base::StringPrintf("%c%c%c%c", fourcc & 0xFF, (fourcc >> 8) & 0xFF,
128 (fourcc >> 16) & 0xFF, (fourcc >> 24) & 0xFF);
131 V4L2CaptureDelegate::BufferTracker::BufferTracker() {
134 V4L2CaptureDelegate::BufferTracker::~BufferTracker() {
135 for (const auto& plane : planes_) {
136 if (plane.start == nullptr)
137 continue;
138 const int result = munmap(plane.start, plane.length);
139 PLOG_IF(ERROR, result < 0) << "Error munmap()ing V4L2 buffer";
143 void V4L2CaptureDelegate::BufferTracker::AddMmapedPlane(uint8_t* const start,
144 size_t length) {
145 Plane plane;
146 plane.start = start;
147 plane.length = length;
148 plane.payload_size = 0;
149 planes_.push_back(plane);
152 V4L2CaptureDelegate::V4L2CaptureDelegate(
153 const VideoCaptureDevice::Name& device_name,
154 const scoped_refptr<base::SingleThreadTaskRunner>& v4l2_task_runner,
155 int power_line_frequency)
156 : capture_type_((device_name.capture_api_type() ==
157 VideoCaptureDevice::Name::V4L2_SINGLE_PLANE)
158 ? V4L2_BUF_TYPE_VIDEO_CAPTURE
159 : V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE),
160 v4l2_task_runner_(v4l2_task_runner),
161 device_name_(device_name),
162 power_line_frequency_(power_line_frequency),
163 is_capturing_(false),
164 timeout_count_(0),
165 rotation_(0) {
168 V4L2CaptureDelegate::~V4L2CaptureDelegate() {
171 void V4L2CaptureDelegate::AllocateAndStart(
172 int width,
173 int height,
174 float frame_rate,
175 scoped_ptr<VideoCaptureDevice::Client> client) {
176 DCHECK(v4l2_task_runner_->BelongsToCurrentThread());
177 DCHECK(client);
178 client_ = client.Pass();
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)));
182 if (!device_fd_.is_valid()) {
183 SetErrorState("Failed to open V4L2 device driver file.");
184 return;
187 v4l2_capability cap = {};
188 if (!((HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QUERYCAP, &cap)) == 0) &&
189 ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE ||
190 cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE) &&
191 !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) &&
192 !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT_MPLANE)))) {
193 device_fd_.reset();
194 SetErrorState("This is not a V4L2 video capture device");
195 return;
198 // Get supported video formats in preferred order.
199 // For large resolutions, favour mjpeg over raw formats.
200 const std::list<uint32_t>& desired_v4l2_formats =
201 GetListOfUsableFourCcs(width > kMjpegWidth || height > kMjpegHeight);
202 std::list<uint32_t>::const_iterator best = desired_v4l2_formats.end();
204 v4l2_fmtdesc fmtdesc = {};
205 fmtdesc.type = capture_type_;
206 for (; HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_ENUM_FMT, &fmtdesc)) == 0;
207 ++fmtdesc.index) {
208 best = std::find(desired_v4l2_formats.begin(), best, fmtdesc.pixelformat);
210 if (best == desired_v4l2_formats.end()) {
211 SetErrorState("Failed to find a supported camera format.");
212 return;
215 DVLOG(1) << "Chosen pixel format is " << FourccToString(*best);
217 video_fmt_.type = capture_type_;
218 if (!FillV4L2Format(&video_fmt_, width, height, *best)) {
219 SetErrorState("Failed filling in V4L2 Format");
220 return;
223 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_FMT, &video_fmt_)) < 0) {
224 SetErrorState("Failed to set video capture format");
225 return;
227 const VideoCapturePixelFormat pixel_format =
228 V4l2FourCcToChromiumPixelFormat(video_fmt_.fmt.pix.pixelformat);
229 if (pixel_format == VIDEO_CAPTURE_PIXEL_FORMAT_UNKNOWN) {
230 SetErrorState("Unsupported pixel format");
231 return;
234 // Set capture framerate in the form of capture interval.
235 v4l2_streamparm streamparm = {};
236 streamparm.type = capture_type_;
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) {
239 // Now check if the device is able to accept a capture framerate set.
240 if (streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) {
241 // |frame_rate| is float, approximate by a fraction.
242 streamparm.parm.capture.timeperframe.numerator =
243 media::kFrameRatePrecision;
244 streamparm.parm.capture.timeperframe.denominator =
245 (frame_rate) ? (frame_rate * media::kFrameRatePrecision)
246 : (kTypicalFramerate * media::kFrameRatePrecision);
248 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_PARM, &streamparm)) <
249 0) {
250 SetErrorState("Failed to set camera framerate");
251 return;
253 DVLOG(2) << "Actual camera driverframerate: "
254 << streamparm.parm.capture.timeperframe.denominator << "/"
255 << streamparm.parm.capture.timeperframe.numerator;
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?
261 // Set anti-banding/anti-flicker to 50/60Hz. May fail due to not supported
262 // operation (|errno| == EINVAL in this case) or plain failure.
263 if ((power_line_frequency_ == V4L2_CID_POWER_LINE_FREQUENCY_50HZ) ||
264 (power_line_frequency_ == V4L2_CID_POWER_LINE_FREQUENCY_60HZ) ||
265 (power_line_frequency_ == V4L2_CID_POWER_LINE_FREQUENCY_AUTO)) {
266 struct v4l2_control control = {};
267 control.id = V4L2_CID_POWER_LINE_FREQUENCY;
268 control.value = power_line_frequency_;
269 const int retval =
270 HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_CTRL, &control));
271 if (retval != 0)
272 DVLOG(1) << "Error setting power line frequency removal";
275 capture_format_.frame_size.SetSize(video_fmt_.fmt.pix.width,
276 video_fmt_.fmt.pix.height);
277 capture_format_.frame_rate = frame_rate;
278 capture_format_.pixel_format = pixel_format;
280 v4l2_requestbuffers r_buffer = {};
281 r_buffer.type = capture_type_;
282 r_buffer.memory = V4L2_MEMORY_MMAP;
283 r_buffer.count = kNumVideoBuffers;
284 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_REQBUFS, &r_buffer)) < 0) {
285 SetErrorState("Error requesting MMAP buffers from V4L2");
286 return;
288 for (unsigned int i = 0; i < r_buffer.count; ++i) {
289 if (!MapAndQueueBuffer(i)) {
290 SetErrorState("Allocate buffer failed");
291 return;
295 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_STREAMON, &capture_type_)) <
296 0) {
297 SetErrorState("VIDIOC_STREAMON failed");
298 return;
301 is_capturing_ = true;
302 // Post task to start fetching frames from v4l2.
303 v4l2_task_runner_->PostTask(
304 FROM_HERE, base::Bind(&V4L2CaptureDelegate::DoCapture, this));
307 void V4L2CaptureDelegate::StopAndDeAllocate() {
308 DCHECK(v4l2_task_runner_->BelongsToCurrentThread());
309 // The order is important: stop streaming, clear |buffer_pool_|,
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_)) <
312 0) {
313 SetErrorState("VIDIOC_STREAMOFF failed");
314 return;
317 buffer_tracker_pool_.clear();
319 v4l2_requestbuffers r_buffer = {};
320 r_buffer.type = capture_type_;
321 r_buffer.memory = V4L2_MEMORY_MMAP;
322 r_buffer.count = 0;
323 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_REQBUFS, &r_buffer)) < 0)
324 SetErrorState("Failed to VIDIOC_REQBUFS with count = 0");
326 // At this point we can close the device.
327 // This is also needed for correctly changing settings later via VIDIOC_S_FMT.
328 device_fd_.reset();
329 is_capturing_ = false;
330 client_.reset();
333 void V4L2CaptureDelegate::SetRotation(int rotation) {
334 DCHECK(v4l2_task_runner_->BelongsToCurrentThread());
335 DCHECK(rotation >= 0 && rotation < 360 && rotation % 90 == 0);
336 rotation_ = rotation;
339 bool V4L2CaptureDelegate::MapAndQueueBuffer(int index) {
340 v4l2_buffer buffer;
341 FillV4L2Buffer(&buffer, index);
343 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QUERYBUF, &buffer)) < 0) {
344 DLOG(ERROR) << "Error querying status of a MMAP V4L2 buffer";
345 return false;
348 const scoped_refptr<BufferTracker>& buffer_tracker = CreateBufferTracker();
349 if (!buffer_tracker->Init(device_fd_.get(), buffer)) {
350 DLOG(ERROR) << "Error creating BufferTracker";
351 return false;
353 buffer_tracker_pool_.push_back(buffer_tracker);
355 // Enqueue the buffer in the drivers incoming queue.
356 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QBUF, &buffer)) < 0) {
357 DLOG(ERROR) << "Error enqueuing a V4L2 buffer back into the driver";
358 return false;
360 return true;
363 void V4L2CaptureDelegate::FillV4L2Buffer(v4l2_buffer* buffer, int i) const {
364 memset(buffer, 0, sizeof(*buffer));
365 buffer->memory = V4L2_MEMORY_MMAP;
366 buffer->index = i;
367 FinishFillingV4L2Buffer(buffer);
370 void V4L2CaptureDelegate::DoCapture() {
371 DCHECK(v4l2_task_runner_->BelongsToCurrentThread());
372 if (!is_capturing_)
373 return;
375 pollfd device_pfd = {};
376 device_pfd.fd = device_fd_.get();
377 device_pfd.events = POLLIN;
378 const int result = HANDLE_EINTR(poll(&device_pfd, 1, kCaptureTimeoutMs));
379 if (result < 0) {
380 SetErrorState("Poll failed");
381 return;
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.
385 if (result == 0) {
386 timeout_count_++;
387 if (timeout_count_ >= kContinuousTimeoutLimit) {
388 SetErrorState("Multiple continuous timeouts while read-polling.");
389 timeout_count_ = 0;
390 return;
392 } else {
393 timeout_count_ = 0;
396 // Deenqueue, send and reenqueue a buffer if the driver has filled one in.
397 if (device_pfd.revents & POLLIN) {
398 v4l2_buffer buffer;
399 FillV4L2Buffer(&buffer, 0);
401 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_DQBUF, &buffer)) < 0) {
402 SetErrorState("Failed to dequeue capture buffer");
403 return;
406 SetPayloadSize(buffer_tracker_pool_[buffer.index], buffer);
407 SendBuffer(buffer_tracker_pool_[buffer.index], video_fmt_);
409 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QBUF, &buffer)) < 0) {
410 SetErrorState("Failed to enqueue capture buffer");
411 return;
415 v4l2_task_runner_->PostTask(
416 FROM_HERE, base::Bind(&V4L2CaptureDelegate::DoCapture, this));
419 void V4L2CaptureDelegate::SetErrorState(const std::string& reason) {
420 DCHECK(v4l2_task_runner_->BelongsToCurrentThread());
421 is_capturing_ = false;
422 client_->OnError(reason);
425 } // namespace media