Support more pixel formats in v4l2 camera backend

These were tested with gstreamer and v4l2loopback, example setup:
$ sudo v4l2loopback-ctl add -n BGRA 10
$ gst-launch-1.0 videotestsrc pattern=smpte-rp-219 ! \
  video/x-raw,format=BGRA ! v4l2sink device=/dev/video10 > /dev/null &

Then conversion was confirmed with video_loopback:
$ ./video_loopback --capture_device_index=3 --logs 2>&1 | grep -i \
  capture

Bug: webrtc:14830
Change-Id: I35c8e453cf7f9a2923935b0ad82477a3144e8c12
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/291532
Commit-Queue: Stefan Holmer <stefan@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Reviewed-by: Stefan Holmer <stefan@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#39979}
This commit is contained in:
Andreas Pehrson 2023-01-27 16:10:42 +01:00 committed by WebRTC LUCI CQ
parent 7220ee97aa
commit 91d5fc2ed6
2 changed files with 126 additions and 8 deletions

View File

@ -27,6 +27,24 @@
#include "modules/video_capture/video_capture_impl.h"
#include "rtc_base/logging.h"
// These defines are here to support building on kernel 3.16 which some
// downstream projects, e.g. Firefox, use.
// TODO(apehrson): Remove them and their undefs when no longer needed.
#ifndef V4L2_PIX_FMT_ABGR32
#define ABGR32_OVERRIDE 1
#define V4L2_PIX_FMT_ABGR32 v4l2_fourcc('A', 'R', '2', '4')
#endif
#ifndef V4L2_PIX_FMT_ARGB32
#define ARGB32_OVERRIDE 1
#define V4L2_PIX_FMT_ARGB32 v4l2_fourcc('B', 'A', '2', '4')
#endif
#ifndef V4L2_PIX_FMT_RGBA32
#define RGBA32_OVERRIDE 1
#define V4L2_PIX_FMT_RGBA32 v4l2_fourcc('A', 'B', '2', '4')
#endif
namespace webrtc {
namespace videocapturemodule {
DeviceInfoV4l2::DeviceInfoV4l2() : DeviceInfoImpl() {}
@ -228,9 +246,13 @@ int32_t DeviceInfoV4l2::FillCapabilities(int fd) {
video_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
video_fmt.fmt.pix.sizeimage = 0;
unsigned int videoFormats[] = {V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_YUV420,
V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_UYVY,
V4L2_PIX_FMT_NV12};
unsigned int videoFormats[] = {
V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_YUV420,
V4L2_PIX_FMT_YVU420, V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_UYVY,
V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_BGR24, V4L2_PIX_FMT_RGB24,
V4L2_PIX_FMT_RGB565, V4L2_PIX_FMT_ABGR32, V4L2_PIX_FMT_ARGB32,
V4L2_PIX_FMT_RGBA32, V4L2_PIX_FMT_BGR32, V4L2_PIX_FMT_RGB32,
};
constexpr int totalFmts = sizeof(videoFormats) / sizeof(unsigned int);
int sizes = 13;
@ -255,12 +277,38 @@ int32_t DeviceInfoV4l2::FillCapabilities(int fd) {
cap.videoType = VideoType::kYUY2;
} else if (videoFormats[fmts] == V4L2_PIX_FMT_YUV420) {
cap.videoType = VideoType::kI420;
} else if (videoFormats[fmts] == V4L2_PIX_FMT_MJPEG) {
} else if (videoFormats[fmts] == V4L2_PIX_FMT_YVU420) {
cap.videoType = VideoType::kYV12;
} else if (videoFormats[fmts] == V4L2_PIX_FMT_MJPEG ||
videoFormats[fmts] == V4L2_PIX_FMT_JPEG) {
cap.videoType = VideoType::kMJPEG;
} else if (videoFormats[fmts] == V4L2_PIX_FMT_UYVY) {
cap.videoType = VideoType::kUYVY;
} else if (videoFormats[fmts] == V4L2_PIX_FMT_NV12) {
cap.videoType = VideoType::kNV12;
} else if (videoFormats[fmts] == V4L2_PIX_FMT_BGR24) {
// NB that for RGB formats, `VideoType` follows naming conventions
// of libyuv[1], where e.g. the format for FOURCC "ARGB" stores
// pixels in BGRA order in memory. V4L2[2] on the other hand names
// its formats based on the order of the RGB components as stored in
// memory. Applies to all RGB formats below.
// [1]https://chromium.googlesource.com/libyuv/libyuv/+/refs/heads/main/docs/formats.md#the-argb-fourcc
// [2]https://www.kernel.org/doc/html/v6.2/userspace-api/media/v4l/pixfmt-rgb.html#bits-per-component
cap.videoType = VideoType::kRGB24;
} else if (videoFormats[fmts] == V4L2_PIX_FMT_RGB24) {
cap.videoType = VideoType::kBGR24;
} else if (videoFormats[fmts] == V4L2_PIX_FMT_RGB565) {
cap.videoType = VideoType::kRGB565;
} else if (videoFormats[fmts] == V4L2_PIX_FMT_ABGR32) {
cap.videoType = VideoType::kARGB;
} else if (videoFormats[fmts] == V4L2_PIX_FMT_ARGB32) {
cap.videoType = VideoType::kBGRA;
} else if (videoFormats[fmts] == V4L2_PIX_FMT_BGR32) {
cap.videoType = VideoType::kARGB;
} else if (videoFormats[fmts] == V4L2_PIX_FMT_RGB32) {
cap.videoType = VideoType::kBGRA;
} else if (videoFormats[fmts] == V4L2_PIX_FMT_RGBA32) {
cap.videoType = VideoType::kABGR;
} else {
RTC_DCHECK_NOTREACHED();
}
@ -289,3 +337,18 @@ int32_t DeviceInfoV4l2::FillCapabilities(int fd) {
} // namespace videocapturemodule
} // namespace webrtc
#ifdef ABGR32_OVERRIDE
#undef ABGR32_OVERRIDE
#undef V4L2_PIX_FMT_ABGR32
#endif
#ifdef ARGB32_OVERRIDE
#undef ARGB32_OVERRIDE
#undef V4L2_PIX_FMT_ARGB32
#endif
#ifdef RGBA32_OVERRIDE
#undef RGBA32_OVERRIDE
#undef V4L2_PIX_FMT_RGBA32
#endif

View File

@ -29,6 +29,24 @@
#include "modules/video_capture/video_capture.h"
#include "rtc_base/logging.h"
// These defines are here to support building on kernel 3.16 which some
// downstream projects, e.g. Firefox, use.
// TODO(apehrson): Remove them and their undefs when no longer needed.
#ifndef V4L2_PIX_FMT_ABGR32
#define ABGR32_OVERRIDE 1
#define V4L2_PIX_FMT_ABGR32 v4l2_fourcc('A', 'R', '2', '4')
#endif
#ifndef V4L2_PIX_FMT_ARGB32
#define ARGB32_OVERRIDE 1
#define V4L2_PIX_FMT_ARGB32 v4l2_fourcc('B', 'A', '2', '4')
#endif
#ifndef V4L2_PIX_FMT_RGBA32
#define RGBA32_OVERRIDE 1
#define V4L2_PIX_FMT_RGBA32 v4l2_fourcc('A', 'B', '2', '4')
#endif
namespace webrtc {
namespace videocapturemodule {
VideoCaptureModuleV4L2::VideoCaptureModuleV4L2()
@ -116,12 +134,18 @@ int32_t VideoCaptureModuleV4L2::StartCapture(
// If the requested resolution is larger than VGA, we prefer MJPEG. Go for
// I420 otherwise.
unsigned int hdFmts[] = {
V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_YUYV,
V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_JPEG,
V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_YVU420,
V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_NV12,
V4L2_PIX_FMT_ABGR32, V4L2_PIX_FMT_ARGB32, V4L2_PIX_FMT_RGBA32,
V4L2_PIX_FMT_BGR32, V4L2_PIX_FMT_RGB32, V4L2_PIX_FMT_BGR24,
V4L2_PIX_FMT_RGB24, V4L2_PIX_FMT_RGB565, V4L2_PIX_FMT_JPEG,
};
unsigned int sdFmts[] = {
V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_UYVY,
V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_JPEG,
V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_YVU420, V4L2_PIX_FMT_YUYV,
V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_ABGR32,
V4L2_PIX_FMT_ARGB32, V4L2_PIX_FMT_RGBA32, V4L2_PIX_FMT_BGR32,
V4L2_PIX_FMT_RGB32, V4L2_PIX_FMT_BGR24, V4L2_PIX_FMT_RGB24,
V4L2_PIX_FMT_RGB565, V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_JPEG,
};
const bool isHd = capability.width > 640 || capability.height > 480;
unsigned int* fmts = isHd ? hdFmts : sdFmts;
@ -168,10 +192,26 @@ int32_t VideoCaptureModuleV4L2::StartCapture(
_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_YVU420)
_captureVideoType = VideoType::kYV12;
else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY)
_captureVideoType = VideoType::kUYVY;
else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_NV12)
_captureVideoType = VideoType::kNV12;
else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24)
_captureVideoType = VideoType::kRGB24;
else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24)
_captureVideoType = VideoType::kBGR24;
else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565)
_captureVideoType = VideoType::kRGB565;
else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_ABGR32 ||
video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR32)
_captureVideoType = VideoType::kARGB;
else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_ARGB32 ||
video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB32)
_captureVideoType = VideoType::kBGRA;
else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_RGBA32)
_captureVideoType = VideoType::kABGR;
else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG ||
video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG)
_captureVideoType = VideoType::kMJPEG;
@ -420,3 +460,18 @@ int32_t VideoCaptureModuleV4L2::CaptureSettings(
}
} // namespace videocapturemodule
} // namespace webrtc
#ifdef ABGR32_OVERRIDE
#undef ABGR32_OVERRIDE
#undef V4L2_PIX_FMT_ABGR32
#endif
#ifdef ARGB32_OVERRIDE
#undef ARGB32_OVERRIDE
#undef V4L2_PIX_FMT_ARGB32
#endif
#ifdef RGBA32_OVERRIDE
#undef RGBA32_OVERRIDE
#undef V4L2_PIX_FMT_RGBA32
#endif