1 // Copyright 2014 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/video/capture/linux/video_capture_device_factory_linux.h"
9 #if defined(OS_OPENBSD)
10 #include <sys/videoio.h>
12 #include <linux/videodev2.h>
14 #include <sys/ioctl.h>
16 #include "base/files/file_enumerator.h"
17 #include "base/files/scoped_file.h"
18 #include "base/posix/eintr_wrapper.h"
19 #include "base/strings/stringprintf.h"
20 #if defined(OS_CHROMEOS)
21 #include "media/video/capture/linux/video_capture_device_chromeos.h"
23 #include "media/video/capture/linux/video_capture_device_linux.h"
27 static bool HasUsableFormats(int fd
) {
29 std::list
<int> usable_fourccs
;
31 media::VideoCaptureDeviceLinux::GetListOfUsableFourCCs(false,
34 memset(&fmtdesc
, 0, sizeof(v4l2_fmtdesc
));
35 fmtdesc
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
37 while (HANDLE_EINTR(ioctl(fd
, VIDIOC_ENUM_FMT
, &fmtdesc
)) == 0) {
38 if (std::find(usable_fourccs
.begin(), usable_fourccs
.end(),
39 fmtdesc
.pixelformat
) != usable_fourccs
.end())
47 scoped_ptr
<VideoCaptureDevice
> VideoCaptureDeviceFactoryLinux::Create(
48 scoped_refptr
<base::SingleThreadTaskRunner
> ui_task_runner
,
49 const VideoCaptureDevice::Name
& device_name
) {
50 DCHECK(thread_checker_
.CalledOnValidThread());
51 #if defined(OS_CHROMEOS)
52 VideoCaptureDeviceChromeOS
* self
=
53 new VideoCaptureDeviceChromeOS(ui_task_runner
, device_name
);
55 VideoCaptureDeviceLinux
* self
= new VideoCaptureDeviceLinux(device_name
);
58 return scoped_ptr
<VideoCaptureDevice
>();
59 // Test opening the device driver. This is to make sure it is available.
60 // We will reopen it again in our worker thread when someone
61 // allocates the camera.
62 base::ScopedFD
fd(HANDLE_EINTR(open(device_name
.id().c_str(), O_RDONLY
)));
64 DVLOG(1) << "Cannot open device";
66 return scoped_ptr
<VideoCaptureDevice
>();
69 return scoped_ptr
<VideoCaptureDevice
>(self
);
72 void VideoCaptureDeviceFactoryLinux::GetDeviceNames(
73 VideoCaptureDevice::Names
* const device_names
) {
74 DCHECK(thread_checker_
.CalledOnValidThread());
75 DCHECK(device_names
->empty());
76 base::FilePath
path("/dev/");
77 base::FileEnumerator
enumerator(
78 path
, false, base::FileEnumerator::FILES
, "video*");
80 while (!enumerator
.Next().empty()) {
81 base::FileEnumerator::FileInfo info
= enumerator
.GetInfo();
83 std::string unique_id
= path
.value() + info
.GetName().value();
84 base::ScopedFD
fd(HANDLE_EINTR(open(unique_id
.c_str(), O_RDONLY
)));
86 // Failed to open this device.
89 // Test if this is a V4L2 capture device.
91 if ((HANDLE_EINTR(ioctl(fd
.get(), VIDIOC_QUERYCAP
, &cap
)) == 0) &&
92 (cap
.capabilities
& V4L2_CAP_VIDEO_CAPTURE
) &&
93 !(cap
.capabilities
& V4L2_CAP_VIDEO_OUTPUT
)) {
94 // This is a V4L2 video capture device
95 if (HasUsableFormats(fd
.get())) {
96 VideoCaptureDevice::Name
device_name(base::StringPrintf("%s", cap
.card
),
98 device_names
->push_back(device_name
);
100 DVLOG(1) << "No usable formats reported by " << info
.GetName().value();
106 void VideoCaptureDeviceFactoryLinux::GetDeviceSupportedFormats(
107 const VideoCaptureDevice::Name
& device
,
108 VideoCaptureFormats
* supported_formats
) {
109 DCHECK(thread_checker_
.CalledOnValidThread());
110 if (device
.id().empty())
112 base::ScopedFD
fd(HANDLE_EINTR(open(device
.id().c_str(), O_RDONLY
)));
113 if (!fd
.is_valid()) {
114 // Failed to open this device.
117 supported_formats
->clear();
119 // Retrieve the caps one by one, first get pixel format, then sizes, then
120 // frame rates. See http://linuxtv.org/downloads/v4l-dvb-apis for reference.
121 v4l2_fmtdesc pixel_format
= {};
122 pixel_format
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
123 while (HANDLE_EINTR(ioctl(fd
.get(), VIDIOC_ENUM_FMT
, &pixel_format
)) == 0) {
124 VideoCaptureFormat supported_format
;
125 supported_format
.pixel_format
=
126 VideoCaptureDeviceLinux::V4l2ColorToVideoCaptureColorFormat(
127 (int32
)pixel_format
.pixelformat
);
128 if (supported_format
.pixel_format
== PIXEL_FORMAT_UNKNOWN
) {
129 ++pixel_format
.index
;
133 v4l2_frmsizeenum frame_size
= {};
134 frame_size
.pixel_format
= pixel_format
.pixelformat
;
135 while (HANDLE_EINTR(ioctl(fd
.get(), VIDIOC_ENUM_FRAMESIZES
, &frame_size
)) ==
137 if (frame_size
.type
== V4L2_FRMSIZE_TYPE_DISCRETE
) {
138 supported_format
.frame_size
.SetSize(
139 frame_size
.discrete
.width
, frame_size
.discrete
.height
);
140 } else if (frame_size
.type
== V4L2_FRMSIZE_TYPE_STEPWISE
) {
141 // TODO(mcasas): see http://crbug.com/249953, support these devices.
143 } else if (frame_size
.type
== V4L2_FRMSIZE_TYPE_CONTINUOUS
) {
144 // TODO(mcasas): see http://crbug.com/249953, support these devices.
147 v4l2_frmivalenum frame_interval
= {};
148 frame_interval
.pixel_format
= pixel_format
.pixelformat
;
149 frame_interval
.width
= frame_size
.discrete
.width
;
150 frame_interval
.height
= frame_size
.discrete
.height
;
151 while (HANDLE_EINTR(ioctl(
152 fd
.get(), VIDIOC_ENUM_FRAMEINTERVALS
, &frame_interval
)) == 0) {
153 if (frame_interval
.type
== V4L2_FRMIVAL_TYPE_DISCRETE
) {
154 if (frame_interval
.discrete
.numerator
!= 0) {
155 supported_format
.frame_rate
=
156 static_cast<float>(frame_interval
.discrete
.denominator
) /
157 static_cast<float>(frame_interval
.discrete
.numerator
);
159 supported_format
.frame_rate
= 0;
161 } else if (frame_interval
.type
== V4L2_FRMIVAL_TYPE_CONTINUOUS
) {
162 // TODO(mcasas): see http://crbug.com/249953, support these devices.
165 } else if (frame_interval
.type
== V4L2_FRMIVAL_TYPE_STEPWISE
) {
166 // TODO(mcasas): see http://crbug.com/249953, support these devices.
170 supported_formats
->push_back(supported_format
);
171 ++frame_interval
.index
;
175 ++pixel_format
.index
;