summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/avfoundation/camera/avfcamerasession.h2
-rw-r--r--src/plugins/avfoundation/camera/avfcamerasession.mm23
-rw-r--r--src/plugins/avfoundation/camera/avfcamerautility.h10
-rw-r--r--src/plugins/avfoundation/camera/avfcamerautility.mm151
-rw-r--r--src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm15
-rw-r--r--src/plugins/avfoundation/camera/avfimageencodercontrol.mm32
6 files changed, 140 insertions, 93 deletions
diff --git a/src/plugins/avfoundation/camera/avfcamerasession.h b/src/plugins/avfoundation/camera/avfcamerasession.h
index 4f418cb1d..9fd0b1828 100644
--- a/src/plugins/avfoundation/camera/avfcamerasession.h
+++ b/src/plugins/avfoundation/camera/avfcamerasession.h
@@ -80,6 +80,7 @@ public:
void addProbe(AVFMediaVideoProbeControl *probe);
void removeProbe(AVFMediaVideoProbeControl *probe);
+ FourCharCode defaultCodec();
public Q_SLOTS:
void setState(QCamera::State state);
@@ -119,6 +120,7 @@ private:
QSet<AVFMediaVideoProbeControl *> m_videoProbes;
QMutex m_videoProbesMutex;
+ FourCharCode m_defaultCodec;
};
QT_END_NAMESPACE
diff --git a/src/plugins/avfoundation/camera/avfcamerasession.mm b/src/plugins/avfoundation/camera/avfcamerasession.mm
index 98fbb9865..af30dd312 100644
--- a/src/plugins/avfoundation/camera/avfcamerasession.mm
+++ b/src/plugins/avfoundation/camera/avfcamerasession.mm
@@ -41,6 +41,7 @@
#include "avfmediavideoprobecontrol.h"
#include "avfcameraviewfindersettingscontrol.h"
#include "avfimageencodercontrol.h"
+#include "avfcamerautility.h"
#include <CoreFoundation/CoreFoundation.h>
#include <Foundation/Foundation.h>
@@ -143,6 +144,7 @@ AVFCameraSession::AVFCameraSession(AVFCameraService *service, QObject *parent)
, m_active(false)
, m_videoInput(nil)
, m_audioInput(nil)
+ , m_defaultCodec(0)
{
m_captureSession = [[AVCaptureSession alloc] init];
m_observer = [[AVFCameraSessionObserver alloc] initWithCameraSession:this];
@@ -277,6 +279,8 @@ void AVFCameraSession::setState(QCamera::State newState)
Q_EMIT readyToConfigureConnections();
[m_captureSession commitConfiguration];
[m_captureSession startRunning];
+ m_defaultCodec = 0;
+ defaultCodec();
applyImageEncoderSettings();
applyViewfinderSettings();
}
@@ -407,6 +411,25 @@ void AVFCameraSession::removeProbe(AVFMediaVideoProbeControl *probe)
m_videoProbesMutex.unlock();
}
+FourCharCode AVFCameraSession::defaultCodec()
+{
+ if (!m_defaultCodec) {
+#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 (AVCaptureDevice *device = videoCaptureDevice()) {
+ AVCaptureDeviceFormat *format = device.activeFormat;
+ if (!format || !format.formatDescription)
+ return m_defaultCodec;
+ m_defaultCodec = CMVideoFormatDescriptionGetCodecType(format.formatDescription);
+ }
+ }
+#else
+ // TODO: extract media subtype.
+#endif
+ }
+ return m_defaultCodec;
+}
+
void AVFCameraSession::onCameraFrameFetched(const QVideoFrame &frame)
{
m_videoProbesMutex.lock();
diff --git a/src/plugins/avfoundation/camera/avfcamerautility.h b/src/plugins/avfoundation/camera/avfcamerautility.h
index 1c13736e4..03a61460f 100644
--- a/src/plugins/avfoundation/camera/avfcamerautility.h
+++ b/src/plugins/avfoundation/camera/avfcamerautility.h
@@ -97,13 +97,17 @@ AVFRational qt_float_to_rational(qreal par, int limit);
#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_7_0)
-bool qt_is_video_range_subtype(AVCaptureDeviceFormat *format);
+QVector<AVCaptureDeviceFormat *> qt_unique_device_formats(AVCaptureDevice *captureDevice,
+ FourCharCode preferredFormat);
QSize qt_device_format_resolution(AVCaptureDeviceFormat *format);
QSize qt_device_format_high_resolution(AVCaptureDeviceFormat *format);
QSize qt_device_format_pixel_aspect_ratio(AVCaptureDeviceFormat *format);
QVector<AVFPSRange> qt_device_format_framerates(AVCaptureDeviceFormat *format);
-AVCaptureDeviceFormat *qt_find_best_resolution_match(AVCaptureDevice *captureDevice, const QSize &res);
-AVCaptureDeviceFormat *qt_find_best_framerate_match(AVCaptureDevice *captureDevice, Float64 fps);
+AVCaptureDeviceFormat *qt_find_best_resolution_match(AVCaptureDevice *captureDevice, const QSize &res,
+ FourCharCode preferredFormat);
+AVCaptureDeviceFormat *qt_find_best_framerate_match(AVCaptureDevice *captureDevice,
+ FourCharCode preferredFormat,
+ Float64 fps);
AVFrameRateRange *qt_find_supported_framerate_range(AVCaptureDeviceFormat *format, Float64 fps);
#endif
diff --git a/src/plugins/avfoundation/camera/avfcamerautility.mm b/src/plugins/avfoundation/camera/avfcamerautility.mm
index 554c25cb8..f8d5647eb 100644
--- a/src/plugins/avfoundation/camera/avfcamerautility.mm
+++ b/src/plugins/avfoundation/camera/avfcamerautility.mm
@@ -37,6 +37,7 @@
#include <QtCore/qvector.h>
#include <QtCore/qpair.h>
+#include <functional>
#include <algorithm>
#include <limits>
@@ -107,19 +108,6 @@ AVFRational qt_float_to_rational(qreal par, int limit)
#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_7_0)
-bool qt_is_video_range_subtype(AVCaptureDeviceFormat *format)
-{
- Q_ASSERT(format);
-#ifdef Q_OS_IOS
- // Use only 420f on iOS, not 420v.
- const FourCharCode subType = CMFormatDescriptionGetMediaSubType(format.formatDescription);
- return subType == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
-#else
- Q_UNUSED(format)
-#endif
- return false;
-}
-
namespace {
inline bool qt_area_sane(const QSize &size)
@@ -128,40 +116,25 @@ inline bool qt_area_sane(const QSize &size)
&& std::numeric_limits<int>::max() / size.width() >= size.height();
}
-inline bool avf_format_compare(AVCaptureDeviceFormat *f1, AVCaptureDeviceFormat *f2)
+struct ResolutionPredicate : std::binary_function<AVCaptureDeviceFormat *, AVCaptureDeviceFormat *, bool>
{
- Q_ASSERT(f1);
- Q_ASSERT(f2);
- const QSize r1(qt_device_format_resolution(f1));
- const QSize r2(qt_device_format_resolution(f2));
- return r1.width() > r2.width() && r1.height() > r2.height();
-}
+ bool operator() (AVCaptureDeviceFormat *f1, AVCaptureDeviceFormat *f2)const
+ {
+ Q_ASSERT(f1 && f2);
+ const QSize r1(qt_device_format_resolution(f1));
+ const QSize r2(qt_device_format_resolution(f2));
+ return r1.width() < r2.width() || (r2.width() == r1.width() && r1.height() < r2.height());
+ }
+};
-QVector<AVCaptureDeviceFormat *> qt_sort_device_formats(AVCaptureDevice *captureDevice)
+struct FormatHasNoFPSRange : std::unary_function<AVCaptureDeviceFormat *, bool>
{
- // Select only formats with framerate ranges + sort them by resoluions,
- Q_ASSERT(captureDevice);
-
- QVector<AVCaptureDeviceFormat *>sorted;
-
- NSArray *formats = captureDevice.formats;
- if (!formats || !formats.count)
- return sorted;
-
- sorted.reserve(formats.count);
- for (AVCaptureDeviceFormat *format in formats) {
- if (qt_is_video_range_subtype(format))
- continue;
- if (format.videoSupportedFrameRateRanges && format.videoSupportedFrameRateRanges.count) {
- const QSize resolution(qt_device_format_resolution(format));
- if (!resolution.isNull() && resolution.isValid())
- sorted << format;
- }
+ bool operator() (AVCaptureDeviceFormat *format)
+ {
+ Q_ASSERT(format);
+ return !format.videoSupportedFrameRateRanges || !format.videoSupportedFrameRateRanges.count;
}
-
- std::sort(sorted.begin(), sorted.end(), avf_format_compare);
- return sorted;
-}
+};
Float64 qt_find_min_framerate_distance(AVCaptureDeviceFormat *format, Float64 fps)
{
@@ -180,6 +153,50 @@ Float64 qt_find_min_framerate_distance(AVCaptureDeviceFormat *format, Float64 fp
} // Unnamed namespace.
+QVector<AVCaptureDeviceFormat *> qt_unique_device_formats(AVCaptureDevice *captureDevice, FourCharCode filter)
+{
+ // 'filter' is the format we prefer if we have duplicates.
+ Q_ASSERT(captureDevice);
+
+ QVector<AVCaptureDeviceFormat *> formats;
+
+ if (!captureDevice.formats || !captureDevice.formats.count)
+ return formats;
+
+ formats.reserve(captureDevice.formats.count);
+ for (AVCaptureDeviceFormat *format in captureDevice.formats) {
+ const QSize resolution(qt_device_format_resolution(format));
+ if (resolution.isNull() || !resolution.isValid())
+ continue;
+ formats << format;
+ }
+
+ if (!formats.size())
+ return formats;
+
+ std::sort(formats.begin(), formats.end(), ResolutionPredicate());
+
+ QSize size(qt_device_format_resolution(formats[0]));
+ FourCharCode codec = CMVideoFormatDescriptionGetCodecType(formats[0].formatDescription);
+ int last = 0;
+ for (int i = 1; i < formats.size(); ++i) {
+ const QSize nextSize(qt_device_format_resolution(formats[i]));
+ if (nextSize == size) {
+ if (codec == filter)
+ continue;
+ formats[last] = formats[i];
+ } else {
+ ++last;
+ formats[last] = formats[i];
+ size = nextSize;
+ }
+ codec = CMVideoFormatDescriptionGetCodecType(formats[i].formatDescription);
+ }
+ formats.resize(last + 1);
+
+ return formats;
+}
+
QSize qt_device_format_resolution(AVCaptureDeviceFormat *format)
{
Q_ASSERT(format);
@@ -246,7 +263,9 @@ QSize qt_device_format_pixel_aspect_ratio(AVCaptureDeviceFormat *format)
return QSize(asRatio.first, asRatio.second);
}
-AVCaptureDeviceFormat *qt_find_best_resolution_match(AVCaptureDevice *captureDevice, const QSize &request)
+AVCaptureDeviceFormat *qt_find_best_resolution_match(AVCaptureDevice *captureDevice,
+ const QSize &request,
+ FourCharCode filter)
{
Q_ASSERT(captureDevice);
Q_ASSERT(!request.isNull() && request.isValid());
@@ -254,9 +273,10 @@ AVCaptureDeviceFormat *qt_find_best_resolution_match(AVCaptureDevice *captureDev
if (!captureDevice.formats || !captureDevice.formats.count)
return 0;
- for (AVCaptureDeviceFormat *format in captureDevice.formats) {
- if (qt_is_video_range_subtype(format))
- continue;
+ QVector<AVCaptureDeviceFormat *> formats(qt_unique_device_formats(captureDevice, filter));
+
+ for (int i = 0; i < formats.size(); ++i) {
+ AVCaptureDeviceFormat *format = formats[i];
if (qt_device_format_resolution(format) == request)
return format;
// iOS only (still images).
@@ -269,31 +289,30 @@ AVCaptureDeviceFormat *qt_find_best_resolution_match(AVCaptureDevice *captureDev
typedef QPair<QSize, AVCaptureDeviceFormat *> FormatPair;
- QVector<FormatPair> formats;
- formats.reserve(captureDevice.formats.count);
+ QVector<FormatPair> pairs; // default|HR sizes
+ pairs.reserve(formats.size());
- for (AVCaptureDeviceFormat *format in captureDevice.formats) {
- if (qt_is_video_range_subtype(format))
- continue;
+ for (int i = 0; i < formats.size(); ++i) {
+ AVCaptureDeviceFormat *format = formats[i];
const QSize res(qt_device_format_resolution(format));
if (!res.isNull() && res.isValid() && qt_area_sane(res))
- formats << FormatPair(res, format);
+ pairs << FormatPair(res, format);
const QSize highRes(qt_device_format_high_resolution(format));
if (!highRes.isNull() && highRes.isValid() && qt_area_sane(highRes))
- formats << FormatPair(highRes, format);
+ pairs << FormatPair(highRes, format);
}
- if (!formats.size())
+ if (!pairs.size())
return 0;
- AVCaptureDeviceFormat *best = formats[0].second;
- QSize next(formats[0].first);
+ AVCaptureDeviceFormat *best = pairs[0].second;
+ QSize next(pairs[0].first);
int wDiff = qAbs(request.width() - next.width());
int hDiff = qAbs(request.height() - next.height());
const int area = request.width() * request.height();
int areaDiff = qAbs(area - next.width() * next.height());
- for (int i = 1; i < formats.size(); ++i) {
- next = formats[i].first;
+ for (int i = 1; i < pairs.size(); ++i) {
+ next = pairs[i].first;
const int newWDiff = qAbs(next.width() - request.width());
const int newHDiff = qAbs(next.height() - request.height());
const int newAreaDiff = qAbs(area - next.width() * next.height());
@@ -302,7 +321,7 @@ AVCaptureDeviceFormat *qt_find_best_resolution_match(AVCaptureDevice *captureDev
|| ((newWDiff <= wDiff || newHDiff <= hDiff) && newAreaDiff <= areaDiff)) {
wDiff = newWDiff;
hDiff = newHDiff;
- best = formats[i].second;
+ best = pairs[i].second;
areaDiff = newAreaDiff;
}
}
@@ -310,15 +329,21 @@ AVCaptureDeviceFormat *qt_find_best_resolution_match(AVCaptureDevice *captureDev
return best;
}
-AVCaptureDeviceFormat *qt_find_best_framerate_match(AVCaptureDevice *captureDevice, Float64 fps)
+AVCaptureDeviceFormat *qt_find_best_framerate_match(AVCaptureDevice *captureDevice,
+ FourCharCode filter,
+ Float64 fps)
{
Q_ASSERT(captureDevice);
Q_ASSERT(fps > 0.);
const qreal epsilon = 0.1;
- // Sort formats by their resolution.
- const QVector<AVCaptureDeviceFormat *> sorted(qt_sort_device_formats(captureDevice));
+ QVector<AVCaptureDeviceFormat *>sorted(qt_unique_device_formats(captureDevice, filter));
+ // Sort formats by their resolution in decreasing order:
+ std::sort(sorted.begin(), sorted.end(), std::not2(ResolutionPredicate()));
+ // We can use only formats with framerate ranges:
+ sorted.erase(std::remove_if(sorted.begin(), sorted.end(), FormatHasNoFPSRange()), sorted.end());
+
if (!sorted.size())
return nil;
diff --git a/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm b/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm
index c5aa5733d..250aae9c1 100644
--- a/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm
+++ b/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm
@@ -279,9 +279,11 @@ QList<QCameraViewfinderSettings> AVFCameraViewfinderSettingsControl2::supportedV
return supportedSettings;
}
- for (AVCaptureDeviceFormat *format in m_captureDevice.formats) {
- if (qt_is_video_range_subtype(format))
- continue;
+ const QVector<AVCaptureDeviceFormat *> formats(qt_unique_device_formats(m_captureDevice,
+ m_session->defaultCodec()));
+ for (int i = 0; i < formats.size(); ++i) {
+ AVCaptureDeviceFormat *format = formats[i];
+
const QSize res(qt_device_format_resolution(format));
if (res.isNull() || !res.isValid())
continue;
@@ -435,12 +437,14 @@ AVCaptureDeviceFormat *AVFCameraViewfinderSettingsControl2::findBestFormatMatch(
#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);
+ Q_ASSERT(m_session);
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);
+ return qt_find_best_resolution_match(m_captureDevice, resolution,
+ m_session->defaultCodec());
}
// No resolution requested, what about framerates?
@@ -453,7 +457,8 @@ AVCaptureDeviceFormat *AVFCameraViewfinderSettingsControl2::findBestFormatMatch(
const qreal minFPS(settings.minimumFrameRate());
const qreal maxFPS(settings.maximumFrameRate());
if (minFPS || maxFPS)
- return qt_find_best_framerate_match(m_captureDevice, maxFPS ? maxFPS : minFPS);
+ return qt_find_best_framerate_match(m_captureDevice, maxFPS ? maxFPS : minFPS,
+ m_session->defaultCodec());
// 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.
diff --git a/src/plugins/avfoundation/camera/avfimageencodercontrol.mm b/src/plugins/avfoundation/camera/avfimageencodercontrol.mm
index ea25665eb..36050c3a2 100644
--- a/src/plugins/avfoundation/camera/avfimageencodercontrol.mm
+++ b/src/plugins/avfoundation/camera/avfimageencodercontrol.mm
@@ -48,20 +48,6 @@
QT_BEGIN_NAMESPACE
-QSize qt_image_high_resolution(AVCaptureDeviceFormat *format)
-{
- Q_ASSERT(format);
- QSize res;
-#if defined(Q_OS_IOS) && QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_8_0)
- if (QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_8_0) {
- const CMVideoDimensions hrDim(format.highResolutionStillImageDimensions);
- res.setWidth(hrDim.width);
- res.setHeight(hrDim.height);
- }
-#endif
- return res;
-}
-
AVFImageEncoderControl::AVFImageEncoderControl(AVFCameraService *service)
: m_service(service)
{
@@ -94,9 +80,11 @@ QList<QSize> AVFImageEncoderControl::supportedResolutions(const QImageEncoderSet
#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)) {
AVCaptureDevice *captureDevice = m_service->session()->videoCaptureDevice();
- for (AVCaptureDeviceFormat *format in captureDevice.formats) {
- if (qt_is_video_range_subtype(format))
- continue;
+ const QVector<AVCaptureDeviceFormat *> formats(qt_unique_device_formats(captureDevice,
+ m_service->session()->defaultCodec()));
+
+ for (int i = 0; i < formats.size(); ++i) {
+ AVCaptureDeviceFormat *format = formats[i];
const QSize res(qt_device_format_resolution(format));
if (!res.isNull() && res.isValid())
@@ -108,7 +96,7 @@ QList<QSize> AVFImageEncoderControl::supportedResolutions(const QImageEncoderSet
// its source AVCaptureDevice instance’s activeFormat.formatDescription. However,
// if you set this property to YES, the receiver emits still images at the capture
// device’s highResolutionStillImageDimensions value.
- const QSize hrRes(qt_image_high_resolution(format));
+ const QSize hrRes(qt_device_format_high_resolution(format));
if (!hrRes.isNull() && hrRes.isValid())
resolutions << res;
}
@@ -152,7 +140,7 @@ QImageEncoderSettings AVFImageEncoderControl::imageSettings() const
AVCaptureStillImageOutput *stillImageOutput = m_service->imageCaptureControl()->stillImageOutput();
if (stillImageOutput.highResolutionStillImageOutputEnabled)
- res = qt_image_high_resolution(captureDevice.activeFormat);
+ res = qt_device_format_high_resolution(captureDevice.activeFormat);
}
#endif
if (res.isNull() || !res.isValid()) {
@@ -179,7 +167,6 @@ void AVFImageEncoderControl::setImageSettings(const QImageEncoderSettings &setti
return;
m_settings = settings;
-
applySettings();
}
@@ -223,7 +210,8 @@ void AVFImageEncoderControl::applySettings()
#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)) {
AVCaptureDevice *captureDevice = m_service->session()->videoCaptureDevice();
- AVCaptureDeviceFormat *match = qt_find_best_resolution_match(captureDevice, res);
+ AVCaptureDeviceFormat *match = qt_find_best_resolution_match(captureDevice, res,
+ m_service->session()->defaultCodec());
if (!match) {
qDebugCamera() << Q_FUNC_INFO << "unsupported resolution:" << res;
@@ -242,7 +230,7 @@ void AVFImageEncoderControl::applySettings()
#if defined(Q_OS_IOS) && QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_8_0)
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_8_0) {
AVCaptureStillImageOutput *imageOutput = m_service->imageCaptureControl()->stillImageOutput();
- if (res == qt_image_high_resolution(captureDevice.activeFormat))
+ if (res == qt_device_format_high_resolution(captureDevice.activeFormat))
imageOutput.highResolutionStillImageOutputEnabled = YES;
else
imageOutput.highResolutionStillImageOutputEnabled = NO;