diff options
14 files changed, 1367 insertions, 462 deletions
diff --git a/src/plugins/multimedia/qnx/CMakeLists.txt b/src/plugins/multimedia/qnx/CMakeLists.txt index 18d062343..af7ca686b 100644 --- a/src/plugins/multimedia/qnx/CMakeLists.txt +++ b/src/plugins/multimedia/qnx/CMakeLists.txt @@ -5,6 +5,7 @@ qt_internal_add_plugin(QQnxMediaPlugin SOURCES SOURCES camera/qqnxcamera.cpp camera/qqnxcamera_p.h + camera/qqnxplatformcamera.cpp camera/qqnxplatformcamera_p.h camera/qqnxcameraframebuffer.cpp camera/qqnxcameraframebuffer_p.h camera/qqnximagecapture.cpp camera/qqnximagecapture_p.h common/qqnxaudioinput.cpp common/qqnxaudioinput_p.h diff --git a/src/plugins/multimedia/qnx/camera/qqnxcamera.cpp b/src/plugins/multimedia/qnx/camera/qqnxcamera.cpp index 35008be45..ec238be4f 100644 --- a/src/plugins/multimedia/qnx/camera/qqnxcamera.cpp +++ b/src/plugins/multimedia/qnx/camera/qqnxcamera.cpp @@ -46,21 +46,15 @@ #include <private/qmediastoragelocation_p.h> -static constexpr camera_focusmode_t qnxFocusMode(QCamera::FocusMode mode) +QDebug &operator<<(QDebug &d, const QQnxCamera::VideoFormat &f) { - switch (mode) { - default: - case QCamera::FocusModeAuto: - case QCamera::FocusModeAutoFar: - case QCamera::FocusModeInfinity: - return CAMERA_FOCUSMODE_CONTINUOUS_AUTO; - case QCamera::FocusModeAutoNear: - return CAMERA_FOCUSMODE_CONTINUOUS_MACRO; - case QCamera::FocusModeHyperfocal: - return CAMERA_FOCUSMODE_EDOF; - case QCamera::FocusModeManual: - return CAMERA_FOCUSMODE_MANUAL; - } + d << "VideoFormat - width=" << f.width + << "height=" << f.height + << "rotation=" << f.rotation + << "frameRate=" << f.frameRate + << "frameType=" << f.frameType; + + return d; } static QString statusToString(camera_devstatus_t status) @@ -101,10 +95,28 @@ static QString statusToString(camera_devstatus_t status) QT_BEGIN_NAMESPACE -QQnxCamera::QQnxCamera(QCamera *parent) - : QPlatformCamera(parent) +QQnxCamera::QQnxCamera(camera_unit_t unit, QObject *parent) + : QObject(parent) + , m_cameraUnit(unit) { - setCamera(QMediaDevices::defaultVideoInput()); + if (!m_handle.open(m_cameraUnit, CAMERA_MODE_RW)) + qWarning("QQnxCamera: Failed to open camera (0x%x)", m_handle.lastError()); + + if (camera_set_vf_mode(m_handle.get(), CAMERA_VFMODE_VIDEO) != CAMERA_EOK) { + qWarning("QQnxCamera: unable to configure viewfinder mode"); + return; + } + + if (camera_set_vf_property(m_handle.get(), CAMERA_IMGPROP_CREATEWINDOW, 0, + CAMERA_IMGPROP_RENDERTOWINDOW, 0) != CAMERA_EOK) { + qWarning("QQnxCamera: failed to set camera properties"); + return; + } + + updateZoomLimits(); + updateSupportedWhiteBalanceValues(); + + m_valid = true; } QQnxCamera::~QQnxCamera() @@ -112,43 +124,38 @@ QQnxCamera::~QQnxCamera() stop(); } -bool QQnxCamera::isActive() const -{ - return m_handle.isOpen() && m_viewfinderActive; -} - -void QQnxCamera::setActive(bool active) +camera_unit_t QQnxCamera::unit() const { - if (active) - start(); - else - stop(); + return m_cameraUnit; } -void QQnxCamera::start() +QString QQnxCamera::name() const { - if (isActive()) - return; + char name[CAMERA_LOCATION_NAMELEN]; - updateCameraFeatures(); - - if (camera_set_vf_property(m_handle.get(), CAMERA_IMGPROP_CREATEWINDOW, 0, - CAMERA_IMGPROP_RENDERTOWINDOW, 0) != CAMERA_EOK) { - qWarning("QQnxCamera: failed to set camera properties"); - return; + if (camera_get_location_property(m_cameraUnit, + CAMERA_LOCATION_NAME, &name, CAMERA_LOCATION_END) != CAMERA_EOK) { + qWarning("QQnxCamera: unable to obtain camera name"); + return {}; } - constexpr camera_vfmode_t mode = CAMERA_VFMODE_DEFAULT; + return QString::fromUtf8(name); +} - if (!supportedVfModes().contains(mode)) { - qWarning("QQnxCamera: unsupported viewfinder mode"); - return; - } +bool QQnxCamera::isValid() const +{ + return m_valid; +} - if (camera_set_vf_mode(m_handle.get(), mode) != CAMERA_EOK) { - qWarning("QQnxCamera: unable to configure viewfinder mode"); +bool QQnxCamera::isActive() const +{ + return m_handle.isOpen() && m_viewfinderActive; +} + +void QQnxCamera::start() +{ + if (isActive()) return; - } if (camera_start_viewfinder(m_handle.get(), viewfinderCallback, statusCallback, this) != CAMERA_EOK) { @@ -157,12 +164,6 @@ void QQnxCamera::start() } m_viewfinderActive = true; - - if (m_session) - m_videoSink = m_session->videoSink(); - - if (isVideoEncodingSupported() && m_outputUrl.isValid()) - startVideoRecording(); } void QQnxCamera::stop() @@ -177,35 +178,17 @@ void QQnxCamera::stop() qWarning("QQnxCamera: Failed to stop camera"); m_viewfinderActive = false; - - m_videoSink = nullptr; } -void QQnxCamera::setCamera(const QCameraDevice &camera) -{ - if (m_camera == camera) - return; - - stop(); - - m_handle = {}; - - m_camera = camera; - m_cameraUnit = camera_unit_t(camera.id().toUInt()); - - if (!m_handle.open(m_cameraUnit, CAMERA_MODE_RO|CAMERA_MODE_PWRITE)) - qWarning("QQnxCamera: Failed to open camera (0x%x)", m_handle.lastError()); -} - -bool QQnxCamera::setCameraFormat(const QCameraFormat &format) +bool QQnxCamera::setCameraFormat(uint32_t width, uint32_t height, double frameRate) { if (!m_handle.isOpen()) return false; const camera_error_t error = camera_set_vf_property(m_handle.get(), - CAMERA_IMGPROP_WIDTH, format.resolution().width(), - CAMERA_IMGPROP_HEIGHT, format.resolution().height(), - CAMERA_IMGPROP_FRAMERATE, format.maxFrameRate()); + CAMERA_IMGPROP_WIDTH, width, + CAMERA_IMGPROP_HEIGHT, height, + CAMERA_IMGPROP_FRAMERATE, frameRate); if (error != CAMERA_EOK) { qWarning("QQnxCamera: failed to set camera format"); @@ -215,118 +198,250 @@ bool QQnxCamera::setCameraFormat(const QCameraFormat &format) return true; } -void QQnxCamera::setCaptureSession(QPlatformMediaCaptureSession *session) +bool QQnxCamera::isFocusModeSupported(camera_focusmode_t mode) const { - if (m_session == session) - return; - m_session = static_cast<QQnxMediaCaptureSession *>(session); + return supportedFocusModes().contains(mode); } -bool QQnxCamera::isFocusModeSupported(QCamera::FocusMode mode) const +bool QQnxCamera::setFocusMode(camera_focusmode_t mode) { - return supportedFocusModes().contains(::qnxFocusMode(mode)); + if (!isActive()) + return false; + + const camera_error_t result = camera_set_focus_mode(m_handle.get(), mode); + + if (result != CAMERA_EOK) { + qWarning("QQnxCamera: Unable to set focus mode (0x%x)", result); + return false; + } + + focusModeChanged(mode); + + return true; } -void QQnxCamera::setFocusMode(QCamera::FocusMode mode) +camera_focusmode_t QQnxCamera::focusMode() const { if (!isActive()) - return; + return CAMERA_FOCUSMODE_OFF; + + camera_focusmode_t mode; - const camera_error_t result = camera_set_focus_mode(m_handle.get(), ::qnxFocusMode(mode)); + const camera_error_t result = camera_get_focus_mode(m_handle.get(), &mode); if (result != CAMERA_EOK) { qWarning("QQnxCamera: Unable to set focus mode (0x%x)", result); - return; + return CAMERA_FOCUSMODE_OFF; } - focusModeChanged(mode); + return mode; +} + +QQnxCamera::VideoFormat QQnxCamera::vfFormat() const +{ + VideoFormat f = {}; + + if (camera_get_vf_property(m_handle.get(), + CAMERA_IMGPROP_WIDTH, &f.width, + CAMERA_IMGPROP_HEIGHT, &f.height, + CAMERA_IMGPROP_ROTATION, &f.rotation, + CAMERA_IMGPROP_FRAMERATE, &f.frameRate, + CAMERA_IMGPROP_FORMAT, &f.frameType) != CAMERA_EOK) { + qWarning("QQnxCamera: Failed to query video finder frameType"); + } + + return f; +} + +void QQnxCamera::setVfFormat(const VideoFormat &f) +{ + const bool active = isActive(); + + if (active) + stop(); + + if (camera_set_vf_property(m_handle.get(), + CAMERA_IMGPROP_WIDTH, f.width, + CAMERA_IMGPROP_HEIGHT, f.height, + CAMERA_IMGPROP_ROTATION, f.rotation, + CAMERA_IMGPROP_FRAMERATE, f.frameRate, + CAMERA_IMGPROP_FORMAT, f.frameType) != CAMERA_EOK) { + qWarning("QQnxCamera: Failed to set video finder frameType"); + } + + if (active) + start(); +} + +QQnxCamera::VideoFormat QQnxCamera::recordingFormat() const +{ + VideoFormat f = {}; + + if (camera_get_video_property(m_handle.get(), + CAMERA_IMGPROP_WIDTH, &f.width, + CAMERA_IMGPROP_HEIGHT, &f.height, + CAMERA_IMGPROP_ROTATION, &f.rotation, + CAMERA_IMGPROP_FRAMERATE, &f.frameRate, + CAMERA_IMGPROP_FORMAT, &f.frameType) != CAMERA_EOK) { + qWarning("QQnxCamera: Failed to query recording frameType"); + } + + return f; +} + +void QQnxCamera::setRecordingFormat(const VideoFormat &f) +{ + if (camera_set_video_property(m_handle.get(), + CAMERA_IMGPROP_WIDTH, f.width, + CAMERA_IMGPROP_HEIGHT, f.height, + CAMERA_IMGPROP_ROTATION, f.rotation, + CAMERA_IMGPROP_FRAMERATE, f.frameRate, + CAMERA_IMGPROP_FORMAT, f.frameType) != CAMERA_EOK) { + qWarning("QQnxCamera: Failed to set recording frameType"); + } } void QQnxCamera::setCustomFocusPoint(const QPointF &point) { - // get the size of the viewfinder - int width = 0; - int height = 0; - auto result = camera_get_vf_property(m_handle.get(), - CAMERA_IMGPROP_WIDTH, width, - CAMERA_IMGPROP_HEIGHT, height); - if (result != CAMERA_EOK) + const QSize vfSize = viewFinderSize(); + + if (vfSize.isEmpty()) return; + const auto toUint32 = [](double value) { + return static_cast<uint32_t>(std::max(0.0, value)); + }; + // define a 40x40 pixel focus region around the custom focus point - camera_region_t focusRegion; - focusRegion.left = qMax(0, static_cast<int>(point.x() * width) - 20); - focusRegion.top = qMax(0, static_cast<int>(point.y() * height) - 20); - focusRegion.width = 40; - focusRegion.height = 40; + constexpr int pixelSize = 40; - result = camera_set_focus_regions(m_handle.get(), 1, &focusRegion); - if (result != CAMERA_EOK) { - qWarning("QQnxCamera: Unable to set focus region (0x%x)", result); - return; - } - auto qnxMode = ::qnxFocusMode(focusMode()); - result = camera_set_focus_mode(m_handle.get(), qnxMode); - if (result != CAMERA_EOK) { - qWarning("QQnxCamera: Unable to set focus region (0x%x)", result); + const auto left = toUint32(point.x() * vfSize.width() - pixelSize / 2); + const auto top = toUint32(point.y() * vfSize.height() - pixelSize / 2); + + camera_region_t focusRegion { + .left = left, + .top = top, + .width = pixelSize, + .height = pixelSize, + .extra = 0 + }; + + if (camera_set_focus_regions(m_handle.get(), 1, &focusRegion) != CAMERA_EOK) { + qWarning("QQnxCamera: Unable to set focus region"); return; } - customFocusPointChanged(point); + + if (setFocusMode(focusMode())) + customFocusPointChanged(point); } -void QQnxCamera::setFocusDistance(float distance) +void QQnxCamera::setManualFocusStep(int step) { - if (!isActive() || !isFocusModeSupported(QCamera::FocusModeManual)) + if (!isActive()) { + qWarning("QQnxCamera: Failed to set focus distance - view finder not active"); return; + } - const int maxDistance = maxFocusDistance(); - - if (maxDistance < 0) + if (!isFocusModeSupported(CAMERA_FOCUSMODE_MANUAL)) { + qWarning("QQnxCamera: Failed to set focus distance - manual focus mode not supported"); return; + } - const int qnxDistance = maxDistance * std::min(distance, 1.0f); - - if (camera_set_manual_focus_step(m_handle.get(), qnxDistance) != CAMERA_EOK) + if (camera_set_manual_focus_step(m_handle.get(), step) != CAMERA_EOK) qWarning("QQnxCamera: Failed to set focus distance"); } -int QQnxCamera::maxFocusDistance() const +int QQnxCamera::manualFocusStep() const { - if (!isActive() || !isFocusModeSupported(QCamera::FocusModeManual)) - return -1; + return focusStep().step; +} - int maxstep; - int step; +int QQnxCamera::maxFocusStep() const +{ + return focusStep().maxStep; +} - if (camera_get_manual_focus_step(m_handle.get(), &maxstep, &step) != CAMERA_EOK) { +QQnxCamera::FocusStep QQnxCamera::focusStep() const +{ + constexpr FocusStep invalidStep { -1, -1 }; + + if (!isActive()) { + qWarning("QQnxCamera: Failed to query max focus distance - view finder not active"); + return invalidStep; + } + + if (!isFocusModeSupported(CAMERA_FOCUSMODE_MANUAL)) { + qWarning("QQnxCamera: Failed to query max focus distance - " + "manual focus mode not supported"); + return invalidStep; + } + + FocusStep focusStep; + + if (camera_get_manual_focus_step(m_handle.get(), + &focusStep.maxStep, &focusStep.step) != CAMERA_EOK) { qWarning("QQnxCamera: Unable to query camera focus step"); - return -1; + return invalidStep; } - return maxstep; + return focusStep; } -void QQnxCamera::zoomTo(float factor, float) + +QSize QQnxCamera::viewFinderSize() const { - if (!isActive()) - return; + // get the size of the viewfinder + int width = 0; + int height = 0; - if (maxZoom <= minZoom) - return; - // QNX has an integer based API. Interpolate between the levels according to the factor we get - const float max = maxZoomFactor(); - const float min = minZoomFactor(); - if (max <= min) - return; - factor = qBound(min, factor, max) - min; - uint zoom = minZoom + (uint)qRound(factor*(maxZoom - minZoom)/(max - min)); + if (camera_get_vf_property(m_handle.get(), + CAMERA_IMGPROP_WIDTH, width, + CAMERA_IMGPROP_HEIGHT, height) != CAMERA_EOK) { + qWarning("QQnxCamera: failed to query view finder size"); + return {}; + } - auto error = camera_set_vf_property(m_handle.get(), CAMERA_IMGPROP_ZOOMFACTOR, zoom); - if (error == CAMERA_EOK) - zoomFactorChanged(factor); + return { width, height }; } -void QQnxCamera::setExposureCompensation(float ev) +uint32_t QQnxCamera::minimumZoomLevel() const +{ + return m_minZoom; +} + +uint32_t QQnxCamera::maximumZoomLevel() const +{ + return m_maxZoom; +} + +bool QQnxCamera::isSmoothZoom() const +{ + return m_smoothZoom; +} + +double QQnxCamera::zoomRatio(uint32_t zoomLevel) const +{ + double ratio; + + if (camera_get_zoom_ratio_from_zoom_level(m_handle.get(), zoomLevel, &ratio) != CAMERA_EOK) { + qWarning("QQnxCamera: failed to query zoom ratio from zoom level"); + return 0.0; + } + + return ratio; +} + +bool QQnxCamera::setZoomFactor(uint32_t factor) +{ + if (camera_set_vf_property(m_handle.get(), CAMERA_IMGPROP_ZOOMFACTOR, factor) != CAMERA_EOK) { + qWarning("QQnxCamera: failed to set zoom factor"); + return false; + } + + return true; +} + +void QQnxCamera::setEvOffset(float ev) { if (!isActive()) return; @@ -335,12 +450,12 @@ void QQnxCamera::setExposureCompensation(float ev) qWarning("QQnxCamera: Failed to setup exposure compensation"); } -int QQnxCamera::isoSensitivity() const +uint32_t QQnxCamera::manualIsoSensitivity() const { if (!isActive()) return 0; - unsigned int isoValue; + uint32_t isoValue; if (camera_get_manual_iso(m_handle.get(), &isoValue) != CAMERA_EOK) { qWarning("QQnxCamera: Failed to query ISO value"); @@ -350,18 +465,16 @@ int QQnxCamera::isoSensitivity() const return isoValue; } -void QQnxCamera::setManualIsoSensitivity(int value) +void QQnxCamera::setManualIsoSensitivity(uint32_t value) { if (!isActive()) return; - const unsigned int isoValue = std::max(0, value); - - if (camera_set_manual_iso(m_handle.get(), isoValue) != CAMERA_EOK) + if (camera_set_manual_iso(m_handle.get(), value) != CAMERA_EOK) qWarning("QQnxCamera: Failed to set ISO value"); } -void QQnxCamera::setManualExposureTime(float seconds) +void QQnxCamera::setManualExposureTime(double seconds) { if (!isActive()) return; @@ -370,95 +483,120 @@ void QQnxCamera::setManualExposureTime(float seconds) qWarning("QQnxCamera: Failed to set exposure time"); } -float QQnxCamera::exposureTime() const +double QQnxCamera::manualExposureTime() const { if (!isActive()) - return 0; + return 0.0; double shutterSpeed; if (camera_get_manual_shutter_speed(m_handle.get(), &shutterSpeed) != CAMERA_EOK) { qWarning("QQnxCamera: Failed to get exposure time"); - return 0; + return 0.0; } - return static_cast<float>(shutterSpeed); + return shutterSpeed; } -bool QQnxCamera::isWhiteBalanceModeSupported(QCamera::WhiteBalanceMode mode) const +bool QQnxCamera::hasFeature(camera_feature_t feature) const { - if (!whiteBalanceModesChecked) { - whiteBalanceModesChecked = true; - unsigned numWhiteBalanceValues = 0; - auto error = camera_get_supported_manual_white_balance_values(m_handle.get(), 0, &numWhiteBalanceValues, - nullptr, &continuousColorTemperatureSupported); - if (error == CAMERA_EOK) { - manualColorTemperatureValues.resize(numWhiteBalanceValues); - auto error = camera_get_supported_manual_white_balance_values(m_handle.get(), numWhiteBalanceValues, &numWhiteBalanceValues, - manualColorTemperatureValues.data(), - &continuousColorTemperatureSupported); + return camera_has_feature(m_handle.get(), feature); +} - minColorTemperature = 1024*1014; // large enough :) - for (int temp : qAsConst(manualColorTemperatureValues)) { - minColorTemperature = qMin(minColorTemperature, temp); - maxColorTemperature = qMax(maxColorTemperature, temp); - } - } else { - maxColorTemperature = 0; - } +void QQnxCamera::setWhiteBalanceMode(camera_whitebalancemode_t mode) +{ + if (!isActive()) + return; + + if (camera_set_whitebalance_mode(m_handle.get(), mode) != CAMERA_EOK) + qWarning("QQnxCamera: failed to set whitebalance mode"); +} + +camera_whitebalancemode_t QQnxCamera::whiteBalanceMode() const +{ + if (!isActive()) + return CAMERA_WHITEBALANCEMODE_OFF; + + camera_whitebalancemode_t mode; + + if (camera_get_whitebalance_mode(m_handle.get(), &mode) != CAMERA_EOK) { + qWarning("QQnxCamera: failed to get white balance mode"); + return CAMERA_WHITEBALANCEMODE_OFF; } - if (maxColorTemperature != 0) - return true; - return mode == QCamera::WhiteBalanceAuto; + return mode; } -void QQnxCamera::setWhiteBalanceMode(QCamera::WhiteBalanceMode mode) +void QQnxCamera::setManualWhiteBalance(uint32_t value) { - if (mode == QCamera::WhiteBalanceAuto) { - camera_set_whitebalance_mode(m_handle.get(), CAMERA_WHITEBALANCEMODE_AUTO); + if (!isActive()) return; - } - camera_set_whitebalance_mode(m_handle.get(), CAMERA_WHITEBALANCEMODE_MANUAL); - setColorTemperature(colorTemperatureForWhiteBalance(mode)); + + if (camera_set_manual_white_balance(m_handle.get(), value) != CAMERA_EOK) + qWarning("QQnxCamera: failed to set manual white balance"); } -void QQnxCamera::setColorTemperature(int temperature) +uint32_t QQnxCamera::manualWhiteBalance() const { + if (!isActive()) + return 0; - if (maxColorTemperature == 0) - return; + uint32_t value; - unsigned bestTemp = 0; - if (!continuousColorTemperatureSupported) { - // find the closest match - int delta = 1024*1024; - for (unsigned temp : qAsConst(manualColorTemperatureValues)) { - int d = qAbs(int(temp) - temperature); - if (d < delta) { - bestTemp = temp; - delta = d; - } - } - } else { - bestTemp = (unsigned)qBound(minColorTemperature, temperature, maxColorTemperature); + if (camera_get_manual_white_balance(m_handle.get(), &value) != CAMERA_EOK) { + qWarning("QQnxCamera: failed to get manual white balance"); + return 0; } - auto error = camera_set_manual_white_balance(m_handle.get(), bestTemp); + return value; } -void QQnxCamera::startVideoRecording() +bool QQnxCamera::startVideoRecording(const QString &filename) { - const QString container = m_encoderSettings.mimeType().preferredSuffix(); - const QString location = QMediaStorageLocation::generateFileName(m_outputUrl.toLocalFile(), - QStandardPaths::MoviesLocation, container); + // when preview is video, we must ensure that the recording properties + // match the view finder properties + if (hasFeature(CAMERA_FEATURE_PREVIEWISVIDEO)) { + VideoFormat newFormat = vfFormat(); - if (camera_start_video(m_handle.get(), qPrintable(location), - nullptr, nullptr, nullptr) != CAMERA_EOK) { - qWarning("QQnxCamera: failed to start video encoding"); - } else { + const QList<camera_frametype_t> recordingTypes = supportedRecordingFrameTypes(); + + // find a suitable matching frame type in case the current view finder + // frametype is not supported + if (newFormat.frameType != recordingFormat().frameType + && !recordingTypes.contains(newFormat.frameType)) { + + bool found = false; + + for (const camera_frametype_t type : supportedVfFrameTypes()) { + if (recordingTypes.contains(type)) { + newFormat.frameType = type; + found = true; + break; + } + } + + if (found) { + m_originalVfFormat = vfFormat(); + + // reconfigure and restart the view finder + setVfFormat(newFormat); + } else { + qWarning("QQnxCamera: failed to find suitable frame type for recording - aborting"); + return false; + } + } + + setRecordingFormat(newFormat); + } + + if (camera_start_video(m_handle.get(), qPrintable(filename), + nullptr, nullptr, nullptr) == CAMERA_EOK) { m_recordingVideo = true; + } else { + qWarning("QQnxCamera: failed to start video encoding"); } + + return m_recordingVideo; } void QQnxCamera::stopVideoRecording() @@ -467,6 +605,12 @@ void QQnxCamera::stopVideoRecording() if (camera_stop_video(m_handle.get()) != CAMERA_EOK) qWarning("QQnxCamera: error when stopping video recording"); + + // restore original vf format + if (m_originalVfFormat) { + setVfFormat(*m_originalVfFormat); + m_originalVfFormat.reset(); + } } bool QQnxCamera::isVideoEncodingSupported() const @@ -477,47 +621,50 @@ bool QQnxCamera::isVideoEncodingSupported() const return camera_has_feature(m_handle.get(), CAMERA_FEATURE_VIDEO); } -void QQnxCamera::setOutputUrl(const QUrl &url) +camera_handle_t QQnxCamera::handle() const { - m_outputUrl = url; + return m_handle.get(); } -void QQnxCamera::setMediaEncoderSettings(const QMediaEncoderSettings &settings) +void QQnxCamera::updateZoomLimits() { - m_encoderSettings = settings; -} + bool smooth; -camera_handle_t QQnxCamera::handle() const -{ - return m_handle.get(); + if (camera_get_zoom_limits(m_handle.get(), &m_minZoom, &m_maxZoom, &smooth) != CAMERA_EOK) { + qWarning("QQnxCamera: failed to update zoom limits - using default values"); + m_minZoom = m_maxZoom = 0; + } } -void QQnxCamera::updateCameraFeatures() +void QQnxCamera::updateSupportedWhiteBalanceValues() { - whiteBalanceModesChecked = false; + uint32_t numSupported = 0; - bool smooth; - const camera_error_t error = camera_get_zoom_limits(m_handle.get(), - &minZoom, &maxZoom, &smooth); - - if (error == CAMERA_EOK) { - double level; - camera_get_zoom_ratio_from_zoom_level(m_handle.get(), minZoom, &level); - minimumZoomFactorChanged(level); - camera_get_zoom_ratio_from_zoom_level(m_handle.get(), maxZoom, &level); - maximumZoomFactorChanged(level); - } else { - minZoom = maxZoom = 1; + const camera_error_t result = camera_get_supported_manual_white_balance_values( + m_handle.get(), 0, &numSupported, nullptr, &m_continuousWhiteBalanceValues); + + if (result != CAMERA_EOK) { + if (result == CAMERA_EOPNOTSUPP) + qWarning("QQnxCamera: white balance not supported"); + else + qWarning("QQnxCamera: unable to query manual white balance value count"); + + m_supportedWhiteBalanceValues.clear(); + + return; } - QCamera::Features features = {}; + m_supportedWhiteBalanceValues.resize(numSupported); - if (camera_has_feature(m_handle.get(), CAMERA_FEATURE_REGIONFOCUS)) - features |= QCamera::Feature::CustomFocusPoint; + if (camera_get_supported_manual_white_balance_values(m_handle.get(), + m_supportedWhiteBalanceValues.size(), + &numSupported, + m_supportedWhiteBalanceValues.data(), + &m_continuousWhiteBalanceValues) != CAMERA_EOK) { + qWarning("QQnxCamera: unable to query manual white balance values"); - minimumZoomFactorChanged(minZoom); - maximumZoomFactorChanged(maxZoom); - supportedFeaturesChanged(features); + m_supportedWhiteBalanceValues.clear(); + } } QList<camera_vfmode_t> QQnxCamera::supportedVfModes() const @@ -530,19 +677,78 @@ QList<camera_res_t> QQnxCamera::supportedVfResolutions() const return queryValues(camera_get_supported_vf_resolutions); } +QList<camera_frametype_t> QQnxCamera::supportedVfFrameTypes() const +{ + return queryValues(camera_get_supported_vf_frame_types); +} + QList<camera_focusmode_t> QQnxCamera::supportedFocusModes() const { return queryValues(camera_get_focus_modes); } +QList<double> QQnxCamera::specifiedVfFrameRates(camera_frametype_t frameType, + camera_res_t resolution) const +{ + uint32_t numSupported = 0; + + if (camera_get_specified_vf_framerates(m_handle.get(), frameType, resolution, + 0, &numSupported, nullptr, nullptr) != CAMERA_EOK) { + qWarning("QQnxCamera: unable to query specified framerates count"); + return {}; + } + + QList<double> values(numSupported); + + if (camera_get_specified_vf_framerates(m_handle.get(), frameType, resolution, + values.size(), &numSupported, values.data(), nullptr) != CAMERA_EOK) { + qWarning("QQnxCamera: unable to query specified framerates values"); + return {}; + } + + return values; +} + +QList<camera_frametype_t> QQnxCamera::supportedRecordingFrameTypes() const +{ + return queryValues(camera_get_video_frame_types); +} + +QList<uint32_t> QQnxCamera::supportedWhiteBalanceValues() const +{ + return m_supportedWhiteBalanceValues; +} + +bool QQnxCamera::hasContinuousWhiteBalanceValues() const +{ + return m_continuousWhiteBalanceValues; +} + +QList<camera_unit_t> QQnxCamera::supportedUnits() +{ + unsigned int numSupported = 0; + + if (camera_get_supported_cameras(0, &numSupported, nullptr) != CAMERA_EOK) { + qWarning("QQnxCamera: failed to query supported camera unit count"); + return {}; + } + + QList<camera_unit_t> cameraUnits(numSupported); + + if (camera_get_supported_cameras(cameraUnits.size(), &numSupported, + cameraUnits.data()) != CAMERA_EOK) { + qWarning("QQnxCamera: failed to enumerate supported camera units"); + return {}; + } + + return cameraUnits; +} + template <typename T, typename U> QList<T> QQnxCamera::queryValues(QueryFuncPtr<T,U> func) const { static_assert(std::is_integral_v<U>, "Parameter U must be of integral type"); - if (!isActive()) - return {}; - U numSupported = 0; if (func(m_handle.get(), 0, &numSupported, nullptr) != CAMERA_EOK) { @@ -562,9 +768,6 @@ QList<T> QQnxCamera::queryValues(QueryFuncPtr<T,U> func) const void QQnxCamera::handleVfBuffer(camera_buffer_t *buffer) { - if (!m_videoSink) - return; - // process the frame on this thread before locking the mutex auto frame = std::make_unique<QQnxCameraFrameBuffer>(buffer); @@ -573,9 +776,8 @@ void QQnxCamera::handleVfBuffer(camera_buffer_t *buffer) m_currentFrame = std::move(frame); m_currentFrameMutex.unlock(); - QMetaObject::invokeMethod(this, "processFrame", Qt::QueuedConnection); + Q_EMIT frameAvailable(); } - } void QQnxCamera::handleVfStatus(camera_devstatus_t status, uint16_t extraData) @@ -590,34 +792,46 @@ void QQnxCamera::handleStatusChange(camera_devstatus_t status, uint16_t extraDat Q_UNUSED(extraData); switch (status) { - case CAMERA_STATUS_DISCONNECTED: - case CAMERA_STATUS_POWERDOWN: - case CAMERA_STATUS_VIDEOVF: + case CAMERA_STATUS_BUFFER_UNDERFLOW: + case CAMERA_STATUS_CAPTURECOMPLETE: case CAMERA_STATUS_CAPTURE_ABORTED: + case CAMERA_STATUS_CONNECTED: + case CAMERA_STATUS_DISCONNECTED: + case CAMERA_STATUS_FILESIZE_ERROR: + case CAMERA_STATUS_FILESIZE_LIMIT_WARNING: case CAMERA_STATUS_FILESIZE_WARNING: + case CAMERA_STATUS_FLASH_LEVEL_CHANGE: case CAMERA_STATUS_FOCUS_CHANGE: - case CAMERA_STATUS_RESOURCENOTAVAIL: - case CAMERA_STATUS_VIEWFINDER_ERROR: + case CAMERA_STATUS_FRAME_DROPPED: + case CAMERA_STATUS_LOWLIGHT: case CAMERA_STATUS_MM_ERROR: - case CAMERA_STATUS_FILESIZE_ERROR: case CAMERA_STATUS_NOSPACE_ERROR: - case CAMERA_STATUS_BUFFER_UNDERFLOW: - Q_EMIT(status, ::statusToString(status)); - stop(); - break; - default: + case CAMERA_STATUS_PHOTOVF: + case CAMERA_STATUS_POWERDOWN: + case CAMERA_STATUS_POWERUP: + case CAMERA_STATUS_RESOURCENOTAVAIL: + case CAMERA_STATUS_UNKNOWN: + case CAMERA_STATUS_VIDEOLIGHT_CHANGE: + case CAMERA_STATUS_VIDEOLIGHT_LEVEL_CHANGE: + case CAMERA_STATUS_VIDEOVF: + case CAMERA_STATUS_VIDEO_PAUSE: + case CAMERA_STATUS_VIDEO_RESUME: + case CAMERA_STATUS_VIEWFINDER_ACTIVE: + case CAMERA_STATUS_VIEWFINDER_ERROR: + case CAMERA_STATUS_VIEWFINDER_FREEZE: + case CAMERA_STATUS_VIEWFINDER_SUSPEND: + case CAMERA_STATUS_VIEWFINDER_UNFREEZE: + case CAMERA_STATUS_VIEWFINDER_UNSUSPEND: + qDebug() << "QQnxCamera:" << ::statusToString(status); break; } } -void QQnxCamera::processFrame() +std::unique_ptr<QQnxCameraFrameBuffer> QQnxCamera::takeCurrentFrame() { QMutexLocker l(&m_currentFrameMutex); - const QVideoFrame actualFrame(m_currentFrame.get(), - QVideoFrameFormat(m_currentFrame->size(), m_currentFrame->pixelFormat())); - - m_videoSink->setVideoFrame(actualFrame); + return std::move(m_currentFrame); } void QQnxCamera::viewfinderCallback(camera_handle_t handle, camera_buffer_t *buffer, void *arg) diff --git a/src/plugins/multimedia/qnx/camera/qqnxcamera_p.h b/src/plugins/multimedia/qnx/camera/qqnxcamera_p.h index aab112000..540d8bf4c 100644 --- a/src/plugins/multimedia/qnx/camera/qqnxcamera_p.h +++ b/src/plugins/multimedia/qnx/camera/qqnxcamera_p.h @@ -36,8 +36,8 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ -#ifndef QQnxCamera_H -#define QQnxCamera_H +#ifndef QQNXCAMERA_H +#define QQNXCAMERA_H // // W A R N I N G @@ -50,17 +50,18 @@ // We mean it. // -#include <private/qplatformcamera_p.h> -#include <private/qplatformmediarecorder_p.h> +#include "qqnxcamerahandle_p.h" #include <QtCore/qlist.h> #include <QtCore/qmutex.h> +#include <QtCore/qobject.h> #include <QtCore/qurl.h> #include <camera/camera_api.h> #include <camera/camera_3a.h> #include <memory> +#include <optional> QT_BEGIN_NAMESPACE @@ -68,156 +69,128 @@ class QQnxCameraFrameBuffer; class QQnxMediaCaptureSession; class QQnxVideoSink; -class CameraHandle +class QQnxCamera : public QObject { + Q_OBJECT public: - CameraHandle() = default; + explicit QQnxCamera(camera_unit_t unit, QObject *parent = nullptr); + ~QQnxCamera(); - explicit CameraHandle(camera_handle_t h) - : m_handle (h) {} + camera_unit_t unit() const; - explicit CameraHandle(CameraHandle &&other) - : m_handle(other.m_handle) - , m_lastError(other.m_lastError) - { - other = CameraHandle(); - } + QString name() const; - CameraHandle(const CameraHandle&) = delete; + bool isValid() const; - CameraHandle& operator=(CameraHandle&& other) - { - m_handle = other.m_handle; - m_lastError = other.m_lastError; + bool isActive() const; + void start(); + void stop(); - other = CameraHandle(); + bool startVideoRecording(const QString &filename); + void stopVideoRecording(); - return *this; - } + bool setCameraFormat(uint32_t width, uint32_t height, double frameRate); - ~CameraHandle() - { - close(); - } + bool isFocusModeSupported(camera_focusmode_t mode) const; + bool setFocusMode(camera_focusmode_t mode); + camera_focusmode_t focusMode() const; - bool open(camera_unit_t unit, uint32_t mode) - { - if (isOpen()) { - m_lastError = CAMERA_EALREADY; - return false; - } + void setCustomFocusPoint(const QPointF &point); - return cacheError(camera_open, unit, mode, &m_handle); - } + void setManualFocusStep(int step); + int manualFocusStep() const; + int maxFocusStep() const; - bool close() - { - if (!isOpen()) - return true; + QSize viewFinderSize() const; - const bool success = cacheError(camera_close, m_handle); - m_handle = CAMERA_HANDLE_INVALID; + uint32_t minimumZoomLevel() const; + uint32_t maximumZoomLevel() const; + bool isSmoothZoom() const; + double zoomRatio(uint32_t zoomLevel) const; + bool setZoomFactor(uint32_t factor); - return success; - } + void setEvOffset(float ev); - camera_handle_t get() const - { - return m_handle; - } + uint32_t manualIsoSensitivity() const; + void setManualIsoSensitivity(uint32_t value); + void setManualExposureTime(double seconds); + double manualExposureTime() const; - bool isOpen() const - { - return m_handle != CAMERA_HANDLE_INVALID; - } + void setWhiteBalanceMode(camera_whitebalancemode_t mode); + camera_whitebalancemode_t whiteBalanceMode() const; - camera_error_t lastError() const - { - return m_lastError; - } - -private: - template <typename Func, typename ...Args> - bool cacheError(Func f, Args &&...args) - { - m_lastError = f(std::forward<Args>(args)...); - - return m_lastError == CAMERA_EOK; - } + void setManualWhiteBalance(uint32_t value); + uint32_t manualWhiteBalance() const; - camera_handle_t m_handle = CAMERA_HANDLE_INVALID; - camera_error_t m_lastError = CAMERA_EOK; -}; + bool hasFeature(camera_feature_t feature) const; + camera_handle_t handle() const; -class QQnxCamera : public QPlatformCamera -{ - Q_OBJECT -public: - explicit QQnxCamera(QCamera *parent); - ~QQnxCamera(); - - bool isActive() const override; - void setActive(bool active) override; - void start(); - void stop(); + QList<camera_vfmode_t> supportedVfModes() const; + QList<camera_res_t> supportedVfResolutions() const; + QList<camera_frametype_t> supportedVfFrameTypes() const; + QList<camera_focusmode_t> supportedFocusModes() const; + QList<double> specifiedVfFrameRates(camera_frametype_t frameType, + camera_res_t resolution) const; - void setCamera(const QCameraDevice &camera) override; + QList<camera_frametype_t> supportedRecordingFrameTypes() const; - bool setCameraFormat(const QCameraFormat &format) override; + QList<uint32_t> supportedWhiteBalanceValues() const; - void setCaptureSession(QPlatformMediaCaptureSession *session) override; + bool hasContinuousWhiteBalanceValues() const; - bool isFocusModeSupported(QCamera::FocusMode mode) const override; - void setFocusMode(QCamera::FocusMode mode) override; + static QList<camera_unit_t> supportedUnits(); - void setCustomFocusPoint(const QPointF &point) override; + std::unique_ptr<QQnxCameraFrameBuffer> takeCurrentFrame(); - void setFocusDistance(float distance) override; +Q_SIGNALS: + void focusModeChanged(camera_focusmode_t mode); + void customFocusPointChanged(const QPointF &point); + void minimumZoomFactorChanged(double factor); - int maxFocusDistance() const; + double maximumZoomFactorChanged(double factor); - void zoomTo(float /*newZoomFactor*/, float /*rate*/ = -1.) override; + void frameAvailable(); - void setExposureCompensation(float ev) override; +private: + struct FocusStep + { + int step; // current step + int maxStep; // max supported step + }; - int isoSensitivity() const override; - void setManualIsoSensitivity(int value) override; - void setManualExposureTime(float seconds) override; - float exposureTime() const override; + FocusStep focusStep() const; - bool isWhiteBalanceModeSupported(QCamera::WhiteBalanceMode mode) const override; - void setWhiteBalanceMode(QCamera::WhiteBalanceMode /*mode*/) override; - void setColorTemperature(int /*temperature*/) override; + struct VideoFormat + { + uint32_t width; + uint32_t height; + uint32_t rotation; + double frameRate; + camera_frametype_t frameType; + }; - void setOutputUrl(const QUrl &url); - void setMediaEncoderSettings(const QMediaEncoderSettings &settings); + friend QDebug &operator<<(QDebug&, const VideoFormat&); - camera_handle_t handle() const; + VideoFormat vfFormat() const; + void setVfFormat(const VideoFormat &format); - QList<camera_vfmode_t> supportedVfModes() const; - QList<camera_res_t> supportedVfResolutions() const; - QList<camera_focusmode_t> supportedFocusModes() const; + VideoFormat recordingFormat() const; + void setRecordingFormat(const VideoFormat &format); -private: - void updateCameraFeatures(); + void updateZoomLimits(); + void updateSupportedWhiteBalanceValues(); void setColorTemperatureInternal(unsigned temp); - void startVideoRecording(); - void stopVideoRecording(); - bool isVideoEncodingSupported() const; void handleVfBuffer(camera_buffer_t *buffer); - Q_INVOKABLE void processFrame(); - // viewfinder callback void handleVfStatus(camera_devstatus_t status, uint16_t extraData); // our handler running on main thread - void handleStatusChange(camera_devstatus_t status, uint16_t extraData); - + Q_INVOKABLE void handleStatusChange(camera_devstatus_t status, uint16_t extraData); template <typename T, typename U> using QueryFuncPtr = camera_error_t (*)(camera_handle_t, U, U *, T *); @@ -225,9 +198,6 @@ private: template <typename T, typename U> QList<T> queryValues(QueryFuncPtr<T, U> func) const; - template <typename ...Args> - using CamAPIFunc = camera_error_t (*)(camera_handle_t, Args...); - static void viewfinderCallback(camera_handle_t handle, camera_buffer_t *buffer, void *arg); @@ -235,35 +205,32 @@ private: uint16_t extraData, void *arg); QQnxMediaCaptureSession *m_session = nullptr; - QQnxVideoSink *m_videoSink = nullptr; - QCameraDevice m_camera; camera_unit_t m_cameraUnit = CAMERA_UNIT_NONE; - QUrl m_outputUrl; - - QMediaEncoderSettings m_encoderSettings; - - CameraHandle m_handle; + QQnxCameraHandle m_handle; - uint minZoom = 1; - uint maxZoom = 1; - mutable bool whiteBalanceModesChecked = false; - mutable bool continuousColorTemperatureSupported = false; - mutable int minColorTemperature = 0; - mutable int maxColorTemperature = 0; - mutable QList<unsigned> manualColorTemperatureValues; + uint32_t m_minZoom = 0; + uint32_t m_maxZoom = 0; QMutex m_currentFrameMutex; + QList<uint32_t> m_supportedWhiteBalanceValues; + std::unique_ptr<QQnxCameraFrameBuffer> m_currentFrame; + std::optional<VideoFormat> m_originalVfFormat; + bool m_viewfinderActive = false; bool m_recordingVideo = false; + bool m_valid = false; + bool m_smoothZoom = false; + bool m_continuousWhiteBalanceValues = false; }; QT_END_NAMESPACE Q_DECLARE_METATYPE(camera_devstatus_t) +Q_DECLARE_METATYPE(uint16_t) #endif diff --git a/src/plugins/multimedia/qnx/camera/qqnxcamerahandle_p.h b/src/plugins/multimedia/qnx/camera/qqnxcamerahandle_p.h new file mode 100644 index 000000000..1a7ec1d8e --- /dev/null +++ b/src/plugins/multimedia/qnx/camera/qqnxcamerahandle_p.h @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QQNXCAMERAHANDLE_P_H +#define QQNXCAMERAHANDLE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <camera/camera_api.h> + +#include <utility> + +class QQnxCameraHandle +{ +public: + QQnxCameraHandle() = default; + + explicit QQnxCameraHandle(camera_handle_t h) + : m_handle (h) {} + + explicit QQnxCameraHandle(QQnxCameraHandle &&other) + : m_handle(other.m_handle) + , m_lastError(other.m_lastError) + { + other = QQnxCameraHandle(); + } + + QQnxCameraHandle(const QQnxCameraHandle&) = delete; + + QQnxCameraHandle& operator=(QQnxCameraHandle&& other) + { + m_handle = other.m_handle; + m_lastError = other.m_lastError; + + other = QQnxCameraHandle(); + + return *this; + } + + ~QQnxCameraHandle() + { + close(); + } + + bool open(camera_unit_t unit, uint32_t mode) + { + if (isOpen()) { + m_lastError = CAMERA_EALREADY; + return false; + } + + return cacheError(camera_open, unit, mode, &m_handle); + } + + bool close() + { + if (!isOpen()) + return true; + + const bool success = cacheError(camera_close, m_handle); + m_handle = CAMERA_HANDLE_INVALID; + + return success; + } + + camera_handle_t get() const + { + return m_handle; + } + + bool isOpen() const + { + return m_handle != CAMERA_HANDLE_INVALID; + } + + camera_error_t lastError() const + { + return m_lastError; + } + +private: + template <typename Func, typename ...Args> + bool cacheError(Func f, Args &&...args) + { + m_lastError = f(std::forward<Args>(args)...); + + return m_lastError == CAMERA_EOK; + } + + camera_handle_t m_handle = CAMERA_HANDLE_INVALID; + camera_error_t m_lastError = CAMERA_EOK; +}; + +#endif diff --git a/src/plugins/multimedia/qnx/camera/qqnximagecapture.cpp b/src/plugins/multimedia/qnx/camera/qqnximagecapture.cpp index 6557267b2..3d9ad1193 100644 --- a/src/plugins/multimedia/qnx/camera/qqnximagecapture.cpp +++ b/src/plugins/multimedia/qnx/camera/qqnximagecapture.cpp @@ -38,6 +38,7 @@ ****************************************************************************/ #include "qqnximagecapture_p.h" +#include "qqnxplatformcamera_p.h" #include "qqnxmediacapturesession_p.h" #include "qqnxcamera_p.h" #include "qfile.h" @@ -55,7 +56,7 @@ bool QQnxImageCapture::isReadyForCapture() const { if (!m_session) return false; - auto *camera = static_cast<QQnxCamera *>(m_session->camera()); + auto *camera = static_cast<QQnxPlatformCamera *>(m_session->camera()); // ### add can take photo return camera && camera->isActive(); } @@ -141,7 +142,7 @@ static void imageCaptureImageCallback(camera_handle_t handle, camera_buffer_t *b int QQnxImageCapture::capture(const QString &fileName) { - auto *camera = static_cast<QQnxCamera *>(m_session->camera()); + auto *camera = static_cast<QQnxPlatformCamera *>(m_session->camera()); // ### add can take photo if (!camera || !camera->isActive()) { emit error(-1, QImageCapture::NotReadyError, QPlatformImageCapture::msgCameraNotReady()); diff --git a/src/plugins/multimedia/qnx/camera/qqnxplatformcamera.cpp b/src/plugins/multimedia/qnx/camera/qqnxplatformcamera.cpp new file mode 100644 index 000000000..ede2f4c88 --- /dev/null +++ b/src/plugins/multimedia/qnx/camera/qqnxplatformcamera.cpp @@ -0,0 +1,447 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Research In Motion +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "qqnxplatformcamera_p.h" +#include "qqnxcameraframebuffer_p.h" +#include "qqnxmediacapturesession_p.h" +#include "qqnxvideosink_p.h" + +#include <qcameradevice.h> +#include <qmediadevices.h> + +#include <private/qmediastoragelocation_p.h> + +#include <camera/camera_api.h> +#include <camera/camera_3a.h> + +#include <algorithm> +#include <array> + +#include <dlfcn.h> + +struct FocusModeMapping +{ + QCamera::FocusMode qt; + camera_focusmode_t qnx; +}; + +constexpr std::array<FocusModeMapping, 6> focusModes {{ + { QCamera::FocusModeAuto, CAMERA_FOCUSMODE_CONTINUOUS_AUTO }, + { QCamera::FocusModeAutoFar, CAMERA_FOCUSMODE_CONTINUOUS_AUTO }, + { QCamera::FocusModeInfinity, CAMERA_FOCUSMODE_CONTINUOUS_AUTO }, + { QCamera::FocusModeAutoNear, CAMERA_FOCUSMODE_CONTINUOUS_MACRO }, + { QCamera::FocusModeHyperfocal, CAMERA_FOCUSMODE_EDOF }, + { QCamera::FocusModeManual, CAMERA_FOCUSMODE_MANUAL }, +}}; + +template <typename Mapping, typename From, typename To, size_t N> +static constexpr To convert(const std::array<Mapping, N> &mapping, + From Mapping::* from, To Mapping::* to, From value, To defaultValue) +{ + for (const Mapping &m : mapping) { + const auto fromValue = m.*from; + const auto toValue = m.*to; + + if (value == fromValue) + return toValue; + } + + return defaultValue; +} + +static constexpr camera_focusmode_t qnxFocusMode(QCamera::FocusMode mode) +{ + return convert(focusModes, &FocusModeMapping::qt, + &FocusModeMapping::qnx, mode, CAMERA_FOCUSMODE_CONTINUOUS_AUTO); +} + +static constexpr QCamera::FocusMode qtFocusMode(camera_focusmode_t mode) +{ + return convert(focusModes, &FocusModeMapping::qnx, + &FocusModeMapping::qt, mode, QCamera::FocusModeAuto); +} + +QT_BEGIN_NAMESPACE + +QQnxPlatformCamera::QQnxPlatformCamera(QCamera *parent) + : QPlatformCamera(parent) +{ + if (parent) + setCamera(parent->cameraDevice()); + else + setCamera(QMediaDevices::defaultVideoInput()); +} + +QQnxPlatformCamera::~QQnxPlatformCamera() +{ + stop(); +} + +bool QQnxPlatformCamera::isActive() const +{ + return m_qnxCamera && m_qnxCamera->isActive(); +} + +void QQnxPlatformCamera::setActive(bool active) +{ + if (active) + start(); + else + stop(); +} + +void QQnxPlatformCamera::start() +{ + if (!m_qnxCamera || isActive()) + return; + + if (m_session) + m_videoSink = m_session->videoSink(); + + m_qnxCamera->start(); + + Q_EMIT activeChanged(true); +} + +void QQnxPlatformCamera::stop() +{ + if (!m_qnxCamera) + return; + + m_qnxCamera->stop(); + + m_videoSink = nullptr; + + Q_EMIT activeChanged(false); +} + +void QQnxPlatformCamera::setCamera(const QCameraDevice &camera) +{ + if (m_cameraDevice == camera) + return; + + const auto cameraUnit = static_cast<camera_unit_t>(camera.id().toUInt()); + + m_qnxCamera = std::make_unique<QQnxCamera>(cameraUnit); + + connect(m_qnxCamera.get(), &QQnxCamera::focusModeChanged, + [this](camera_focusmode_t mode) { Q_EMIT focusModeChanged(qtFocusMode(mode)); }); + connect(m_qnxCamera.get(), &QQnxCamera::customFocusPointChanged, + this, &QQnxPlatformCamera::customFocusPointChanged); + connect(m_qnxCamera.get(), &QQnxCamera::frameAvailable, + this, &QQnxPlatformCamera::onFrameAvailable, Qt::QueuedConnection); + + m_cameraDevice = camera; + + updateCameraFeatures(); +} + +bool QQnxPlatformCamera::setCameraFormat(const QCameraFormat &format) +{ + const QSize resolution = format.resolution(); + + if (resolution.isEmpty()) { + qWarning("QQnxPlatformCamera: invalid resolution requested"); + return false; + } + + return m_qnxCamera->setCameraFormat(resolution.width(), + resolution.height(), format.maxFrameRate()); +} + +void QQnxPlatformCamera::setCaptureSession(QPlatformMediaCaptureSession *session) +{ + if (m_session == session) + return; + + m_session = static_cast<QQnxMediaCaptureSession *>(session); +} + +bool QQnxPlatformCamera::isFocusModeSupported(QCamera::FocusMode mode) const +{ + if (!m_qnxCamera) + return false; + + return m_qnxCamera->supportedFocusModes().contains(::qnxFocusMode(mode)); +} + +void QQnxPlatformCamera::setFocusMode(QCamera::FocusMode mode) +{ + if (!m_qnxCamera) + return; + + m_qnxCamera->setFocusMode(::qnxFocusMode(mode)); +} + +void QQnxPlatformCamera::setCustomFocusPoint(const QPointF &point) +{ + if (!m_qnxCamera) + return; + + m_qnxCamera->setCustomFocusPoint(point); +} + +void QQnxPlatformCamera::setFocusDistance(float distance) +{ + if (!m_qnxCamera) + return; + + const int maxDistance = m_qnxCamera->maxFocusStep(); + + if (maxDistance < 0) + return; + + const int qnxDistance = maxDistance * std::min(distance, 1.0f); + + m_qnxCamera->setManualFocusStep(qnxDistance); +} + +void QQnxPlatformCamera::zoomTo(float factor, float) +{ + if (!m_qnxCamera) + return; + + const uint32_t minZoom = m_qnxCamera->minimumZoomLevel(); + const uint32_t maxZoom = m_qnxCamera->maximumZoomLevel(); + + if (maxZoom <= minZoom) + return; + + // QNX has an integer based API. Interpolate between the levels according to the factor we get + const float max = maxZoomFactor(); + const float min = minZoomFactor(); + + if (max <= min) + return; + + factor = qBound(min, factor, max) - min; + + const uint32_t zoom = minZoom + + static_cast<uint32_t>(qRound(factor*(maxZoom - minZoom)/(max - min))); + + if (m_qnxCamera->setZoomFactor(zoom)) + zoomFactorChanged(factor); +} + +void QQnxPlatformCamera::setExposureCompensation(float ev) +{ + if (!m_qnxCamera) + return; + + m_qnxCamera->setEvOffset(ev); +} + +int QQnxPlatformCamera::isoSensitivity() const +{ + if (!m_qnxCamera) + return 0; + + return m_qnxCamera->manualIsoSensitivity(); +} + +void QQnxPlatformCamera::setManualIsoSensitivity(int value) +{ + if (!m_qnxCamera) + return; + + const uint32_t isoValue = std::max(0, value); + + m_qnxCamera->setManualIsoSensitivity(isoValue); +} + +void QQnxPlatformCamera::setManualExposureTime(float seconds) +{ + if (!m_qnxCamera) + return; + + m_qnxCamera->setManualExposureTime(seconds); +} + +float QQnxPlatformCamera::exposureTime() const +{ + if (!m_qnxCamera) + return 0.0; + + return static_cast<float>(m_qnxCamera->manualExposureTime()); +} + +bool QQnxPlatformCamera::isWhiteBalanceModeSupported(QCamera::WhiteBalanceMode mode) const +{ + if (m_maxColorTemperature != 0) + return true; + + return mode == QCamera::WhiteBalanceAuto; +} + +void QQnxPlatformCamera::setWhiteBalanceMode(QCamera::WhiteBalanceMode mode) +{ + if (!m_qnxCamera) + return; + + if (mode == QCamera::WhiteBalanceAuto) { + m_qnxCamera->setWhiteBalanceMode(CAMERA_WHITEBALANCEMODE_AUTO); + } else { + m_qnxCamera->setWhiteBalanceMode(CAMERA_WHITEBALANCEMODE_MANUAL); + setColorTemperature(colorTemperatureForWhiteBalance(mode)); + } +} + +void QQnxPlatformCamera::setColorTemperature(int temperature) +{ + if (!m_qnxCamera) + return; + + const auto normalizedTemp = std::clamp<uint32_t>(std::max(0, temperature), + m_minColorTemperature, m_maxColorTemperature); + + if (m_qnxCamera->hasContinuousWhiteBalanceValues()) { + m_qnxCamera->setManualWhiteBalance(normalizedTemp); + } else { + uint32_t delta = std::numeric_limits<uint32_t>::max(); + uint32_t closestTemp = 0; + + for (uint32_t value : m_qnxCamera->supportedWhiteBalanceValues()) { + const auto &[min, max] = std::minmax(value, normalizedTemp); + const uint32_t currentDelta = max - min; + + if (currentDelta < delta) { + closestTemp = value; + delta = currentDelta; + } + } + + m_qnxCamera->setManualWhiteBalance(closestTemp); + } +} + +bool QQnxPlatformCamera::startVideoRecording() +{ + if (!m_qnxCamera) { + qWarning("QQnxPlatformCamera: cannot start video recording - no no camera assigned"); + return false; + } + + if (!isVideoEncodingSupported()) { + qWarning("QQnxPlatformCamera: cannot start video recording - not supported"); + return false; + } + + if (!m_qnxCamera->isActive()) { + qWarning("QQnxPlatformCamera: cannot start video recording - camera not started"); + return false; + } + + const QString container = m_encoderSettings.mimeType().preferredSuffix(); + const QString location = QMediaStorageLocation::generateFileName(m_outputUrl.toLocalFile(), + QStandardPaths::MoviesLocation, container); + +#if 0 + { + static void *libScreen = nullptr; + + if (!libScreen) + libScreen = dlopen("/usr/lib/libscreen.so.1", RTLD_GLOBAL); + } +#endif + + qDebug() << "Recording to" << location; + return m_qnxCamera->startVideoRecording(location); +} + +bool QQnxPlatformCamera::isVideoEncodingSupported() const +{ + return m_qnxCamera && m_qnxCamera->hasFeature(CAMERA_FEATURE_VIDEO); +} + +void QQnxPlatformCamera::setOutputUrl(const QUrl &url) +{ + m_outputUrl = url; +} + +void QQnxPlatformCamera::setMediaEncoderSettings(const QMediaEncoderSettings &settings) +{ + m_encoderSettings = settings; +} + +void QQnxPlatformCamera::updateCameraFeatures() +{ + if (!m_qnxCamera) + return; + + QCamera::Features features = {}; + + if (m_qnxCamera->hasFeature(CAMERA_FEATURE_REGIONFOCUS)) + features |= QCamera::Feature::CustomFocusPoint; + + supportedFeaturesChanged(features); + + minimumZoomFactorChanged(m_qnxCamera->minimumZoomLevel()); + maximumZoomFactorChanged(m_qnxCamera->maximumZoomLevel()); + + const QList<uint32_t> wbValues = m_qnxCamera->supportedWhiteBalanceValues(); + + if (wbValues.isEmpty()) { + m_minColorTemperature = m_maxColorTemperature = 0; + } else { + const auto &[minTemp, maxTemp] = std::minmax_element(wbValues.begin(), wbValues.end()); + + m_minColorTemperature = *minTemp; + m_maxColorTemperature = *maxTemp; + } +} + +void QQnxPlatformCamera::onFrameAvailable() +{ + if (!m_videoSink) + return; + + std::unique_ptr<QQnxCameraFrameBuffer> currentFrame = m_qnxCamera->takeCurrentFrame(); + + if (!currentFrame) + return; + + const QVideoFrame actualFrame(currentFrame.get(), + QVideoFrameFormat(currentFrame->size(), currentFrame->pixelFormat())); + + currentFrame.release(); // QVideoFrame has taken ownership of the internal + // buffer + + m_videoSink->setVideoFrame(actualFrame); +} + +QT_END_NAMESPACE diff --git a/src/plugins/multimedia/qnx/camera/qqnxplatformcamera_p.h b/src/plugins/multimedia/qnx/camera/qqnxplatformcamera_p.h new file mode 100644 index 000000000..0e16c9cf7 --- /dev/null +++ b/src/plugins/multimedia/qnx/camera/qqnxplatformcamera_p.h @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Research In Motion +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QQNXPLATFORMCAMERA_H +#define QQNXPLATFORMCAMERA_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qqnxcamera_p.h" + +#include <private/qplatformcamera_p.h> +#include <private/qplatformmediarecorder_p.h> + +#include <QtCore/qlist.h> +#include <QtCore/qmutex.h> +#include <QtCore/qurl.h> + +#include <memory> + +QT_BEGIN_NAMESPACE + +class QQnxPlatformCameraFrameBuffer; +class QQnxMediaCaptureSession; +class QQnxVideoSink; +class QQnxCameraFrameBuffer; + +class QQnxPlatformCamera : public QPlatformCamera +{ + Q_OBJECT +public: + explicit QQnxPlatformCamera(QCamera *parent); + ~QQnxPlatformCamera(); + + bool isActive() const override; + void setActive(bool active) override; + void start(); + void stop(); + + void setCamera(const QCameraDevice &camera) override; + + bool setCameraFormat(const QCameraFormat &format) override; + + void setCaptureSession(QPlatformMediaCaptureSession *session) override; + + bool isFocusModeSupported(QCamera::FocusMode mode) const override; + void setFocusMode(QCamera::FocusMode mode) override; + + void setCustomFocusPoint(const QPointF &point) override; + + void setFocusDistance(float distance) override; + + void zoomTo(float newZoomFactor, float rate = -1.) override; + + void setExposureCompensation(float ev) override; + + int isoSensitivity() const override; + void setManualIsoSensitivity(int value) override; + void setManualExposureTime(float seconds) override; + float exposureTime() const override; + + bool isWhiteBalanceModeSupported(QCamera::WhiteBalanceMode mode) const override; + void setWhiteBalanceMode(QCamera::WhiteBalanceMode mode) override; + void setColorTemperature(int temperature) override; + + void setOutputUrl(const QUrl &url); + void setMediaEncoderSettings(const QMediaEncoderSettings &settings); + + bool startVideoRecording(); + +private: + void updateCameraFeatures(); + void setColorTemperatureInternal(unsigned temp); + + bool isVideoEncodingSupported() const; + + void onFrameAvailable(); + + QQnxMediaCaptureSession *m_session = nullptr; + QQnxVideoSink *m_videoSink = nullptr; + + QCameraDevice m_cameraDevice; + + QUrl m_outputUrl; + + QMediaEncoderSettings m_encoderSettings; + + uint32_t m_minColorTemperature = 0; + uint32_t m_maxColorTemperature = 0; + + QMutex m_currentFrameMutex; + + std::unique_ptr<QQnxCamera> m_qnxCamera; + std::unique_ptr<QQnxCameraFrameBuffer> m_currentFrame; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/multimedia/qnx/capture/qqnxmediacapturesession.cpp b/src/plugins/multimedia/qnx/capture/qqnxmediacapturesession.cpp index c38dcfd80..99ca0ab8b 100644 --- a/src/plugins/multimedia/qnx/capture/qqnxmediacapturesession.cpp +++ b/src/plugins/multimedia/qnx/capture/qqnxmediacapturesession.cpp @@ -39,7 +39,7 @@ #include "qqnxmediacapturesession_p.h" #include "qqnxaudioinput_p.h" -#include "qqnxcamera_p.h" +#include "qqnxplatformcamera_p.h" #include "qqnximagecapture_p.h" #include "qqnxmediarecorder_p.h" #include "qqnxvideosink_p.h" @@ -65,7 +65,8 @@ void QQnxMediaCaptureSession::setCamera(QPlatformCamera *camera) { if (camera == m_camera) return; - m_camera = static_cast<QQnxCamera *>(camera); + m_camera = static_cast<QQnxPlatformCamera *>(camera); + m_camera->setCaptureSession(this); emit cameraChanged(); } diff --git a/src/plugins/multimedia/qnx/capture/qqnxmediacapturesession_p.h b/src/plugins/multimedia/qnx/capture/qqnxmediacapturesession_p.h index ec15d80ba..7b2f46793 100644 --- a/src/plugins/multimedia/qnx/capture/qqnxmediacapturesession_p.h +++ b/src/plugins/multimedia/qnx/capture/qqnxmediacapturesession_p.h @@ -57,7 +57,7 @@ QT_BEGIN_NAMESPACE class QQnxAudioInput; -class QQnxCamera; +class QQnxPlatformCamera; class QQnxImageCapture; class QQnxMediaRecorder; class QQnxVideoSink; @@ -90,7 +90,7 @@ public: QQnxVideoSink *videoSink() const; private: - QQnxCamera *m_camera = nullptr; + QQnxPlatformCamera *m_camera = nullptr; QQnxImageCapture *m_imageCapture = nullptr; QQnxMediaRecorder *m_mediaRecorder = nullptr; QQnxAudioInput *m_audioInput = nullptr; diff --git a/src/plugins/multimedia/qnx/capture/qqnxmediarecorder.cpp b/src/plugins/multimedia/qnx/capture/qqnxmediarecorder.cpp index 6aa0c686b..282743dbe 100644 --- a/src/plugins/multimedia/qnx/capture/qqnxmediarecorder.cpp +++ b/src/plugins/multimedia/qnx/capture/qqnxmediarecorder.cpp @@ -39,6 +39,7 @@ ****************************************************************************/ #include "qqnxmediarecorder_p.h" +#include "qqnxplatformcamera_p.h" #include "qqnxaudioinput_p.h" #include "qqnxcamera_p.h" #include "qqnxmediacapturesession_p.h" @@ -118,11 +119,13 @@ void QQnxMediaRecorder::startVideoRecording(QMediaEncoderSettings &settings) if (!hasCamera()) return; - auto *camera = static_cast<QQnxCamera*>(m_session->camera()); + auto *camera = static_cast<QQnxPlatformCamera*>(m_session->camera()); camera->setMediaEncoderSettings(settings); camera->setOutputUrl(outputLocation()); - camera->start(); + + if (camera->startVideoRecording()) + stateChanged(QMediaRecorder::RecordingState); } void QQnxMediaRecorder::stopVideoRecording() @@ -130,10 +133,11 @@ void QQnxMediaRecorder::stopVideoRecording() if (!hasCamera()) return; - auto *camera = static_cast<QQnxCamera*>(m_session->camera()); + auto *camera = static_cast<QQnxPlatformCamera*>(m_session->camera()); camera->stop(); + stateChanged(QMediaRecorder::StoppedState); } bool QQnxMediaRecorder::hasCamera() const diff --git a/src/plugins/multimedia/qnx/qqnxmediaintegration.cpp b/src/plugins/multimedia/qnx/qqnxmediaintegration.cpp index 14d403b64..cbae28160 100644 --- a/src/plugins/multimedia/qnx/qqnxmediaintegration.cpp +++ b/src/plugins/multimedia/qnx/qqnxmediaintegration.cpp @@ -44,6 +44,8 @@ #include "qqnxvideodevices_p.h" #include "qqnxvideosink_p.h" #include "qqnxmediaplayer_p.h" +#include "qqnximagecapture_p.h" +#include "qqnxplatformcamera_p.h" #include <QtMultimedia/private/qplatformmediaplugin_p.h> QT_BEGIN_NAMESPACE @@ -103,6 +105,11 @@ QPlatformMediaRecorder *QQnxMediaIntegration::createRecorder(QMediaRecorder *par return new QQnxMediaRecorder(parent); } +QPlatformCamera *QQnxMediaIntegration::createCamera(QCamera *parent) +{ + return new QQnxPlatformCamera(parent); +} + QT_END_NAMESPACE #include "qqnxmediaintegration.moc" diff --git a/src/plugins/multimedia/qnx/qqnxmediaintegration_p.h b/src/plugins/multimedia/qnx/qqnxmediaintegration_p.h index a480841a5..1567fce8f 100644 --- a/src/plugins/multimedia/qnx/qqnxmediaintegration_p.h +++ b/src/plugins/multimedia/qnx/qqnxmediaintegration_p.h @@ -74,6 +74,8 @@ public: QPlatformMediaRecorder *createRecorder(QMediaRecorder *parent) override; + QPlatformCamera *createCamera(QCamera *parent) override; + QQnxFormatInfo *m_formatInfo = nullptr; }; diff --git a/src/plugins/multimedia/qnx/qqnxvideodevices.cpp b/src/plugins/multimedia/qnx/qqnxvideodevices.cpp index 5414990f9..a0bd53833 100644 --- a/src/plugins/multimedia/qnx/qqnxvideodevices.cpp +++ b/src/plugins/multimedia/qnx/qqnxvideodevices.cpp @@ -38,14 +38,15 @@ ****************************************************************************/ #include "qqnxvideodevices_p.h" +#include "qqnxcamera_p.h" #include "private/qcameradevice_p.h" #include "qcameradevice.h" -#include <camera/camera_api.h> - #include <qdir.h> #include <qdebug.h> +#include <optional> + QT_BEGIN_NAMESPACE static QVideoFrameFormat::PixelFormat fromCameraFrametype(camera_frametype_t type) @@ -71,77 +72,51 @@ static QVideoFrameFormat::PixelFormat fromCameraFrametype(camera_frametype_t typ } } -static QList<QCameraDevice> enumerateCameras() +static std::optional<QCameraDevice> createCameraDevice(camera_unit_t unit, bool isDefault) { + const QQnxCamera camera(unit); - camera_unit_t cameraUnits[64]; - - unsigned int knownCameras = 0; - const camera_error_t result = camera_get_supported_cameras(64, &knownCameras, cameraUnits); - if (result != CAMERA_EOK) { - qWarning() << "Unable to retrieve supported camera types:" << result; + if (!camera.isValid()) { + qWarning() << "Invalid camera unit:" << unit; return {}; } - QList<QCameraDevice> cameras; - for (unsigned int i = 0; i < knownCameras; ++i) { - QCameraDevicePrivate *p = new QCameraDevicePrivate; - p->id = QByteArray::number(cameraUnits[i]); - - char name[CAMERA_LOCATION_NAMELEN]; - camera_get_location_property(cameraUnits[i], CAMERA_LOCATION_NAME, &name, CAMERA_LOCATION_END); - p->description = QString::fromUtf8(name); - - if (i == 0) - p->isDefault = true; - - camera_handle_t handle; - if (camera_open(cameraUnits[i], CAMERA_MODE_PREAD, &handle) == CAMERA_EOK) { - // query camera properties - - uint32_t nResolutions = 0; - camera_get_supported_vf_resolutions(handle, 0, &nResolutions, nullptr); - QVarLengthArray<camera_res_t> resolutions(nResolutions); - camera_get_supported_vf_resolutions(handle, nResolutions, &nResolutions, resolutions.data()); - - uint32_t nFrameTypes; - camera_get_supported_vf_frame_types(handle, 0, &nFrameTypes, nullptr); - QVarLengthArray<camera_frametype_t> frameTypes(nFrameTypes); - camera_get_supported_vf_frame_types(handle, nFrameTypes, &nFrameTypes, frameTypes.data()); - - for (auto res : resolutions) { - QSize resolution(res.width, res.height); - p->photoResolutions.append(resolution); - - for (auto frameType : frameTypes) { - auto pixelFormat = fromCameraFrametype(frameType); - if (pixelFormat == QVideoFrameFormat::Format_Invalid) - continue; - - uint32_t nFrameRates; - camera_get_specified_vf_framerates(handle, frameType, res, 0, &nFrameRates, nullptr, nullptr); - QVarLengthArray<double> frameRates(nFrameRates); - bool continuous = false; - camera_get_specified_vf_framerates(handle, frameType, res, nFrameRates, &nFrameRates, frameRates.data(), &continuous); - - QCameraFormatPrivate *f = new QCameraFormatPrivate; - f->resolution = resolution; - f->pixelFormat = pixelFormat; - f->minFrameRate = 1.e10; - for (auto fr : frameRates) { - if (fr < f->minFrameRate) - f->minFrameRate = fr; - if (fr > f->maxFrameRate) - f->maxFrameRate = fr; - } - p->videoFormats.append(f->create()); - } + auto *p = new QCameraDevicePrivate; + + p->id = QByteArray::number(camera.unit()); + p->description = camera.name(); + p->isDefault = isDefault; + + const QList<camera_frametype_t> frameTypes = camera.supportedVfFrameTypes(); + + for (camera_res_t res : camera.supportedVfResolutions()) { + const QSize resolution(res.width, res.height); + + p->photoResolutions.append(resolution); + + for (camera_frametype_t frameType : camera.supportedVfFrameTypes()) { + const QVideoFrameFormat::PixelFormat pixelFormat = fromCameraFrametype(frameType); + + if (pixelFormat == QVideoFrameFormat::Format_Invalid) + continue; + + auto *f = new QCameraFormatPrivate; + p->videoFormats.append(f->create()); + + f->resolution = resolution; + f->pixelFormat = pixelFormat; + f->minFrameRate = 1.e10; + + for (double fr : camera.specifiedVfFrameRates(frameType, res)) { + if (fr < f->minFrameRate) + f->minFrameRate = fr; + if (fr > f->maxFrameRate) + f->maxFrameRate = fr; } } - - cameras.append(p->create()); } - return cameras; + + return p->create(); } QQnxVideoDevices::QQnxVideoDevices(QPlatformMediaIntegration *integration) @@ -151,10 +126,21 @@ QQnxVideoDevices::QQnxVideoDevices(QPlatformMediaIntegration *integration) QList<QCameraDevice> QQnxVideoDevices::videoDevices() const { - if (!camerasChecked) { - camerasChecked = true; - cameras = enumerateCameras(); + QList<QCameraDevice> cameras; + + bool isDefault = true; + + for (const camera_unit_t cameraUnit : QQnxCamera::supportedUnits()) { + const std::optional<QCameraDevice> cameraDevice = createCameraDevice(cameraUnit, isDefault); + + if (!cameraDevice) + continue; + + cameras.append(*cameraDevice); + + isDefault = false; } + return cameras; } diff --git a/src/plugins/multimedia/qnx/qqnxvideodevices_p.h b/src/plugins/multimedia/qnx/qqnxvideodevices_p.h index 8900319c1..883064217 100644 --- a/src/plugins/multimedia/qnx/qqnxvideodevices_p.h +++ b/src/plugins/multimedia/qnx/qqnxvideodevices_p.h @@ -52,20 +52,15 @@ // #include <private/qplatformvideodevices_p.h> -#include <qcameradevice.h> QT_BEGIN_NAMESPACE class QQnxVideoDevices : public QPlatformVideoDevices { public: - QQnxVideoDevices(QPlatformMediaIntegration *integration); + explicit QQnxVideoDevices(QPlatformMediaIntegration *integration); QList<QCameraDevice> videoDevices() const override; - -private: - mutable bool camerasChecked = false; - mutable QList<QCameraDevice> cameras; }; QT_END_NAMESPACE |