Split out V4L2 specific code in the Linux Capture backend
This is in preparation for adding a portal / pipewire backend.
This just renames one class and moved the code to different files.
There are no changes to the implementation.
Bug: webrtc:13177
Change-Id: Iae101fcabafdb6cddd4d82adbb26219e4b37557f
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/261680
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Reviewed-by: Per Kjellander <perkj@webrtc.org>
Commit-Queue: Ilya Nikolaevskiy <ilnik@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#36848}
diff --git a/modules/video_capture/BUILD.gn b/modules/video_capture/BUILD.gn
index 98fb04a..616be5d 100644
--- a/modules/video_capture/BUILD.gn
+++ b/modules/video_capture/BUILD.gn
@@ -65,9 +65,11 @@
if (is_linux || is_chromeos) {
sources = [
"linux/device_info_linux.cc",
- "linux/device_info_linux.h",
+ "linux/device_info_v4l2.cc",
+ "linux/device_info_v4l2.h",
"linux/video_capture_linux.cc",
- "linux/video_capture_linux.h",
+ "linux/video_capture_v4l2.cc",
+ "linux/video_capture_v4l2.h",
]
deps += [ "../../media:rtc_media_base" ]
}
diff --git a/modules/video_capture/linux/device_info_linux.cc b/modules/video_capture/linux/device_info_linux.cc
index cde3b86..ccbbeae 100644
--- a/modules/video_capture/linux/device_info_linux.cc
+++ b/modules/video_capture/linux/device_info_linux.cc
@@ -8,8 +8,6 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "modules/video_capture/linux/device_info_linux.h"
-
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
@@ -22,6 +20,7 @@
#include <vector>
+#include "modules/video_capture/linux/device_info_v4l2.h"
#include "modules/video_capture/video_capture.h"
#include "modules/video_capture/video_capture_defines.h"
#include "modules/video_capture/video_capture_impl.h"
@@ -30,265 +29,7 @@
namespace webrtc {
namespace videocapturemodule {
VideoCaptureModule::DeviceInfo* VideoCaptureImpl::CreateDeviceInfo() {
- return new videocapturemodule::DeviceInfoLinux();
+ return new videocapturemodule::DeviceInfoV4l2();
}
-
-DeviceInfoLinux::DeviceInfoLinux() : DeviceInfoImpl() {}
-
-int32_t DeviceInfoLinux::Init() {
- return 0;
-}
-
-DeviceInfoLinux::~DeviceInfoLinux() {}
-
-uint32_t DeviceInfoLinux::NumberOfDevices() {
- uint32_t count = 0;
- char device[20];
- int fd = -1;
- struct v4l2_capability cap;
-
- /* detect /dev/video [0-63]VideoCaptureModule entries */
- for (int n = 0; n < 64; n++) {
- sprintf(device, "/dev/video%d", n);
- if ((fd = open(device, O_RDONLY)) != -1) {
- // query device capabilities and make sure this is a video capture device
- if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0 ||
- !(cap.device_caps & V4L2_CAP_VIDEO_CAPTURE)) {
- close(fd);
- continue;
- }
-
- close(fd);
- count++;
- }
- }
-
- return count;
-}
-
-int32_t DeviceInfoLinux::GetDeviceName(uint32_t deviceNumber,
- char* deviceNameUTF8,
- uint32_t deviceNameLength,
- char* deviceUniqueIdUTF8,
- uint32_t deviceUniqueIdUTF8Length,
- char* /*productUniqueIdUTF8*/,
- uint32_t /*productUniqueIdUTF8Length*/) {
- // Travel through /dev/video [0-63]
- uint32_t count = 0;
- char device[20];
- int fd = -1;
- bool found = false;
- struct v4l2_capability cap;
- for (int n = 0; n < 64; n++) {
- sprintf(device, "/dev/video%d", n);
- if ((fd = open(device, O_RDONLY)) != -1) {
- // query device capabilities and make sure this is a video capture device
- if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0 ||
- !(cap.device_caps & V4L2_CAP_VIDEO_CAPTURE)) {
- close(fd);
- continue;
- }
- if (count == deviceNumber) {
- // Found the device
- found = true;
- break;
- } else {
- close(fd);
- count++;
- }
- }
- }
-
- if (!found)
- return -1;
-
- // query device capabilities
- if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0) {
- RTC_LOG(LS_INFO) << "error in querying the device capability for device "
- << device << ". errno = " << errno;
- close(fd);
- return -1;
- }
-
- close(fd);
-
- char cameraName[64];
- memset(deviceNameUTF8, 0, deviceNameLength);
- memcpy(cameraName, cap.card, sizeof(cap.card));
-
- if (deviceNameLength > strlen(cameraName)) {
- memcpy(deviceNameUTF8, cameraName, strlen(cameraName));
- } else {
- RTC_LOG(LS_INFO) << "buffer passed is too small";
- return -1;
- }
-
- if (cap.bus_info[0] != 0) // may not available in all drivers
- {
- // copy device id
- if (deviceUniqueIdUTF8Length > strlen((const char*)cap.bus_info)) {
- memset(deviceUniqueIdUTF8, 0, deviceUniqueIdUTF8Length);
- memcpy(deviceUniqueIdUTF8, cap.bus_info,
- strlen((const char*)cap.bus_info));
- } else {
- RTC_LOG(LS_INFO) << "buffer passed is too small";
- return -1;
- }
- }
-
- return 0;
-}
-
-int32_t DeviceInfoLinux::CreateCapabilityMap(const char* deviceUniqueIdUTF8) {
- int fd;
- char device[32];
- bool found = false;
-
- const int32_t deviceUniqueIdUTF8Length =
- (int32_t)strlen((char*)deviceUniqueIdUTF8);
- if (deviceUniqueIdUTF8Length >= kVideoCaptureUniqueNameLength) {
- RTC_LOG(LS_INFO) << "Device name too long";
- return -1;
- }
- RTC_LOG(LS_INFO) << "CreateCapabilityMap called for device "
- << deviceUniqueIdUTF8;
-
- /* detect /dev/video [0-63] entries */
- for (int n = 0; n < 64; ++n) {
- sprintf(device, "/dev/video%d", n);
- fd = open(device, O_RDONLY);
- if (fd == -1)
- continue;
-
- // query device capabilities
- struct v4l2_capability cap;
- if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == 0) {
- // skip devices without video capture capability
- if (!(cap.device_caps & V4L2_CAP_VIDEO_CAPTURE)) {
- continue;
- }
-
- if (cap.bus_info[0] != 0) {
- if (strncmp((const char*)cap.bus_info, (const char*)deviceUniqueIdUTF8,
- strlen((const char*)deviceUniqueIdUTF8)) ==
- 0) // match with device id
- {
- found = true;
- break; // fd matches with device unique id supplied
- }
- } else // match for device name
- {
- if (IsDeviceNameMatches((const char*)cap.card,
- (const char*)deviceUniqueIdUTF8)) {
- found = true;
- break;
- }
- }
- }
- close(fd); // close since this is not the matching device
- }
-
- if (!found) {
- RTC_LOG(LS_INFO) << "no matching device found";
- return -1;
- }
-
- // now fd will point to the matching device
- // reset old capability list.
- _captureCapabilities.clear();
-
- int size = FillCapabilities(fd);
- close(fd);
-
- // Store the new used device name
- _lastUsedDeviceNameLength = deviceUniqueIdUTF8Length;
- _lastUsedDeviceName =
- (char*)realloc(_lastUsedDeviceName, _lastUsedDeviceNameLength + 1);
- memcpy(_lastUsedDeviceName, deviceUniqueIdUTF8,
- _lastUsedDeviceNameLength + 1);
-
- RTC_LOG(LS_INFO) << "CreateCapabilityMap " << _captureCapabilities.size();
-
- return size;
-}
-
-int32_t DeviceInfoLinux::DisplayCaptureSettingsDialogBox(
- const char* /*deviceUniqueIdUTF8*/,
- const char* /*dialogTitleUTF8*/,
- void* /*parentWindow*/,
- uint32_t /*positionX*/,
- uint32_t /*positionY*/) {
- return -1;
-}
-
-bool DeviceInfoLinux::IsDeviceNameMatches(const char* name,
- const char* deviceUniqueIdUTF8) {
- if (strncmp(deviceUniqueIdUTF8, name, strlen(name)) == 0)
- return true;
- return false;
-}
-
-int32_t DeviceInfoLinux::FillCapabilities(int fd) {
- // set image format
- struct v4l2_format video_fmt;
- memset(&video_fmt, 0, sizeof(struct v4l2_format));
-
- video_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- video_fmt.fmt.pix.sizeimage = 0;
-
- int totalFmts = 4;
- unsigned int videoFormats[] = {V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_YUV420,
- V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_UYVY};
-
- int sizes = 13;
- unsigned int size[][2] = {{128, 96}, {160, 120}, {176, 144}, {320, 240},
- {352, 288}, {640, 480}, {704, 576}, {800, 600},
- {960, 720}, {1280, 720}, {1024, 768}, {1440, 1080},
- {1920, 1080}};
-
- for (int fmts = 0; fmts < totalFmts; fmts++) {
- for (int i = 0; i < sizes; i++) {
- video_fmt.fmt.pix.pixelformat = videoFormats[fmts];
- video_fmt.fmt.pix.width = size[i][0];
- video_fmt.fmt.pix.height = size[i][1];
-
- if (ioctl(fd, VIDIOC_TRY_FMT, &video_fmt) >= 0) {
- if ((video_fmt.fmt.pix.width == size[i][0]) &&
- (video_fmt.fmt.pix.height == size[i][1])) {
- VideoCaptureCapability cap;
- cap.width = video_fmt.fmt.pix.width;
- cap.height = video_fmt.fmt.pix.height;
- if (videoFormats[fmts] == V4L2_PIX_FMT_YUYV) {
- cap.videoType = VideoType::kYUY2;
- } else if (videoFormats[fmts] == V4L2_PIX_FMT_YUV420) {
- cap.videoType = VideoType::kI420;
- } else if (videoFormats[fmts] == V4L2_PIX_FMT_MJPEG) {
- cap.videoType = VideoType::kMJPEG;
- } else if (videoFormats[fmts] == V4L2_PIX_FMT_UYVY) {
- cap.videoType = VideoType::kUYVY;
- }
-
- // get fps of current camera mode
- // V4l2 does not have a stable method of knowing so we just guess.
- if (cap.width >= 800 && cap.videoType != VideoType::kMJPEG) {
- cap.maxFPS = 15;
- } else {
- cap.maxFPS = 30;
- }
-
- _captureCapabilities.push_back(cap);
- RTC_LOG(LS_VERBOSE) << "Camera capability, width:" << cap.width
- << " height:" << cap.height
- << " type:" << static_cast<int32_t>(cap.videoType)
- << " fps:" << cap.maxFPS;
- }
- }
- }
- }
-
- RTC_LOG(LS_INFO) << "CreateCapabilityMap " << _captureCapabilities.size();
- return _captureCapabilities.size();
-}
-
} // namespace videocapturemodule
} // namespace webrtc
diff --git a/modules/video_capture/linux/device_info_v4l2.cc b/modules/video_capture/linux/device_info_v4l2.cc
new file mode 100644
index 0000000..c1062d4
--- /dev/null
+++ b/modules/video_capture/linux/device_info_v4l2.cc
@@ -0,0 +1,286 @@
+/*
+ * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/video_capture/linux/device_info_v4l2.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+// v4l includes
+#include <linux/videodev2.h>
+
+#include <vector>
+
+#include "modules/video_capture/video_capture.h"
+#include "modules/video_capture/video_capture_defines.h"
+#include "modules/video_capture/video_capture_impl.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+namespace videocapturemodule {
+DeviceInfoV4l2::DeviceInfoV4l2() : DeviceInfoImpl() {}
+
+int32_t DeviceInfoV4l2::Init() {
+ return 0;
+}
+
+DeviceInfoV4l2::~DeviceInfoV4l2() {}
+
+uint32_t DeviceInfoV4l2::NumberOfDevices() {
+ uint32_t count = 0;
+ char device[20];
+ int fd = -1;
+ struct v4l2_capability cap;
+
+ /* detect /dev/video [0-63]VideoCaptureModule entries */
+ for (int n = 0; n < 64; n++) {
+ snprintf(device, sizeof(device), "/dev/video%d", n);
+ if ((fd = open(device, O_RDONLY)) != -1) {
+ // query device capabilities and make sure this is a video capture device
+ if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0 ||
+ !(cap.device_caps & V4L2_CAP_VIDEO_CAPTURE)) {
+ close(fd);
+ continue;
+ }
+
+ close(fd);
+ count++;
+ }
+ }
+
+ return count;
+}
+
+int32_t DeviceInfoV4l2::GetDeviceName(uint32_t deviceNumber,
+ char* deviceNameUTF8,
+ uint32_t deviceNameLength,
+ char* deviceUniqueIdUTF8,
+ uint32_t deviceUniqueIdUTF8Length,
+ char* /*productUniqueIdUTF8*/,
+ uint32_t /*productUniqueIdUTF8Length*/) {
+ // Travel through /dev/video [0-63]
+ uint32_t count = 0;
+ char device[20];
+ int fd = -1;
+ bool found = false;
+ struct v4l2_capability cap;
+ for (int n = 0; n < 64; n++) {
+ snprintf(device, sizeof(device), "/dev/video%d", n);
+ if ((fd = open(device, O_RDONLY)) != -1) {
+ // query device capabilities and make sure this is a video capture device
+ if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0 ||
+ !(cap.device_caps & V4L2_CAP_VIDEO_CAPTURE)) {
+ close(fd);
+ continue;
+ }
+ if (count == deviceNumber) {
+ // Found the device
+ found = true;
+ break;
+ } else {
+ close(fd);
+ count++;
+ }
+ }
+ }
+
+ if (!found)
+ return -1;
+
+ // query device capabilities
+ if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0) {
+ RTC_LOG(LS_INFO) << "error in querying the device capability for device "
+ << device << ". errno = " << errno;
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+
+ char cameraName[64];
+ memset(deviceNameUTF8, 0, deviceNameLength);
+ memcpy(cameraName, cap.card, sizeof(cap.card));
+
+ if (deviceNameLength > strlen(cameraName)) {
+ memcpy(deviceNameUTF8, cameraName, strlen(cameraName));
+ } else {
+ RTC_LOG(LS_INFO) << "buffer passed is too small";
+ return -1;
+ }
+
+ if (cap.bus_info[0] != 0) { // may not available in all drivers
+ // copy device id
+ size_t len = strlen(reinterpret_cast<const char*>(cap.bus_info));
+ if (deviceUniqueIdUTF8Length > len) {
+ memset(deviceUniqueIdUTF8, 0, deviceUniqueIdUTF8Length);
+ memcpy(deviceUniqueIdUTF8, cap.bus_info, len);
+ } else {
+ RTC_LOG(LS_INFO) << "buffer passed is too small";
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int32_t DeviceInfoV4l2::CreateCapabilityMap(const char* deviceUniqueIdUTF8) {
+ int fd;
+ char device[32];
+ bool found = false;
+
+ const int32_t deviceUniqueIdUTF8Length = strlen(deviceUniqueIdUTF8);
+ if (deviceUniqueIdUTF8Length >= kVideoCaptureUniqueNameLength) {
+ RTC_LOG(LS_INFO) << "Device name too long";
+ return -1;
+ }
+ RTC_LOG(LS_INFO) << "CreateCapabilityMap called for device "
+ << deviceUniqueIdUTF8;
+
+ /* detect /dev/video [0-63] entries */
+ for (int n = 0; n < 64; ++n) {
+ snprintf(device, sizeof(device), "/dev/video%d", n);
+ fd = open(device, O_RDONLY);
+ if (fd == -1)
+ continue;
+
+ // query device capabilities
+ struct v4l2_capability cap;
+ if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == 0) {
+ // skip devices without video capture capability
+ if (!(cap.device_caps & V4L2_CAP_VIDEO_CAPTURE)) {
+ continue;
+ }
+
+ if (cap.bus_info[0] != 0) {
+ if (strncmp(reinterpret_cast<const char*>(cap.bus_info),
+ deviceUniqueIdUTF8,
+ strlen(deviceUniqueIdUTF8)) == 0) { // match with device id
+ found = true;
+ break; // fd matches with device unique id supplied
+ }
+ } else { // match for device name
+ if (IsDeviceNameMatches(reinterpret_cast<const char*>(cap.card),
+ deviceUniqueIdUTF8)) {
+ found = true;
+ break;
+ }
+ }
+ }
+ close(fd); // close since this is not the matching device
+ }
+
+ if (!found) {
+ RTC_LOG(LS_INFO) << "no matching device found";
+ return -1;
+ }
+
+ // now fd will point to the matching device
+ // reset old capability list.
+ _captureCapabilities.clear();
+
+ int size = FillCapabilities(fd);
+ close(fd);
+
+ // Store the new used device name
+ _lastUsedDeviceNameLength = deviceUniqueIdUTF8Length;
+ _lastUsedDeviceName = reinterpret_cast<char*>(
+ realloc(_lastUsedDeviceName, _lastUsedDeviceNameLength + 1));
+ memcpy(_lastUsedDeviceName, deviceUniqueIdUTF8,
+ _lastUsedDeviceNameLength + 1);
+
+ RTC_LOG(LS_INFO) << "CreateCapabilityMap " << _captureCapabilities.size();
+
+ return size;
+}
+
+int32_t DeviceInfoV4l2::DisplayCaptureSettingsDialogBox(
+ const char* /*deviceUniqueIdUTF8*/,
+ const char* /*dialogTitleUTF8*/,
+ void* /*parentWindow*/,
+ uint32_t /*positionX*/,
+ uint32_t /*positionY*/) {
+ return -1;
+}
+
+bool DeviceInfoV4l2::IsDeviceNameMatches(const char* name,
+ const char* deviceUniqueIdUTF8) {
+ if (strncmp(deviceUniqueIdUTF8, name, strlen(name)) == 0)
+ return true;
+ return false;
+}
+
+int32_t DeviceInfoV4l2::FillCapabilities(int fd) {
+ // set image format
+ struct v4l2_format video_fmt;
+ memset(&video_fmt, 0, sizeof(struct v4l2_format));
+
+ video_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ video_fmt.fmt.pix.sizeimage = 0;
+
+ int totalFmts = 4;
+ unsigned int videoFormats[] = {V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_YUV420,
+ V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_UYVY};
+
+ int sizes = 13;
+ unsigned int size[][2] = {{128, 96}, {160, 120}, {176, 144}, {320, 240},
+ {352, 288}, {640, 480}, {704, 576}, {800, 600},
+ {960, 720}, {1280, 720}, {1024, 768}, {1440, 1080},
+ {1920, 1080}};
+
+ for (int fmts = 0; fmts < totalFmts; fmts++) {
+ for (int i = 0; i < sizes; i++) {
+ video_fmt.fmt.pix.pixelformat = videoFormats[fmts];
+ video_fmt.fmt.pix.width = size[i][0];
+ video_fmt.fmt.pix.height = size[i][1];
+
+ if (ioctl(fd, VIDIOC_TRY_FMT, &video_fmt) >= 0) {
+ if ((video_fmt.fmt.pix.width == size[i][0]) &&
+ (video_fmt.fmt.pix.height == size[i][1])) {
+ VideoCaptureCapability cap;
+ cap.width = video_fmt.fmt.pix.width;
+ cap.height = video_fmt.fmt.pix.height;
+ if (videoFormats[fmts] == V4L2_PIX_FMT_YUYV) {
+ cap.videoType = VideoType::kYUY2;
+ } else if (videoFormats[fmts] == V4L2_PIX_FMT_YUV420) {
+ cap.videoType = VideoType::kI420;
+ } else if (videoFormats[fmts] == V4L2_PIX_FMT_MJPEG) {
+ cap.videoType = VideoType::kMJPEG;
+ } else if (videoFormats[fmts] == V4L2_PIX_FMT_UYVY) {
+ cap.videoType = VideoType::kUYVY;
+ }
+
+ // get fps of current camera mode
+ // V4l2 does not have a stable method of knowing so we just guess.
+ if (cap.width >= 800 && cap.videoType != VideoType::kMJPEG) {
+ cap.maxFPS = 15;
+ } else {
+ cap.maxFPS = 30;
+ }
+
+ _captureCapabilities.push_back(cap);
+ RTC_LOG(LS_VERBOSE) << "Camera capability, width:" << cap.width
+ << " height:" << cap.height
+ << " type:" << static_cast<int32_t>(cap.videoType)
+ << " fps:" << cap.maxFPS;
+ }
+ }
+ }
+ }
+
+ RTC_LOG(LS_INFO) << "CreateCapabilityMap " << _captureCapabilities.size();
+ return _captureCapabilities.size();
+}
+
+} // namespace videocapturemodule
+} // namespace webrtc
diff --git a/modules/video_capture/linux/device_info_linux.h b/modules/video_capture/linux/device_info_v4l2.h
similarity index 85%
rename from modules/video_capture/linux/device_info_linux.h
rename to modules/video_capture/linux/device_info_v4l2.h
index 304ae71..fb95a60 100644
--- a/modules/video_capture/linux/device_info_linux.h
+++ b/modules/video_capture/linux/device_info_v4l2.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef MODULES_VIDEO_CAPTURE_MAIN_SOURCE_LINUX_DEVICE_INFO_LINUX_H_
-#define MODULES_VIDEO_CAPTURE_MAIN_SOURCE_LINUX_DEVICE_INFO_LINUX_H_
+#ifndef MODULES_VIDEO_CAPTURE_LINUX_DEVICE_INFO_V4L2_H_
+#define MODULES_VIDEO_CAPTURE_LINUX_DEVICE_INFO_V4L2_H_
#include <stdint.h>
@@ -17,10 +17,10 @@
namespace webrtc {
namespace videocapturemodule {
-class DeviceInfoLinux : public DeviceInfoImpl {
+class DeviceInfoV4l2 : public DeviceInfoImpl {
public:
- DeviceInfoLinux();
- ~DeviceInfoLinux() override;
+ DeviceInfoV4l2();
+ ~DeviceInfoV4l2() override;
uint32_t NumberOfDevices() override;
int32_t GetDeviceName(uint32_t deviceNumber,
char* deviceNameUTF8,
@@ -48,4 +48,4 @@
};
} // namespace videocapturemodule
} // namespace webrtc
-#endif // MODULES_VIDEO_CAPTURE_MAIN_SOURCE_LINUX_DEVICE_INFO_LINUX_H_
+#endif // MODULES_VIDEO_CAPTURE_LINUX_DEVICE_INFO_V4L2_H_
diff --git a/modules/video_capture/linux/video_capture_linux.cc b/modules/video_capture/linux/video_capture_linux.cc
index 321355f..2bc889f 100644
--- a/modules/video_capture/linux/video_capture_linux.cc
+++ b/modules/video_capture/linux/video_capture_linux.cc
@@ -8,8 +8,6 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "modules/video_capture/linux/video_capture_linux.h"
-
#include <errno.h>
#include <fcntl.h>
#include <linux/videodev2.h>
@@ -26,6 +24,7 @@
#include "api/scoped_refptr.h"
#include "media/base/video_common.h"
+#include "modules/video_capture/linux/video_capture_v4l2.h"
#include "modules/video_capture/video_capture.h"
#include "rtc_base/logging.h"
#include "rtc_base/ref_counted_object.h"
@@ -41,394 +40,5 @@
return implementation;
}
-
-VideoCaptureModuleV4L2::VideoCaptureModuleV4L2()
- : VideoCaptureImpl(),
- _deviceId(-1),
- _deviceFd(-1),
- _buffersAllocatedByDevice(-1),
- _currentWidth(-1),
- _currentHeight(-1),
- _currentFrameRate(-1),
- _captureStarted(false),
- _captureVideoType(VideoType::kI420),
- _pool(NULL) {}
-
-int32_t VideoCaptureModuleV4L2::Init(const char* deviceUniqueIdUTF8) {
- int len = strlen((const char*)deviceUniqueIdUTF8);
- _deviceUniqueId = new (std::nothrow) char[len + 1];
- if (_deviceUniqueId) {
- memcpy(_deviceUniqueId, deviceUniqueIdUTF8, len + 1);
- }
-
- int fd;
- char device[32];
- bool found = false;
-
- /* detect /dev/video [0-63] entries */
- int n;
- for (n = 0; n < 64; n++) {
- sprintf(device, "/dev/video%d", n);
- if ((fd = open(device, O_RDONLY)) != -1) {
- // query device capabilities
- struct v4l2_capability cap;
- if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == 0) {
- if (cap.bus_info[0] != 0) {
- if (strncmp((const char*)cap.bus_info,
- (const char*)deviceUniqueIdUTF8,
- strlen((const char*)deviceUniqueIdUTF8)) ==
- 0) // match with device id
- {
- close(fd);
- found = true;
- break; // fd matches with device unique id supplied
- }
- }
- }
- close(fd); // close since this is not the matching device
- }
- }
- if (!found) {
- RTC_LOG(LS_INFO) << "no matching device found";
- return -1;
- }
- _deviceId = n; // store the device id
- return 0;
-}
-
-VideoCaptureModuleV4L2::~VideoCaptureModuleV4L2() {
- StopCapture();
- if (_deviceFd != -1)
- close(_deviceFd);
-}
-
-int32_t VideoCaptureModuleV4L2::StartCapture(
- const VideoCaptureCapability& capability) {
- if (_captureStarted) {
- if (capability.width == _currentWidth &&
- capability.height == _currentHeight &&
- _captureVideoType == capability.videoType) {
- return 0;
- } else {
- StopCapture();
- }
- }
-
- MutexLock lock(&capture_lock_);
- // first open /dev/video device
- char device[20];
- sprintf(device, "/dev/video%d", (int)_deviceId);
-
- if ((_deviceFd = open(device, O_RDWR | O_NONBLOCK, 0)) < 0) {
- RTC_LOG(LS_INFO) << "error in opening " << device << " errono = " << errno;
- return -1;
- }
-
- // Supported video formats in preferred order.
- // If the requested resolution is larger than VGA, we prefer MJPEG. Go for
- // I420 otherwise.
- const int nFormats = 5;
- unsigned int fmts[nFormats];
- if (capability.width > 640 || capability.height > 480) {
- fmts[0] = V4L2_PIX_FMT_MJPEG;
- fmts[1] = V4L2_PIX_FMT_YUV420;
- fmts[2] = V4L2_PIX_FMT_YUYV;
- fmts[3] = V4L2_PIX_FMT_UYVY;
- fmts[4] = V4L2_PIX_FMT_JPEG;
- } else {
- fmts[0] = V4L2_PIX_FMT_YUV420;
- fmts[1] = V4L2_PIX_FMT_YUYV;
- fmts[2] = V4L2_PIX_FMT_UYVY;
- fmts[3] = V4L2_PIX_FMT_MJPEG;
- fmts[4] = V4L2_PIX_FMT_JPEG;
- }
-
- // Enumerate image formats.
- struct v4l2_fmtdesc fmt;
- int fmtsIdx = nFormats;
- memset(&fmt, 0, sizeof(fmt));
- fmt.index = 0;
- fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- RTC_LOG(LS_INFO) << "Video Capture enumerats supported image formats:";
- while (ioctl(_deviceFd, VIDIOC_ENUM_FMT, &fmt) == 0) {
- RTC_LOG(LS_INFO) << " { pixelformat = "
- << cricket::GetFourccName(fmt.pixelformat)
- << ", description = '" << fmt.description << "' }";
- // Match the preferred order.
- for (int i = 0; i < nFormats; i++) {
- if (fmt.pixelformat == fmts[i] && i < fmtsIdx)
- fmtsIdx = i;
- }
- // Keep enumerating.
- fmt.index++;
- }
-
- if (fmtsIdx == nFormats) {
- RTC_LOG(LS_INFO) << "no supporting video formats found";
- return -1;
- } else {
- RTC_LOG(LS_INFO) << "We prefer format "
- << cricket::GetFourccName(fmts[fmtsIdx]);
- }
-
- struct v4l2_format video_fmt;
- memset(&video_fmt, 0, sizeof(struct v4l2_format));
- video_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- video_fmt.fmt.pix.sizeimage = 0;
- video_fmt.fmt.pix.width = capability.width;
- video_fmt.fmt.pix.height = capability.height;
- video_fmt.fmt.pix.pixelformat = fmts[fmtsIdx];
-
- if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
- _captureVideoType = VideoType::kYUY2;
- else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420)
- _captureVideoType = VideoType::kI420;
- else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY)
- _captureVideoType = VideoType::kUYVY;
- else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG ||
- video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG)
- _captureVideoType = VideoType::kMJPEG;
-
- // set format and frame size now
- if (ioctl(_deviceFd, VIDIOC_S_FMT, &video_fmt) < 0) {
- RTC_LOG(LS_INFO) << "error in VIDIOC_S_FMT, errno = " << errno;
- return -1;
- }
-
- // initialize current width and height
- _currentWidth = video_fmt.fmt.pix.width;
- _currentHeight = video_fmt.fmt.pix.height;
-
- // Trying to set frame rate, before check driver capability.
- bool driver_framerate_support = true;
- struct v4l2_streamparm streamparms;
- memset(&streamparms, 0, sizeof(streamparms));
- streamparms.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- if (ioctl(_deviceFd, VIDIOC_G_PARM, &streamparms) < 0) {
- RTC_LOG(LS_INFO) << "error in VIDIOC_G_PARM errno = " << errno;
- driver_framerate_support = false;
- // continue
- } else {
- // check the capability flag is set to V4L2_CAP_TIMEPERFRAME.
- if (streamparms.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) {
- // driver supports the feature. Set required framerate.
- memset(&streamparms, 0, sizeof(streamparms));
- streamparms.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- streamparms.parm.capture.timeperframe.numerator = 1;
- streamparms.parm.capture.timeperframe.denominator = capability.maxFPS;
- if (ioctl(_deviceFd, VIDIOC_S_PARM, &streamparms) < 0) {
- RTC_LOG(LS_INFO) << "Failed to set the framerate. errno=" << errno;
- driver_framerate_support = false;
- } else {
- _currentFrameRate = capability.maxFPS;
- }
- }
- }
- // If driver doesn't support framerate control, need to hardcode.
- // Hardcoding the value based on the frame size.
- if (!driver_framerate_support) {
- if (_currentWidth >= 800 && _captureVideoType != VideoType::kMJPEG) {
- _currentFrameRate = 15;
- } else {
- _currentFrameRate = 30;
- }
- }
-
- if (!AllocateVideoBuffers()) {
- RTC_LOG(LS_INFO) << "failed to allocate video capture buffers";
- return -1;
- }
-
- // start capture thread;
- if (_captureThread.empty()) {
- quit_ = false;
- _captureThread = rtc::PlatformThread::SpawnJoinable(
- [this] {
- while (CaptureProcess()) {
- }
- },
- "CaptureThread",
- rtc::ThreadAttributes().SetPriority(rtc::ThreadPriority::kHigh));
- }
-
- // Needed to start UVC camera - from the uvcview application
- enum v4l2_buf_type type;
- type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- if (ioctl(_deviceFd, VIDIOC_STREAMON, &type) == -1) {
- RTC_LOG(LS_INFO) << "Failed to turn on stream";
- return -1;
- }
-
- _captureStarted = true;
- return 0;
-}
-
-int32_t VideoCaptureModuleV4L2::StopCapture() {
- if (!_captureThread.empty()) {
- {
- MutexLock lock(&capture_lock_);
- quit_ = true;
- }
- // Make sure the capture thread stops using the mutex.
- _captureThread.Finalize();
- }
-
- MutexLock lock(&capture_lock_);
- if (_captureStarted) {
- _captureStarted = false;
-
- DeAllocateVideoBuffers();
- close(_deviceFd);
- _deviceFd = -1;
- }
-
- return 0;
-}
-
-// critical section protected by the caller
-
-bool VideoCaptureModuleV4L2::AllocateVideoBuffers() {
- struct v4l2_requestbuffers rbuffer;
- memset(&rbuffer, 0, sizeof(v4l2_requestbuffers));
-
- rbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- rbuffer.memory = V4L2_MEMORY_MMAP;
- rbuffer.count = kNoOfV4L2Bufffers;
-
- if (ioctl(_deviceFd, VIDIOC_REQBUFS, &rbuffer) < 0) {
- RTC_LOG(LS_INFO) << "Could not get buffers from device. errno = " << errno;
- return false;
- }
-
- if (rbuffer.count > kNoOfV4L2Bufffers)
- rbuffer.count = kNoOfV4L2Bufffers;
-
- _buffersAllocatedByDevice = rbuffer.count;
-
- // Map the buffers
- _pool = new Buffer[rbuffer.count];
-
- for (unsigned int i = 0; i < rbuffer.count; i++) {
- struct v4l2_buffer buffer;
- memset(&buffer, 0, sizeof(v4l2_buffer));
- buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buffer.memory = V4L2_MEMORY_MMAP;
- buffer.index = i;
-
- if (ioctl(_deviceFd, VIDIOC_QUERYBUF, &buffer) < 0) {
- return false;
- }
-
- _pool[i].start = mmap(NULL, buffer.length, PROT_READ | PROT_WRITE,
- MAP_SHARED, _deviceFd, buffer.m.offset);
-
- if (MAP_FAILED == _pool[i].start) {
- for (unsigned int j = 0; j < i; j++)
- munmap(_pool[j].start, _pool[j].length);
- return false;
- }
-
- _pool[i].length = buffer.length;
-
- if (ioctl(_deviceFd, VIDIOC_QBUF, &buffer) < 0) {
- return false;
- }
- }
- return true;
-}
-
-bool VideoCaptureModuleV4L2::DeAllocateVideoBuffers() {
- // unmap buffers
- for (int i = 0; i < _buffersAllocatedByDevice; i++)
- munmap(_pool[i].start, _pool[i].length);
-
- delete[] _pool;
-
- // turn off stream
- enum v4l2_buf_type type;
- type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- if (ioctl(_deviceFd, VIDIOC_STREAMOFF, &type) < 0) {
- RTC_LOG(LS_INFO) << "VIDIOC_STREAMOFF error. errno: " << errno;
- }
-
- return true;
-}
-
-bool VideoCaptureModuleV4L2::CaptureStarted() {
- return _captureStarted;
-}
-
-bool VideoCaptureModuleV4L2::CaptureProcess() {
- int retVal = 0;
- fd_set rSet;
- struct timeval timeout;
-
- FD_ZERO(&rSet);
- FD_SET(_deviceFd, &rSet);
- timeout.tv_sec = 1;
- timeout.tv_usec = 0;
-
- // _deviceFd written only in StartCapture, when this thread isn't running.
- retVal = select(_deviceFd + 1, &rSet, NULL, NULL, &timeout);
-
- {
- MutexLock lock(&capture_lock_);
-
- if (quit_) {
- return false;
- }
-
- if (retVal < 0 && errno != EINTR) // continue if interrupted
- {
- // select failed
- return false;
- } else if (retVal == 0) {
- // select timed out
- return true;
- } else if (!FD_ISSET(_deviceFd, &rSet)) {
- // not event on camera handle
- return true;
- }
-
- if (_captureStarted) {
- struct v4l2_buffer buf;
- memset(&buf, 0, sizeof(struct v4l2_buffer));
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buf.memory = V4L2_MEMORY_MMAP;
- // dequeue a buffer - repeat until dequeued properly!
- while (ioctl(_deviceFd, VIDIOC_DQBUF, &buf) < 0) {
- if (errno != EINTR) {
- RTC_LOG(LS_INFO) << "could not sync on a buffer on device "
- << strerror(errno);
- return true;
- }
- }
- VideoCaptureCapability frameInfo;
- frameInfo.width = _currentWidth;
- frameInfo.height = _currentHeight;
- frameInfo.videoType = _captureVideoType;
-
- // convert to to I420 if needed
- IncomingFrame((unsigned char*)_pool[buf.index].start, buf.bytesused,
- frameInfo);
- // enqueue the buffer again
- if (ioctl(_deviceFd, VIDIOC_QBUF, &buf) == -1) {
- RTC_LOG(LS_INFO) << "Failed to enqueue capture buffer";
- }
- }
- }
- usleep(0);
- return true;
-}
-
-int32_t VideoCaptureModuleV4L2::CaptureSettings(
- VideoCaptureCapability& settings) {
- settings.width = _currentWidth;
- settings.height = _currentHeight;
- settings.maxFPS = _currentFrameRate;
- settings.videoType = _captureVideoType;
-
- return 0;
-}
} // namespace videocapturemodule
} // namespace webrtc
diff --git a/modules/video_capture/linux/video_capture_v4l2.cc b/modules/video_capture/linux/video_capture_v4l2.cc
new file mode 100644
index 0000000..6bd3823
--- /dev/null
+++ b/modules/video_capture/linux/video_capture_v4l2.cc
@@ -0,0 +1,422 @@
+/*
+ * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/video_capture/linux/video_capture_v4l2.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/videodev2.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/select.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <new>
+#include <string>
+
+#include "api/scoped_refptr.h"
+#include "media/base/video_common.h"
+#include "modules/video_capture/video_capture.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/ref_counted_object.h"
+
+namespace webrtc {
+namespace videocapturemodule {
+VideoCaptureModuleV4L2::VideoCaptureModuleV4L2()
+ : VideoCaptureImpl(),
+ _deviceId(-1),
+ _deviceFd(-1),
+ _buffersAllocatedByDevice(-1),
+ _currentWidth(-1),
+ _currentHeight(-1),
+ _currentFrameRate(-1),
+ _captureStarted(false),
+ _captureVideoType(VideoType::kI420),
+ _pool(NULL) {}
+
+int32_t VideoCaptureModuleV4L2::Init(const char* deviceUniqueIdUTF8) {
+ int len = strlen((const char*)deviceUniqueIdUTF8);
+ _deviceUniqueId = new (std::nothrow) char[len + 1];
+ if (_deviceUniqueId) {
+ memcpy(_deviceUniqueId, deviceUniqueIdUTF8, len + 1);
+ }
+
+ int fd;
+ char device[32];
+ bool found = false;
+
+ /* detect /dev/video [0-63] entries */
+ int n;
+ for (n = 0; n < 64; n++) {
+ snprintf(device, sizeof(device), "/dev/video%d", n);
+ if ((fd = open(device, O_RDONLY)) != -1) {
+ // query device capabilities
+ struct v4l2_capability cap;
+ if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == 0) {
+ if (cap.bus_info[0] != 0) {
+ if (strncmp((const char*)cap.bus_info,
+ (const char*)deviceUniqueIdUTF8,
+ strlen((const char*)deviceUniqueIdUTF8)) ==
+ 0) { // match with device id
+ close(fd);
+ found = true;
+ break; // fd matches with device unique id supplied
+ }
+ }
+ }
+ close(fd); // close since this is not the matching device
+ }
+ }
+ if (!found) {
+ RTC_LOG(LS_INFO) << "no matching device found";
+ return -1;
+ }
+ _deviceId = n; // store the device id
+ return 0;
+}
+
+VideoCaptureModuleV4L2::~VideoCaptureModuleV4L2() {
+ StopCapture();
+ if (_deviceFd != -1)
+ close(_deviceFd);
+}
+
+int32_t VideoCaptureModuleV4L2::StartCapture(
+ const VideoCaptureCapability& capability) {
+ if (_captureStarted) {
+ if (capability.width == _currentWidth &&
+ capability.height == _currentHeight &&
+ _captureVideoType == capability.videoType) {
+ return 0;
+ } else {
+ StopCapture();
+ }
+ }
+
+ MutexLock lock(&capture_lock_);
+ // first open /dev/video device
+ char device[20];
+ snprintf(device, sizeof(device), "/dev/video%d", _deviceId);
+
+ if ((_deviceFd = open(device, O_RDWR | O_NONBLOCK, 0)) < 0) {
+ RTC_LOG(LS_INFO) << "error in opening " << device << " errono = " << errno;
+ return -1;
+ }
+
+ // Supported video formats in preferred order.
+ // If the requested resolution is larger than VGA, we prefer MJPEG. Go for
+ // I420 otherwise.
+ const int nFormats = 5;
+ unsigned int fmts[nFormats];
+ if (capability.width > 640 || capability.height > 480) {
+ fmts[0] = V4L2_PIX_FMT_MJPEG;
+ fmts[1] = V4L2_PIX_FMT_YUV420;
+ fmts[2] = V4L2_PIX_FMT_YUYV;
+ fmts[3] = V4L2_PIX_FMT_UYVY;
+ fmts[4] = V4L2_PIX_FMT_JPEG;
+ } else {
+ fmts[0] = V4L2_PIX_FMT_YUV420;
+ fmts[1] = V4L2_PIX_FMT_YUYV;
+ fmts[2] = V4L2_PIX_FMT_UYVY;
+ fmts[3] = V4L2_PIX_FMT_MJPEG;
+ fmts[4] = V4L2_PIX_FMT_JPEG;
+ }
+
+ // Enumerate image formats.
+ struct v4l2_fmtdesc fmt;
+ int fmtsIdx = nFormats;
+ memset(&fmt, 0, sizeof(fmt));
+ fmt.index = 0;
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ RTC_LOG(LS_INFO) << "Video Capture enumerats supported image formats:";
+ while (ioctl(_deviceFd, VIDIOC_ENUM_FMT, &fmt) == 0) {
+ RTC_LOG(LS_INFO) << " { pixelformat = "
+ << cricket::GetFourccName(fmt.pixelformat)
+ << ", description = '" << fmt.description << "' }";
+ // Match the preferred order.
+ for (int i = 0; i < nFormats; i++) {
+ if (fmt.pixelformat == fmts[i] && i < fmtsIdx)
+ fmtsIdx = i;
+ }
+ // Keep enumerating.
+ fmt.index++;
+ }
+
+ if (fmtsIdx == nFormats) {
+ RTC_LOG(LS_INFO) << "no supporting video formats found";
+ return -1;
+ } else {
+ RTC_LOG(LS_INFO) << "We prefer format "
+ << cricket::GetFourccName(fmts[fmtsIdx]);
+ }
+
+ struct v4l2_format video_fmt;
+ memset(&video_fmt, 0, sizeof(struct v4l2_format));
+ video_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ video_fmt.fmt.pix.sizeimage = 0;
+ video_fmt.fmt.pix.width = capability.width;
+ video_fmt.fmt.pix.height = capability.height;
+ video_fmt.fmt.pix.pixelformat = fmts[fmtsIdx];
+
+ if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
+ _captureVideoType = VideoType::kYUY2;
+ else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420)
+ _captureVideoType = VideoType::kI420;
+ else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY)
+ _captureVideoType = VideoType::kUYVY;
+ else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG ||
+ video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG)
+ _captureVideoType = VideoType::kMJPEG;
+
+ // set format and frame size now
+ if (ioctl(_deviceFd, VIDIOC_S_FMT, &video_fmt) < 0) {
+ RTC_LOG(LS_INFO) << "error in VIDIOC_S_FMT, errno = " << errno;
+ return -1;
+ }
+
+ // initialize current width and height
+ _currentWidth = video_fmt.fmt.pix.width;
+ _currentHeight = video_fmt.fmt.pix.height;
+
+ // Trying to set frame rate, before check driver capability.
+ bool driver_framerate_support = true;
+ struct v4l2_streamparm streamparms;
+ memset(&streamparms, 0, sizeof(streamparms));
+ streamparms.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ if (ioctl(_deviceFd, VIDIOC_G_PARM, &streamparms) < 0) {
+ RTC_LOG(LS_INFO) << "error in VIDIOC_G_PARM errno = " << errno;
+ driver_framerate_support = false;
+ // continue
+ } else {
+ // check the capability flag is set to V4L2_CAP_TIMEPERFRAME.
+ if (streamparms.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) {
+ // driver supports the feature. Set required framerate.
+ memset(&streamparms, 0, sizeof(streamparms));
+ streamparms.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ streamparms.parm.capture.timeperframe.numerator = 1;
+ streamparms.parm.capture.timeperframe.denominator = capability.maxFPS;
+ if (ioctl(_deviceFd, VIDIOC_S_PARM, &streamparms) < 0) {
+ RTC_LOG(LS_INFO) << "Failed to set the framerate. errno=" << errno;
+ driver_framerate_support = false;
+ } else {
+ _currentFrameRate = capability.maxFPS;
+ }
+ }
+ }
+ // If driver doesn't support framerate control, need to hardcode.
+ // Hardcoding the value based on the frame size.
+ if (!driver_framerate_support) {
+ if (_currentWidth >= 800 && _captureVideoType != VideoType::kMJPEG) {
+ _currentFrameRate = 15;
+ } else {
+ _currentFrameRate = 30;
+ }
+ }
+
+ if (!AllocateVideoBuffers()) {
+ RTC_LOG(LS_INFO) << "failed to allocate video capture buffers";
+ return -1;
+ }
+
+ // start capture thread;
+ if (_captureThread.empty()) {
+ quit_ = false;
+ _captureThread = rtc::PlatformThread::SpawnJoinable(
+ [this] {
+ while (CaptureProcess()) {
+ }
+ },
+ "CaptureThread",
+ rtc::ThreadAttributes().SetPriority(rtc::ThreadPriority::kHigh));
+ }
+
+ // Needed to start UVC camera - from the uvcview application
+ enum v4l2_buf_type type;
+ type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ if (ioctl(_deviceFd, VIDIOC_STREAMON, &type) == -1) {
+ RTC_LOG(LS_INFO) << "Failed to turn on stream";
+ return -1;
+ }
+
+ _captureStarted = true;
+ return 0;
+}
+
+int32_t VideoCaptureModuleV4L2::StopCapture() {
+ if (!_captureThread.empty()) {
+ {
+ MutexLock lock(&capture_lock_);
+ quit_ = true;
+ }
+ // Make sure the capture thread stops using the mutex.
+ _captureThread.Finalize();
+ }
+
+ MutexLock lock(&capture_lock_);
+ if (_captureStarted) {
+ _captureStarted = false;
+
+ DeAllocateVideoBuffers();
+ close(_deviceFd);
+ _deviceFd = -1;
+ }
+
+ return 0;
+}
+
+// critical section protected by the caller
+
+bool VideoCaptureModuleV4L2::AllocateVideoBuffers() {
+ struct v4l2_requestbuffers rbuffer;
+ memset(&rbuffer, 0, sizeof(v4l2_requestbuffers));
+
+ rbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ rbuffer.memory = V4L2_MEMORY_MMAP;
+ rbuffer.count = kNoOfV4L2Bufffers;
+
+ if (ioctl(_deviceFd, VIDIOC_REQBUFS, &rbuffer) < 0) {
+ RTC_LOG(LS_INFO) << "Could not get buffers from device. errno = " << errno;
+ return false;
+ }
+
+ if (rbuffer.count > kNoOfV4L2Bufffers)
+ rbuffer.count = kNoOfV4L2Bufffers;
+
+ _buffersAllocatedByDevice = rbuffer.count;
+
+ // Map the buffers
+ _pool = new Buffer[rbuffer.count];
+
+ for (unsigned int i = 0; i < rbuffer.count; i++) {
+ struct v4l2_buffer buffer;
+ memset(&buffer, 0, sizeof(v4l2_buffer));
+ buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buffer.memory = V4L2_MEMORY_MMAP;
+ buffer.index = i;
+
+ if (ioctl(_deviceFd, VIDIOC_QUERYBUF, &buffer) < 0) {
+ return false;
+ }
+
+ _pool[i].start = mmap(NULL, buffer.length, PROT_READ | PROT_WRITE,
+ MAP_SHARED, _deviceFd, buffer.m.offset);
+
+ if (MAP_FAILED == _pool[i].start) {
+ for (unsigned int j = 0; j < i; j++)
+ munmap(_pool[j].start, _pool[j].length);
+ return false;
+ }
+
+ _pool[i].length = buffer.length;
+
+ if (ioctl(_deviceFd, VIDIOC_QBUF, &buffer) < 0) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool VideoCaptureModuleV4L2::DeAllocateVideoBuffers() {
+ // unmap buffers
+ for (int i = 0; i < _buffersAllocatedByDevice; i++)
+ munmap(_pool[i].start, _pool[i].length);
+
+ delete[] _pool;
+
+ // turn off stream
+ enum v4l2_buf_type type;
+ type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ if (ioctl(_deviceFd, VIDIOC_STREAMOFF, &type) < 0) {
+ RTC_LOG(LS_INFO) << "VIDIOC_STREAMOFF error. errno: " << errno;
+ }
+
+ return true;
+}
+
+bool VideoCaptureModuleV4L2::CaptureStarted() {
+ return _captureStarted;
+}
+
+bool VideoCaptureModuleV4L2::CaptureProcess() {
+ int retVal = 0;
+ fd_set rSet;
+ struct timeval timeout;
+
+ FD_ZERO(&rSet);
+ FD_SET(_deviceFd, &rSet);
+ timeout.tv_sec = 1;
+ timeout.tv_usec = 0;
+
+ // _deviceFd written only in StartCapture, when this thread isn't running.
+ retVal = select(_deviceFd + 1, &rSet, NULL, NULL, &timeout);
+
+ {
+ MutexLock lock(&capture_lock_);
+
+ if (quit_) {
+ return false;
+ }
+
+ if (retVal < 0 && errno != EINTR) { // continue if interrupted
+ // select failed
+ return false;
+ } else if (retVal == 0) {
+ // select timed out
+ return true;
+ } else if (!FD_ISSET(_deviceFd, &rSet)) {
+ // not event on camera handle
+ return true;
+ }
+
+ if (_captureStarted) {
+ struct v4l2_buffer buf;
+ memset(&buf, 0, sizeof(struct v4l2_buffer));
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.memory = V4L2_MEMORY_MMAP;
+ // dequeue a buffer - repeat until dequeued properly!
+ while (ioctl(_deviceFd, VIDIOC_DQBUF, &buf) < 0) {
+ if (errno != EINTR) {
+ RTC_LOG(LS_INFO) << "could not sync on a buffer on device "
+ << strerror(errno);
+ return true;
+ }
+ }
+ VideoCaptureCapability frameInfo;
+ frameInfo.width = _currentWidth;
+ frameInfo.height = _currentHeight;
+ frameInfo.videoType = _captureVideoType;
+
+ // convert to to I420 if needed
+ IncomingFrame(reinterpret_cast<uint8_t*>(_pool[buf.index].start),
+ buf.bytesused, frameInfo);
+ // enqueue the buffer again
+ if (ioctl(_deviceFd, VIDIOC_QBUF, &buf) == -1) {
+ RTC_LOG(LS_INFO) << "Failed to enqueue capture buffer";
+ }
+ }
+ }
+ usleep(0);
+ return true;
+}
+
+int32_t VideoCaptureModuleV4L2::CaptureSettings(
+ VideoCaptureCapability& settings) {
+ settings.width = _currentWidth;
+ settings.height = _currentHeight;
+ settings.maxFPS = _currentFrameRate;
+ settings.videoType = _captureVideoType;
+
+ return 0;
+}
+} // namespace videocapturemodule
+} // namespace webrtc
diff --git a/modules/video_capture/linux/video_capture_linux.h b/modules/video_capture/linux/video_capture_v4l2.h
similarity index 88%
rename from modules/video_capture/linux/video_capture_linux.h
rename to modules/video_capture/linux/video_capture_v4l2.h
index fa06d72..65e89e2 100644
--- a/modules/video_capture/linux/video_capture_linux.h
+++ b/modules/video_capture/linux/video_capture_v4l2.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef MODULES_VIDEO_CAPTURE_MAIN_SOURCE_LINUX_VIDEO_CAPTURE_LINUX_H_
-#define MODULES_VIDEO_CAPTURE_MAIN_SOURCE_LINUX_VIDEO_CAPTURE_LINUX_H_
+#ifndef MODULES_VIDEO_CAPTURE_LINUX_VIDEO_CAPTURE_V4L2_H_
+#define MODULES_VIDEO_CAPTURE_LINUX_VIDEO_CAPTURE_V4L2_H_
#include <stddef.h>
#include <stdint.h>
@@ -62,4 +62,4 @@
} // namespace videocapturemodule
} // namespace webrtc
-#endif // MODULES_VIDEO_CAPTURE_MAIN_SOURCE_LINUX_VIDEO_CAPTURE_LINUX_H_
+#endif // MODULES_VIDEO_CAPTURE_LINUX_VIDEO_CAPTURE_V4L2_H_