diff options
12 files changed, 521 insertions, 45 deletions
diff --git a/src/plugins/android/src/mediacapture/mediacapture.pri b/src/plugins/android/src/mediacapture/mediacapture.pri index 2811f0371..a42a6a40c 100644 --- a/src/plugins/android/src/mediacapture/mediacapture.pri +++ b/src/plugins/android/src/mediacapture/mediacapture.pri @@ -14,6 +14,7 @@ SOURCES += \ $$PWD/qandroidcameracapturebufferformatcontrol.cpp \ $$PWD/qandroidcameraflashcontrol.cpp \ $$PWD/qandroidcamerafocuscontrol.cpp \ + $$PWD/qandroidviewfindersettingscontrol.cpp \ $$PWD/qandroidcameralockscontrol.cpp \ $$PWD/qandroidcapturesession.cpp \ $$PWD/qandroidmediarecordercontrol.cpp \ @@ -39,6 +40,7 @@ HEADERS += \ $$PWD/qandroidcameracapturebufferformatcontrol.h \ $$PWD/qandroidcameraflashcontrol.h \ $$PWD/qandroidcamerafocuscontrol.h \ + $$PWD/qandroidviewfindersettingscontrol.h \ $$PWD/qandroidcameralockscontrol.h \ $$PWD/qandroidcapturesession.h \ $$PWD/qandroidmediarecordercontrol.h \ diff --git a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp index b44c0fe9f..9137fbc05 100644 --- a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp +++ b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2016 Ruslan Baratov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. @@ -67,7 +68,6 @@ QAndroidCameraSession::QAndroidCameraSession(QObject *parent) , m_savedState(-1) , m_status(QCamera::UnloadedStatus) , m_previewStarted(false) - , m_imageSettingsDirty(true) , m_captureDestination(QCameraImageCapture::CaptureToFile) , m_captureImageDriveMode(QCameraImageCapture::SingleImageCapture) , m_lastImageCaptureId(0) @@ -100,7 +100,7 @@ void QAndroidCameraSession::setCaptureMode(QCamera::CaptureModes mode) emit captureModeChanged(m_captureMode); if (m_previewStarted && m_captureMode.testFlag(QCamera::CaptureStillImage)) - adjustViewfinderSize(m_imageSettings.resolution()); + applyViewfinderSettings(m_actualImageSettings.resolution()); } bool QAndroidCameraSession::isCaptureModeSupported(QCamera::CaptureModes mode) const @@ -223,7 +223,8 @@ void QAndroidCameraSession::close() m_readyForCapture = false; m_currentImageCaptureId = -1; m_currentImageCaptureFileName.clear(); - m_imageSettingsDirty = true; + m_actualImageSettings = m_requestedImageSettings; + m_actualViewfinderSettings = m_requestedViewfinderSettings; m_camera->release(); delete m_camera; @@ -251,37 +252,108 @@ void QAndroidCameraSession::setVideoOutput(QAndroidVideoOutput *output) } } -void QAndroidCameraSession::adjustViewfinderSize(const QSize &captureSize, bool restartPreview) +void QAndroidCameraSession::setViewfinderSettings(const QCameraViewfinderSettings &settings) +{ + if (m_requestedViewfinderSettings == settings) + return; + + m_requestedViewfinderSettings = m_actualViewfinderSettings = settings; + + if (m_readyForCapture) + applyViewfinderSettings(); +} + +void QAndroidCameraSession::applyViewfinderSettings(const QSize &captureSize, bool restartPreview) { if (!m_camera) return; - QSize currentViewfinderResolution = m_camera->previewSize(); - QSize adjustedViewfinderResolution; + const QSize currentViewfinderResolution = m_camera->previewSize(); + const AndroidCamera::ImageFormat currentPreviewFormat = m_camera->getPreviewFormat(); + const AndroidCamera::FpsRange currentFpsRange = m_camera->getPreviewFpsRange(); - if (m_captureMode.testFlag(QCamera::CaptureVideo) && m_camera->getPreferredPreviewSizeForVideo().isEmpty()) { + // -- adjust resolution + QSize adjustedViewfinderResolution; + const bool validCaptureSize = captureSize.width() > 0 && captureSize.height() > 0; + if (m_captureMode.testFlag(QCamera::CaptureVideo) + && validCaptureSize + && m_camera->getPreferredPreviewSizeForVideo().isEmpty()) { // According to the Android doc, if getPreferredPreviewSizeForVideo() returns null, it means // the preview size cannot be different from the capture size adjustedViewfinderResolution = captureSize; } else { - // search for viewfinder resolution with the same aspect ratio - const qreal aspectRatio = qreal(captureSize.width()) / qreal(captureSize.height()); - QList<QSize> previewSizes = m_camera->getSupportedPreviewSizes(); - for (int i = previewSizes.count() - 1; i >= 0; --i) { - const QSize &size = previewSizes.at(i); - if (qAbs(aspectRatio - (qreal(size.width()) / size.height())) < 0.01) { - adjustedViewfinderResolution = size; - break; + qreal captureAspectRatio = 0; + if (validCaptureSize) + captureAspectRatio = qreal(captureSize.width()) / qreal(captureSize.height()); + + const QList<QSize> previewSizes = m_camera->getSupportedPreviewSizes(); + + const QSize vfRes = m_requestedViewfinderSettings.resolution(); + if (vfRes.width() > 0 && vfRes.height() > 0 + && (!validCaptureSize || qAbs(captureAspectRatio - (qreal(vfRes.width()) / vfRes.height())) < 0.01) + && previewSizes.contains(vfRes)) { + adjustedViewfinderResolution = vfRes; + } else if (validCaptureSize) { + // search for viewfinder resolution with the same aspect ratio + for (int i = previewSizes.count() - 1; i >= 0; --i) { + const QSize &size = previewSizes.at(i); + if (qAbs(captureAspectRatio - (qreal(size.width()) / size.height())) < 0.01) { + adjustedViewfinderResolution = size; + break; + } + } + if (!adjustedViewfinderResolution.isValid()) { + qWarning("Cannot find a viewfinder resolution matching the capture aspect ratio."); + return; } + } else { + adjustedViewfinderResolution = previewSizes.last(); } + } + m_actualViewfinderSettings.setResolution(adjustedViewfinderResolution); - if (!adjustedViewfinderResolution.isValid()) { - qWarning("Cannot find a viewfinder resolution matching the capture aspect ratio."); - return; + // -- adjust pixel format + + AndroidCamera::ImageFormat adjustedPreviewFormat = AndroidCamera::NV21; + if (m_requestedViewfinderSettings.pixelFormat() != QVideoFrame::Format_Invalid) { + const AndroidCamera::ImageFormat f = AndroidImageFormatFromQtPixelFormat(m_requestedViewfinderSettings.pixelFormat()); + if (f == AndroidCamera::UnknownImageFormat || !m_camera->getSupportedPreviewFormats().contains(f)) + qWarning("Unsupported viewfinder pixel format"); + else + adjustedPreviewFormat = f; + } + m_actualViewfinderSettings.setPixelFormat(QtPixelFormatFromAndroidImageFormat(adjustedPreviewFormat)); + + // -- adjust FPS + + AndroidCamera::FpsRange adjustedFps = currentFpsRange; + const AndroidCamera::FpsRange requestedFpsRange = AndroidCamera::FpsRange::makeFromQReal(m_requestedViewfinderSettings.minimumFrameRate(), + m_requestedViewfinderSettings.maximumFrameRate()); + if (requestedFpsRange.min > 0 || requestedFpsRange.max > 0) { + int minDist = INT_MAX; + const QList<AndroidCamera::FpsRange> supportedFpsRanges = m_camera->getSupportedPreviewFpsRange(); + auto it = supportedFpsRanges.rbegin(), end = supportedFpsRanges.rend(); + for (; it != end; ++it) { + int dist = (requestedFpsRange.min > 0 ? qAbs(requestedFpsRange.min - it->min) : 0) + + (requestedFpsRange.max > 0 ? qAbs(requestedFpsRange.max - it->max) : 0); + if (dist < minDist) { + minDist = dist; + adjustedFps = *it; + if (minDist == 0) + break; // exact match + } } } + m_actualViewfinderSettings.setMinimumFrameRate(adjustedFps.getMinReal()); + m_actualViewfinderSettings.setMaximumFrameRate(adjustedFps.getMaxReal()); + + // -- Set values on camera + + if (currentViewfinderResolution != adjustedViewfinderResolution + || currentPreviewFormat != adjustedPreviewFormat + || currentFpsRange.min != adjustedFps.min + || currentFpsRange.max != adjustedFps.max) { - if (currentViewfinderResolution != adjustedViewfinderResolution) { if (m_videoOutput) m_videoOutput->setVideoSize(adjustedViewfinderResolution); @@ -290,6 +362,8 @@ void QAndroidCameraSession::adjustViewfinderSize(const QSize &captureSize, bool m_camera->stopPreview(); m_camera->setPreviewSize(adjustedViewfinderResolution); + m_camera->setPreviewFormat(adjustedPreviewFormat); + m_camera->setPreviewFpsRange(adjustedFps); // restart preview if (m_previewStarted && restartPreview) @@ -297,6 +371,36 @@ void QAndroidCameraSession::adjustViewfinderSize(const QSize &captureSize, bool } } +QList<QSize> QAndroidCameraSession::getSupportedPreviewSizes() const +{ + return m_camera ? m_camera->getSupportedPreviewSizes() : QList<QSize>(); +} + +QList<QVideoFrame::PixelFormat> QAndroidCameraSession::getSupportedPixelFormats() const +{ + QList<QVideoFrame::PixelFormat> formats; + + if (!m_camera) + return formats; + + const QList<AndroidCamera::ImageFormat> nativeFormats = m_camera->getSupportedPreviewFormats(); + + formats.reserve(nativeFormats.size()); + + for (AndroidCamera::ImageFormat nativeFormat : nativeFormats) { + QVideoFrame::PixelFormat format = QtPixelFormatFromAndroidImageFormat(nativeFormat); + if (format != QVideoFrame::Format_Invalid) + formats.append(format); + } + + return formats; +} + +QList<AndroidCamera::FpsRange> QAndroidCameraSession::getSupportedPreviewFpsRange() const +{ + return m_camera ? m_camera->getSupportedPreviewFpsRange() : QList<AndroidCamera::FpsRange>(); +} + bool QAndroidCameraSession::startPreview() { if (!m_camera) @@ -323,7 +427,8 @@ bool QAndroidCameraSession::startPreview() emit statusChanged(m_status); applyImageSettings(); - adjustViewfinderSize(m_imageSettings.resolution()); + applyViewfinderSettings(m_captureMode.testFlag(QCamera::CaptureStillImage) ? m_actualImageSettings.resolution() + : QSize()); AndroidMultimediaUtils::enableOrientationListener(true); @@ -357,19 +462,15 @@ void QAndroidCameraSession::stopPreview() void QAndroidCameraSession::setImageSettings(const QImageEncoderSettings &settings) { - if (m_imageSettings == settings) + if (m_requestedImageSettings == settings) return; - m_imageSettings = settings; - if (m_imageSettings.codec().isEmpty()) - m_imageSettings.setCodec(QLatin1String("jpeg")); - - m_imageSettingsDirty = true; + m_requestedImageSettings = m_actualImageSettings = settings; applyImageSettings(); if (m_readyForCapture && m_captureMode.testFlag(QCamera::CaptureStillImage)) - adjustViewfinderSize(m_imageSettings.resolution()); + applyViewfinderSettings(m_actualImageSettings.resolution()); } int QAndroidCameraSession::currentCameraRotation() const @@ -426,15 +527,32 @@ void QAndroidCameraSession::setPreviewCallback(PreviewCallback *callback) void QAndroidCameraSession::applyImageSettings() { - if (!m_camera || !m_imageSettingsDirty) + if (!m_camera) return; - const QSize requestedResolution = m_imageSettings.resolution(); - const QList<QSize> supportedResolutions = m_camera->getSupportedPictureSizes(); + if (m_actualImageSettings.codec().isEmpty()) + m_actualImageSettings.setCodec(QLatin1String("jpeg")); + const QSize requestedResolution = m_requestedImageSettings.resolution(); + const QList<QSize> supportedResolutions = m_camera->getSupportedPictureSizes(); if (!requestedResolution.isValid()) { - // if no resolution is set, use the highest supported one - m_imageSettings.setResolution(supportedResolutions.last()); + // if the viewfinder resolution is explicitly set, pick the highest available capture + // resolution with the same aspect ratio + if (m_requestedViewfinderSettings.resolution().isValid()) { + const QSize vfResolution = m_actualViewfinderSettings.resolution(); + const qreal vfAspectRatio = qreal(vfResolution.width()) / vfResolution.height(); + + auto it = supportedResolutions.rbegin(), end = supportedResolutions.rend(); + for (; it != end; ++it) { + if (qAbs(vfAspectRatio - (qreal(it->width()) / it->height())) < 0.01) { + m_actualImageSettings.setResolution(*it); + break; + } + } + } else { + // otherwise, use the highest supported one + m_actualImageSettings.setResolution(supportedResolutions.last()); + } } else if (!supportedResolutions.contains(requestedResolution)) { // if the requested resolution is not supported, find the closest one int reqPixelCount = requestedResolution.width() * requestedResolution.height(); @@ -444,11 +562,12 @@ void QAndroidCameraSession::applyImageSettings() supportedPixelCounts.append(s.width() * s.height()); } int closestIndex = qt_findClosestValue(supportedPixelCounts, reqPixelCount); - m_imageSettings.setResolution(supportedResolutions.at(closestIndex)); + m_actualImageSettings.setResolution(supportedResolutions.at(closestIndex)); } + m_camera->setPictureSize(m_actualImageSettings.resolution()); int jpegQuality = 100; - switch (m_imageSettings.quality()) { + switch (m_requestedImageSettings.quality()) { case QMultimedia::VeryLowQuality: jpegQuality = 20; break; @@ -465,11 +584,7 @@ void QAndroidCameraSession::applyImageSettings() jpegQuality = 100; break; } - - m_camera->setPictureSize(m_imageSettings.resolution()); m_camera->setJpegQuality(jpegQuality); - - m_imageSettingsDirty = false; } bool QAndroidCameraSession::isCaptureDestinationSupported(QCameraImageCapture::CaptureDestinations destination) const @@ -531,7 +646,7 @@ int QAndroidCameraSession::capture(const QString &fileName) m_currentImageCaptureFileName = fileName; applyImageSettings(); - adjustViewfinderSize(m_imageSettings.resolution()); + applyViewfinderSettings(m_actualImageSettings.resolution()); // adjust picture rotation depending on the device orientation m_camera->setRotation(currentCameraRotation()); @@ -610,7 +725,7 @@ void QAndroidCameraSession::onCameraPictureCaptured(const QByteArray &data) QtConcurrent::run(this, &QAndroidCameraSession::processCapturedImage, m_currentImageCaptureId, data, - m_imageSettings.resolution(), + m_actualImageSettings.resolution(), m_captureDestination, m_currentImageCaptureFileName); } @@ -702,6 +817,42 @@ void QAndroidCameraSession::processCapturedImage(int id, } } +QVideoFrame::PixelFormat QAndroidCameraSession::QtPixelFormatFromAndroidImageFormat(AndroidCamera::ImageFormat format) +{ + switch (format) { + case AndroidCamera::RGB565: + return QVideoFrame::Format_RGB565; + case AndroidCamera::NV21: + return QVideoFrame::Format_NV21; + case AndroidCamera::YUY2: + return QVideoFrame::Format_YUYV; + case AndroidCamera::JPEG: + return QVideoFrame::Format_Jpeg; + case AndroidCamera::YV12: + return QVideoFrame::Format_YV12; + default: + return QVideoFrame::Format_Invalid; + } +} + +AndroidCamera::ImageFormat QAndroidCameraSession::AndroidImageFormatFromQtPixelFormat(QVideoFrame::PixelFormat format) +{ + switch (format) { + case QVideoFrame::Format_RGB565: + return AndroidCamera::RGB565; + case QVideoFrame::Format_NV21: + return AndroidCamera::NV21; + case QVideoFrame::Format_YUYV: + return AndroidCamera::YUY2; + case QVideoFrame::Format_Jpeg: + return AndroidCamera::JPEG; + case QVideoFrame::Format_YV12: + return AndroidCamera::YV12; + default: + return AndroidCamera::UnknownImageFormat; + } +} + void QAndroidCameraSession::onVideoOutputReady(bool ready) { if (ready && m_state == QCamera::ActiveState) diff --git a/src/plugins/android/src/mediacapture/qandroidcamerasession.h b/src/plugins/android/src/mediacapture/qandroidcamerasession.h index 9bc14277d..d08f2f6ac 100644 --- a/src/plugins/android/src/mediacapture/qandroidcamerasession.h +++ b/src/plugins/android/src/mediacapture/qandroidcamerasession.h @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2016 Ruslan Baratov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. @@ -74,11 +75,18 @@ public: void setCaptureMode(QCamera::CaptureModes mode); bool isCaptureModeSupported(QCamera::CaptureModes mode) const; + QCameraViewfinderSettings viewfinderSettings() const { return m_actualViewfinderSettings; } + void setViewfinderSettings(const QCameraViewfinderSettings &settings); + void applyViewfinderSettings(const QSize &captureSize = QSize(), bool restartPreview = true); + QAndroidVideoOutput *videoOutput() const { return m_videoOutput; } void setVideoOutput(QAndroidVideoOutput *output); - void adjustViewfinderSize(const QSize &captureSize, bool restartPreview = true); - QImageEncoderSettings imageSettings() const { return m_imageSettings; } + QList<QSize> getSupportedPreviewSizes() const; + QList<QVideoFrame::PixelFormat> getSupportedPixelFormats() const; + QList<AndroidCamera::FpsRange> getSupportedPreviewFpsRange() const; + + QImageEncoderSettings imageSettings() const { return m_actualImageSettings; } void setImageSettings(const QImageEncoderSettings &settings); bool isCaptureDestinationSupported(QCameraImageCapture::CaptureDestinations destination) const; @@ -154,6 +162,9 @@ private: QCameraImageCapture::CaptureDestinations dest, const QString &fileName); + static QVideoFrame::PixelFormat QtPixelFormatFromAndroidImageFormat(AndroidCamera::ImageFormat); + static AndroidCamera::ImageFormat AndroidImageFormatFromQtPixelFormat(QVideoFrame::PixelFormat); + int m_selectedCamera; AndroidCamera *m_camera; int m_nativeOrientation; @@ -165,8 +176,11 @@ private: QCamera::Status m_status; bool m_previewStarted; - QImageEncoderSettings m_imageSettings; - bool m_imageSettingsDirty; + QCameraViewfinderSettings m_requestedViewfinderSettings; + QCameraViewfinderSettings m_actualViewfinderSettings; + + QImageEncoderSettings m_requestedImageSettings; + QImageEncoderSettings m_actualImageSettings; QCameraImageCapture::CaptureDestinations m_captureDestination; QCameraImageCapture::DriveMode m_captureImageDriveMode; int m_lastImageCaptureId; diff --git a/src/plugins/android/src/mediacapture/qandroidcaptureservice.cpp b/src/plugins/android/src/mediacapture/qandroidcaptureservice.cpp index caade58d2..65df54c3f 100644 --- a/src/plugins/android/src/mediacapture/qandroidcaptureservice.cpp +++ b/src/plugins/android/src/mediacapture/qandroidcaptureservice.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2016 Ruslan Baratov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. @@ -51,6 +52,7 @@ #include "qandroidcameraexposurecontrol.h" #include "qandroidcameraflashcontrol.h" #include "qandroidcamerafocuscontrol.h" +#include "qandroidviewfindersettingscontrol.h" #include "qandroidcameralockscontrol.h" #include "qandroidcameraimageprocessingcontrol.h" #include "qandroidimageencodercontrol.h" @@ -80,6 +82,7 @@ QAndroidCaptureService::QAndroidCaptureService(const QString &service, QObject * m_cameraExposureControl = new QAndroidCameraExposureControl(m_cameraSession); m_cameraFlashControl = new QAndroidCameraFlashControl(m_cameraSession); m_cameraFocusControl = new QAndroidCameraFocusControl(m_cameraSession); + m_viewfinderSettingsControl2 = new QAndroidViewfinderSettingsControl2(m_cameraSession); m_cameraLocksControl = new QAndroidCameraLocksControl(m_cameraSession); m_cameraImageProcessingControl = new QAndroidCameraImageProcessingControl(m_cameraSession); m_imageEncoderControl = new QAndroidImageEncoderControl(m_cameraSession); @@ -96,6 +99,7 @@ QAndroidCaptureService::QAndroidCaptureService(const QString &service, QObject * m_cameraExposureControl = 0; m_cameraFlashControl = 0; m_cameraFocusControl = 0; + m_viewfinderSettingsControl2 = 0; m_cameraLocksControl = 0; m_cameraImageProcessingControl = 0; m_imageEncoderControl = 0; @@ -134,6 +138,7 @@ QAndroidCaptureService::~QAndroidCaptureService() delete m_cameraExposureControl; delete m_cameraFlashControl; delete m_cameraFocusControl; + delete m_viewfinderSettingsControl2; delete m_cameraLocksControl; delete m_cameraImageProcessingControl; delete m_imageEncoderControl; @@ -181,6 +186,9 @@ QMediaControl *QAndroidCaptureService::requestControl(const char *name) if (qstrcmp(name, QCameraFocusControl_iid) == 0) return m_cameraFocusControl; + if (qstrcmp(name, QCameraViewfinderSettingsControl2_iid) == 0) + return m_viewfinderSettingsControl2; + if (qstrcmp(name, QCameraLocksControl_iid) == 0) return m_cameraLocksControl; diff --git a/src/plugins/android/src/mediacapture/qandroidcaptureservice.h b/src/plugins/android/src/mediacapture/qandroidcaptureservice.h index 7240bce6b..85816fdd6 100644 --- a/src/plugins/android/src/mediacapture/qandroidcaptureservice.h +++ b/src/plugins/android/src/mediacapture/qandroidcaptureservice.h @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2016 Ruslan Baratov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. @@ -57,6 +58,7 @@ class QAndroidCameraZoomControl; class QAndroidCameraExposureControl; class QAndroidCameraFlashControl; class QAndroidCameraFocusControl; +class QAndroidViewfinderSettingsControl2; class QAndroidCameraLocksControl; class QAndroidCameraImageProcessingControl; class QAndroidImageEncoderControl; @@ -93,6 +95,7 @@ private: QAndroidCameraExposureControl *m_cameraExposureControl; QAndroidCameraFlashControl *m_cameraFlashControl; QAndroidCameraFocusControl *m_cameraFocusControl; + QAndroidViewfinderSettingsControl2 *m_viewfinderSettingsControl2; QAndroidCameraLocksControl *m_cameraLocksControl; QAndroidCameraImageProcessingControl *m_cameraImageProcessingControl; QAndroidImageEncoderControl *m_imageEncoderControl; diff --git a/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp b/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp index 92a020882..9e38c8539 100644 --- a/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp +++ b/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp @@ -436,7 +436,7 @@ void QAndroidCaptureSession::applySettings() void QAndroidCaptureSession::updateViewfinder() { m_cameraSession->camera()->stopPreviewSynchronous(); - m_cameraSession->adjustViewfinderSize(m_videoSettings.resolution(), false); + m_cameraSession->applyViewfinderSettings(m_videoSettings.resolution(), false); } void QAndroidCaptureSession::restartViewfinder() diff --git a/src/plugins/android/src/mediacapture/qandroidviewfindersettingscontrol.cpp b/src/plugins/android/src/mediacapture/qandroidviewfindersettingscontrol.cpp new file mode 100644 index 000000000..2a2882cb9 --- /dev/null +++ b/src/plugins/android/src/mediacapture/qandroidviewfindersettingscontrol.cpp @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2016 Ruslan Baratov +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qandroidviewfindersettingscontrol.h" +#include "qandroidcamerasession.h" + +QT_BEGIN_NAMESPACE + +QAndroidViewfinderSettingsControl2::QAndroidViewfinderSettingsControl2(QAndroidCameraSession *session) + : m_cameraSession(session) +{ +} + +QList<QCameraViewfinderSettings> QAndroidViewfinderSettingsControl2::supportedViewfinderSettings() const +{ + QList<QCameraViewfinderSettings> viewfinderSettings; + + const QList<QSize> previewSizes = m_cameraSession->getSupportedPreviewSizes(); + const QList<QVideoFrame::PixelFormat> pixelFormats = m_cameraSession->getSupportedPixelFormats(); + const QList<AndroidCamera::FpsRange> fpsRanges = m_cameraSession->getSupportedPreviewFpsRange(); + + viewfinderSettings.reserve(previewSizes.size() * pixelFormats.size() * fpsRanges.size()); + + for (const QSize& size : previewSizes) { + for (QVideoFrame::PixelFormat pixelFormat : pixelFormats) { + for (const AndroidCamera::FpsRange& fpsRange : fpsRanges) { + QCameraViewfinderSettings s; + s.setResolution(size); + s.setPixelAspectRatio(QSize(1, 1)); + s.setPixelFormat(pixelFormat); + s.setMinimumFrameRate(fpsRange.getMinReal()); + s.setMaximumFrameRate(fpsRange.getMaxReal()); + viewfinderSettings << s; + } + } + } + return viewfinderSettings; +} + +QCameraViewfinderSettings QAndroidViewfinderSettingsControl2::viewfinderSettings() const +{ + return m_cameraSession->viewfinderSettings(); +} + +void QAndroidViewfinderSettingsControl2::setViewfinderSettings(const QCameraViewfinderSettings &settings) +{ + m_cameraSession->setViewfinderSettings(settings); +} + +QT_END_NAMESPACE + +#include "moc_qandroidviewfindersettingscontrol.cpp" diff --git a/src/plugins/android/src/mediacapture/qandroidviewfindersettingscontrol.h b/src/plugins/android/src/mediacapture/qandroidviewfindersettingscontrol.h new file mode 100644 index 000000000..a6bf70857 --- /dev/null +++ b/src/plugins/android/src/mediacapture/qandroidviewfindersettingscontrol.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2016 Ruslan Baratov +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QANDROIDVIEWFINDERSETTINGSCONTROL_H +#define QANDROIDVIEWFINDERSETTINGSCONTROL_H + +#include <QtMultimedia/qcameraviewfindersettingscontrol.h> +#include <QtMultimedia/qcameraviewfindersettings.h> + +#include <QtCore/qpointer.h> +#include <QtCore/qglobal.h> +#include <QtCore/qsize.h> + +QT_BEGIN_NAMESPACE + +class QAndroidCameraSession; + +class QAndroidViewfinderSettingsControl2 : public QCameraViewfinderSettingsControl2 +{ + Q_OBJECT +public: + explicit QAndroidViewfinderSettingsControl2(QAndroidCameraSession *session); + + QList<QCameraViewfinderSettings> supportedViewfinderSettings() const Q_DECL_OVERRIDE; + QCameraViewfinderSettings viewfinderSettings() const Q_DECL_OVERRIDE; + void setViewfinderSettings(const QCameraViewfinderSettings &settings) Q_DECL_OVERRIDE; + +private: + QAndroidCameraSession *m_cameraSession; +}; + +QT_END_NAMESPACE + +#endif // QANDROIDVIEWFINDERSETTINGSCONTROL_H diff --git a/src/plugins/android/src/wrappers/jni/androidcamera.cpp b/src/plugins/android/src/wrappers/jni/androidcamera.cpp index 476fb8957..fd5522e10 100644 --- a/src/plugins/android/src/wrappers/jni/androidcamera.cpp +++ b/src/plugins/android/src/wrappers/jni/androidcamera.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2016 Ruslan Baratov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. @@ -171,11 +172,17 @@ public: Q_INVOKABLE QSize getPreferredPreviewSizeForVideo(); Q_INVOKABLE QList<QSize> getSupportedPreviewSizes(); + Q_INVOKABLE QList<AndroidCamera::FpsRange> getSupportedPreviewFpsRange(); + + Q_INVOKABLE AndroidCamera::FpsRange getPreviewFpsRange(); + Q_INVOKABLE void setPreviewFpsRange(int min, int max); + Q_INVOKABLE AndroidCamera::ImageFormat getPreviewFormat(); Q_INVOKABLE void setPreviewFormat(AndroidCamera::ImageFormat fmt); Q_INVOKABLE QList<AndroidCamera::ImageFormat> getSupportedPreviewFormats(); Q_INVOKABLE QSize previewSize() const { return m_previewSize; } + Q_INVOKABLE QSize getPreviewSize(); Q_INVOKABLE void updatePreviewSize(); Q_INVOKABLE bool setPreviewTexture(void *surfaceTexture); Q_INVOKABLE bool setPreviewDisplay(void *surfaceHolder); @@ -380,6 +387,24 @@ QList<QSize> AndroidCamera::getSupportedPreviewSizes() return d->getSupportedPreviewSizes(); } +QList<AndroidCamera::FpsRange> AndroidCamera::getSupportedPreviewFpsRange() +{ + Q_D(AndroidCamera); + return d->getSupportedPreviewFpsRange(); +} + +AndroidCamera::FpsRange AndroidCamera::getPreviewFpsRange() +{ + Q_D(AndroidCamera); + return d->getPreviewFpsRange(); +} + +void AndroidCamera::setPreviewFpsRange(FpsRange range) +{ + Q_D(AndroidCamera); + QMetaObject::invokeMethod(d, "setPreviewFpsRange", Q_ARG(int, range.min), Q_ARG(int, range.max)); +} + AndroidCamera::ImageFormat AndroidCamera::getPreviewFormat() { Q_D(AndroidCamera); @@ -404,6 +429,12 @@ QSize AndroidCamera::previewSize() const return d->m_previewSize; } +QSize AndroidCamera::actualPreviewSize() +{ + Q_D(AndroidCamera); + return d->getPreviewSize(); +} + void AndroidCamera::setPreviewSize(const QSize &size) { Q_D(AndroidCamera); @@ -877,6 +908,80 @@ QList<QSize> AndroidCameraPrivate::getSupportedPreviewSizes() return list; } +QList<AndroidCamera::FpsRange> AndroidCameraPrivate::getSupportedPreviewFpsRange() +{ + QMutexLocker parametersLocker(&m_parametersMutex); + + QJNIEnvironmentPrivate env; + + QList<AndroidCamera::FpsRange> rangeList; + + if (m_parameters.isValid()) { + QJNIObjectPrivate rangeListNative = m_parameters.callObjectMethod("getSupportedPreviewFpsRange", + "()Ljava/util/List;"); + int count = rangeListNative.callMethod<jint>("size"); + + rangeList.reserve(count); + + for (int i = 0; i < count; ++i) { + QJNIObjectPrivate range = rangeListNative.callObjectMethod("get", + "(I)Ljava/lang/Object;", + i); + + jintArray jRange = static_cast<jintArray>(range.object()); + jint* rangeArray = env->GetIntArrayElements(jRange, 0); + + AndroidCamera::FpsRange fpsRange; + + fpsRange.min = rangeArray[0]; + fpsRange.max = rangeArray[1]; + + env->ReleaseIntArrayElements(jRange, rangeArray, 0); + + rangeList << fpsRange; + } + } + + return rangeList; +} + +AndroidCamera::FpsRange AndroidCameraPrivate::getPreviewFpsRange() +{ + QMutexLocker parametersLocker(&m_parametersMutex); + + QJNIEnvironmentPrivate env; + + AndroidCamera::FpsRange range; + + if (!m_parameters.isValid()) + return range; + + jintArray jRangeArray = env->NewIntArray(2); + m_parameters.callMethod<void>("getPreviewFpsRange", "([I)V", jRangeArray); + + jint* jRangeElements = env->GetIntArrayElements(jRangeArray, 0); + + range.min = jRangeElements[0]; + range.max = jRangeElements[1]; + + env->ReleaseIntArrayElements(jRangeArray, jRangeElements, 0); + env->DeleteLocalRef(jRangeArray); + + return range; +} + +void AndroidCameraPrivate::setPreviewFpsRange(int min, int max) +{ + QMutexLocker parametersLocker(&m_parametersMutex); + + if (!m_parameters.isValid()) + return; + + QJNIEnvironmentPrivate env; + m_parameters.callMethod<void>("setPreviewFpsRange", "(II)V", min, max); + exceptionCheckAndClear(env); +} + AndroidCamera::ImageFormat AndroidCameraPrivate::getPreviewFormat() { QMutexLocker parametersLocker(&m_parametersMutex); @@ -919,6 +1024,22 @@ QList<AndroidCamera::ImageFormat> AndroidCameraPrivate::getSupportedPreviewForma return list; } +QSize AndroidCameraPrivate::getPreviewSize() +{ + QMutexLocker parametersLocker(&m_parametersMutex); + + if (!m_parameters.isValid()) + return QSize(); + + QJNIObjectPrivate size = m_parameters.callObjectMethod("getPreviewSize", + "()Landroid/hardware/Camera$Size;"); + + if (!size.isValid()) + return QSize(); + + return QSize(size.getField<jint>("width"), size.getField<jint>("height")); +} + void AndroidCameraPrivate::updatePreviewSize() { QMutexLocker parametersLocker(&m_parametersMutex); diff --git a/src/plugins/android/src/wrappers/jni/androidcamera.h b/src/plugins/android/src/wrappers/jni/androidcamera.h index 788da82da..f4694d7dc 100644 --- a/src/plugins/android/src/wrappers/jni/androidcamera.h +++ b/src/plugins/android/src/wrappers/jni/androidcamera.h @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2016 Ruslan Baratov ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. @@ -83,6 +84,26 @@ public: YV12 = 842094169 }; + // http://developer.android.com/reference/android/hardware/Camera.Parameters.html#getSupportedPreviewFpsRange%28%29 + // "The values are multiplied by 1000 and represented in integers" + struct FpsRange { + int min; + int max; + + FpsRange(): min(0), max(0) {} + + qreal getMinReal() const { return min / 1000.0; } + qreal getMaxReal() const { return max / 1000.0; } + + static FpsRange makeFromQReal(qreal min, qreal max) + { + FpsRange range; + range.min = static_cast<int>(min * 1000.0); + range.max = static_cast<int>(max * 1000.0); + return range; + } + }; + ~AndroidCamera(); static AndroidCamera *open(int cameraId); @@ -100,11 +121,17 @@ public: QSize getPreferredPreviewSizeForVideo(); QList<QSize> getSupportedPreviewSizes(); + QList<FpsRange> getSupportedPreviewFpsRange(); + + FpsRange getPreviewFpsRange(); + void setPreviewFpsRange(FpsRange); + ImageFormat getPreviewFormat(); void setPreviewFormat(ImageFormat fmt); QList<ImageFormat> getSupportedPreviewFormats(); QSize previewSize() const; + QSize actualPreviewSize(); void setPreviewSize(const QSize &size); bool setPreviewTexture(AndroidSurfaceTexture *surfaceTexture); bool setPreviewDisplay(AndroidSurfaceHolder *surfaceHolder); diff --git a/tests/auto/integration/qaudioinput/BLACKLIST b/tests/auto/integration/qaudioinput/BLACKLIST index f6a8a670f..ab3f9e037 100644 --- a/tests/auto/integration/qaudioinput/BLACKLIST +++ b/tests/auto/integration/qaudioinput/BLACKLIST @@ -3,5 +3,6 @@ redhatenterpriselinuxworkstation-6.6 rhel-7.2 ubuntu-14.04 +ubuntu-16.04 opensuse-13.1 opensuse-42.1 diff --git a/tests/auto/integration/qmediaplayerbackend/BLACKLIST b/tests/auto/integration/qmediaplayerbackend/BLACKLIST index 7ce72c7ac..43b8e8b26 100644 --- a/tests/auto/integration/qmediaplayerbackend/BLACKLIST +++ b/tests/auto/integration/qmediaplayerbackend/BLACKLIST @@ -23,6 +23,7 @@ opensuse-13.1 64bit redhatenterpriselinuxworkstation-6.6 rhel-7.1 ubuntu-14.04 64bit +ubuntu-16.04 64bit windows 64bit developer-build rhel-7.2 |