| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 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/video/capture/linux/video_capture_device_factory_linux.h" | 5 #include "media/video/capture/linux/video_capture_device_factory_linux.h" |
| 6 | 6 |
| 7 #include <errno.h> | 7 #include <errno.h> |
| 8 #include <fcntl.h> | 8 #include <fcntl.h> |
| 9 #if defined(OS_OPENBSD) | 9 #if defined(OS_OPENBSD) |
| 10 #include <sys/videoio.h> | 10 #include <sys/videoio.h> |
| 11 #else | 11 #else |
| 12 #include <linux/videodev2.h> | 12 #include <linux/videodev2.h> |
| 13 #endif | 13 #endif |
| 14 #include <sys/ioctl.h> | 14 #include <sys/ioctl.h> |
| 15 | 15 |
| 16 #include "base/files/file_enumerator.h" | 16 #include "base/files/file_enumerator.h" |
| 17 #include "base/files/scoped_file.h" | 17 #include "base/files/scoped_file.h" |
| 18 #include "base/posix/eintr_wrapper.h" | 18 #include "base/posix/eintr_wrapper.h" |
| 19 #include "base/strings/stringprintf.h" | 19 #include "base/strings/stringprintf.h" |
| 20 #if defined(OS_CHROMEOS) | 20 #if defined(OS_CHROMEOS) |
| 21 #include "media/video/capture/linux/video_capture_device_chromeos.h" | 21 #include "media/video/capture/linux/video_capture_device_chromeos.h" |
| 22 #endif | 22 #endif |
| 23 #include "media/video/capture/linux/video_capture_device_linux.h" | 23 #include "media/video/capture/linux/video_capture_device_linux.h" |
| 24 | 24 |
| 25 namespace media { | 25 namespace media { |
| 26 | 26 |
| 27 static bool HasUsableFormats(int fd) { | 27 static bool HasUsableFormats(int fd) { |
| 28 v4l2_fmtdesc fmtdesc; | 28 const std::list<int>& usable_fourccs = |
| 29 std::list<int> usable_fourccs; | 29 VideoCaptureDeviceLinux::GetListOfUsableFourCCs(false); |
| 30 | 30 |
| 31 media::VideoCaptureDeviceLinux::GetListOfUsableFourCCs(false, | 31 v4l2_fmtdesc fmtdesc = {}; |
| 32 &usable_fourccs); | |
| 33 | |
| 34 memset(&fmtdesc, 0, sizeof(v4l2_fmtdesc)); | |
| 35 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 32 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 36 | 33 for (; HANDLE_EINTR(ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc)) == 0; |
| 37 while (HANDLE_EINTR(ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc)) == 0) { | 34 ++fmtdesc.index) { |
| 38 if (std::find(usable_fourccs.begin(), usable_fourccs.end(), | 35 if (std::find(usable_fourccs.begin(), usable_fourccs.end(), |
| 39 fmtdesc.pixelformat) != usable_fourccs.end()) | 36 fmtdesc.pixelformat) != usable_fourccs.end()) |
| 40 return true; | 37 return true; |
| 41 | |
| 42 fmtdesc.index++; | |
| 43 } | 38 } |
| 44 return false; | 39 return false; |
| 45 } | 40 } |
| 46 | 41 |
| 47 VideoCaptureDeviceFactoryLinux::VideoCaptureDeviceFactoryLinux( | 42 VideoCaptureDeviceFactoryLinux::VideoCaptureDeviceFactoryLinux( |
| 48 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) | 43 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) |
| 49 : ui_task_runner_(ui_task_runner) { | 44 : ui_task_runner_(ui_task_runner) { |
| 50 } | 45 } |
| 51 | 46 |
| 52 VideoCaptureDeviceFactoryLinux::~VideoCaptureDeviceFactoryLinux() { | 47 VideoCaptureDeviceFactoryLinux::~VideoCaptureDeviceFactoryLinux() { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 73 return scoped_ptr<VideoCaptureDevice>(); | 68 return scoped_ptr<VideoCaptureDevice>(); |
| 74 } | 69 } |
| 75 | 70 |
| 76 return scoped_ptr<VideoCaptureDevice>(self); | 71 return scoped_ptr<VideoCaptureDevice>(self); |
| 77 } | 72 } |
| 78 | 73 |
| 79 void VideoCaptureDeviceFactoryLinux::GetDeviceNames( | 74 void VideoCaptureDeviceFactoryLinux::GetDeviceNames( |
| 80 VideoCaptureDevice::Names* const device_names) { | 75 VideoCaptureDevice::Names* const device_names) { |
| 81 DCHECK(thread_checker_.CalledOnValidThread()); | 76 DCHECK(thread_checker_.CalledOnValidThread()); |
| 82 DCHECK(device_names->empty()); | 77 DCHECK(device_names->empty()); |
| 83 base::FilePath path("/dev/"); | 78 const base::FilePath path("/dev/"); |
| 84 base::FileEnumerator enumerator( | 79 base::FileEnumerator enumerator( |
| 85 path, false, base::FileEnumerator::FILES, "video*"); | 80 path, false, base::FileEnumerator::FILES, "video*"); |
| 86 | 81 |
| 87 while (!enumerator.Next().empty()) { | 82 while (!enumerator.Next().empty()) { |
| 88 base::FileEnumerator::FileInfo info = enumerator.GetInfo(); | 83 const base::FileEnumerator::FileInfo info = enumerator.GetInfo(); |
| 89 | 84 const std::string unique_id = path.value() + info.GetName().value(); |
| 90 std::string unique_id = path.value() + info.GetName().value(); | 85 const base::ScopedFD fd(HANDLE_EINTR(open(unique_id.c_str(), O_RDONLY))); |
| 91 base::ScopedFD fd(HANDLE_EINTR(open(unique_id.c_str(), O_RDONLY))); | |
| 92 if (!fd.is_valid()) { | 86 if (!fd.is_valid()) { |
| 93 // Failed to open this device. | 87 DLOG(ERROR) << "Couldn't open " << info.GetName().value(); |
| 94 continue; | 88 continue; |
| 95 } | 89 } |
| 96 // Test if this is a V4L2 capture device. | 90 // Test if this is a V4L2 capture device and if it has at least one |
| 91 // supported capture format. Devices that have capture and output |
| 92 // capabilities at the same time are memory-to-memory and are skipped, see |
| 93 // http://crbug.com/139356. |
| 97 v4l2_capability cap; | 94 v4l2_capability cap; |
| 98 if ((HANDLE_EINTR(ioctl(fd.get(), VIDIOC_QUERYCAP, &cap)) == 0) && | 95 if ((HANDLE_EINTR(ioctl(fd.get(), VIDIOC_QUERYCAP, &cap)) == 0) && |
| 99 (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) && | 96 (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE && |
| 100 !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)) { | 97 !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)) && |
| 101 // This is a V4L2 video capture device | 98 HasUsableFormats(fd.get())) { |
| 102 if (HasUsableFormats(fd.get())) { | 99 device_names->push_front(VideoCaptureDevice::Name( |
| 103 VideoCaptureDevice::Name device_name(base::StringPrintf("%s", cap.card), | 100 base::StringPrintf("%s", cap.card), unique_id)); |
| 104 unique_id); | |
| 105 device_names->push_back(device_name); | |
| 106 } else { | |
| 107 DVLOG(1) << "No usable formats reported by " << info.GetName().value(); | |
| 108 } | |
| 109 } | 101 } |
| 110 } | 102 } |
| 111 } | 103 } |
| 112 | 104 |
| 113 void VideoCaptureDeviceFactoryLinux::GetDeviceSupportedFormats( | 105 void VideoCaptureDeviceFactoryLinux::GetDeviceSupportedFormats( |
| 114 const VideoCaptureDevice::Name& device, | 106 const VideoCaptureDevice::Name& device, |
| 115 VideoCaptureFormats* supported_formats) { | 107 VideoCaptureFormats* supported_formats) { |
| 116 DCHECK(thread_checker_.CalledOnValidThread()); | 108 DCHECK(thread_checker_.CalledOnValidThread()); |
| 117 if (device.id().empty()) | 109 if (device.id().empty()) |
| 118 return; | 110 return; |
| 119 base::ScopedFD fd(HANDLE_EINTR(open(device.id().c_str(), O_RDONLY))); | 111 base::ScopedFD fd(HANDLE_EINTR(open(device.id().c_str(), O_RDONLY))); |
| 120 if (!fd.is_valid()) { | 112 if (!fd.is_valid()) // Failed to open this device. |
| 121 // Failed to open this device. | |
| 122 return; | 113 return; |
| 123 } | |
| 124 supported_formats->clear(); | 114 supported_formats->clear(); |
| 125 | 115 |
| 126 // Retrieve the caps one by one, first get pixel format, then sizes, then | 116 // Retrieve the caps one by one, first get pixel format, then sizes, then |
| 127 // frame rates. See http://linuxtv.org/downloads/v4l-dvb-apis for reference. | 117 // frame rates. |
| 128 v4l2_fmtdesc pixel_format = {}; | 118 v4l2_fmtdesc pixel_format = {}; |
| 129 pixel_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 119 pixel_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 130 while (HANDLE_EINTR(ioctl(fd.get(), VIDIOC_ENUM_FMT, &pixel_format)) == 0) { | 120 for (; HANDLE_EINTR(ioctl(fd.get(), VIDIOC_ENUM_FMT, &pixel_format)) == 0; |
| 121 ++pixel_format.index) { |
| 131 VideoCaptureFormat supported_format; | 122 VideoCaptureFormat supported_format; |
| 132 supported_format.pixel_format = | 123 supported_format.pixel_format = |
| 133 VideoCaptureDeviceLinux::V4l2ColorToVideoCaptureColorFormat( | 124 VideoCaptureDeviceLinux::V4l2FourCcToChromiumPixelFormat( |
| 134 (int32)pixel_format.pixelformat); | 125 pixel_format.pixelformat); |
| 135 if (supported_format.pixel_format == PIXEL_FORMAT_UNKNOWN) { | 126 if (supported_format.pixel_format == PIXEL_FORMAT_UNKNOWN) |
| 136 ++pixel_format.index; | |
| 137 continue; | 127 continue; |
| 138 } | |
| 139 | 128 |
| 140 v4l2_frmsizeenum frame_size = {}; | 129 v4l2_frmsizeenum frame_size = {}; |
| 141 frame_size.pixel_format = pixel_format.pixelformat; | 130 frame_size.pixel_format = pixel_format.pixelformat; |
| 142 while (HANDLE_EINTR(ioctl(fd.get(), VIDIOC_ENUM_FRAMESIZES, &frame_size)) == | 131 for (; HANDLE_EINTR(ioctl(fd.get(), VIDIOC_ENUM_FRAMESIZES, |
| 143 0) { | 132 &frame_size)) == 0; |
| 133 ++frame_size.index) { |
| 144 if (frame_size.type == V4L2_FRMSIZE_TYPE_DISCRETE) { | 134 if (frame_size.type == V4L2_FRMSIZE_TYPE_DISCRETE) { |
| 145 supported_format.frame_size.SetSize( | 135 supported_format.frame_size.SetSize( |
| 146 frame_size.discrete.width, frame_size.discrete.height); | 136 frame_size.discrete.width, frame_size.discrete.height); |
| 147 } else if (frame_size.type == V4L2_FRMSIZE_TYPE_STEPWISE) { | 137 } else if (frame_size.type == V4L2_FRMSIZE_TYPE_STEPWISE || |
| 148 // TODO(mcasas): see http://crbug.com/249953, support these devices. | 138 frame_size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) { |
| 149 NOTIMPLEMENTED(); | |
| 150 } else if (frame_size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) { | |
| 151 // TODO(mcasas): see http://crbug.com/249953, support these devices. | 139 // TODO(mcasas): see http://crbug.com/249953, support these devices. |
| 152 NOTIMPLEMENTED(); | 140 NOTIMPLEMENTED(); |
| 153 } | 141 } |
| 142 |
| 154 v4l2_frmivalenum frame_interval = {}; | 143 v4l2_frmivalenum frame_interval = {}; |
| 155 frame_interval.pixel_format = pixel_format.pixelformat; | 144 frame_interval.pixel_format = pixel_format.pixelformat; |
| 156 frame_interval.width = frame_size.discrete.width; | 145 frame_interval.width = frame_size.discrete.width; |
| 157 frame_interval.height = frame_size.discrete.height; | 146 frame_interval.height = frame_size.discrete.height; |
| 158 std::list<float> frame_rates; | 147 std::list<float> frame_rates; |
| 159 while (HANDLE_EINTR(ioctl( | 148 for (; HANDLE_EINTR(ioctl(fd.get(), VIDIOC_ENUM_FRAMEINTERVALS, |
| 160 fd.get(), VIDIOC_ENUM_FRAMEINTERVALS, &frame_interval)) == 0) { | 149 &frame_interval)) == 0; |
| 150 ++frame_interval.index) { |
| 161 if (frame_interval.type == V4L2_FRMIVAL_TYPE_DISCRETE) { | 151 if (frame_interval.type == V4L2_FRMIVAL_TYPE_DISCRETE) { |
| 162 if (frame_interval.discrete.numerator != 0) { | 152 if (frame_interval.discrete.numerator != 0) { |
| 163 frame_rates.push_back( | 153 frame_rates.push_back(frame_interval.discrete.denominator / |
| 164 static_cast<float>(frame_interval.discrete.denominator) / | |
| 165 static_cast<float>(frame_interval.discrete.numerator)); | 154 static_cast<float>(frame_interval.discrete.numerator)); |
| 166 } | 155 } |
| 167 } else if (frame_interval.type == V4L2_FRMIVAL_TYPE_CONTINUOUS) { | 156 } else if (frame_interval.type == V4L2_FRMIVAL_TYPE_CONTINUOUS || |
| 168 // TODO(mcasas): see http://crbug.com/249953, support these devices. | 157 frame_interval.type == V4L2_FRMIVAL_TYPE_STEPWISE) { |
| 169 NOTIMPLEMENTED(); | |
| 170 break; | |
| 171 } else if (frame_interval.type == V4L2_FRMIVAL_TYPE_STEPWISE) { | |
| 172 // TODO(mcasas): see http://crbug.com/249953, support these devices. | 158 // TODO(mcasas): see http://crbug.com/249953, support these devices. |
| 173 NOTIMPLEMENTED(); | 159 NOTIMPLEMENTED(); |
| 174 break; | 160 break; |
| 175 } | 161 } |
| 176 ++frame_interval.index; | |
| 177 } | 162 } |
| 163 // Some devices, e.g. Kinect, do not enumerate any frame rates, see |
| 164 // http://crbug.com/412284. Set their frame_rate to zero. |
| 165 if (frame_rates.empty()) |
| 166 frame_rates.push_back(0.0f); |
| 178 | 167 |
| 179 // Some devices, e.g. Kinect, do not enumerate any frame rates. For these | 168 for (const auto& it : frame_rates) { |
| 180 // devices, we do not want to lose all enumeration (pixel format and | 169 supported_format.frame_rate = it; |
| 181 // resolution), so we return a frame rate of zero instead. | |
| 182 if (frame_rates.empty()) | |
| 183 frame_rates.push_back(0); | |
| 184 | |
| 185 for (std::list<float>::iterator it = frame_rates.begin(); | |
| 186 it != frame_rates.end(); ++it) { | |
| 187 supported_format.frame_rate = *it; | |
| 188 supported_formats->push_back(supported_format); | 170 supported_formats->push_back(supported_format); |
| 189 DVLOG(1) << device.name() << " " << supported_format.ToString(); | 171 DVLOG(1) << device.name() << " " << supported_format.ToString(); |
| 190 } | 172 } |
| 191 ++frame_size.index; | |
| 192 } | 173 } |
| 193 ++pixel_format.index; | |
| 194 } | 174 } |
| 195 return; | 175 return; |
| 196 } | 176 } |
| 197 | 177 |
| 198 // static | 178 // static |
| 199 VideoCaptureDeviceFactory* | 179 VideoCaptureDeviceFactory* |
| 200 VideoCaptureDeviceFactory::CreateVideoCaptureDeviceFactory( | 180 VideoCaptureDeviceFactory::CreateVideoCaptureDeviceFactory( |
| 201 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) { | 181 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) { |
| 202 return new VideoCaptureDeviceFactoryLinux(ui_task_runner); | 182 return new VideoCaptureDeviceFactoryLinux(ui_task_runner); |
| 203 } | 183 } |
| 204 | 184 |
| 205 } // namespace media | 185 } // namespace media |
| OLD | NEW |