From 9b5a67d810a1aafb9afbb0861ef016f3fcaf903f Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Thu, 12 Nov 2015 15:40:21 +0100 Subject: AVFoundation: improve viewfinder settings. Retrieving the supported viewfinder settings don't actually require a video surface, we just need a capture device. The supported settings can now be retrieved without calling QCamera::setSurface(). More generally, all viewfinder settings that don't require a video surface can now be gotten/set before calling setSurface(). Task-number: QTBUG-49170 Change-Id: I39b14eeb40517a9ba399748b5778be8bbc8cfcda Reviewed-by: Timur Pocheptsov --- .../camera/avfcameraviewfindersettingscontrol.h | 8 +- .../camera/avfcameraviewfindersettingscontrol.mm | 204 ++++++++++----------- 2 files changed, 102 insertions(+), 110 deletions(-) (limited to 'src/plugins/avfoundation/camera') diff --git a/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.h b/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.h index cf2f512a7..8d9b88c01 100644 --- a/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.h +++ b/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.h @@ -78,15 +78,11 @@ private: 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; + + AVCaptureConnection *videoConnection() const; AVFCameraService *m_service; - mutable AVFCameraSession *m_session; QCameraViewfinderSettings m_settings; - mutable AVCaptureDevice *m_captureDevice; - mutable AVCaptureVideoDataOutput *m_videoOutput; - mutable AVCaptureConnection *m_videoConnection; }; class AVFCameraViewfinderSettingsControl : public QCameraViewfinderSettingsControl diff --git a/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm b/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm index c5da1c343..95fadb816 100644 --- a/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm +++ b/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm @@ -206,7 +206,6 @@ void qt_set_framerate_limits(AVCaptureDevice *captureDevice, 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) @@ -234,7 +233,8 @@ AVFPSRange qt_current_framerates(AVCaptureDevice *captureDevice, AVCaptureConnec #else // OSX < 10.7 or iOS < 7.0 { #endif // QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_7_0) - fps = qt_connection_framerates(videoConnection); + if (videoConnection) + fps = qt_connection_framerates(videoConnection); } return fps; @@ -244,24 +244,20 @@ void qt_set_framerate_limits(AVCaptureDevice *captureDevice, AVCaptureConnection 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 + if (videoConnection) + qt_set_framerate_limits(videoConnection, settings); + } } // Unnamed namespace. AVFCameraViewfinderSettingsControl2::AVFCameraViewfinderSettingsControl2(AVFCameraService *service) - : m_service(service), - m_captureDevice(0), - m_videoOutput(0), - m_videoConnection(0) + : m_service(service) { Q_ASSERT(service); } @@ -270,8 +266,9 @@ QList AVFCameraViewfinderSettingsControl2::supportedV { QList supportedSettings; - if (!updateAVFoundationObjects()) { - qDebugCamera() << Q_FUNC_INFO << "no capture device or video output found"; + AVCaptureDevice *captureDevice = m_service->session()->videoCaptureDevice(); + if (!captureDevice) { + qDebugCamera() << Q_FUNC_INFO << "no capture device found"; return supportedSettings; } @@ -281,15 +278,16 @@ QList AVFCameraViewfinderSettingsControl2::supportedV 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) { + if (!captureDevice.formats || !captureDevice.formats.count) { qDebugCamera() << Q_FUNC_INFO << "no capture device formats found"; return supportedSettings; } - const QVector formats(qt_unique_device_formats(m_captureDevice, - m_session->defaultCodec())); + const QVector formats(qt_unique_device_formats(captureDevice, + m_service->session()->defaultCodec())); for (int i = 0; i < formats.size(); ++i) { AVCaptureDeviceFormat *format = formats[i]; @@ -320,15 +318,18 @@ QList AVFCameraViewfinderSettingsControl2::supportedV #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; + AVCaptureConnection *connection = videoConnection(); + if (connection) { + // TODO: resolution and PAR. + framerates << qt_connection_framerates(connection); + 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; + } } } } @@ -340,20 +341,21 @@ QCameraViewfinderSettings AVFCameraViewfinderSettingsControl2::viewfinderSetting { QCameraViewfinderSettings settings; - if (!updateAVFoundationObjects()) { - qDebugCamera() << Q_FUNC_INFO << "no capture device or video output found"; + AVCaptureDevice *captureDevice = m_service->session()->videoCaptureDevice(); + if (!captureDevice) { + qDebugCamera() << Q_FUNC_INFO << "no capture device 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) { + if (!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)); + const QSize res(qt_device_format_resolution(captureDevice.activeFormat)); + const QSize par(qt_device_format_pixel_aspect_ratio(captureDevice.activeFormat)); if (res.isNull() || !res.isValid() || par.isNull() || !par.isValid()) { qDebugCamera() << Q_FUNC_INFO << "failed to obtain resolution/pixel aspect ratio"; return settings; @@ -364,12 +366,14 @@ QCameraViewfinderSettings AVFCameraViewfinderSettingsControl2::viewfinderSetting } #endif // TODO: resolution and PAR before 7.0. - const AVFPSRange fps = qt_current_framerates(m_captureDevice, m_videoConnection); + const AVFPSRange fps = qt_current_framerates(captureDevice, videoConnection()); settings.setMinimumFrameRate(fps.first); settings.setMaximumFrameRate(fps.second); - if (NSObject *obj = [m_videoOutput.videoSettings objectForKey:(id)kCVPixelBufferPixelFormatTypeKey]) { - if ([obj isKindOfClass:[NSNumber class]]) { + AVCaptureVideoDataOutput *videoOutput = m_service->videoOutput() ? m_service->videoOutput()->videoDataOutput() : 0; + if (videoOutput) { + NSObject *obj = [videoOutput.videoSettings objectForKey:(id)kCVPixelBufferPixelFormatTypeKey]; + if (obj && [obj isKindOfClass:[NSNumber class]]) { NSNumber *nsNum = static_cast(obj); settings.setPixelFormat(QtPixelFormatFromCVFormat([nsNum unsignedIntValue])); } @@ -449,17 +453,19 @@ bool AVFCameraViewfinderSettingsControl2::CVPixelFormatFromQtFormat(QVideoFrame: AVCaptureDeviceFormat *AVFCameraViewfinderSettingsControl2::findBestFormatMatch(const QCameraViewfinderSettings &settings) const { + AVCaptureDevice *captureDevice = m_service->session()->videoCaptureDevice(); + if (!captureDevice) + return nil; + #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, - m_session->defaultCodec()); + return qt_find_best_resolution_match(captureDevice, resolution, + m_service->session()->defaultCodec()); } // No resolution requested, what about framerates? @@ -472,22 +478,28 @@ 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, - m_session->defaultCodec()); + return qt_find_best_framerate_match(captureDevice, maxFPS ? maxFPS : minFPS, + m_service->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. } #endif + return nil; } QVector AVFCameraViewfinderSettingsControl2::viewfinderPixelFormats() const { - Q_ASSERT(m_videoOutput); - QVector qtFormats; - NSArray *pixelFormats = [m_videoOutput availableVideoCVPixelFormatTypes]; + + AVCaptureVideoDataOutput *videoOutput = m_service->videoOutput() ? m_service->videoOutput()->videoDataOutput() : 0; + if (!videoOutput) { + qDebugCamera() << Q_FUNC_INFO << "no video output found"; + return qtFormats; + } + + NSArray *pixelFormats = [videoOutput availableVideoCVPixelFormatTypes]; for (NSObject *obj in pixelFormats) { if (![obj isKindOfClass:[NSNumber class]]) @@ -508,17 +520,19 @@ QVector AVFCameraViewfinderSettingsControl2::viewfinde bool AVFCameraViewfinderSettingsControl2::convertPixelFormatIfSupported(QVideoFrame::PixelFormat qtFormat, unsigned &avfFormat)const { - Q_ASSERT(m_videoOutput); + AVCaptureVideoDataOutput *videoOutput = m_service->videoOutput() ? m_service->videoOutput()->videoDataOutput() : 0; + if (!videoOutput) + return false; unsigned conv = 0; if (!CVPixelFormatFromQtFormat(qtFormat, conv)) return false; - NSArray *formats = [m_videoOutput availableVideoCVPixelFormatTypes]; + NSArray *formats = [videoOutput availableVideoCVPixelFormatTypes]; if (!formats || !formats.count) return false; - if (m_service->videoOutput() && m_service->videoOutput()->surface()) { + if (m_service->videoOutput()->surface()) { const QAbstractVideoSurface *surface = m_service->videoOutput()->surface(); if (!surface->supportedPixelFormats().contains(qtFormat)) return false; @@ -544,26 +558,27 @@ void AVFCameraViewfinderSettingsControl2::applySettings() if (m_settings.isNull()) return; - if (!updateAVFoundationObjects()) + if (m_service->session()->state() != QCamera::LoadedState && + m_service->session()->state() != QCamera::ActiveState) { return; + } - if (m_session->state() != QCamera::LoadedState && - m_session->state() != QCamera::ActiveState) { + AVCaptureDevice *captureDevice = m_service->session()->videoCaptureDevice(); + if (!captureDevice) 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 (match != captureDevice.activeFormat) { + const AVFConfigurationLock lock(captureDevice); if (!lock) { qDebugCamera() << Q_FUNC_INFO << "failed to lock for configuration"; return; } - m_captureDevice.activeFormat = match; + captureDevice.activeFormat = match; } } else { qDebugCamera() << Q_FUNC_INFO << "matching device format not found"; @@ -571,43 +586,45 @@ void AVFCameraViewfinderSettingsControl2::applySettings() } #endif - unsigned avfPixelFormat = 0; - if (!convertPixelFormatIfSupported(m_settings.pixelFormat(), avfPixelFormat)) { - // If the the pixel format is not specified or invalid, pick the preferred video surface - // format, or if no surface is set, the preferred capture device format - - const QVector deviceFormats = viewfinderPixelFormats(); - QVideoFrame::PixelFormat pickedFormat = deviceFormats.first(); - - QAbstractVideoSurface *surface = m_service->videoOutput() ? m_service->videoOutput()->surface() - : 0; - if (surface) { - if (m_service->videoOutput()->supportsTextures()) { - pickedFormat = QVideoFrame::Format_ARGB32; - } else { - QList surfaceFormats = m_service->videoOutput()->surface()->supportedPixelFormats(); - - for (int i = 0; i < surfaceFormats.count(); ++i) { - const QVideoFrame::PixelFormat surfaceFormat = surfaceFormats.at(i); - if (deviceFormats.contains(surfaceFormat)) { - pickedFormat = surfaceFormat; - break; + AVCaptureVideoDataOutput *videoOutput = m_service->videoOutput() ? m_service->videoOutput()->videoDataOutput() : 0; + if (videoOutput) { + unsigned avfPixelFormat = 0; + if (!convertPixelFormatIfSupported(m_settings.pixelFormat(), avfPixelFormat)) { + // If the the pixel format is not specified or invalid, pick the preferred video surface + // format, or if no surface is set, the preferred capture device format + + const QVector deviceFormats = viewfinderPixelFormats(); + QVideoFrame::PixelFormat pickedFormat = deviceFormats.first(); + + QAbstractVideoSurface *surface = m_service->videoOutput()->surface(); + if (surface) { + if (m_service->videoOutput()->supportsTextures()) { + pickedFormat = QVideoFrame::Format_ARGB32; + } else { + QList surfaceFormats = surface->supportedPixelFormats(); + + for (int i = 0; i < surfaceFormats.count(); ++i) { + const QVideoFrame::PixelFormat surfaceFormat = surfaceFormats.at(i); + if (deviceFormats.contains(surfaceFormat)) { + pickedFormat = surfaceFormat; + break; + } } } } - } - CVPixelFormatFromQtFormat(pickedFormat, avfPixelFormat); - } + CVPixelFormatFromQtFormat(pickedFormat, avfPixelFormat); + } - if (avfPixelFormat != 0) { - [videoSettings setObject:[NSNumber numberWithUnsignedInt:avfPixelFormat] - forKey:(id)kCVPixelBufferPixelFormatTypeKey]; + if (avfPixelFormat != 0) { + [videoSettings setObject:[NSNumber numberWithUnsignedInt:avfPixelFormat] + forKey:(id)kCVPixelBufferPixelFormatTypeKey]; - m_videoOutput.videoSettings = videoSettings; + videoOutput.videoSettings = videoSettings; + } } - qt_set_framerate_limits(m_captureDevice, m_videoConnection, m_settings); + qt_set_framerate_limits(captureDevice, videoConnection(), m_settings); } QCameraViewfinderSettings AVFCameraViewfinderSettingsControl2::requestedSettings() const @@ -615,33 +632,12 @@ QCameraViewfinderSettings AVFCameraViewfinderSettingsControl2::requestedSettings return m_settings; } -bool AVFCameraViewfinderSettingsControl2::updateAVFoundationObjects() const +AVCaptureConnection *AVFCameraViewfinderSettingsControl2::videoConnection() 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; + return nil; - 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; + return [m_service->videoOutput()->videoDataOutput() connectionWithMediaType:AVMediaTypeVideo]; } AVFCameraViewfinderSettingsControl::AVFCameraViewfinderSettingsControl(AVFCameraService *service) -- cgit v1.2.3 From 8dc46cef05d901bb48f0d87e19a8b35b5e70757e Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Thu, 19 Nov 2015 15:19:23 +0100 Subject: AVFoundation: fix setting the camera viewfinder resolution. Image capture resolution and viewfinder resolution must be the same, with the image capture resolution taking precedence over the viewfinder resolution when both are explicitly set. The code was getting the active image capture resolution, instead of the one explicitly requested, to adjust the viewfinder resolution. That effectively made the viewfinder resolution always ignored since the active capture resolution always has a default value. Task-number: QTBUG-49170 Change-Id: I2f3d01366d83a3e28c0a1ea0109663cfdfa75963 Reviewed-by: Timur Pocheptsov --- src/plugins/avfoundation/camera/avfcamerasession.mm | 4 +++- src/plugins/avfoundation/camera/avfimageencodercontrol.h | 2 ++ src/plugins/avfoundation/camera/avfimageencodercontrol.mm | 5 +++++ 3 files changed, 10 insertions(+), 1 deletion(-) (limited to 'src/plugins/avfoundation/camera') diff --git a/src/plugins/avfoundation/camera/avfcamerasession.mm b/src/plugins/avfoundation/camera/avfcamerasession.mm index 2cb3824db..5bf841bec 100644 --- a/src/plugins/avfoundation/camera/avfcamerasession.mm +++ b/src/plugins/avfoundation/camera/avfcamerasession.mm @@ -365,8 +365,10 @@ void AVFCameraSession::applyViewfinderSettings() { if (AVFCameraViewfinderSettingsControl2 *vfControl = m_service->viewfinderSettingsControl2()) { QCameraViewfinderSettings vfSettings(vfControl->requestedSettings()); + // Viewfinder and image capture solutions must be the same, if an image capture + // resolution is set, it takes precedence over the viewfinder resolution. if (AVFImageEncoderControl *imControl = m_service->imageEncoderControl()) { - const QSize imageResolution(imControl->imageSettings().resolution()); + const QSize imageResolution(imControl->requestedSettings().resolution()); if (!imageResolution.isNull() && imageResolution.isValid()) { vfSettings.setResolution(imageResolution); vfControl->setViewfinderSettings(vfSettings); diff --git a/src/plugins/avfoundation/camera/avfimageencodercontrol.h b/src/plugins/avfoundation/camera/avfimageencodercontrol.h index fcb665a03..c805b3e21 100644 --- a/src/plugins/avfoundation/camera/avfimageencodercontrol.h +++ b/src/plugins/avfoundation/camera/avfimageencodercontrol.h @@ -62,6 +62,8 @@ public: QImageEncoderSettings imageSettings() const Q_DECL_OVERRIDE; void setImageSettings(const QImageEncoderSettings &settings) Q_DECL_OVERRIDE; + QImageEncoderSettings requestedSettings() const; + private: AVFCameraService *m_service; QImageEncoderSettings m_settings; diff --git a/src/plugins/avfoundation/camera/avfimageencodercontrol.mm b/src/plugins/avfoundation/camera/avfimageencodercontrol.mm index 36050c3a2..a5e9c0e09 100644 --- a/src/plugins/avfoundation/camera/avfimageencodercontrol.mm +++ b/src/plugins/avfoundation/camera/avfimageencodercontrol.mm @@ -115,6 +115,11 @@ QList AVFImageEncoderControl::supportedResolutions(const QImageEncoderSet return resolutions; } +QImageEncoderSettings AVFImageEncoderControl::requestedSettings() const +{ + return m_settings; +} + QImageEncoderSettings AVFImageEncoderControl::imageSettings() const { QImageEncoderSettings settings; -- cgit v1.2.3 From 5ed9b6d6d77c420ea02aac5f01af1e9f85731f1b Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Thu, 19 Nov 2015 15:32:48 +0100 Subject: AVFoundation: fix setting up the video capture session. Because of an incorrect 'if' condition, the video capture session was set up twice when starting the camera. Change-Id: I4211a8c77ab9b8086628fb0f12fb28842de830cf Reviewed-by: Timur Pocheptsov Reviewed-by: Yoann Lopes --- src/plugins/avfoundation/camera/avfmediarecordercontrol.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/plugins/avfoundation/camera') diff --git a/src/plugins/avfoundation/camera/avfmediarecordercontrol.mm b/src/plugins/avfoundation/camera/avfmediarecordercontrol.mm index 412dab76c..115d70864 100644 --- a/src/plugins/avfoundation/camera/avfmediarecordercontrol.mm +++ b/src/plugins/avfoundation/camera/avfmediarecordercontrol.mm @@ -359,7 +359,7 @@ void AVFMediaRecorderControl::setupSessionForCapture() } } else if (m_connected && (!m_cameraControl->captureMode().testFlag(QCamera::CaptureVideo) - || m_session->state() != QCamera::ActiveState)) { + || m_session->state() == QCamera::UnloadedState)) { [captureSession removeOutput:m_movieOutput]; -- cgit v1.2.3 From 604a5753fa2d9b8e1ef65ccd8c5fb72465462479 Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Thu, 19 Nov 2015 15:41:01 +0100 Subject: AVFoundation: correctly set the activeFormat on the AVCaptureDevice. According to the AVCaptureDevice documentation, the device must be locked before starting the capture session to prevent the activeFormat from being overridden. We now do that, but only if we explicitly set an activeFormat. Otherwise the device is not locked, which allows the session to find an appropriate format for the capture device. The device is also locked when enabling video capture, as doing so might also reset the activeFormat. Task-number: QTBUG-49170 Change-Id: I75478fd4bbfec96cd2abd2c3ae2951088b38978e Reviewed-by: Timur Pocheptsov --- src/plugins/avfoundation/camera/avfcamerasession.h | 4 +-- .../avfoundation/camera/avfcamerasession.mm | 30 +++++++++++++++++----- .../camera/avfcameraviewfindersettingscontrol.h | 2 +- .../camera/avfcameraviewfindersettingscontrol.mm | 30 ++++++++++------------ .../avfoundation/camera/avfimageencodercontrol.h | 2 +- .../avfoundation/camera/avfimageencodercontrol.mm | 25 ++++++++++-------- .../avfoundation/camera/avfmediarecordercontrol.mm | 7 +++++ 7 files changed, 62 insertions(+), 38 deletions(-) (limited to 'src/plugins/avfoundation/camera') diff --git a/src/plugins/avfoundation/camera/avfcamerasession.h b/src/plugins/avfoundation/camera/avfcamerasession.h index 2b322cfaf..1be847b7c 100644 --- a/src/plugins/avfoundation/camera/avfcamerasession.h +++ b/src/plugins/avfoundation/camera/avfcamerasession.h @@ -102,8 +102,8 @@ Q_SIGNALS: private: static void updateCameraDevices(); void attachVideoInputDevice(); - void applyImageEncoderSettings(); - void applyViewfinderSettings(); + bool applyImageEncoderSettings(); + bool applyViewfinderSettings(); static int m_defaultCameraIndex; static QList m_cameraDevices; diff --git a/src/plugins/avfoundation/camera/avfcamerasession.mm b/src/plugins/avfoundation/camera/avfcamerasession.mm index 5bf841bec..4ede4a514 100644 --- a/src/plugins/avfoundation/camera/avfcamerasession.mm +++ b/src/plugins/avfoundation/camera/avfcamerasession.mm @@ -285,10 +285,23 @@ void AVFCameraSession::setState(QCamera::State newState) Q_EMIT readyToConfigureConnections(); m_defaultCodec = 0; defaultCodec(); - applyImageEncoderSettings(); - applyViewfinderSettings(); + + bool activeFormatSet = applyImageEncoderSettings(); + activeFormatSet |= applyViewfinderSettings(); + [m_captureSession commitConfiguration]; + + if (activeFormatSet) { + // According to the doc, the capture device must be locked before + // startRunning to prevent the format we set to be overriden by the + // session preset. + [videoCaptureDevice() lockForConfiguration:nil]; + } + [m_captureSession startRunning]; + + if (activeFormatSet) + [videoCaptureDevice() unlockForConfiguration]; } if (oldState == QCamera::ActiveState) { @@ -355,13 +368,15 @@ void AVFCameraSession::attachVideoInputDevice() } } -void AVFCameraSession::applyImageEncoderSettings() +bool AVFCameraSession::applyImageEncoderSettings() { if (AVFImageEncoderControl *control = m_service->imageEncoderControl()) - control->applySettings(); + return control->applySettings(); + + return false; } -void AVFCameraSession::applyViewfinderSettings() +bool AVFCameraSession::applyViewfinderSettings() { if (AVFCameraViewfinderSettingsControl2 *vfControl = m_service->viewfinderSettingsControl2()) { QCameraViewfinderSettings vfSettings(vfControl->requestedSettings()); @@ -372,12 +387,13 @@ void AVFCameraSession::applyViewfinderSettings() if (!imageResolution.isNull() && imageResolution.isValid()) { vfSettings.setResolution(imageResolution); vfControl->setViewfinderSettings(vfSettings); - return; } } - vfControl->applySettings(); + return vfControl->applySettings(); } + + return false; } void AVFCameraSession::addProbe(AVFMediaVideoProbeControl *probe) diff --git a/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.h b/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.h index 8d9b88c01..9a5bbd5de 100644 --- a/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.h +++ b/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.h @@ -76,7 +76,7 @@ private: AVCaptureDeviceFormat *findBestFormatMatch(const QCameraViewfinderSettings &settings) const; QVector viewfinderPixelFormats() const; bool convertPixelFormatIfSupported(QVideoFrame::PixelFormat format, unsigned &avfFormat) const; - void applySettings(); + bool applySettings(); QCameraViewfinderSettings requestedSettings() const; AVCaptureConnection *videoConnection() const; diff --git a/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm b/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm index 95fadb816..3c20801e5 100644 --- a/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm +++ b/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm @@ -384,11 +384,6 @@ QCameraViewfinderSettings AVFCameraViewfinderSettingsControl2::viewfinderSetting void AVFCameraViewfinderSettingsControl2::setViewfinderSettings(const QCameraViewfinderSettings &settings) { - if (settings.isNull()) { - qDebugCamera() << Q_FUNC_INFO << "empty viewfinder settings"; - return; - } - if (m_settings == settings) return; @@ -454,7 +449,7 @@ bool AVFCameraViewfinderSettingsControl2::CVPixelFormatFromQtFormat(QVideoFrame: AVCaptureDeviceFormat *AVFCameraViewfinderSettingsControl2::findBestFormatMatch(const QCameraViewfinderSettings &settings) const { AVCaptureDevice *captureDevice = m_service->session()->videoCaptureDevice(); - if (!captureDevice) + if (!captureDevice || settings.isNull()) return nil; #if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_7_0) @@ -553,32 +548,30 @@ bool AVFCameraViewfinderSettingsControl2::convertPixelFormatIfSupported(QVideoFr return found; } -void AVFCameraViewfinderSettingsControl2::applySettings() +bool AVFCameraViewfinderSettingsControl2::applySettings() { - if (m_settings.isNull()) - return; - if (m_service->session()->state() != QCamera::LoadedState && m_service->session()->state() != QCamera::ActiveState) { - return; + return false; } AVCaptureDevice *captureDevice = m_service->session()->videoCaptureDevice(); if (!captureDevice) - return; + return false; + + bool activeFormatChanged = false; - 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 != captureDevice.activeFormat) { const AVFConfigurationLock lock(captureDevice); - if (!lock) { + if (lock) { + captureDevice.activeFormat = match; + activeFormatChanged = true; + } else { qDebugCamera() << Q_FUNC_INFO << "failed to lock for configuration"; - return; } - - captureDevice.activeFormat = match; } } else { qDebugCamera() << Q_FUNC_INFO << "matching device format not found"; @@ -617,6 +610,7 @@ void AVFCameraViewfinderSettingsControl2::applySettings() } if (avfPixelFormat != 0) { + NSMutableDictionary *videoSettings = [NSMutableDictionary dictionaryWithCapacity:1]; [videoSettings setObject:[NSNumber numberWithUnsignedInt:avfPixelFormat] forKey:(id)kCVPixelBufferPixelFormatTypeKey]; @@ -625,6 +619,8 @@ void AVFCameraViewfinderSettingsControl2::applySettings() } qt_set_framerate_limits(captureDevice, videoConnection(), m_settings); + + return activeFormatChanged; } QCameraViewfinderSettings AVFCameraViewfinderSettingsControl2::requestedSettings() const diff --git a/src/plugins/avfoundation/camera/avfimageencodercontrol.h b/src/plugins/avfoundation/camera/avfimageencodercontrol.h index c805b3e21..d3af77ffd 100644 --- a/src/plugins/avfoundation/camera/avfimageencodercontrol.h +++ b/src/plugins/avfoundation/camera/avfimageencodercontrol.h @@ -68,7 +68,7 @@ private: AVFCameraService *m_service; QImageEncoderSettings m_settings; - void applySettings(); + bool applySettings(); bool videoCaptureDeviceIsValid() const; }; diff --git a/src/plugins/avfoundation/camera/avfimageencodercontrol.mm b/src/plugins/avfoundation/camera/avfimageencodercontrol.mm index a5e9c0e09..e2eb0bd01 100644 --- a/src/plugins/avfoundation/camera/avfimageencodercontrol.mm +++ b/src/plugins/avfoundation/camera/avfimageencodercontrol.mm @@ -168,40 +168,40 @@ QImageEncoderSettings AVFImageEncoderControl::imageSettings() const void AVFImageEncoderControl::setImageSettings(const QImageEncoderSettings &settings) { - if (m_settings == settings || settings.isNull()) + if (m_settings == settings) return; m_settings = settings; applySettings(); } -void AVFImageEncoderControl::applySettings() +bool AVFImageEncoderControl::applySettings() { if (!videoCaptureDeviceIsValid()) - return; + return false; AVFCameraSession *session = m_service->session(); if (!session || (session->state() != QCamera::ActiveState && session->state() != QCamera::LoadedState)) { - return; + return false; } if (!m_service->imageCaptureControl() || !m_service->imageCaptureControl()->stillImageOutput()) { qDebugCamera() << Q_FUNC_INFO << "no still image output"; - return; + return false; } if (m_settings.codec().size() && m_settings.codec() != QLatin1String("jpeg")) { qDebugCamera() << Q_FUNC_INFO << "unsupported codec:" << m_settings.codec(); - return; + return false; } QSize res(m_settings.resolution()); if (res.isNull()) { qDebugCamera() << Q_FUNC_INFO << "invalid resolution:" << res; - return; + return false; } if (!res.isValid()) { @@ -209,9 +209,11 @@ void AVFImageEncoderControl::applySettings() // Here we could choose the best format available, but // activeFormat is already equal to 'preset high' by default, // which is good enough, otherwise we can end in some format with low framerates. - return; + return false; } + bool activeFormatChanged = false; + #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(); @@ -220,16 +222,17 @@ void AVFImageEncoderControl::applySettings() if (!match) { qDebugCamera() << Q_FUNC_INFO << "unsupported resolution:" << res; - return; + return false; } if (match != captureDevice.activeFormat) { const AVFConfigurationLock lock(captureDevice); if (!lock) { qDebugCamera() << Q_FUNC_INFO << "failed to lock for configuration"; - return; + return false; } captureDevice.activeFormat = match; + activeFormatChanged = true; } #if defined(Q_OS_IOS) && QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_8_0) @@ -247,6 +250,8 @@ void AVFImageEncoderControl::applySettings() #endif // TODO: resolution without capture device format ... } + + return activeFormatChanged; } bool AVFImageEncoderControl::videoCaptureDeviceIsValid() const diff --git a/src/plugins/avfoundation/camera/avfmediarecordercontrol.mm b/src/plugins/avfoundation/camera/avfmediarecordercontrol.mm index 115d70864..1b6e23ee5 100644 --- a/src/plugins/avfoundation/camera/avfmediarecordercontrol.mm +++ b/src/plugins/avfoundation/camera/avfmediarecordercontrol.mm @@ -37,6 +37,7 @@ #include "avfcameraservice.h" #include "avfcameracontrol.h" #include "avfaudioinputselectorcontrol.h" +#include "avfcamerautility.h" #include #include @@ -330,6 +331,9 @@ void AVFMediaRecorderControl::setupSessionForCapture() && m_cameraControl->captureMode().testFlag(QCamera::CaptureVideo) && m_session->state() != QCamera::UnloadedState) { + // Lock the video capture device to make sure the active format is not reset + const AVFConfigurationLock lock(m_session->videoCaptureDevice()); + // Add audio input // Allow recording even if something wrong happens with the audio input initialization AVCaptureDevice *audioDevice = m_audioInputControl->createCaptureDevice(); @@ -361,6 +365,9 @@ void AVFMediaRecorderControl::setupSessionForCapture() && (!m_cameraControl->captureMode().testFlag(QCamera::CaptureVideo) || m_session->state() == QCamera::UnloadedState)) { + // Lock the video capture device to make sure the active format is not reset + const AVFConfigurationLock lock(m_session->videoCaptureDevice()); + [captureSession removeOutput:m_movieOutput]; if (m_audioInput) { -- cgit v1.2.3