Revision control
Copy as Markdown
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <mediacapture/qgstreamercamera_p.h>
#include <QtMultimedia/qcameradevice.h>
#include <QtMultimedia/qmediacapturesession.h>
#include <QtMultimedia/private/qcameradevice_p.h>
#include <QtMultimedia/private/qmultimediautils_p.h>
#include <QtCore/qdebug.h>
#include <common/qgst_debug_p.h>
#include <qgstreamervideodevices_p.h>
#include <qgstreamerintegration_p.h>
#if QT_CONFIG(linux_v4l)
#include <linux/videodev2.h>
#include <private/qcore_unix_p.h>
#endif
QT_BEGIN_NAMESPACE
q23::expected<QPlatformCamera *, QString> QGstreamerCamera::create(QCamera *camera)
{
static const auto error = qGstErrorMessageIfElementsNotAvailable(
"videotestsrc", "capsfilter", "videoconvert", "videoscale", "identity");
if (error)
return q23::unexpected{ *error };
return new QGstreamerCamera(camera);
}
QGstreamerCamera::QGstreamerCamera(QCamera *camera)
: QGstreamerCameraBase(camera),
gstCameraBin{
QGstBin::create("camerabin"),
},
gstCamera{
QGstElement::createFromFactory("videotestsrc"),
},
gstCapsFilter{
QGstElement::createFromFactory("capsfilter", "videoCapsFilter"),
},
gstDecode{
QGstElement::createFromFactory("identity"),
},
gstVideoConvert{
QGstElement::createFromFactory("videoconvert", "videoConvert"),
},
gstVideoScale{
QGstElement::createFromFactory("videoscale", "videoScale"),
}
{
gstCameraBin.add(gstCamera, gstCapsFilter, gstDecode, gstVideoConvert, gstVideoScale);
qLinkGstElements(gstCamera, gstCapsFilter, gstDecode, gstVideoConvert, gstVideoScale);
gstCameraBin.addGhostPad(gstVideoScale, "src");
}
QGstreamerCamera::~QGstreamerCamera()
{
gstCameraBin.setStateSync(GST_STATE_NULL);
}
bool QGstreamerCamera::isActive() const
{
return m_active;
}
void QGstreamerCamera::setActive(bool active)
{
if (m_active == active)
return;
if (m_cameraDevice.isNull() && active)
return;
m_active = active;
Q_EMIT activeChanged(active);
}
void QGstreamerCamera::setCamera(const QCameraDevice &camera)
{
using namespace Qt::Literals;
if (m_cameraDevice == camera)
return;
m_cameraDevice = camera;
QGstElement newGstCamera;
if (camera.isNull()) {
newGstCamera = QGstElement::createFromFactory("videotestsrc");
} else {
auto *integration = static_cast<QGstreamerIntegration *>(QGstreamerIntegration::instance());
GstDevice *device = integration->videoDevice(camera.id());
if (!device) {
updateError(QCamera::Error::CameraError,
u"Failed to create GstDevice for camera: "_s
+ QString::fromUtf8(camera.id()));
return;
}
newGstCamera = QGstElement::createFromDevice(device, "camerasrc");
static const auto ioMode = [] {
bool ok = false;
int ioMode = qEnvironmentVariableIntValue("QT_GSTREAMER_V4L2SRC_IOMODE", &ok);
return ok ? std::optional(ioMode) : std::nullopt;
}();
if (ioMode && newGstCamera.factoryName() == "v4l2src")
newGstCamera.set("io-mode", *ioMode);
QUniqueGstStructureHandle properties{
gst_device_get_properties(device),
};
if (properties) {
QGstStructureView propertiesView{ properties };
if (propertiesView.name() == "v4l2deviceprovider")
m_v4l2DevicePath = QString::fromUtf8(propertiesView["device.path"].toString());
}
}
QCameraFormat f = findBestCameraFormat(camera);
m_currentCameraFormat = f;
QGstElement newGstDecode;
if (f.pixelFormat() == QVideoFrameFormat::Format_Jpeg) {
newGstDecode = QGstElement::createFromFactory(
QGstElement::findFactory("v4l2jpegdec") ? "v4l2jpegdec" : "jpegdec");
} else
newGstDecode = QGstElement::createFromFactory("identity");
auto caps = QGstCaps::fromCameraFormat(f);
updateCamera([&] {
qUnlinkGstElements(gstCamera, gstCapsFilter, gstDecode, gstVideoConvert);
gstCameraBin.stopAndRemoveElements(gstCamera, gstDecode);
gstCapsFilter.set("caps", caps);
gstCamera = std::move(newGstCamera);
gstDecode = std::move(newGstDecode);
gstCameraBin.add(gstCamera, gstDecode);
qLinkGstElements(gstCamera, gstCapsFilter, gstDecode, gstVideoConvert);
gstCameraBin.syncChildrenState();
});
updateCameraProperties();
}
bool QGstreamerCamera::setCameraFormat(const QCameraFormat &format)
{
if (!format.isNull() && !m_cameraDevice.videoFormats().contains(format))
return false;
QCameraFormat f = format;
if (f.isNull())
f = findBestCameraFormat(m_cameraDevice);
if (f == m_currentCameraFormat)
return true;
m_currentCameraFormat = f;
QGstElement newGstDecode;
if (f.pixelFormat() == QVideoFrameFormat::Format_Jpeg) {
newGstDecode = QGstElement::createFromFactory(
QGstElement::findFactory("v4l2jpegdec") ? "v4l2jpegdec" : "jpegdec");
} else
newGstDecode = QGstElement::createFromFactory("identity");
auto caps = QGstCaps::fromCameraFormat(f);
updateCamera([&] {
qUnlinkGstElements(gstCamera, gstCapsFilter, gstDecode, gstVideoConvert);
gstCameraBin.stopAndRemoveElements(gstDecode);
gstCapsFilter.set("caps", caps);
gstDecode = std::move(newGstDecode);
gstCameraBin.add(gstDecode);
qLinkGstElements(gstCamera, gstCapsFilter, gstDecode, gstVideoConvert);
gstCameraBin.syncChildrenState();
});
return true;
}
void QGstreamerCamera::updateCameraProperties()
{
#if QT_CONFIG(linux_v4l)
if (isV4L2Camera()) {
initV4L2Controls();
return;
}
#endif
#if QT_CONFIG(gstreamer_photography)
if (auto *p = photography())
gst_photography_set_white_balance_mode(p, GST_PHOTOGRAPHY_WB_MODE_AUTO);
QCamera::Features f = QCamera::Feature::ColorTemperature | QCamera::Feature::ExposureCompensation |
QCamera::Feature::IsoSensitivity | QCamera::Feature::ManualExposureTime;
supportedFeaturesChanged(f);
#endif
}
#if QT_CONFIG(gstreamer_photography)
GstPhotography *QGstreamerCamera::photography() const
{
if (gstCamera && GST_IS_PHOTOGRAPHY(gstCamera.element()))
return GST_PHOTOGRAPHY(gstCamera.element());
return nullptr;
}
#endif
void QGstreamerCamera::setFocusMode(QCamera::FocusMode mode)
{
if (mode == focusMode())
return;
#if QT_CONFIG(gstreamer_photography)
auto p = photography();
if (p) {
GstPhotographyFocusMode photographyMode = GST_PHOTOGRAPHY_FOCUS_MODE_CONTINUOUS_NORMAL;
switch (mode) {
case QCamera::FocusModeAutoNear:
photographyMode = GST_PHOTOGRAPHY_FOCUS_MODE_MACRO;
break;
case QCamera::FocusModeAutoFar:
// not quite, but hey :)
Q_FALLTHROUGH();
case QCamera::FocusModeHyperfocal:
photographyMode = GST_PHOTOGRAPHY_FOCUS_MODE_HYPERFOCAL;
break;
case QCamera::FocusModeInfinity:
photographyMode = GST_PHOTOGRAPHY_FOCUS_MODE_INFINITY;
break;
case QCamera::FocusModeManual:
photographyMode = GST_PHOTOGRAPHY_FOCUS_MODE_MANUAL;
break;
default: // QCamera::FocusModeAuto:
break;
}
if (gst_photography_set_focus_mode(p, photographyMode))
focusModeChanged(mode);
}
#endif
}
bool QGstreamerCamera::isFocusModeSupported(QCamera::FocusMode mode) const
{
#if QT_CONFIG(gstreamer_photography)
if (photography())
return true;
#endif
return mode == QCamera::FocusModeAuto;
}
void QGstreamerCamera::setFlashMode(QCamera::FlashMode mode)
{
Q_UNUSED(mode);
#if QT_CONFIG(gstreamer_photography)
if (auto *p = photography()) {
GstPhotographyFlashMode flashMode;
gst_photography_get_flash_mode(p, &flashMode);
switch (mode) {
case QCamera::FlashAuto:
flashMode = GST_PHOTOGRAPHY_FLASH_MODE_AUTO;
break;
case QCamera::FlashOff:
flashMode = GST_PHOTOGRAPHY_FLASH_MODE_OFF;
break;
case QCamera::FlashOn:
flashMode = GST_PHOTOGRAPHY_FLASH_MODE_ON;
break;
}
if (gst_photography_set_flash_mode(p, flashMode))
flashModeChanged(mode);
}
#endif
}
bool QGstreamerCamera::isFlashModeSupported(QCamera::FlashMode mode) const
{
#if QT_CONFIG(gstreamer_photography)
if (photography())
return true;
#endif
return mode == QCamera::FlashAuto;
}
bool QGstreamerCamera::isFlashReady() const
{
#if QT_CONFIG(gstreamer_photography)
if (photography())
return true;
#endif
return false;
}
void QGstreamerCamera::setExposureMode(QCamera::ExposureMode mode)
{
Q_UNUSED(mode);
#if QT_CONFIG(linux_v4l)
if (isV4L2Camera() && v4l2AutoExposureSupported && v4l2ManualExposureSupported) {
if (mode != QCamera::ExposureAuto && mode != QCamera::ExposureManual)
return;
int value = QCamera::ExposureAuto ? V4L2_EXPOSURE_AUTO : V4L2_EXPOSURE_MANUAL;
setV4L2Parameter(V4L2_CID_EXPOSURE_AUTO, value);
exposureModeChanged(mode);
return;
}
#endif
#if QT_CONFIG(gstreamer_photography)
auto *p = photography();
if (!p)
return;
GstPhotographySceneMode sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_AUTO;
switch (mode) {
case QCamera::ExposureManual:
sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_MANUAL;
break;
case QCamera::ExposurePortrait:
sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_PORTRAIT;
break;
case QCamera::ExposureSports:
sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_SPORT;
break;
case QCamera::ExposureNight:
sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_NIGHT;
break;
case QCamera::ExposureAuto:
sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_AUTO;
break;
case QCamera::ExposureLandscape:
sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_LANDSCAPE;
break;
case QCamera::ExposureSnow:
sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_SNOW;
break;
case QCamera::ExposureBeach:
sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_BEACH;
break;
case QCamera::ExposureAction:
sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_ACTION;
break;
case QCamera::ExposureNightPortrait:
sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_NIGHT_PORTRAIT;
break;
case QCamera::ExposureTheatre:
sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_THEATRE;
break;
case QCamera::ExposureSunset:
sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_SUNSET;
break;
case QCamera::ExposureSteadyPhoto:
sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_STEADY_PHOTO;
break;
case QCamera::ExposureFireworks:
sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_FIREWORKS;
break;
case QCamera::ExposureParty:
sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_PARTY;
break;
case QCamera::ExposureCandlelight:
sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_CANDLELIGHT;
break;
case QCamera::ExposureBarcode:
sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_BARCODE;
break;
default:
return;
}
if (gst_photography_set_scene_mode(p, sceneMode))
exposureModeChanged(mode);
#endif
}
bool QGstreamerCamera::isExposureModeSupported(QCamera::ExposureMode mode) const
{
if (mode == QCamera::ExposureAuto)
return true;
#if QT_CONFIG(linux_v4l)
if (isV4L2Camera() && v4l2ManualExposureSupported && v4l2AutoExposureSupported)
return mode == QCamera::ExposureManual;
#endif
#if QT_CONFIG(gstreamer_photography)
if (photography())
return true;
#endif
return false;
}
void QGstreamerCamera::setExposureCompensation(float compensation)
{
Q_UNUSED(compensation);
#if QT_CONFIG(linux_v4l)
if (isV4L2Camera() && (v4l2MinExposureAdjustment != 0 || v4l2MaxExposureAdjustment != 0)) {
int value = qBound(v4l2MinExposureAdjustment, (int)(compensation*1000), v4l2MaxExposureAdjustment);
setV4L2Parameter(V4L2_CID_AUTO_EXPOSURE_BIAS, value);
exposureCompensationChanged(value/1000.);
return;
}
#endif
#if QT_CONFIG(gstreamer_photography)
if (auto *p = photography()) {
if (gst_photography_set_ev_compensation(p, compensation))
exposureCompensationChanged(compensation);
}
#endif
}
void QGstreamerCamera::setManualIsoSensitivity(int iso)
{
Q_UNUSED(iso);
#if QT_CONFIG(linux_v4l)
if (isV4L2Camera()) {
if (!(supportedFeatures() & QCamera::Feature::IsoSensitivity))
return;
setV4L2Parameter(V4L2_CID_ISO_SENSITIVITY_AUTO, iso <= 0 ? V4L2_ISO_SENSITIVITY_AUTO : V4L2_ISO_SENSITIVITY_MANUAL);
if (iso > 0) {
iso = qBound(minIso(), iso, maxIso());
setV4L2Parameter(V4L2_CID_ISO_SENSITIVITY, iso);
}
return;
}
#endif
#if QT_CONFIG(gstreamer_photography)
if (auto *p = photography()) {
if (gst_photography_set_iso_speed(p, iso))
isoSensitivityChanged(iso);
}
#endif
}
int QGstreamerCamera::isoSensitivity() const
{
#if QT_CONFIG(linux_v4l)
if (isV4L2Camera()) {
if (!(supportedFeatures() & QCamera::Feature::IsoSensitivity))
return -1;
return getV4L2Parameter(V4L2_CID_ISO_SENSITIVITY);
}
#endif
#if QT_CONFIG(gstreamer_photography)
if (auto *p = photography()) {
guint speed = 0;
if (gst_photography_get_iso_speed(p, &speed))
return speed;
}
#endif
return 100;
}
void QGstreamerCamera::setManualExposureTime(float secs)
{
Q_UNUSED(secs);
#if QT_CONFIG(linux_v4l)
if (isV4L2Camera() && v4l2ManualExposureSupported && v4l2AutoExposureSupported) {
int exposure = qBound(v4l2MinExposure, qRound(secs*10000.), v4l2MaxExposure);
setV4L2Parameter(V4L2_CID_EXPOSURE_ABSOLUTE, exposure);
exposureTimeChanged(exposure/10000.);
return;
}
#endif
#if QT_CONFIG(gstreamer_photography)
if (auto *p = photography()) {
if (gst_photography_set_exposure(p, guint(secs*1000000)))
exposureTimeChanged(secs);
}
#endif
}
float QGstreamerCamera::exposureTime() const
{
#if QT_CONFIG(linux_v4l)
if (isV4L2Camera()) {
return getV4L2Parameter(V4L2_CID_EXPOSURE_ABSOLUTE)/10000.;
}
#endif
#if QT_CONFIG(gstreamer_photography)
if (auto *p = photography()) {
guint32 exposure = 0;
if (gst_photography_get_exposure(p, &exposure))
return exposure/1000000.;
}
#endif
return -1;
}
bool QGstreamerCamera::isWhiteBalanceModeSupported(QCamera::WhiteBalanceMode mode) const
{
if (mode == QCamera::WhiteBalanceAuto)
return true;
#if QT_CONFIG(linux_v4l)
if (isV4L2Camera()) {
if (v4l2AutoWhiteBalanceSupported && v4l2ColorTemperatureSupported)
return true;
}
#endif
#if QT_CONFIG(gstreamer_photography)
if (auto *p = photography()) {
Q_UNUSED(p);
switch (mode) {
case QCamera::WhiteBalanceAuto:
case QCamera::WhiteBalanceSunlight:
case QCamera::WhiteBalanceCloudy:
case QCamera::WhiteBalanceShade:
case QCamera::WhiteBalanceSunset:
case QCamera::WhiteBalanceTungsten:
case QCamera::WhiteBalanceFluorescent:
return true;
case QCamera::WhiteBalanceManual: {
GstPhotographyInterface *iface = GST_PHOTOGRAPHY_GET_INTERFACE(p);
if (iface->set_color_temperature && iface->get_color_temperature)
return true;
break;
}
default:
break;
}
}
#endif
return mode == QCamera::WhiteBalanceAuto;
}
void QGstreamerCamera::setWhiteBalanceMode(QCamera::WhiteBalanceMode mode)
{
Q_ASSERT(isWhiteBalanceModeSupported(mode));
#if QT_CONFIG(linux_v4l)
if (isV4L2Camera()) {
int temperature = colorTemperatureForWhiteBalance(mode);
int t = setV4L2ColorTemperature(temperature);
if (t == 0)
mode = QCamera::WhiteBalanceAuto;
whiteBalanceModeChanged(mode);
return;
}
#endif
#if QT_CONFIG(gstreamer_photography)
if (auto *p = photography()) {
GstPhotographyWhiteBalanceMode gstMode = GST_PHOTOGRAPHY_WB_MODE_AUTO;
switch (mode) {
case QCamera::WhiteBalanceSunlight:
gstMode = GST_PHOTOGRAPHY_WB_MODE_DAYLIGHT;
break;
case QCamera::WhiteBalanceCloudy:
gstMode = GST_PHOTOGRAPHY_WB_MODE_CLOUDY;
break;
case QCamera::WhiteBalanceShade:
gstMode = GST_PHOTOGRAPHY_WB_MODE_SHADE;
break;
case QCamera::WhiteBalanceSunset:
gstMode = GST_PHOTOGRAPHY_WB_MODE_SUNSET;
break;
case QCamera::WhiteBalanceTungsten:
gstMode = GST_PHOTOGRAPHY_WB_MODE_TUNGSTEN;
break;
case QCamera::WhiteBalanceFluorescent:
gstMode = GST_PHOTOGRAPHY_WB_MODE_FLUORESCENT;
break;
case QCamera::WhiteBalanceAuto:
default:
break;
}
if (gst_photography_set_white_balance_mode(p, gstMode)) {
whiteBalanceModeChanged(mode);
return;
}
}
#endif
}
void QGstreamerCamera::setColorTemperature(int temperature)
{
if (temperature == 0) {
setWhiteBalanceMode(QCamera::WhiteBalanceAuto);
return;
}
Q_ASSERT(isWhiteBalanceModeSupported(QCamera::WhiteBalanceManual));
#if QT_CONFIG(linux_v4l)
if (isV4L2Camera()) {
int t = setV4L2ColorTemperature(temperature);
if (t)
colorTemperatureChanged(t);
return;
}
#endif
#if QT_CONFIG(gstreamer_photography)
if (auto *p = photography()) {
GstPhotographyInterface *iface = GST_PHOTOGRAPHY_GET_INTERFACE(p);
Q_ASSERT(iface->set_color_temperature);
iface->set_color_temperature(p, temperature);
return;
}
#endif
}
#if QT_CONFIG(linux_v4l)
bool QGstreamerCamera::isV4L2Camera() const
{
return !m_v4l2DevicePath.isEmpty();
}
void QGstreamerCamera::initV4L2Controls()
{
using namespace QtMultimediaPrivate;
v4l2AutoWhiteBalanceSupported = false;
v4l2ColorTemperatureSupported = false;
QCamera::Features features{};
Q_ASSERT(!m_v4l2DevicePath.isEmpty());
withV4L2DeviceFileDescriptor([&](int fd) {
struct v4l2_queryctrl queryControl = {};
queryControl.id = V4L2_CID_AUTO_WHITE_BALANCE;
if (qt_safe_ioctl(fd, VIDIOC_QUERYCTRL, &queryControl) == 0) {
v4l2AutoWhiteBalanceSupported = true;
setV4L2Parameter(V4L2_CID_AUTO_WHITE_BALANCE, true);
}
queryControl = {};
queryControl.id = V4L2_CID_WHITE_BALANCE_TEMPERATURE;
if (qt_safe_ioctl(fd, VIDIOC_QUERYCTRL, &queryControl) == 0) {
v4l2MinColorTemp = queryControl.minimum;
v4l2MaxColorTemp = queryControl.maximum;
v4l2ColorTemperatureSupported = true;
features |= QCamera::Feature::ColorTemperature;
}
queryControl = {};
queryControl.id = V4L2_CID_EXPOSURE_AUTO;
if (qt_safe_ioctl(fd, VIDIOC_QUERYCTRL, &queryControl) == 0) {
v4l2AutoExposureSupported = true;
}
queryControl = {};
queryControl.id = V4L2_CID_EXPOSURE_ABSOLUTE;
if (qt_safe_ioctl(fd, VIDIOC_QUERYCTRL, &queryControl) == 0) {
v4l2ManualExposureSupported = true;
v4l2MinExposure = queryControl.minimum;
v4l2MaxExposure = queryControl.maximum;
features |= QCamera::Feature::ManualExposureTime;
}
queryControl = {};
queryControl.id = V4L2_CID_AUTO_EXPOSURE_BIAS;
if (qt_safe_ioctl(fd, VIDIOC_QUERYCTRL, &queryControl) == 0) {
v4l2MinExposureAdjustment = queryControl.minimum;
v4l2MaxExposureAdjustment = queryControl.maximum;
features |= QCamera::Feature::ExposureCompensation;
}
queryControl = {};
queryControl.id = V4L2_CID_ISO_SENSITIVITY_AUTO;
if (qt_safe_ioctl(fd, VIDIOC_QUERYCTRL, &queryControl) == 0) {
queryControl.id = V4L2_CID_ISO_SENSITIVITY;
if (qt_safe_ioctl(fd, VIDIOC_QUERYCTRL, &queryControl) == 0) {
features |= QCamera::Feature::IsoSensitivity;
minIsoChanged(queryControl.minimum);
maxIsoChanged(queryControl.minimum);
}
}
});
supportedFeaturesChanged(features);
}
int QGstreamerCamera::setV4L2ColorTemperature(int temperature)
{
if (v4l2AutoWhiteBalanceSupported) {
setV4L2Parameter(V4L2_CID_AUTO_WHITE_BALANCE, temperature == 0 ? true : false);
} else if (temperature == 0) {
temperature = 5600;
}
if (temperature != 0 && v4l2ColorTemperatureSupported) {
temperature = qBound(v4l2MinColorTemp, temperature, v4l2MaxColorTemp);
if (!setV4L2Parameter(V4L2_CID_WHITE_BALANCE_TEMPERATURE, qBound(v4l2MinColorTemp, temperature, v4l2MaxColorTemp)))
temperature = 0;
} else {
temperature = 0;
}
return temperature;
}
bool QGstreamerCamera::setV4L2Parameter(quint32 id, qint32 value)
{
return withV4L2DeviceFileDescriptor([&](int fd) {
v4l2_control control{ id, value };
if (QtMultimediaPrivate::qt_safe_ioctl(fd, VIDIOC_S_CTRL, &control) != 0) {
qWarning() << "Unable to set the V4L2 Parameter" << Qt::hex << id << "to" << value
<< qt_error_string(errno);
return false;
}
return true;
});
}
int QGstreamerCamera::getV4L2Parameter(quint32 id) const
{
return withV4L2DeviceFileDescriptor([&](int fd) {
v4l2_control control{ id, 0 };
if (QtMultimediaPrivate::qt_safe_ioctl(fd, VIDIOC_G_CTRL, &control) != 0) {
qWarning() << "Unable to get the V4L2 Parameter" << Qt::hex << id
<< qt_error_string(errno);
return 0;
}
return control.value;
});
}
#endif // QT_CONFIG(linux_v4l)
QGstreamerCustomCamera::QGstreamerCustomCamera(QObject *camera, QGstElement element)
: QGstreamerCameraBase{ camera }, gstCamera{ std::move(element) }
{
}
bool QGstreamerCustomCamera::isActive() const
{
return m_active;
}
void QGstreamerCustomCamera::setActive(bool active)
{
if (m_active == active)
return;
m_active = active;
Q_EMIT activeChanged(active);
}
QT_END_NAMESPACE