summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/avfoundation/camera/avfcamerarenderercontrol.h2
-rw-r--r--src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm18
-rw-r--r--src/plugins/avfoundation/camera/avfcameraservice.h4
-rw-r--r--src/plugins/avfoundation/camera/avfcameraservice.mm7
-rw-r--r--src/plugins/avfoundation/camera/avfcamerasession.h1
-rw-r--r--src/plugins/avfoundation/camera/avfcamerasession.mm11
-rw-r--r--src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.h91
-rw-r--r--src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm579
-rw-r--r--src/plugins/avfoundation/camera/camera.pro6
9 files changed, 716 insertions, 3 deletions
diff --git a/src/plugins/avfoundation/camera/avfcamerarenderercontrol.h b/src/plugins/avfoundation/camera/avfcamerarenderercontrol.h
index 5fbbcb678..92ab75bd0 100644
--- a/src/plugins/avfoundation/camera/avfcamerarenderercontrol.h
+++ b/src/plugins/avfoundation/camera/avfcamerarenderercontrol.h
@@ -61,6 +61,8 @@ public:
void configureAVCaptureSession(AVFCameraSession *cameraSession);
void syncHandleViewfinderFrame(const QVideoFrame &frame);
+ AVCaptureVideoDataOutput *videoDataOutput() const;
+
Q_SIGNALS:
void surfaceChanged(QAbstractVideoSurface *surface);
diff --git a/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm b/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm
index 05edd0a91..87bfeb82a 100644
--- a/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm
+++ b/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm
@@ -31,6 +31,7 @@
**
****************************************************************************/
+#include "avfcameraviewfindersettingscontrol.h"
#include "avfcamerarenderercontrol.h"
#include "avfcamerasession.h"
#include "avfcameraservice.h"
@@ -129,7 +130,17 @@ private:
int height = CVPixelBufferGetHeight(imageBuffer);
QAbstractVideoBuffer *buffer = new CVPixelBufferVideoBuffer(imageBuffer);
- QVideoFrame frame(buffer, QSize(width, height), QVideoFrame::Format_RGB32);
+
+ QVideoFrame::PixelFormat format = QVideoFrame::Format_RGB32;
+ if ([captureOutput isKindOfClass:[AVCaptureVideoDataOutput class]]) {
+ NSDictionary *settings = ((AVCaptureVideoDataOutput *)captureOutput).videoSettings;
+ if (settings && [settings objectForKey:(id)kCVPixelBufferPixelFormatTypeKey]) {
+ NSNumber *avf = [settings objectForKey:(id)kCVPixelBufferPixelFormatTypeKey];
+ format = AVFCameraViewfinderSettingsControl2::QtPixelFormatFromCVFormat([avf unsignedIntValue]);
+ }
+ }
+
+ QVideoFrame frame(buffer, QSize(width, height), format);
m_renderer->syncHandleViewfinderFrame(frame);
}
@end
@@ -236,6 +247,11 @@ void AVFCameraRendererControl::syncHandleViewfinderFrame(const QVideoFrame &fram
m_cameraSession->onCameraFrameFetched(m_lastViewfinderFrame);
}
+AVCaptureVideoDataOutput *AVFCameraRendererControl::videoDataOutput() const
+{
+ return m_videoDataOutput;
+}
+
void AVFCameraRendererControl::handleViewfinderFrame()
{
QVideoFrame frame;
diff --git a/src/plugins/avfoundation/camera/avfcameraservice.h b/src/plugins/avfoundation/camera/avfcameraservice.h
index 752065bff..fffa14422 100644
--- a/src/plugins/avfoundation/camera/avfcameraservice.h
+++ b/src/plugins/avfoundation/camera/avfcameraservice.h
@@ -55,6 +55,7 @@ class AVFAudioInputSelectorControl;
class AVFCameraFocusControl;
class AVFCameraExposureControl;
class AVFCameraZoomControl;
+class AVFCameraViewfinderSettingsControl2;
class AVFCameraService : public QMediaService
{
@@ -76,6 +77,8 @@ public:
AVFCameraFocusControl *cameraFocusControl() const { return m_cameraFocusControl; }
AVFCameraExposureControl *cameraExposureControl() const {return m_cameraExposureControl; }
AVFCameraZoomControl *cameraZoomControl() const {return m_cameraZoomControl; }
+ AVFCameraRendererControl *videoOutput() const {return m_videoOutput; }
+ AVFCameraViewfinderSettingsControl2 *viewfinderSettingsControl2() const {return m_viewfinderSettingsControl2; }
private:
AVFCameraSession *m_session;
@@ -90,6 +93,7 @@ private:
AVFCameraFocusControl *m_cameraFocusControl;
AVFCameraExposureControl *m_cameraExposureControl;
AVFCameraZoomControl *m_cameraZoomControl;
+ AVFCameraViewfinderSettingsControl2 *m_viewfinderSettingsControl2;
};
QT_END_NAMESPACE
diff --git a/src/plugins/avfoundation/camera/avfcameraservice.mm b/src/plugins/avfoundation/camera/avfcameraservice.mm
index 5b4a90bb3..188dc821a 100644
--- a/src/plugins/avfoundation/camera/avfcameraservice.mm
+++ b/src/plugins/avfoundation/camera/avfcameraservice.mm
@@ -50,6 +50,7 @@
#include "avfmediavideoprobecontrol.h"
#include "avfcamerafocuscontrol.h"
#include "avfcameraexposurecontrol.h"
+#include "avfcameraviewfindersettingscontrol.h"
#ifdef Q_OS_IOS
#include "avfcamerazoomcontrol.h"
@@ -84,6 +85,7 @@ AVFCameraService::AVFCameraService(QObject *parent):
#ifdef Q_OS_IOS
m_cameraZoomControl = new AVFCameraZoomControl(this);
#endif
+ m_viewfinderSettingsControl2 = new AVFCameraViewfinderSettingsControl2(this);
}
AVFCameraService::~AVFCameraService()
@@ -107,6 +109,8 @@ AVFCameraService::~AVFCameraService()
#ifdef Q_OS_IOS
delete m_cameraZoomControl;
#endif
+ delete m_viewfinderSettingsControl2;
+
delete m_session;
}
@@ -140,6 +144,9 @@ QMediaControl *AVFCameraService::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,QMediaVideoProbeControl_iid) == 0) {
AVFMediaVideoProbeControl *videoProbe = 0;
videoProbe = new AVFMediaVideoProbeControl(this);
diff --git a/src/plugins/avfoundation/camera/avfcamerasession.h b/src/plugins/avfoundation/camera/avfcamerasession.h
index 8598d7c00..c5bae660c 100644
--- a/src/plugins/avfoundation/camera/avfcamerasession.h
+++ b/src/plugins/avfoundation/camera/avfcamerasession.h
@@ -98,6 +98,7 @@ Q_SIGNALS:
private:
static void updateCameraDevices();
void attachInputDevices();
+ void applyViewfinderSettings();
static QByteArray m_defaultCameraDevice;
static QList<QByteArray> m_cameraDevices;
diff --git a/src/plugins/avfoundation/camera/avfcamerasession.mm b/src/plugins/avfoundation/camera/avfcamerasession.mm
index e7e886488..5570aa83b 100644
--- a/src/plugins/avfoundation/camera/avfcamerasession.mm
+++ b/src/plugins/avfoundation/camera/avfcamerasession.mm
@@ -39,6 +39,7 @@
#include "avfcameradevicecontrol.h"
#include "avfaudioinputselectorcontrol.h"
#include "avfmediavideoprobecontrol.h"
+#include "avfcameraviewfindersettingscontrol.h"
#include <CoreFoundation/CoreFoundation.h>
#include <Foundation/Foundation.h>
@@ -275,6 +276,7 @@ void AVFCameraSession::setState(QCamera::State newState)
Q_EMIT readyToConfigureConnections();
[m_captureSession commitConfiguration];
[m_captureSession startRunning];
+ applyViewfinderSettings();
}
if (oldState == QCamera::ActiveState) {
@@ -364,6 +366,15 @@ void AVFCameraSession::attachInputDevices()
}
}
+void AVFCameraSession::applyViewfinderSettings()
+{
+ if (AVFCameraViewfinderSettingsControl2 *control = m_service->viewfinderSettingsControl2()) {
+ QCameraViewfinderSettings settings(control->requestedSettings());
+ // TODO: Adjust the resolution (from image encoder control), updating 'settings'.
+ control->setViewfinderSettings(settings);
+ }
+}
+
void AVFCameraSession::addProbe(AVFMediaVideoProbeControl *probe)
{
m_videoProbesMutex.lock();
diff --git a/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.h b/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.h
new file mode 100644
index 000000000..d2864c62a
--- /dev/null
+++ b/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** 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 AVFCAMERAVIEWFINDERSETTINGSCONTROL_H
+#define AVFCAMERAVIEWFINDERSETTINGSCONTROL_H
+
+#include <QtMultimedia/qcameraviewfindersettingscontrol.h>
+#include <QtMultimedia/qcameraviewfindersettings.h>
+#include <QtMultimedia/qvideoframe.h>
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qsize.h>
+
+@class AVCaptureDevice;
+@class AVCaptureVideoDataOutput;
+@class AVCaptureConnection;
+@class AVCaptureDeviceFormat;
+
+QT_BEGIN_NAMESPACE
+
+class AVFCameraSession;
+class AVFCameraService;
+
+class AVFCameraViewfinderSettingsControl2 : public QCameraViewfinderSettingsControl2
+{
+ Q_OBJECT
+
+ friend class AVFCameraSession;
+public:
+ AVFCameraViewfinderSettingsControl2(AVFCameraService *service);
+
+ QList<QCameraViewfinderSettings> supportedViewfinderSettings() const Q_DECL_OVERRIDE;
+ QCameraViewfinderSettings viewfinderSettings() const Q_DECL_OVERRIDE;
+ void setViewfinderSettings(const QCameraViewfinderSettings &settings) Q_DECL_OVERRIDE;
+
+ // "Converters":
+ static QVideoFrame::PixelFormat QtPixelFormatFromCVFormat(unsigned avPixelFormat);
+ static bool CVPixelFormatFromQtFormat(QVideoFrame::PixelFormat qtFormat, unsigned &conv);
+
+private:
+ void setResolution(const QSize &resolution);
+ void setFramerate(qreal minFPS, qreal maxFPS, bool useActive);
+ void setPixelFormat(QVideoFrame::PixelFormat newFormat);
+ AVCaptureDeviceFormat *findBestFormatMatch(const QCameraViewfinderSettings &settings) const;
+ bool convertPixelFormatIfSupported(QVideoFrame::PixelFormat format, unsigned &avfFormat) const;
+ void applySettings();
+ QCameraViewfinderSettings requestedSettings() const;
+ // Aux. function to extract things like captureDevice, videoOutput, etc.
+ bool updateAVFoundationObjects() const;
+
+ AVFCameraService *m_service;
+ mutable AVFCameraSession *m_session;
+ QCameraViewfinderSettings m_settings;
+ mutable AVCaptureDevice *m_captureDevice;
+ mutable AVCaptureVideoDataOutput *m_videoOutput;
+ mutable AVCaptureConnection *m_videoConnection;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm b/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm
new file mode 100644
index 000000000..c9d04f626
--- /dev/null
+++ b/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm
@@ -0,0 +1,579 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** 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 "avfcameraviewfindersettingscontrol.h"
+#include "avfcamerarenderercontrol.h"
+#include "avfcamerautility.h"
+#include "avfcamerasession.h"
+#include "avfcameraservice.h"
+#include "avfcameradebug.h"
+
+#include <QtCore/qvariant.h>
+#include <QtCore/qsysinfo.h>
+#include <QtCore/qvector.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qlist.h>
+
+#include <algorithm>
+
+#include <AVFoundation/AVFoundation.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+
+QVector<QVideoFrame::PixelFormat> qt_viewfinder_pixel_formats(AVCaptureVideoDataOutput *videoOutput)
+{
+ Q_ASSERT(videoOutput);
+
+ QVector<QVideoFrame::PixelFormat> qtFormats;
+
+ NSArray *pixelFormats = [videoOutput availableVideoCVPixelFormatTypes];
+ for (NSObject *obj in pixelFormats) {
+ if (![obj isKindOfClass:[NSNumber class]])
+ continue;
+
+ NSNumber *formatAsNSNumber = static_cast<NSNumber *>(obj);
+ // It's actually FourCharCode (== UInt32):
+ const QVideoFrame::PixelFormat qtFormat(AVFCameraViewfinderSettingsControl2::
+ QtPixelFormatFromCVFormat([formatAsNSNumber unsignedIntValue]));
+ if (qtFormat != QVideoFrame::Format_Invalid)
+ qtFormats << qtFormat;
+ }
+
+ return qtFormats;
+}
+
+bool qt_framerates_sane(const QCameraViewfinderSettings &settings)
+{
+ const qreal minFPS = settings.minimumFrameRate();
+ const qreal maxFPS = settings.maximumFrameRate();
+
+ if (minFPS < 0. || maxFPS < 0.)
+ return false;
+
+ return !maxFPS || maxFPS >= minFPS;
+}
+
+void qt_set_framerate_limits(AVCaptureConnection *videoConnection,
+ const QCameraViewfinderSettings &settings)
+{
+ Q_ASSERT(videoConnection);
+
+ if (!qt_framerates_sane(settings)) {
+ qDebugCamera() << Q_FUNC_INFO << "invalid framerate (min, max):"
+ << settings.minimumFrameRate() << settings.maximumFrameRate();
+ return;
+ }
+
+ const qreal minFPS = settings.minimumFrameRate();
+ const qreal maxFPS = settings.maximumFrameRate();
+
+ CMTime minDuration = kCMTimeInvalid;
+ CMTime maxDuration = kCMTimeInvalid;
+ if (minFPS > 0. || maxFPS > 0.) {
+ if (maxFPS) {
+ if (!videoConnection.supportsVideoMinFrameDuration)
+ qDebugCamera() << Q_FUNC_INFO << "maximum framerate is not supported";
+ else
+ minDuration = CMTimeMake(1, maxFPS);
+ }
+
+ if (minFPS) {
+ if (!videoConnection.supportsVideoMaxFrameDuration)
+ qDebugCamera() << Q_FUNC_INFO << "minimum framerate is not supported";
+ else
+ maxDuration = CMTimeMake(1, minFPS);
+ }
+ }
+
+ if (videoConnection.supportsVideoMinFrameDuration)
+ videoConnection.videoMinFrameDuration = minDuration;
+ if (videoConnection.supportsVideoMaxFrameDuration)
+ videoConnection.videoMaxFrameDuration = maxDuration;
+}
+
+#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_7_0)
+
+CMTime qt_adjusted_frame_duration(AVFrameRateRange *range, qreal fps)
+{
+ Q_ASSERT(range);
+ Q_ASSERT(fps > 0.);
+
+ if (range.maxFrameRate - range.minFrameRate < 0.1) {
+ // Can happen on OS X.
+ return range.minFrameDuration;
+ }
+
+ if (fps <= range.minFrameRate)
+ return range.maxFrameDuration;
+ if (fps >= range.maxFrameRate)
+ return range.minFrameDuration;
+
+ const AVFRational timeAsRational(qt_float_to_rational(1. / fps, 1000));
+ return CMTimeMake(timeAsRational.first, timeAsRational.second);
+}
+
+void qt_set_framerate_limits(AVCaptureDevice *captureDevice,
+ const QCameraViewfinderSettings &settings)
+{
+ Q_ASSERT(captureDevice);
+ if (!captureDevice.activeFormat) {
+ qDebugCamera() << Q_FUNC_INFO << "no active capture device format";
+ return;
+ }
+
+ const qreal minFPS = settings.minimumFrameRate();
+ const qreal maxFPS = settings.maximumFrameRate();
+ if (!qt_framerates_sane(settings)) {
+ qDebugCamera() << Q_FUNC_INFO << "invalid framerates (min, max):"
+ << minFPS << maxFPS;
+ return;
+ }
+
+ CMTime minFrameDuration = kCMTimeInvalid;
+ CMTime maxFrameDuration = kCMTimeInvalid;
+ if (maxFPS || minFPS) {
+ AVFrameRateRange *range = qt_find_supported_framerate_range(captureDevice.activeFormat,
+ maxFPS ? maxFPS : minFPS);
+ if (!range) {
+ qDebugCamera() << Q_FUNC_INFO << "no framerate range found, (min, max):"
+ << minFPS << maxFPS;
+ return;
+ }
+
+ if (maxFPS)
+ minFrameDuration = qt_adjusted_frame_duration(range, maxFPS);
+ if (minFPS)
+ maxFrameDuration = qt_adjusted_frame_duration(range, minFPS);
+ }
+
+ const AVFConfigurationLock lock(captureDevice);
+ if (!lock) {
+ qDebugCamera() << Q_FUNC_INFO << "failed to lock for configuration";
+ return;
+ }
+
+ // While Apple's docs say kCMTimeInvalid will end in default
+ // settings for this format, kCMTimeInvalid on OS X ends with a runtime
+ // exception:
+ // "The activeVideoMinFrameDuration passed is not supported by the device."
+#ifdef Q_OS_IOS
+ [captureDevice setActiveVideoMinFrameDuration:minFrameDuration];
+ [captureDevice setActiveVideoMaxFrameDuration:maxFrameDuration];
+#else
+ if (CMTimeCompare(minFrameDuration, kCMTimeInvalid))
+ [captureDevice setActiveVideoMinFrameDuration:minFrameDuration];
+ if (CMTimeCompare(maxFrameDuration, kCMTimeInvalid))
+ [captureDevice setActiveVideoMaxFrameDuration:maxFrameDuration];
+#endif
+}
+
+#endif // Platform SDK >= 10.9, >= 7.0.
+
+// 'Dispatchers':
+
+AVFPSRange qt_current_framerates(AVCaptureDevice *captureDevice, AVCaptureConnection *videoConnection)
+{
+ Q_ASSERT(captureDevice);
+ Q_ASSERT(videoConnection);
+
+ AVFPSRange fps;
+#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_7_0)
+ if (QSysInfo::MacintoshVersion >= qt_OS_limit(QSysInfo::MV_10_7, QSysInfo::MV_IOS_7_0)) {
+ const CMTime minDuration = captureDevice.activeVideoMinFrameDuration;
+ if (CMTimeCompare(minDuration, kCMTimeInvalid)) {
+ if (const Float64 minSeconds = CMTimeGetSeconds(minDuration))
+ fps.second = 1. / minSeconds; // Max FPS = 1 / MinDuration.
+ }
+
+ const CMTime maxDuration = captureDevice.activeVideoMaxFrameDuration;
+ if (CMTimeCompare(maxDuration, kCMTimeInvalid)) {
+ if (const Float64 maxSeconds = CMTimeGetSeconds(maxDuration))
+ fps.first = 1. / maxSeconds; // Min FPS = 1 / MaxDuration.
+ }
+ } else {
+#else
+ {
+#endif
+ fps = qt_connection_framerates(videoConnection);
+ }
+
+ return fps;
+}
+
+void qt_set_framerate_limits(AVCaptureDevice *captureDevice, AVCaptureConnection *videoConnection,
+ const QCameraViewfinderSettings &settings)
+{
+ Q_ASSERT(captureDevice);
+ Q_ASSERT(videoConnection);
+#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_7_0)
+ if (QSysInfo::MacintoshVersion >= qt_OS_limit(QSysInfo::MV_10_9, QSysInfo::MV_IOS_7_0))
+ qt_set_framerate_limits(captureDevice, settings);
+ else
+ qt_set_framerate_limits(videoConnection, settings);
+#else
+ qt_set_framerate_limits(videoConnection, settings);
+#endif
+}
+
+} // Unnamed namespace.
+
+AVFCameraViewfinderSettingsControl2::AVFCameraViewfinderSettingsControl2(AVFCameraService *service)
+ : m_service(service),
+ m_captureDevice(0),
+ m_videoOutput(0),
+ m_videoConnection(0)
+{
+ Q_ASSERT(service);
+}
+
+QList<QCameraViewfinderSettings> AVFCameraViewfinderSettingsControl2::supportedViewfinderSettings() const
+{
+ QList<QCameraViewfinderSettings> supportedSettings;
+
+ if (!updateAVFoundationObjects()) {
+ qDebugCamera() << Q_FUNC_INFO << "no capture device or video output found";
+ return supportedSettings;
+ }
+
+ QVector<AVFPSRange> framerates;
+
+ QVector<QVideoFrame::PixelFormat> pixelFormats(qt_viewfinder_pixel_formats(m_videoOutput));
+ if (!pixelFormats.size())
+ pixelFormats << QVideoFrame::Format_Invalid; // The default value.
+#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_7_0)
+ if (QSysInfo::MacintoshVersion >= qt_OS_limit(QSysInfo::MV_10_7, QSysInfo::MV_IOS_7_0)) {
+ if (!m_captureDevice.formats || !m_captureDevice.formats.count) {
+ qDebugCamera() << Q_FUNC_INFO << "no capture device formats found";
+ return supportedSettings;
+ }
+
+ for (AVCaptureDeviceFormat *format in m_captureDevice.formats) {
+ if (qt_is_video_range_subtype(format))
+ continue;
+ const QSize res(qt_device_format_resolution(format));
+ if (res.isNull() || !res.isValid())
+ continue;
+ const QSize par(qt_device_format_pixel_aspect_ratio(format));
+ if (par.isNull() || !par.isValid())
+ continue;
+
+ framerates = qt_device_format_framerates(format);
+ if (!framerates.size())
+ framerates << AVFPSRange(); // The default value.
+
+ for (int i = 0; i < pixelFormats.size(); ++i) {
+ for (int j = 0; j < framerates.size(); ++j) {
+ QCameraViewfinderSettings newSet;
+ newSet.setResolution(res);
+ newSet.setPixelAspectRatio(par);
+ newSet.setPixelFormat(pixelFormats[i]);
+ newSet.setMinimumFrameRate(framerates[j].first);
+ newSet.setMaximumFrameRate(framerates[j].second);
+ supportedSettings << newSet;
+ }
+ }
+ }
+ } else {
+#else
+ {
+#endif
+ // TODO: resolution and PAR.
+ framerates << qt_connection_framerates(m_videoConnection);
+ for (int i = 0; i < pixelFormats.size(); ++i) {
+ for (int j = 0; j < framerates.size(); ++j) {
+ QCameraViewfinderSettings newSet;
+ newSet.setPixelFormat(pixelFormats[i]);
+ newSet.setMinimumFrameRate(framerates[j].first);
+ newSet.setMaximumFrameRate(framerates[j].second);
+ supportedSettings << newSet;
+ }
+ }
+ }
+
+ return supportedSettings;
+}
+
+QCameraViewfinderSettings AVFCameraViewfinderSettingsControl2::viewfinderSettings() const
+{
+ QCameraViewfinderSettings settings;
+
+ if (!updateAVFoundationObjects()) {
+ qDebugCamera() << Q_FUNC_INFO << "no capture device or video output found";
+ return settings;
+ }
+
+#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_7_0)
+ if (QSysInfo::MacintoshVersion >= qt_OS_limit(QSysInfo::MV_10_7, QSysInfo::MV_IOS_7_0)) {
+ if (!m_captureDevice.activeFormat) {
+ qDebugCamera() << Q_FUNC_INFO << "no active capture device format";
+ return settings;
+ }
+
+ const QSize res(qt_device_format_resolution(m_captureDevice.activeFormat));
+ const QSize par(qt_device_format_pixel_aspect_ratio(m_captureDevice.activeFormat));
+ if (res.isNull() || !res.isValid() || par.isNull() || !par.isValid()) {
+ qDebugCamera() << Q_FUNC_INFO << "failed to obtain resolution/pixel aspect ratio";
+ return settings;
+ }
+
+ settings.setResolution(res);
+ settings.setPixelAspectRatio(par);
+ }
+#endif
+ // TODO: resolution and PAR before 7.0.
+ const AVFPSRange fps = qt_current_framerates(m_captureDevice, m_videoConnection);
+ settings.setMinimumFrameRate(fps.first);
+ settings.setMaximumFrameRate(fps.second);
+
+ if (NSObject *obj = [m_videoOutput.videoSettings objectForKey:(id)kCVPixelBufferPixelFormatTypeKey]) {
+ if ([obj isKindOfClass:[NSNumber class]]) {
+ NSNumber *nsNum = static_cast<NSNumber *>(obj);
+ settings.setPixelFormat(QtPixelFormatFromCVFormat([nsNum unsignedIntValue]));
+ }
+ }
+
+ return settings;
+}
+
+void AVFCameraViewfinderSettingsControl2::setViewfinderSettings(const QCameraViewfinderSettings &settings)
+{
+ if (settings.isNull()) {
+ qDebugCamera() << Q_FUNC_INFO << "empty viewfinder settings";
+ return;
+ }
+
+ if (m_settings == settings)
+ return;
+
+ m_settings = settings;
+ applySettings();
+}
+
+QVideoFrame::PixelFormat AVFCameraViewfinderSettingsControl2::QtPixelFormatFromCVFormat(unsigned avPixelFormat)
+{
+ // BGRA <-> ARGB "swap" is intentional:
+ // to work correctly with GL_RGBA, color swap shaders
+ // (in QSG node renderer etc.).
+ switch (avPixelFormat) {
+ case kCVPixelFormatType_32ARGB:
+ return QVideoFrame::Format_BGRA32;
+ case kCVPixelFormatType_32BGRA:
+ return QVideoFrame::Format_ARGB32;
+ case kCVPixelFormatType_24RGB:
+ return QVideoFrame::Format_RGB24;
+ case kCVPixelFormatType_24BGR:
+ return QVideoFrame::Format_BGR24;
+ default:
+ return QVideoFrame::Format_Invalid;
+ }
+}
+
+bool AVFCameraViewfinderSettingsControl2::CVPixelFormatFromQtFormat(QVideoFrame::PixelFormat qtFormat, unsigned &conv)
+{
+ // BGRA <-> ARGB "swap" is intentional:
+ // to work correctly with GL_RGBA, color swap shaders
+ // (in QSG node renderer etc.).
+ switch (qtFormat) {
+ case QVideoFrame::Format_ARGB32:
+ conv = kCVPixelFormatType_32BGRA;
+ break;
+ case QVideoFrame::Format_BGRA32:
+ conv = kCVPixelFormatType_32ARGB;
+ break;
+ // These two formats below are not supported
+ // by QSGVideoNodeFactory_RGB, so for now I have to
+ // disable them.
+ /*
+ case QVideoFrame::Format_RGB24:
+ conv = kCVPixelFormatType_24RGB;
+ break;
+ case QVideoFrame::Format_BGR24:
+ conv = kCVPixelFormatType_24BGR;
+ break;
+ */
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+AVCaptureDeviceFormat *AVFCameraViewfinderSettingsControl2::findBestFormatMatch(const QCameraViewfinderSettings &settings) const
+{
+#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_7_0)
+ if (QSysInfo::MacintoshVersion >= qt_OS_limit(QSysInfo::MV_10_7, QSysInfo::MV_IOS_7_0)) {
+ Q_ASSERT(m_captureDevice);
+
+ const QSize &resolution = settings.resolution();
+ if (!resolution.isNull() && resolution.isValid()) {
+ // Either the exact match (including high resolution for images on iOS)
+ // or a format with a resolution close to the requested one.
+ return qt_find_best_resolution_match(m_captureDevice, resolution);
+ }
+
+ // No resolution requested, what about framerates?
+ if (!qt_framerates_sane(settings)) {
+ qDebugCamera() << Q_FUNC_INFO << "invalid framerate requested (min/max):"
+ << settings.minimumFrameRate() << settings.maximumFrameRate();
+ return nil;
+ }
+
+ const qreal minFPS(settings.minimumFrameRate());
+ const qreal maxFPS(settings.maximumFrameRate());
+ if (minFPS || maxFPS)
+ return qt_find_best_framerate_match(m_captureDevice, maxFPS ? maxFPS : minFPS);
+ // Ignore PAR for the moment (PAR without resolution can
+ // pick a format with really bad resolution).
+ // No need to test pixel format, just return settings.
+ }
+#endif
+ return nil;
+}
+
+bool AVFCameraViewfinderSettingsControl2::convertPixelFormatIfSupported(QVideoFrame::PixelFormat qtFormat, unsigned &avfFormat)const
+{
+ Q_ASSERT(m_videoOutput);
+
+ unsigned conv = 0;
+ if (!CVPixelFormatFromQtFormat(qtFormat, conv))
+ return false;
+
+ NSArray *formats = [m_videoOutput availableVideoCVPixelFormatTypes];
+ if (!formats || !formats.count)
+ return false;
+
+ for (NSObject *obj in formats) {
+ if (![obj isKindOfClass:[NSNumber class]])
+ continue;
+ NSNumber *nsNum = static_cast<NSNumber *>(obj);
+ if ([nsNum unsignedIntValue] == conv) {
+ avfFormat = conv;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void AVFCameraViewfinderSettingsControl2::applySettings()
+{
+ if (m_settings.isNull())
+ return;
+
+ if (!updateAVFoundationObjects())
+ return;
+
+ if (m_session->state() != QCamera::LoadedState &&
+ m_session->state() != QCamera::ActiveState) {
+ return;
+ }
+
+ NSMutableDictionary *videoSettings = [NSMutableDictionary dictionaryWithCapacity:1];
+#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_7_0)
+ AVCaptureDeviceFormat *match = findBestFormatMatch(m_settings);
+ if (match) {
+ if (match != m_captureDevice.activeFormat) {
+ const AVFConfigurationLock lock(m_captureDevice);
+ if (!lock) {
+ qDebugCamera() << Q_FUNC_INFO << "failed to lock for configuration";
+ return;
+ }
+
+ m_captureDevice.activeFormat = match;
+ }
+ } else {
+ qDebugCamera() << Q_FUNC_INFO << "matching device format not found";
+ // We still can update the pixel format at least.
+ }
+#endif
+
+ unsigned avfPixelFormat = 0;
+ if (m_settings.pixelFormat() != QVideoFrame::Format_Invalid &&
+ convertPixelFormatIfSupported(m_settings.pixelFormat(), avfPixelFormat)) {
+ [videoSettings setObject:[NSNumber numberWithUnsignedInt:avfPixelFormat]
+ forKey:(id)kCVPixelBufferPixelFormatTypeKey];
+ } else {
+ // We have to set the pixel format, otherwise AVFoundation can change it to something we do not support.
+ if (NSObject *oldFormat = [m_videoOutput.videoSettings objectForKey:(id)kCVPixelBufferPixelFormatTypeKey]) {
+ [videoSettings setObject:oldFormat forKey:(id)kCVPixelBufferPixelFormatTypeKey];
+ } else {
+ [videoSettings setObject:[NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA]
+ forKey:(id)kCVPixelBufferPixelFormatTypeKey];
+ }
+ }
+
+ if (videoSettings.count)
+ m_videoOutput.videoSettings = videoSettings;
+
+ qt_set_framerate_limits(m_captureDevice, m_videoConnection, m_settings);
+}
+
+QCameraViewfinderSettings AVFCameraViewfinderSettingsControl2::requestedSettings() const
+{
+ return m_settings;
+}
+
+bool AVFCameraViewfinderSettingsControl2::updateAVFoundationObjects() const
+{
+ m_session = 0;
+ m_captureDevice = 0;
+ m_videoOutput = 0;
+ m_videoConnection = 0;
+
+ if (!m_service->session())
+ return false;
+
+ if (!m_service->session()->videoCaptureDevice())
+ return false;
+
+ if (!m_service->videoOutput() || !m_service->videoOutput()->videoDataOutput())
+ return false;
+
+ AVCaptureVideoDataOutput *output = m_service->videoOutput()->videoDataOutput();
+ AVCaptureConnection *connection = [output connectionWithMediaType:AVMediaTypeVideo];
+ if (!connection)
+ return false;
+
+ m_session = m_service->session();
+ m_captureDevice = m_session->videoCaptureDevice();
+ m_videoOutput = output;
+ m_videoConnection = connection;
+
+ return true;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_avfcameraviewfindersettingscontrol.cpp"
diff --git a/src/plugins/avfoundation/camera/camera.pro b/src/plugins/avfoundation/camera/camera.pro
index 82084a1bc..19e3e631c 100644
--- a/src/plugins/avfoundation/camera/camera.pro
+++ b/src/plugins/avfoundation/camera/camera.pro
@@ -39,7 +39,8 @@ HEADERS += \
avfcameradevicecontrol.h \
avfcamerafocuscontrol.h \
avfcameraexposurecontrol.h \
- avfcamerautility.h
+ avfcamerautility.h \
+ avfcameraviewfindersettingscontrol.h
OBJECTIVE_SOURCES += \
avfcameraserviceplugin.mm \
@@ -58,7 +59,8 @@ OBJECTIVE_SOURCES += \
avfcamerarenderercontrol.mm \
avfcamerafocuscontrol.mm \
avfcameraexposurecontrol.mm \
- avfcamerautility.mm
+ avfcamerautility.mm \
+ avfcameraviewfindersettingscontrol.mm
ios {