Index: media/video/capture/linux/video_capture_device_factory_linux.cc |
diff --git a/media/video/capture/linux/video_capture_device_factory_linux.cc b/media/video/capture/linux/video_capture_device_factory_linux.cc |
index c33c6b78fab5696e5ee8b5569ef0cbaec47c9015..9bbc50a7f9c1f26af89030e4547a6b5e23a0d621 100644 |
--- a/media/video/capture/linux/video_capture_device_factory_linux.cc |
+++ b/media/video/capture/linux/video_capture_device_factory_linux.cc |
@@ -24,21 +24,105 @@ |
namespace media { |
-static bool HasUsableFormats(int fd) { |
+static bool HasUsableFormats(int fd, uint32 capabilities) { |
const std::list<int>& usable_fourccs = |
VideoCaptureDeviceLinux::GetListOfUsableFourCCs(false); |
- v4l2_fmtdesc fmtdesc = {}; |
- fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
- for (; HANDLE_EINTR(ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc)) == 0; |
- ++fmtdesc.index) { |
- if (std::find(usable_fourccs.begin(), usable_fourccs.end(), |
- fmtdesc.pixelformat) != usable_fourccs.end()) |
- return true; |
+ static const struct { |
+ int capability; |
+ v4l2_buf_type buf_type; |
+ } kCapabilityAndBufferTypes[] = { |
+ {V4L2_CAP_VIDEO_CAPTURE, V4L2_BUF_TYPE_VIDEO_CAPTURE}, |
+ {V4L2_CAP_VIDEO_CAPTURE_MPLANE, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE} |
+ }; |
+ |
+ for (const auto& capability_and_buffer_type : kCapabilityAndBufferTypes) { |
+ v4l2_fmtdesc fmtdesc = {}; |
+ if (capabilities & capability_and_buffer_type.capability) { |
+ fmtdesc.type = capability_and_buffer_type.buf_type; |
+ for (; HANDLE_EINTR(ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc)) == 0; |
+ ++fmtdesc.index) { |
+ if (std::find(usable_fourccs.begin(), usable_fourccs.end(), |
+ fmtdesc.pixelformat) != usable_fourccs.end()) |
+ return true; |
+ } |
+ } |
} |
return false; |
} |
+static std::list<float> GetFrameRateList(int fd, |
+ uint32 fourcc, |
+ uint32 width, |
+ uint32 height) { |
+ std::list<float> frame_rates; |
+ |
+ v4l2_frmivalenum frame_interval = {}; |
+ frame_interval.pixel_format = fourcc; |
+ frame_interval.width = width; |
+ frame_interval.height = height; |
+ for (; HANDLE_EINTR(ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, |
+ &frame_interval)) == 0; ++frame_interval.index) { |
+ if (frame_interval.type == V4L2_FRMIVAL_TYPE_DISCRETE) { |
+ if (frame_interval.discrete.numerator != 0) { |
+ frame_rates.push_back(frame_interval.discrete.denominator / |
+ static_cast<float>(frame_interval.discrete.numerator)); |
+ } |
+ } else if (frame_interval.type == V4L2_FRMIVAL_TYPE_CONTINUOUS || |
+ frame_interval.type == V4L2_FRMIVAL_TYPE_STEPWISE) { |
+ // TODO(mcasas): see http://crbug.com/249953, support these devices. |
+ NOTIMPLEMENTED(); |
+ break; |
+ } |
+ } |
+ // Some devices, e.g. Kinect, do not enumerate any frame rates, see |
+ // http://crbug.com/412284. Set their frame_rate to zero. |
+ if (frame_rates.empty()) |
+ frame_rates.push_back(0); |
+ return frame_rates; |
+} |
+ |
+static void GetSupportedFormatsForV4L2BufferType( |
+ int fd, |
+ v4l2_buf_type buf_type, |
+ media::VideoCaptureFormats* supported_formats) { |
+ v4l2_fmtdesc v4l2_format = {}; |
+ v4l2_format.type = buf_type; |
+ for (; HANDLE_EINTR(ioctl(fd, VIDIOC_ENUM_FMT, &v4l2_format)) == 0; |
+ ++v4l2_format.index) { |
+ VideoCaptureFormat supported_format; |
+ supported_format.pixel_format = |
+ VideoCaptureDeviceLinux::V4l2FourCcToChromiumPixelFormat( |
+ v4l2_format.pixelformat); |
+ |
+ if (supported_format.pixel_format == PIXEL_FORMAT_UNKNOWN) |
+ continue; |
+ |
+ v4l2_frmsizeenum frame_size = {}; |
+ frame_size.pixel_format = v4l2_format.pixelformat; |
+ for (; HANDLE_EINTR(ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frame_size)) == 0; |
+ ++frame_size.index) { |
+ if (frame_size.type == V4L2_FRMSIZE_TYPE_DISCRETE) { |
+ supported_format.frame_size.SetSize(frame_size.discrete.width, |
+ frame_size.discrete.height); |
+ } else if (frame_size.type == V4L2_FRMSIZE_TYPE_STEPWISE || |
+ frame_size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) { |
+ // TODO(mcasas): see http://crbug.com/249953, support these devices. |
+ NOTIMPLEMENTED(); |
+ } |
+ |
+ const std::list<float> frame_rates = GetFrameRateList( |
+ fd, v4l2_format.pixelformat, frame_size.discrete.width, |
+ frame_size.discrete.height); |
+ for (const auto& frame_rate : frame_rates) { |
+ supported_format.frame_rate = frame_rate; |
+ supported_formats->push_back(supported_format); |
+ DVLOG(1) << supported_format.ToString(); |
+ } |
+ } |
+ } |
+} |
+ |
VideoCaptureDeviceFactoryLinux::VideoCaptureDeviceFactoryLinux( |
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) |
: ui_task_runner_(ui_task_runner) { |
@@ -63,7 +147,7 @@ scoped_ptr<VideoCaptureDevice> VideoCaptureDeviceFactoryLinux::Create( |
// allocates the camera. |
base::ScopedFD fd(HANDLE_EINTR(open(device_name.id().c_str(), O_RDONLY))); |
if (!fd.is_valid()) { |
- DVLOG(1) << "Cannot open device"; |
+ DLOG(ERROR) << "Cannot open device"; |
delete self; |
return scoped_ptr<VideoCaptureDevice>(); |
} |
@@ -93,11 +177,14 @@ void VideoCaptureDeviceFactoryLinux::GetDeviceNames( |
// http://crbug.com/139356. |
v4l2_capability cap; |
if ((HANDLE_EINTR(ioctl(fd.get(), VIDIOC_QUERYCAP, &cap)) == 0) && |
- (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE && |
- !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)) && |
- HasUsableFormats(fd.get())) { |
- device_names->push_front(VideoCaptureDevice::Name( |
- base::StringPrintf("%s", cap.card), unique_id)); |
+ ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE || |
+ cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE) && |
+ !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) && |
+ !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT_MPLANE)) && |
+ HasUsableFormats(fd.get(), cap.capabilities)) { |
+ VideoCaptureDevice::Name device_name(base::StringPrintf("%s", cap.card), |
+ unique_id); |
+ device_names->push_back(device_name); |
} |
} |
} |
@@ -113,65 +200,10 @@ void VideoCaptureDeviceFactoryLinux::GetDeviceSupportedFormats( |
return; |
supported_formats->clear(); |
- // Retrieve the caps one by one, first get pixel format, then sizes, then |
- // frame rates. |
- v4l2_fmtdesc pixel_format = {}; |
- pixel_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
- for (; HANDLE_EINTR(ioctl(fd.get(), VIDIOC_ENUM_FMT, &pixel_format)) == 0; |
- ++pixel_format.index) { |
- VideoCaptureFormat supported_format; |
- supported_format.pixel_format = |
- VideoCaptureDeviceLinux::V4l2FourCcToChromiumPixelFormat( |
- pixel_format.pixelformat); |
- if (supported_format.pixel_format == PIXEL_FORMAT_UNKNOWN) |
- continue; |
- |
- v4l2_frmsizeenum frame_size = {}; |
- frame_size.pixel_format = pixel_format.pixelformat; |
- for (; HANDLE_EINTR(ioctl(fd.get(), VIDIOC_ENUM_FRAMESIZES, |
- &frame_size)) == 0; |
- ++frame_size.index) { |
- if (frame_size.type == V4L2_FRMSIZE_TYPE_DISCRETE) { |
- supported_format.frame_size.SetSize( |
- frame_size.discrete.width, frame_size.discrete.height); |
- } else if (frame_size.type == V4L2_FRMSIZE_TYPE_STEPWISE || |
- frame_size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) { |
- // TODO(mcasas): see http://crbug.com/249953, support these devices. |
- NOTIMPLEMENTED(); |
- } |
- |
- v4l2_frmivalenum frame_interval = {}; |
- frame_interval.pixel_format = pixel_format.pixelformat; |
- frame_interval.width = frame_size.discrete.width; |
- frame_interval.height = frame_size.discrete.height; |
- std::list<float> frame_rates; |
- for (; HANDLE_EINTR(ioctl(fd.get(), VIDIOC_ENUM_FRAMEINTERVALS, |
- &frame_interval)) == 0; |
- ++frame_interval.index) { |
- if (frame_interval.type == V4L2_FRMIVAL_TYPE_DISCRETE) { |
- if (frame_interval.discrete.numerator != 0) { |
- frame_rates.push_back(frame_interval.discrete.denominator / |
- static_cast<float>(frame_interval.discrete.numerator)); |
- } |
- } else if (frame_interval.type == V4L2_FRMIVAL_TYPE_CONTINUOUS || |
- frame_interval.type == V4L2_FRMIVAL_TYPE_STEPWISE) { |
- // TODO(mcasas): see http://crbug.com/249953, support these devices. |
- NOTIMPLEMENTED(); |
- break; |
- } |
- } |
- // Some devices, e.g. Kinect, do not enumerate any frame rates, see |
- // http://crbug.com/412284. Set their frame_rate to zero. |
- if (frame_rates.empty()) |
- frame_rates.push_back(0.0f); |
- |
- for (const auto& it : frame_rates) { |
- supported_format.frame_rate = it; |
- supported_formats->push_back(supported_format); |
- DVLOG(1) << device.name() << " " << supported_format.ToString(); |
- } |
- } |
- } |
+ const v4l2_buf_type kCaptureTypes[] = {V4L2_BUF_TYPE_VIDEO_CAPTURE, |
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE}; |
+ for (const auto& buf_type : kCaptureTypes) |
+ GetSupportedFormatsForV4L2BufferType(fd.get(), buf_type, supported_formats); |
return; |
} |