diff options
Diffstat (limited to 'src/plugins/multimedia/qnx/camera/qqnxcamera.cpp')
-rw-r--r-- | src/plugins/multimedia/qnx/camera/qqnxcamera.cpp | 720 |
1 files changed, 467 insertions, 253 deletions
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) |