8#include <QtCore/QLoggingCategory>
10#include <QtCore/QRect>
17#include <mediactl/mediactl.h>
18#include <mediactl/v4l2subdev.h>
28 case MEDIA_BUS_FMT_FIXED:
return "FIXED";
29 case MEDIA_BUS_FMT_RGB444_1X12:
return "RGB444_1X12";
34 case MEDIA_BUS_FMT_RGB565_1X16:
return "RGB565_1X16";
35 case MEDIA_BUS_FMT_BGR565_2X8_BE:
return "BGR565_2X8_BE";
36 case MEDIA_BUS_FMT_BGR565_2X8_LE:
return "BGR565_2X8_LE";
37 case MEDIA_BUS_FMT_RGB565_2X8_BE:
return "RGB565_2X8_BE";
38 case MEDIA_BUS_FMT_RGB565_2X8_LE:
return "RGB565_2X8_LE";
39 case MEDIA_BUS_FMT_RGB666_1X18:
return "RGB666_1X18";
40 case MEDIA_BUS_FMT_RBG888_1X24:
return "RBG888_1X24";
42 case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
return "RGB666_1X7X3_SPWG";
43 case MEDIA_BUS_FMT_BGR888_1X24:
return "BGR888_1X24";
44 case MEDIA_BUS_FMT_GBR888_1X24:
return "GBR888_1X24";
45 case MEDIA_BUS_FMT_RGB888_1X24:
return "RGB888_1X24";
46 case MEDIA_BUS_FMT_RGB888_2X12_BE:
return "RGB888_2X12_BE";
47 case MEDIA_BUS_FMT_RGB888_2X12_LE:
return "RGB888_2X12_LE";
48 case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
return "RGB888_1X7X4_SPWG";
50 case MEDIA_BUS_FMT_ARGB8888_1X32:
return "ARGB8888_1X32";
51 case MEDIA_BUS_FMT_RGB888_1X32_PADHI:
return "RGB888_1X32_PADHI";
55 case MEDIA_BUS_FMT_Y8_1X8:
return "Y8_1X8";
56 case MEDIA_BUS_FMT_UV8_1X8:
return "UV8_1X8";
57 case MEDIA_BUS_FMT_UYVY8_1_5X8:
return "UYVY8_1_5X8";
58 case MEDIA_BUS_FMT_VYUY8_1_5X8:
return "VYUY8_1_5X8";
59 case MEDIA_BUS_FMT_YUYV8_1_5X8:
return "YUYV8_1_5X8";
60 case MEDIA_BUS_FMT_YVYU8_1_5X8:
return "YVYU8_1_5X8";
61 case MEDIA_BUS_FMT_UYVY8_2X8:
return "UYVY8_2X8";
62 case MEDIA_BUS_FMT_VYUY8_2X8:
return "VYUY8_2X8";
63 case MEDIA_BUS_FMT_YUYV8_2X8:
return "YUYV8_2X8";
64 case MEDIA_BUS_FMT_YVYU8_2X8:
return "YVYU8_2X8";
65 case MEDIA_BUS_FMT_Y10_1X10:
return "Y10_1X10";
66 case MEDIA_BUS_FMT_UYVY10_2X10:
return "UYVY10_2X10";
67 case MEDIA_BUS_FMT_VYUY10_2X10:
return "VYUY10_2X10";
68 case MEDIA_BUS_FMT_YUYV10_2X10:
return "YUYV10_2X10";
69 case MEDIA_BUS_FMT_YVYU10_2X10:
return "YVYU10_2X10";
70 case MEDIA_BUS_FMT_Y12_1X12:
return "Y12_1X12";
71 case MEDIA_BUS_FMT_UYVY12_2X12:
return "UYVY12_2X12";
72 case MEDIA_BUS_FMT_VYUY12_2X12:
return "VYUY12_2X12";
73 case MEDIA_BUS_FMT_YUYV12_2X12:
return "YUYV12_2X12";
74 case MEDIA_BUS_FMT_YVYU12_2X12:
return "YVYU12_2X12";
75 case MEDIA_BUS_FMT_UYVY8_1X16:
return "UYVY8_1X16";
76 case MEDIA_BUS_FMT_VYUY8_1X16:
return "VYUY8_1X16";
77 case MEDIA_BUS_FMT_YUYV8_1X16:
return "YUYV8_1X16";
78 case MEDIA_BUS_FMT_YVYU8_1X16:
return "YVYU8_1X16";
79 case MEDIA_BUS_FMT_YDYUYDYV8_1X16:
return "YDYUYDYV8_1X16";
80 case MEDIA_BUS_FMT_UYVY10_1X20:
return "UYVY10_1X20";
81 case MEDIA_BUS_FMT_VYUY10_1X20:
return "VYUY10_1X20";
82 case MEDIA_BUS_FMT_YUYV10_1X20:
return "YUYV10_1X20";
83 case MEDIA_BUS_FMT_YVYU10_1X20:
return "YVYU10_1X20";
84 case MEDIA_BUS_FMT_VUY8_1X24:
return "VUY8_1X24";
85 case MEDIA_BUS_FMT_YUV8_1X24:
return "YUV8_1X24";
87 case MEDIA_BUS_FMT_UYVY12_1X24:
return "UYVY12_1X24";
88 case MEDIA_BUS_FMT_VYUY12_1X24:
return "VYUY12_1X24";
89 case MEDIA_BUS_FMT_YUYV12_1X24:
return "YUYV12_1X24";
90 case MEDIA_BUS_FMT_YVYU12_1X24:
return "YVYU12_1X24";
91 case MEDIA_BUS_FMT_YUV10_1X30:
return "YUV10_1X30";
93 case MEDIA_BUS_FMT_AYUV8_1X32:
return "AYUV8_1X32";
98 case MEDIA_BUS_FMT_SBGGR8_1X8:
return "SBGGR8_1X8";
99 case MEDIA_BUS_FMT_SGBRG8_1X8:
return "SGBRG8_1X8";
100 case MEDIA_BUS_FMT_SGRBG8_1X8:
return "SGRBG8_1X8";
101 case MEDIA_BUS_FMT_SRGGB8_1X8:
return "SRGGB8_1X8";
102 case MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8:
return "SBGGR10_ALAW8_1X8";
103 case MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8:
return "SGBRG10_ALAW8_1X8";
104 case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8:
return "SGRBG10_ALAW8_1X8";
105 case MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8:
return "SRGGB10_ALAW8_1X8";
106 case MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8:
return "SBGGR10_DPCM8_1X8";
107 case MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8:
return "SGBRG10_DPCM8_1X8";
108 case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
return "SGRBG10_DPCM8_1X8";
109 case MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8:
return "SRGGB10_DPCM8_1X8";
114 case MEDIA_BUS_FMT_SBGGR10_1X10:
return "SBGGR10_1X10";
115 case MEDIA_BUS_FMT_SGBRG10_1X10:
return "SGBRG10_1X10";
116 case MEDIA_BUS_FMT_SGRBG10_1X10:
return "SGRBG10_1X10";
117 case MEDIA_BUS_FMT_SRGGB10_1X10:
return "SRGGB10_1X10";
118 case MEDIA_BUS_FMT_SBGGR12_1X12:
return "SBGGR12_1X12";
119 case MEDIA_BUS_FMT_SGBRG12_1X12:
return "SGBRG12_1X12";
120 case MEDIA_BUS_FMT_SGRBG12_1X12:
return "SGRBG12_1X12";
121 case MEDIA_BUS_FMT_SRGGB12_1X12:
return "SRGGB12_1X12";
122 case MEDIA_BUS_FMT_SBGGR14_1X14:
return "SBGGR14_1X14";
123 case MEDIA_BUS_FMT_SGBRG14_1X14:
return "SGBRG14_1X14";
124 case MEDIA_BUS_FMT_SGRBG14_1X14:
return "SGRBG14_1X14";
125 case MEDIA_BUS_FMT_SRGGB14_1X14:
return "SRGGB14_1X14";
126 case MEDIA_BUS_FMT_SBGGR16_1X16:
return "SBGGR16_1X16";
127 case MEDIA_BUS_FMT_SGBRG16_1X16:
return "SGBRG16_1X16";
128 case MEDIA_BUS_FMT_SGRBG16_1X16:
return "SGRBG16_1X16";
129 case MEDIA_BUS_FMT_SRGGB16_1X16:
return "SRGGB16_1X16";
130 case MEDIA_BUS_FMT_JPEG_1X8:
return "JPEG_1X8";
131 case MEDIA_BUS_FMT_S5C_UYVY_JPEG_1X8:
return "S5C_UYVY_JPEG_1X8";
132 case MEDIA_BUS_FMT_AHSV8888_1X32:
return "AHSV8888_1X32";
140 debug.nospace() <<
"v4l2_mbus_framefmt("
142 <<
"size: " <<
format.width <<
"x" <<
format.height <<
")";
149 debug.nospace() <<
"v4l2_pix_format_mplane("
151 <<
"size: " <<
format.width <<
"x" <<
format.height <<
", "
152 <<
"planes: " <<
format.num_planes <<
")";
157 : m_mediaDevice(media_device_new(devicePath.toStdString().c_str()))
160 qFatal(
"Couldn't get media device");
162 if (media_device_enumerate(m_mediaDevice))
163 qFatal(
"Couldn't enumerate media device");
165 m_info = media_get_info(m_mediaDevice);
167 qCDebug(qLcEglfsKmsDebug) <<
"Opened linux media device:"
168 <<
"\n\t Path:" << devicePath
169 <<
"\n\t Model:" <<
model()
178 media_device_unref(m_mediaDevice);
193 if (media_reset_links(m_mediaDevice)) {
194 qWarning() <<
"Could not reset media controller links.";
197 qCDebug(qLcEglfsKmsDebug) <<
"Reset media links";
203 char *endp =
nullptr;;
204 struct media_link *mediaLink = media_parse_link(m_mediaDevice, link.
toStdString().c_str(), &endp);
207 qWarning() <<
"Failed to parse media link:" << link;
214 struct media_pad *mediaPad = media_parse_pad(m_mediaDevice, pad.
toStdString().c_str(),
nullptr);
217 qWarning() <<
"Failed to parse media pad:" << pad;
224 if (media_setup_link(m_mediaDevice, link->source, link->sink, 1)) {
225 qWarning() <<
"Failed to enable media link.";
233 if (media_setup_link(m_mediaDevice, link->source, link->sink, 0)) {
234 qWarning() <<
"Failed to disable media link.";
248static struct media_entity *
safeGetEntity(
struct media_entity *(get_entity_by_name_fn)(
struct media_device *,
const char *),
251 return get_entity_by_name_fn(
device,
name.toStdString().c_str());
254static struct media_entity *
safeGetEntity(
struct media_entity *(get_entity_by_name_fn)(
struct media_device *,
const char *,
size_t),
255 struct media_device *
device,
258 return get_entity_by_name_fn(
device,
name.toStdString().c_str(),
name.length());
263 struct media_entity *entity =
safeGetEntity(media_get_entity_by_name, m_mediaDevice,
name);
274 const char *
deviceName = media_entity_get_devname(entity);
281 : m_subdevFd(mediaDevice->openVideoDevice(
name))
288 struct v4l2_format
format;
289 memset(&
format, 0,
sizeof(
struct v4l2_format));
290 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
291 if (ioctl(m_subdevFd, VIDIOC_G_FMT, &
format) == -1) {
298 format.fmt.pix_mp.field = V4L2_FIELD_NONE;
299 format.fmt.pix_mp.pixelformat = pixelFormat;
300 format.fmt.pix_mp.num_planes = 1;
301 format.fmt.pix_mp.flags = 0;
302 format.fmt.pix_mp.plane_fmt[0].bytesperline = 0;
303 format.fmt.pix_mp.plane_fmt[0].sizeimage = 0;
305 if (ioctl(m_subdevFd, VIDIOC_S_FMT, &
format) == -1) {
306 qWarning() <<
"Capture device" << m_subdevFd <<
"VIDIOC_S_FMT with format" <<
format.fmt.pix_mp
307 <<
"failed:" << strerror(errno);
311 qCDebug(qLcEglfsKmsDebug) <<
"Capture device" << m_subdevFd <<
"format set:" <<
format.fmt.pix_mp;
317 struct v4l2_requestbuffers requestBuffers;
318 memset(&requestBuffers, 0,
sizeof(requestBuffers));
319 requestBuffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
320 requestBuffers.memory = V4L2_MEMORY_DMABUF;
321 requestBuffers.count = 0;
322 if (ioctl(m_subdevFd, VIDIOC_REQBUFS, &requestBuffers) == -1) {
323 qWarning(
"Capture device %d: VIDIOC_REQBUFS clear failed: %s", m_subdevFd, strerror(errno));
326 qCDebug(qLcEglfsKmsDebug,
"Capture device %d: Deallocced buffers with REQBUF, now has %d buffers", m_subdevFd, requestBuffers.count);
327 Q_ASSERT(requestBuffers.count == 0);
333 struct v4l2_requestbuffers requestBuffers;
334 memset(&requestBuffers, 0,
sizeof(requestBuffers));
335 requestBuffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
336 requestBuffers.memory = V4L2_MEMORY_DMABUF;
337 requestBuffers.count = 1;
338 if (ioctl(m_subdevFd, VIDIOC_REQBUFS, &requestBuffers) == -1) {
340 qWarning(
"Capture device %d: Multi-planar capture or dma buffers not supported", m_subdevFd);
341 qWarning(
"Capture device %d: VIDIOC_REQBUFS failed: %s", m_subdevFd, strerror(errno));
344 Q_ASSERT(requestBuffers.count == 1);
350 const uint numPlanes = 1;
351 struct v4l2_buffer
buffer;
353 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
354 buffer.memory = V4L2_MEMORY_DMABUF;
357 struct v4l2_plane planes[VIDEO_MAX_PLANES];
359 buffer.length = numPlanes;
360 memset(planes, 0,
sizeof(planes));
361 for (
uint i = 0;
i < numPlanes;
i++) {
362 buffer.m.planes[
i].m.fd = dmabufFd;
367 if (ioctl(m_subdevFd, VIDIOC_QBUF, &
buffer) == -1) {
368 qWarning(
"Capture device %d: VIDIOC_QBUF failed for dma buffer with fd %d: %s",
369 m_subdevFd, dmabufFd, strerror(errno));
378 const int numPlanes = 1;
379 struct v4l2_buffer
buffer;
380 struct v4l2_plane planes[VIDEO_MAX_PLANES];
383 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
384 buffer.memory = V4L2_MEMORY_DMABUF;
387 buffer.length = numPlanes;
388 memset(planes, 0,
sizeof(planes));
390 if (ioctl(m_subdevFd, VIDIOC_DQBUF, &
buffer) == -1) {
391 qWarning(
"Capture device %d: VIDIOC_DQBUF failed: %s", m_subdevFd, strerror(errno));
400 return QLinuxMediaDevice::streamOn(m_subdevFd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
405 return QLinuxMediaDevice::streamOff(m_subdevFd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
416 struct v4l2_format
format;
417 memset(&
format, 0,
sizeof(
struct v4l2_format));
418 format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
419 if (ioctl(m_subdevFd, VIDIOC_G_FMT, &
format) == -1) {
426 format.fmt.pix_mp.field = V4L2_FIELD_NONE;
427 format.fmt.pix_mp.pixelformat = pixelFormat;
428 format.fmt.pix_mp.num_planes = 1;
429 format.fmt.pix_mp.flags = 0;
430 format.fmt.pix_mp.plane_fmt[0].bytesperline = bytesPerLine;
431 format.fmt.pix_mp.plane_fmt[0].sizeimage = 0;
433 if (ioctl(m_subdevFd, VIDIOC_S_FMT, &
format) == -1) {
434 qWarning() <<
"Output device" << m_subdevFd <<
"VIDIOC_S_FMT with format" <<
format.fmt.pix_mp
435 <<
"failed:" << strerror(errno);
439 qCDebug(qLcEglfsKmsDebug) <<
"Output device device" << m_subdevFd <<
"format set:" <<
format.fmt.pix_mp;
445 struct v4l2_requestbuffers requestBuffers;
446 memset(&requestBuffers, 0,
sizeof(requestBuffers));
447 requestBuffers.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
448 requestBuffers.memory = V4L2_MEMORY_DMABUF;
449 requestBuffers.count = 0;
450 if (ioctl(m_subdevFd, VIDIOC_REQBUFS, &requestBuffers) == -1) {
451 qWarning(
"Output device %d: VIDIOC_REQBUFS clear failed: %s", m_subdevFd, strerror(errno));
454 qCDebug(qLcEglfsKmsDebug,
"Output device %d: Deallocced buffers with REQBUF, now has %d buffers", m_subdevFd, requestBuffers.count);
455 Q_ASSERT(requestBuffers.count == 0);
461 struct v4l2_requestbuffers requestBuffers;
462 memset(&requestBuffers, 0,
sizeof(requestBuffers));
463 requestBuffers.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
464 requestBuffers.memory = V4L2_MEMORY_DMABUF;
465 requestBuffers.count = 1;
466 if (ioctl(m_subdevFd, VIDIOC_REQBUFS, &requestBuffers) == -1) {
468 qWarning(
"Output device %d: Multi-planar output or dma buffers not supported", m_subdevFd);
469 qWarning(
"Output device %d: VIDIOC_REQBUFS failed: %s", m_subdevFd, strerror(errno));
472 qCDebug(qLcEglfsKmsDebug) <<
"REQBUF returned" << requestBuffers.count <<
"buffers for output device" << m_subdevFd;
478 const int numPlanes = 1;
479 struct v4l2_buffer
buffer;
481 buffer.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
482 buffer.memory = V4L2_MEMORY_DMABUF;
484 buffer.length = numPlanes;
485 buffer.bytesused = bytesUsed;
486 buffer.field = V4L2_FIELD_NONE;
488 struct v4l2_plane planes[numPlanes];
489 memset(planes, 0,
sizeof(planes));
492 for (
int i = 0;
i < numPlanes;
i++) {
493 buffer.m.planes[
i].m.fd = dmabufFd;
495 buffer.m.planes[
i].bytesused = bytesUsed;
498 if (ioctl(m_subdevFd, VIDIOC_QBUF, &
buffer) == -1) {
499 qWarning(
"Output device %d: VIDIOC_QBUF failed for dmabuf %d: %s", m_subdevFd, dmabufFd, strerror(errno));
503 if (!(
buffer.flags & V4L2_BUF_FLAG_QUEUED)) {
504 qWarning() <<
"Queued flag not set on buffer for output device";
513 return QLinuxMediaDevice::streamOn(m_subdevFd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
518 return QLinuxMediaDevice::streamOff(m_subdevFd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
523 const char *
deviceName = media_entity_get_devname(pad->entity);
532 struct v4l2_mbus_framefmt
format;
537 if (v4l2_subdev_set_format(pad->entity, &
format, pad->index, V4L2_SUBDEV_FORMAT_ACTIVE)) {
538 qWarning() <<
"Setting v4l2_subdev_set_format failed for format" <<
format;
542 if (
format.code != mbusFormat) {
548 qCDebug(qLcEglfsKmsDebug) <<
"Set format to" <<
format <<
"for entity" << pad->entity <<
"index" << pad->index;
554 struct v4l2_control control;
555 control.id = V4L2_CID_ALPHA_COMPONENT;
556 control.value =
static_cast<__s32
>(
alpha * 0xff);
557 if (ioctl(subdevFd, VIDIOC_S_CTRL, &control) == -1) {
567 struct v4l2_rect
rect;
573 int ret = v4l2_subdev_set_selection(pad->entity, &
rect, pad->index,
target, V4L2_SUBDEV_FORMAT_ACTIVE);
575 qWarning() <<
"Setting subdev selection failed.";
592bool QLinuxMediaDevice::streamOn(
int subDeviceFd, v4l2_buf_type bufferType)
594 if (ioctl(subDeviceFd, VIDIOC_STREAMON, &bufferType) == -1) {
595 qWarning(
"VIDIOC_STREAMON failed for subdevice %d: %s", subDeviceFd, strerror(errno));
602bool QLinuxMediaDevice::streamOff(
int subDeviceFd, v4l2_buf_type bufferType)
604 if (ioctl(subDeviceFd, VIDIOC_STREAMOFF, &bufferType) == -1) {
605 qWarning(
"VIDIOC_STREAMOFF failed for subdevice %d: %s", subDeviceFd, strerror(errno));
IOBluetoothDevice * device
\inmodule QtCore\reentrant
constexpr int height() const noexcept
Returns the height of the rectangle.
constexpr bool isValid() const noexcept
Returns true if the rectangle is valid, otherwise returns false.
constexpr int top() const noexcept
Returns the y-coordinate of the rectangle's top edge.
constexpr int left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
constexpr int width() const noexcept
Returns the width of the rectangle.
constexpr int height() const noexcept
Returns the height.
constexpr int width() const noexcept
Returns the width.
\macro QT_RESTRICTED_CAST_FROM_ASCII
QStringList split(const QString &sep, Qt::SplitBehavior behavior=Qt::KeepEmptyParts, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Splits the string into substrings wherever sep occurs, and returns the list of those strings.
std::string toStdString() const
Returns a std::string object with the data contained in this QString.
void qErrnoWarning(const char *msg,...)
Combined button and popup list for selecting options.
QT_BEGIN_NAMESPACE QString q_fourccToString(uint code)
#define qCDebug(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLuint GLenum GLsizei length
GLint GLsizei GLsizei GLenum format
GLfloat GLfloat GLfloat alpha
file open(QIODevice::ReadOnly)