diff --git a/modules/video_capture/BUILD.gn b/modules/video_capture/BUILD.gn index 98fb04a0eb..616be5d53f 100644 --- a/modules/video_capture/BUILD.gn +++ b/modules/video_capture/BUILD.gn @@ -65,9 +65,11 @@ if (!build_with_chromium) { 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 cde3b86d5c..ccbbeae3ab 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 #include #include @@ -22,6 +20,7 @@ #include +#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(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 0000000000..c1062d4078 --- /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 +#include +#include +#include +#include +#include +#include +// v4l includes +#include + +#include + +#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(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(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(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( + 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(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 304ae71230..fb95a6020d 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 @@ -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 @@ class DeviceInfoLinux : public DeviceInfoImpl { }; } // 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 321355ffca..2bc889facf 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 #include #include @@ -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 @@ rtc::scoped_refptr VideoCaptureImpl::Create( 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 0000000000..6bd3823ac4 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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(_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 fa06d72b8d..65e89e2daa 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 #include @@ -62,4 +62,4 @@ class VideoCaptureModuleV4L2 : public VideoCaptureImpl { } // namespace videocapturemodule } // namespace webrtc -#endif // MODULES_VIDEO_CAPTURE_MAIN_SOURCE_LINUX_VIDEO_CAPTURE_LINUX_H_ +#endif // MODULES_VIDEO_CAPTURE_LINUX_VIDEO_CAPTURE_V4L2_H_