| OLD | NEW |
| 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 "device/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> |
| 11 #include <utility> | 11 #include <utility> |
| 12 | 12 |
| 13 #include "base/bind.h" | 13 #include "base/bind.h" |
| 14 #include "base/files/file_enumerator.h" | 14 #include "base/files/file_enumerator.h" |
| 15 #include "base/posix/eintr_wrapper.h" | 15 #include "base/posix/eintr_wrapper.h" |
| 16 #include "base/strings/stringprintf.h" | 16 #include "base/strings/stringprintf.h" |
| 17 #include "build/build_config.h" | 17 #include "build/build_config.h" |
| 18 #include "device/capture/video/linux/video_capture_device_linux.h" |
| 18 #include "media/base/bind_to_current_loop.h" | 19 #include "media/base/bind_to_current_loop.h" |
| 19 #include "media/capture/video/linux/video_capture_device_linux.h" | |
| 20 | 20 |
| 21 namespace media { | 21 namespace device { |
| 22 | 22 |
| 23 // Desired number of video buffers to allocate. The actual number of allocated | 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. | 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 | 25 // kNumVideoBuffers should not be too small, or Chrome may not return enough |
| 26 // buffers back to driver in time. | 26 // buffers back to driver in time. |
| 27 const uint32_t kNumVideoBuffers = 4; | 27 const uint32_t kNumVideoBuffers = 4; |
| 28 // Timeout in milliseconds v4l2_thread_ blocks waiting for a frame from the hw. | 28 // Timeout in milliseconds v4l2_thread_ blocks waiting for a frame from the hw. |
| 29 // This value has been fine tuned. Before changing or modifying it see | 29 // This value has been fine tuned. Before changing or modifying it see |
| 30 // https://crbug.com/470717 | 30 // https://crbug.com/470717 |
| 31 const int kCaptureTimeoutMs = 1000; | 31 const int kCaptureTimeoutMs = 1000; |
| 32 // The number of continuous timeouts tolerated before treated as error. | 32 // The number of continuous timeouts tolerated before treated as error. |
| 33 const int kContinuousTimeoutLimit = 10; | 33 const int kContinuousTimeoutLimit = 10; |
| 34 // MJPEG is preferred if the requested width or height is larger than this. | 34 // MJPEG is preferred if the requested width or height is larger than this. |
| 35 const int kMjpegWidth = 640; | 35 const int kMjpegWidth = 640; |
| 36 const int kMjpegHeight = 480; | 36 const int kMjpegHeight = 480; |
| 37 // Typical framerate, in fps | 37 // Typical framerate, in fps |
| 38 const int kTypicalFramerate = 30; | 38 const int kTypicalFramerate = 30; |
| 39 | 39 |
| 40 // V4L2 color formats supported by V4L2CaptureDelegate derived classes. | 40 // V4L2 color formats supported by V4L2CaptureDelegate derived classes. |
| 41 // This list is ordered by precedence of use -- but see caveats for MJPEG. | 41 // This list is ordered by precedence of use -- but see caveats for MJPEG. |
| 42 static struct { | 42 static struct { |
| 43 uint32_t fourcc; | 43 uint32_t fourcc; |
| 44 VideoPixelFormat pixel_format; | 44 VideoPixelFormat pixel_format; |
| 45 size_t num_planes; | 45 size_t num_planes; |
| 46 } const kSupportedFormatsAndPlanarity[] = { | 46 } const kSupportedFormatsAndPlanarity[] = { |
| 47 {V4L2_PIX_FMT_YUV420, PIXEL_FORMAT_I420, 1}, | 47 {V4L2_PIX_FMT_YUV420, media::PIXEL_FORMAT_I420, 1}, |
| 48 {V4L2_PIX_FMT_YUYV, PIXEL_FORMAT_YUY2, 1}, | 48 {V4L2_PIX_FMT_YUYV, media::PIXEL_FORMAT_YUY2, 1}, |
| 49 {V4L2_PIX_FMT_UYVY, PIXEL_FORMAT_UYVY, 1}, | 49 {V4L2_PIX_FMT_UYVY, media::PIXEL_FORMAT_UYVY, 1}, |
| 50 {V4L2_PIX_FMT_RGB24, PIXEL_FORMAT_RGB24, 1}, | 50 {V4L2_PIX_FMT_RGB24, media::PIXEL_FORMAT_RGB24, 1}, |
| 51 // MJPEG is usually sitting fairly low since we don't want to have to | 51 // MJPEG is usually sitting fairly low since we don't want to have to |
| 52 // decode. However, it is needed for large resolutions due to USB bandwidth | 52 // decode. However, it is needed for large resolutions due to USB bandwidth |
| 53 // limitations, so GetListOfUsableFourCcs() can duplicate it on top, see | 53 // limitations, so GetListOfUsableFourCcs() can duplicate it on top, see |
| 54 // that method. | 54 // that method. |
| 55 {V4L2_PIX_FMT_MJPEG, PIXEL_FORMAT_MJPEG, 1}, | 55 {V4L2_PIX_FMT_MJPEG, media::PIXEL_FORMAT_MJPEG, 1}, |
| 56 // JPEG works as MJPEG on some gspca webcams from field reports, see | 56 // JPEG works as MJPEG on some gspca webcams from field reports, see |
| 57 // https://code.google.com/p/webrtc/issues/detail?id=529, put it as the | 57 // https://code.google.com/p/webrtc/issues/detail?id=529, put it as the |
| 58 // least preferred format. | 58 // least preferred format. |
| 59 {V4L2_PIX_FMT_JPEG, PIXEL_FORMAT_MJPEG, 1}, | 59 {V4L2_PIX_FMT_JPEG, media::PIXEL_FORMAT_MJPEG, 1}, |
| 60 }; | 60 }; |
| 61 | 61 |
| 62 // Fill in |format| with the given parameters. | 62 // Fill in |format| with the given parameters. |
| 63 static void FillV4L2Format(v4l2_format* format, | 63 static void FillV4L2Format(v4l2_format* format, |
| 64 uint32_t width, | 64 uint32_t width, |
| 65 uint32_t height, | 65 uint32_t height, |
| 66 uint32_t pixelformat_fourcc) { | 66 uint32_t pixelformat_fourcc) { |
| 67 memset(format, 0, sizeof(*format)); | 67 memset(format, 0, sizeof(*format)); |
| 68 format->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 68 format->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 69 format->fmt.pix.width = width; | 69 format->fmt.pix.width = width; |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 129 } | 129 } |
| 130 | 130 |
| 131 // static | 131 // static |
| 132 VideoPixelFormat V4L2CaptureDelegate::V4l2FourCcToChromiumPixelFormat( | 132 VideoPixelFormat V4L2CaptureDelegate::V4l2FourCcToChromiumPixelFormat( |
| 133 uint32_t v4l2_fourcc) { | 133 uint32_t v4l2_fourcc) { |
| 134 for (const auto& fourcc_and_pixel_format : kSupportedFormatsAndPlanarity) { | 134 for (const auto& fourcc_and_pixel_format : kSupportedFormatsAndPlanarity) { |
| 135 if (fourcc_and_pixel_format.fourcc == v4l2_fourcc) | 135 if (fourcc_and_pixel_format.fourcc == v4l2_fourcc) |
| 136 return fourcc_and_pixel_format.pixel_format; | 136 return fourcc_and_pixel_format.pixel_format; |
| 137 } | 137 } |
| 138 // Not finding a pixel format is OK during device capabilities enumeration. | 138 // Not finding a pixel format is OK during device capabilities enumeration. |
| 139 // Let the caller decide if PIXEL_FORMAT_UNKNOWN is an error or | 139 // Let the caller decide if media::PIXEL_FORMAT_UNKNOWN is an error or |
| 140 // not. | 140 // not. |
| 141 DVLOG(1) << "Unsupported pixel format: " << FourccToString(v4l2_fourcc); | 141 DVLOG(1) << "Unsupported pixel format: " << FourccToString(v4l2_fourcc); |
| 142 return PIXEL_FORMAT_UNKNOWN; | 142 return media::PIXEL_FORMAT_UNKNOWN; |
| 143 } | 143 } |
| 144 | 144 |
| 145 // static | 145 // static |
| 146 std::list<uint32_t> V4L2CaptureDelegate::GetListOfUsableFourCcs( | 146 std::list<uint32_t> V4L2CaptureDelegate::GetListOfUsableFourCcs( |
| 147 bool prefer_mjpeg) { | 147 bool prefer_mjpeg) { |
| 148 std::list<uint32_t> supported_formats; | 148 std::list<uint32_t> supported_formats; |
| 149 for (const auto& format : kSupportedFormatsAndPlanarity) | 149 for (const auto& format : kSupportedFormatsAndPlanarity) |
| 150 supported_formats.push_back(format.fourcc); | 150 supported_formats.push_back(format.fourcc); |
| 151 | 151 |
| 152 // Duplicate MJPEG on top of the list depending on |prefer_mjpeg|. | 152 // Duplicate MJPEG on top of the list depending on |prefer_mjpeg|. |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 212 | 212 |
| 213 DVLOG(1) << "Chosen pixel format is " << FourccToString(*best); | 213 DVLOG(1) << "Chosen pixel format is " << FourccToString(*best); |
| 214 FillV4L2Format(&video_fmt_, width, height, *best); | 214 FillV4L2Format(&video_fmt_, width, height, *best); |
| 215 | 215 |
| 216 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_FMT, &video_fmt_)) < 0) { | 216 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_FMT, &video_fmt_)) < 0) { |
| 217 SetErrorState(FROM_HERE, "Failed to set video capture format"); | 217 SetErrorState(FROM_HERE, "Failed to set video capture format"); |
| 218 return; | 218 return; |
| 219 } | 219 } |
| 220 const VideoPixelFormat pixel_format = | 220 const VideoPixelFormat pixel_format = |
| 221 V4l2FourCcToChromiumPixelFormat(video_fmt_.fmt.pix.pixelformat); | 221 V4l2FourCcToChromiumPixelFormat(video_fmt_.fmt.pix.pixelformat); |
| 222 if (pixel_format == PIXEL_FORMAT_UNKNOWN) { | 222 if (pixel_format == media::PIXEL_FORMAT_UNKNOWN) { |
| 223 SetErrorState(FROM_HERE, "Unsupported pixel format"); | 223 SetErrorState(FROM_HERE, "Unsupported pixel format"); |
| 224 return; | 224 return; |
| 225 } | 225 } |
| 226 | 226 |
| 227 // Set capture framerate in the form of capture interval. | 227 // Set capture framerate in the form of capture interval. |
| 228 v4l2_streamparm streamparm = {}; | 228 v4l2_streamparm streamparm = {}; |
| 229 streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 229 streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 230 // The following line checks that the driver knows about framerate get/set. | 230 // The following line checks that the driver knows about framerate get/set. |
| 231 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_G_PARM, &streamparm)) >= 0) { | 231 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_G_PARM, &streamparm)) >= 0) { |
| 232 // Now check if the device is able to accept a capture framerate set. | 232 // Now check if the device is able to accept a capture framerate set. |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 437 if (start == MAP_FAILED) { | 437 if (start == MAP_FAILED) { |
| 438 DLOG(ERROR) << "Error mmap()ing a V4L2 buffer into userspace"; | 438 DLOG(ERROR) << "Error mmap()ing a V4L2 buffer into userspace"; |
| 439 return false; | 439 return false; |
| 440 } | 440 } |
| 441 start_ = static_cast<uint8_t*>(start); | 441 start_ = static_cast<uint8_t*>(start); |
| 442 length_ = buffer.length; | 442 length_ = buffer.length; |
| 443 payload_size_ = 0; | 443 payload_size_ = 0; |
| 444 return true; | 444 return true; |
| 445 } | 445 } |
| 446 | 446 |
| 447 } // namespace media | 447 } // namespace device |
| OLD | NEW |