9#include <private/qcameradevice_p.h>
10#include <private/qabstractvideobuffer_p.h>
11#include <private/qvideotexturehelper_p.h>
12#include <private/qmultimediautils_p.h>
13#include <private/qplatformmediadevices_p.h>
20#include <private/qcore_unix_p.h>
23#include <linux/videodev2.h>
38 return std::equal(
a.cbegin(),
a.cend(),
b.cbegin(),
b.cend(), areCamerasDataEqual);
89 while (
f->v4l2Format) {
100 while (
f->v4l2Format) {
102 return f->v4l2Format;
109bool QV4L2CameraDevices::doCheckCameras()
124 const int fd =
open(
file.constData(), O_RDONLY);
130 v4l2_fmtdesc formatDesc = {};
132 struct v4l2_capability
cap;
133 if (ioctl(
fd, VIDIOC_QUERYCAP, &
cap) < 0)
136 if (
cap.device_caps & V4L2_CAP_META_CAPTURE)
138 if (!(
cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
140 if (!(
cap.capabilities & V4L2_CAP_STREAMING))
143 auto camera = std::make_unique<QCameraDevicePrivate>();
149 formatDesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
151 while (!ioctl(
fd, VIDIOC_ENUM_FMT, &formatDesc)) {
153 qCDebug(qLV4L2Camera) <<
" " << pixelFmt;
162 frameSize.pixel_format = formatDesc.pixelformat;
164 while (!ioctl(
fd, VIDIOC_ENUM_FRAMESIZES, &
frameSize)) {
166 if (
frameSize.type != V4L2_FRMSIZE_TYPE_DISCRETE)
173 v4l2_frmivalenum frameInterval = {};
174 frameInterval.pixel_format = formatDesc.pixelformat;
178 while (!ioctl(
fd, VIDIOC_ENUM_FRAMEINTERVALS, &frameInterval)) {
179 ++frameInterval.index;
180 if (frameInterval.type != V4L2_FRMIVAL_TYPE_DISCRETE)
182 float rate = float(frameInterval.discrete.denominator)/float(frameInterval.discrete.numerator);
192 auto fmt = std::make_unique<QCameraFormatPrivate>();
193 fmt->pixelFormat = pixelFmt;
194 fmt->resolution = resolution;
196 fmt->maxFrameRate = max;
197 camera->videoFormats.append(
fmt.release()->create());
198 camera->photoResolutions.append(resolution);
214 m_cameras = std::move(newCameras);
261 struct v4l2_buffer
buf = {};
263 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
264 buf.memory = V4L2_MEMORY_MMAP;
268 qWarning() <<
"Couldn't release V4L2 buffer" << errno << strerror(errno) <<
index;
274 munmap(
b.data,
b.size);
299 if (m_cameraDevice.
isNull() && active)
307 setV4L2CameraFormat();
320 if (m_cameraDevice ==
camera)
333 setV4L2CameraFormat();
351 setV4L2CameraFormat();
378 if (!focusDist && !v4l2RangedFocus)
384 setV4L2Parameter(V4L2_CID_FOCUS_AUTO, 1);
386 setV4L2Parameter(V4L2_CID_AUTO_FOCUS_RANGE, V4L2_AUTO_FOCUS_RANGE_AUTO);
389 setV4L2Parameter(V4L2_CID_FOCUS_AUTO, 1);
391 setV4L2Parameter(V4L2_CID_AUTO_FOCUS_RANGE, V4L2_AUTO_FOCUS_RANGE_MACRO);
393 setV4L2Parameter(V4L2_CID_FOCUS_ABSOLUTE, v4l2MinFocus);
396 setV4L2Parameter(V4L2_CID_FOCUS_AUTO, 1);
398 setV4L2Parameter(V4L2_CID_AUTO_FOCUS_RANGE, V4L2_AUTO_FOCUS_RANGE_INFINITY);
401 setV4L2Parameter(V4L2_CID_FOCUS_AUTO, 0);
402 setV4L2Parameter(V4L2_CID_FOCUS_ABSOLUTE, v4l2MaxFocus);
405 setV4L2Parameter(V4L2_CID_FOCUS_AUTO, 0);
414 int distance = v4l2MinFocus + int((v4l2MaxFocus - v4l2MinFocus)*
d);
415 setV4L2Parameter(V4L2_CID_FOCUS_ABSOLUTE,
distance);
421 if (v4l2MaxZoom == v4l2MinZoom)
423 factor =
qBound(1., factor, 2.);
424 int zoom = v4l2MinZoom + (factor - 1.)*(v4l2MaxZoom - v4l2MinZoom);
425 setV4L2Parameter(V4L2_CID_ZOOM_ABSOLUTE, zoom);
442 setV4L2Parameter(V4L2_CID_FLASH_LED_MODE,
mode ==
QCamera::FlashAuto ? V4L2_FLASH_LED_MODE_FLASH : V4L2_FLASH_LED_MODE_NONE);
455 struct v4l2_queryctrl queryControl;
456 ::memset(&queryControl, 0,
sizeof(queryControl));
457 queryControl.id = V4L2_CID_AUTO_WHITE_BALANCE;
459 if (::ioctl(
d->v4l2FileDescriptor, VIDIOC_QUERYCTRL, &queryControl) == 0)
469 setV4L2Parameter(V4L2_CID_FLASH_LED_MODE,
mode ==
QCamera::TorchOn ? V4L2_FLASH_LED_MODE_TORCH : V4L2_FLASH_LED_MODE_NONE);
476 return v4l2TorchSupported;
482 if (v4l2AutoExposureSupported && v4l2ManualExposureSupported) {
486 setV4L2Parameter(V4L2_CID_EXPOSURE_AUTO,
value);
496 if (v4l2ManualExposureSupported && v4l2AutoExposureSupported)
503 if ((v4l2MinExposureAdjustment != 0 || v4l2MaxExposureAdjustment != 0)) {
504 int value =
qBound(v4l2MinExposureAdjustment, (
int)(compensation*1000), v4l2MaxExposureAdjustment);
505 setV4L2Parameter(V4L2_CID_AUTO_EXPOSURE_BIAS,
value);
515 setV4L2Parameter(V4L2_CID_ISO_SENSITIVITY_AUTO, iso <= 0 ? V4L2_ISO_SENSITIVITY_AUTO : V4L2_ISO_SENSITIVITY_MANUAL);
518 setV4L2Parameter(V4L2_CID_ISO_SENSITIVITY, iso);
527 return getV4L2Parameter(V4L2_CID_ISO_SENSITIVITY);
532 if (v4l2ManualExposureSupported && v4l2AutoExposureSupported) {
533 int exposure =
qBound(v4l2MinExposure,
qRound(secs*10000.), v4l2MaxExposure);
534 setV4L2Parameter(V4L2_CID_EXPOSURE_ABSOLUTE, exposure);
542 return getV4L2Parameter(V4L2_CID_EXPOSURE_ABSOLUTE)/10000.;
547 if (v4l2AutoWhiteBalanceSupported && v4l2ColorTemperatureSupported)
558 int t = setV4L2ColorTemperature(temperature);
566 if (temperature == 0) {
573 int t = setV4L2ColorTemperature(temperature);
578void QV4L2Camera::readFrame()
583 v4l2_buffer
buf = {};
584 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
585 buf.memory = V4L2_MEMORY_MMAP;
587 if (ioctl(
d->v4l2FileDescriptor, VIDIOC_DQBUF, &
buf) < 0) {
588 if (errno == ENODEV) {
595 qWarning() <<
"error calling VIDIOC_DQBUF" << errno << strerror(errno);
605 buffer->data.bytesPerLine[0] = bytesPerLine;
607 buffer->data.size[0] =
d->mappedBuffers.at(
i).size;
609 fmt.setColorSpace(colorSpace);
613 if (firstFrameTime.tv_sec == -1)
614 firstFrameTime =
buf.timestamp;
615 qint64 secs =
buf.timestamp.tv_sec - firstFrameTime.tv_sec;
616 qint64 usecs =
buf.timestamp.tv_usec - firstFrameTime.tv_usec;
617 frame.setStartTime(secs*1000000 + usecs);
618 frame.setEndTime(
frame.startTime() + frameDuration);
623void QV4L2Camera::setCameraBusy()
629void QV4L2Camera::initV4L2Controls()
631 v4l2AutoWhiteBalanceSupported =
false;
632 v4l2ColorTemperatureSupported =
false;
633 v4l2RangedFocus =
false;
634 v4l2FlashSupported =
false;
635 v4l2TorchSupported =
false;
636 QCamera::Features features;
648 if (
d->v4l2FileDescriptor == -1) {
653 qCDebug(qLV4L2Camera) <<
"FD=" <<
d->v4l2FileDescriptor;
655 struct v4l2_queryctrl queryControl;
656 ::memset(&queryControl, 0,
sizeof(queryControl));
657 queryControl.id = V4L2_CID_AUTO_WHITE_BALANCE;
659 if (::ioctl(
d->v4l2FileDescriptor, VIDIOC_QUERYCTRL, &queryControl) == 0) {
660 v4l2AutoWhiteBalanceSupported =
true;
661 setV4L2Parameter(V4L2_CID_AUTO_WHITE_BALANCE,
true);
664 ::memset(&queryControl, 0,
sizeof(queryControl));
665 queryControl.id = V4L2_CID_WHITE_BALANCE_TEMPERATURE;
666 if (::ioctl(
d->v4l2FileDescriptor, VIDIOC_QUERYCTRL, &queryControl) == 0) {
667 v4l2MinColorTemp = queryControl.minimum;
668 v4l2MaxColorTemp = queryControl.maximum;
669 v4l2ColorTemperatureSupported =
true;
673 ::memset(&queryControl, 0,
sizeof(queryControl));
674 queryControl.id = V4L2_CID_EXPOSURE_AUTO;
675 if (::ioctl(
d->v4l2FileDescriptor, VIDIOC_QUERYCTRL, &queryControl) == 0) {
676 v4l2AutoExposureSupported =
true;
679 ::memset(&queryControl, 0,
sizeof(queryControl));
680 queryControl.id = V4L2_CID_EXPOSURE_ABSOLUTE;
681 if (::ioctl(
d->v4l2FileDescriptor, VIDIOC_QUERYCTRL, &queryControl) == 0) {
682 v4l2ManualExposureSupported =
true;
683 v4l2MinExposure = queryControl.minimum;
684 v4l2MaxExposure = queryControl.maximum;
688 ::memset(&queryControl, 0,
sizeof(queryControl));
689 queryControl.id = V4L2_CID_AUTO_EXPOSURE_BIAS;
690 if (::ioctl(
d->v4l2FileDescriptor, VIDIOC_QUERYCTRL, &queryControl) == 0) {
691 v4l2MinExposureAdjustment = queryControl.minimum;
692 v4l2MaxExposureAdjustment = queryControl.maximum;
696 ::memset(&queryControl, 0,
sizeof(queryControl));
697 queryControl.id = V4L2_CID_ISO_SENSITIVITY_AUTO;
698 if (::ioctl(
d->v4l2FileDescriptor, VIDIOC_QUERYCTRL, &queryControl) == 0) {
699 queryControl.id = V4L2_CID_ISO_SENSITIVITY;
700 if (::ioctl(
d->v4l2FileDescriptor, VIDIOC_QUERYCTRL, &queryControl) == 0) {
707 ::memset(&queryControl, 0,
sizeof(queryControl));
708 queryControl.id = V4L2_CID_FOCUS_ABSOLUTE;
709 if (::ioctl(
d->v4l2FileDescriptor, VIDIOC_QUERYCTRL, &queryControl) == 0) {
710 v4l2MinExposureAdjustment = queryControl.minimum;
711 v4l2MaxExposureAdjustment = queryControl.maximum;
715 ::memset(&queryControl, 0,
sizeof(queryControl));
716 queryControl.id = V4L2_CID_AUTO_FOCUS_RANGE;
717 if (::ioctl(
d->v4l2FileDescriptor, VIDIOC_QUERYCTRL, &queryControl) == 0) {
718 v4l2RangedFocus =
true;
721 ::memset(&queryControl, 0,
sizeof(queryControl));
722 queryControl.id = V4L2_CID_FLASH_LED_MODE;
723 if (::ioctl(
d->v4l2FileDescriptor, VIDIOC_QUERYCTRL, &queryControl) == 0) {
724 v4l2FlashSupported = queryControl.minimum <= V4L2_FLASH_LED_MODE_FLASH && queryControl.maximum >= V4L2_FLASH_LED_MODE_FLASH;
725 v4l2TorchSupported = queryControl.minimum <= V4L2_FLASH_LED_MODE_TORCH && queryControl.maximum >= V4L2_FLASH_LED_MODE_TORCH;
730 ::memset(&queryControl, 0,
sizeof(queryControl));
731 queryControl.id = V4L2_CID_ZOOM_ABSOLUTE;
732 if (::ioctl(
d->v4l2FileDescriptor, VIDIOC_QUERYCTRL, &queryControl) == 0) {
733 v4l2MinZoom = queryControl.minimum;
734 v4l2MaxZoom = queryControl.maximum;
744void QV4L2Camera::closeV4L2Fd()
746 if (
d &&
d->v4l2FileDescriptor >= 0) {
750 d->v4l2FileDescriptor = -1;
755int QV4L2Camera::setV4L2ColorTemperature(
int temperature)
757 struct v4l2_control control;
758 ::memset(&control, 0,
sizeof(control));
760 if (v4l2AutoWhiteBalanceSupported) {
761 setV4L2Parameter(V4L2_CID_AUTO_WHITE_BALANCE, temperature == 0 ?
true :
false);
762 }
else if (temperature == 0) {
766 if (temperature != 0 && v4l2ColorTemperatureSupported) {
767 temperature =
qBound(v4l2MinColorTemp, temperature, v4l2MaxColorTemp);
768 if (!setV4L2Parameter(V4L2_CID_WHITE_BALANCE_TEMPERATURE,
qBound(v4l2MinColorTemp, temperature, v4l2MaxColorTemp)))
779 struct v4l2_control control{
id,
value};
787int QV4L2Camera::getV4L2Parameter(
quint32 id)
const
789 struct v4l2_control control{
id, 0};
794 return control.value;
797void QV4L2Camera::setV4L2CameraFormat()
802 v4l2_format
fmt = {};
803 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
806 fmt.fmt.pix.width =
size.width();
807 fmt.fmt.pix.height =
size.height();
809 fmt.fmt.pix.field = V4L2_FIELD_ANY;
811 qCDebug(qLV4L2Camera) <<
"setting camera format to" <<
size;
814 if (errno == EBUSY) {
818 qWarning() <<
"Couldn't set video format on v4l2 camera" << strerror(errno);
821 bytesPerLine =
fmt.fmt.pix.bytesperline;
823 switch (v4l2_colorspace(
fmt.fmt.pix.colorspace)) {
825 case V4L2_COLORSPACE_DCI_P3:
828 case V4L2_COLORSPACE_REC709:
831 case V4L2_COLORSPACE_JPEG:
834 case V4L2_COLORSPACE_SRGB:
838 case V4L2_COLORSPACE_BT2020:
843 v4l2_streamparm streamParam = {};
844 streamParam.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
846 streamParam.parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
848 streamParam.parm.capture.timeperframe = { (
uint)
num, (
uint)den };
851 frameDuration = 1000000*streamParam.parm.capture.timeperframe.numerator
852 /streamParam.parm.capture.timeperframe.denominator;
855void QV4L2Camera::initMMap()
860 v4l2_requestbuffers req = {};
862 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
863 req.memory = V4L2_MEMORY_MMAP;
868 qWarning() <<
"requesting mmap'ed buffers failed" << strerror(errno);
873 qWarning() <<
"Can't map 2 or more buffers";
877 for (uint32_t
n = 0;
n < req.count; ++
n) {
878 v4l2_buffer
buf = {};
880 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
881 buf.memory = V4L2_MEMORY_MMAP;
890 buffer.data = mmap(NULL,
buf.length, PROT_READ | PROT_WRITE, MAP_SHARED,
903void QV4L2Camera::stopCapturing()
911 enum v4l2_buf_type
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
915 qWarning() <<
"failed to stop capture";
920void QV4L2Camera::startCapturing()
929 v4l2_buffer
buf = {};
931 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
932 buf.memory = V4L2_MEMORY_MMAP;
935 qWarning() <<
"failed to set up mapped buffer";
939 enum v4l2_buf_type
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
941 qWarning() <<
"failed to start capture";
946 firstFrameTime = { -1, -1 };
IOBluetoothDevice * device
The QAbstractVideoBuffer class is an abstraction for video data. \inmodule QtMultimedia.
static const QCameraDevicePrivate * handle(const QCameraDevice &device)
The QCameraDevice class provides general information about camera devices.
bool isNull() const
Returns true if this QCameraDevice is null or invalid.
QList< QCameraFormat > videoFormats
\qmlproperty CameraFormat QtMultimedia::cameraDevice::videoFormats
QByteArray id
\qmlproperty string QtMultimedia::cameraDevice::id
The QCamera class provides interface for system camera devices.
WhiteBalanceMode
\value WhiteBalanceAuto Auto white balance mode.
TorchMode
\value TorchOff Torch is Off.
FocusMode
\value FocusModeAuto Continuous auto focus mode.
FlashMode
\value FlashOff Flash is Off.
ExposureMode
\value ExposureAuto Automatic mode.
void directoryChanged(const QString &path, QPrivateSignal)
This signal is emitted when the directory at a specified path is modified (e.g., when a file is added...
bool addPath(const QString &file)
Adds path to the file system watcher if path exists.
static QByteArray encodeName(const QString &fileName)
Converts fileName to an 8-bit encoding that you can use in native APIs.
void append(parameter_type t)
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
constexpr int height() const noexcept
Returns the height.
constexpr int width() const noexcept
Returns the width.
void activated(QSocketDescriptor socket, QSocketNotifier::Type activationEvent, QPrivateSignal)
const QChar * constData() const
Returns a pointer to the data stored in the QString.
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
QList< QCameraDevice > videoDevices() const override
QV4L2CameraDevices(QPlatformMediaIntegration *integration)
void zoomTo(float, float=-1.) override
void setManualIsoSensitivity(int) override
void setColorTemperature(int) override
bool isActive() const override
void setFocusMode(QCamera::FocusMode) override
bool setCameraFormat(const QCameraFormat &format) override
void setTorchMode(QCamera::TorchMode) override
void setFocusDistance(float) override
bool isFocusModeSupported(QCamera::FocusMode mode) const override
void setExposureMode(QCamera::ExposureMode) override
void setActive(bool active) override
bool isWhiteBalanceModeSupported(QCamera::WhiteBalanceMode mode) const override
bool isFlashReady() const override
bool resolveCameraFormat(const QCameraFormat &format)
int isoSensitivity() const override
QV4L2Camera(QCamera *parent)
void setExposureCompensation(float) override
void setFlashMode(QCamera::FlashMode) override
bool isFlashModeSupported(QCamera::FlashMode mode) const override
bool isTorchModeSupported(QCamera::TorchMode mode) const override
void setWhiteBalanceMode(QCamera::WhiteBalanceMode) override
bool isExposureModeSupported(QCamera::ExposureMode mode) const override
void setCamera(const QCameraDevice &camera) override
float exposureTime() const override
void setManualExposureTime(float) override
QV4L2VideoBuffer(QV4L2CameraBuffers *d, int index)
QVideoFrame::MapMode mapMode() const override
void unmap() override
Releases the memory mapped by the map() function.
QVideoFrame::MapMode m_mode
MapData map(QVideoFrame::MapMode mode) override
Independently maps the planes of a video buffer to memory.
QExplicitlySharedDataPointer< QV4L2CameraBuffers > d
The QVideoFrame class represents a frame of video data.
MapMode
Enumerates how a video buffer's data is mapped to system memory.
Combined button and popup list for selecting options.
constexpr const T & min(const T &a, const T &b)
QTextStream & hex(QTextStream &stream)
Calls QTextStream::setIntegerBase(16) on stream and returns stream.
static int qt_safe_open(const char *pathname, int flags, mode_t mode=0777)
static int qt_safe_close(int fd)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
int qRound(qfloat16 d) noexcept
Q_DECL_COLD_FUNCTION Q_CORE_EXPORT QString qt_error_string(int errorCode=-1)
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
constexpr const T & qBound(const T &min, const T &val, const T &max)
GLboolean GLboolean GLboolean b
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLsizei GLsizei GLfloat distance
GLenum GLuint GLenum GLsizei const GLchar * buf
GLint GLsizei GLsizei GLenum format
static constexpr QSize frameSize(const T &frame)
QScopeGuard< typename std::decay< F >::type > qScopeGuard(F &&f)
[qScopeGuard]
QLatin1StringView QLatin1String
static QVideoFrameFormat::PixelFormat formatForV4L2Format(uint32_t v4l2Format)
static const struct @727 formatMap[]
static uint32_t v4l2FormatForPixelFormat(QVideoFrameFormat::PixelFormat format)
QVideoFrameFormat::PixelFormat fmt
static bool areCamerasEqual(QList< QCameraDevice > a, QList< QCameraDevice > b)
file open(QIODevice::ReadOnly)
bool contains(const AT &t) const noexcept
QList< MappedBuffer > mappedBuffers