summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/multimedia/platform/darwin/camera/avfcamerasession.mm210
-rw-r--r--src/multimedia/platform/darwin/camera/avfcamerasession_p.h13
-rw-r--r--src/multimedia/platform/darwin/camera/avfmediaassetwriter.mm17
3 files changed, 174 insertions, 66 deletions
diff --git a/src/multimedia/platform/darwin/camera/avfcamerasession.mm b/src/multimedia/platform/darwin/camera/avfcamerasession.mm
index ce0234370..1dedd801b 100644
--- a/src/multimedia/platform/darwin/camera/avfcamerasession.mm
+++ b/src/multimedia/platform/darwin/camera/avfcamerasession.mm
@@ -53,6 +53,7 @@
#include <QtCore/qdatetime.h>
#include <QtCore/qurl.h>
#include <QtCore/qelapsedtimer.h>
+#include <QtCore/qpointer.h>
#include <private/qplatformaudioinput_p.h>
#include <private/qplatformaudiooutput_p.h>
@@ -179,26 +180,9 @@ void AVFCameraSession::setActiveCamera(const QCameraDevice &info)
if (m_activeCameraDevice != info) {
m_activeCameraDevice = info;
- auto recorder = m_service->recorderControl();
- if (recorder && recorder->state() == QMediaRecorder::RecordingState)
- recorder->toggleRecord(false);
-
- [m_captureSession beginConfiguration];
-
- attachVideoInputDevice();
- if (!m_activeCameraDevice.isNull() && !m_videoOutput) {
- setVideoOutput(new AVFCameraRenderer(this));
- connect(m_videoOutput, &AVFCameraRenderer::newViewfinderFrame,
- this, &AVFCameraSession::newViewfinderFrame);
- updateVideoOutput();
- }
- m_videoOutput->deviceOrientationChanged();
-
- [m_captureSession commitConfiguration];
-
- if (recorder && recorder->state() == QMediaRecorder::RecordingState)
- recorder->toggleRecord(true);
- Q_EMIT readyToConfigureConnections();
+ requestCameraPermissionIfNeeded();
+ if (m_cameraAuthorizationStatus == AVAuthorizationStatusAuthorized)
+ updateVideoInput();
}
}
@@ -206,6 +190,12 @@ void AVFCameraSession::setCameraFormat(const QCameraFormat &format)
{
if (m_cameraFormat == format)
return;
+
+ updateCameraFormat(format);
+}
+
+void AVFCameraSession::updateCameraFormat(const QCameraFormat &format)
+{
m_cameraFormat = format;
AVCaptureDevice *captureDevice = videoCaptureDevice();
@@ -382,6 +372,9 @@ AVCaptureDevice *AVFCameraSession::createAudioCaptureDevice()
void AVFCameraSession::attachVideoInputDevice()
{
+ if (m_cameraAuthorizationStatus != AVAuthorizationStatusAuthorized)
+ return;
+
if (m_videoInput) {
[m_captureSession removeInput:m_videoInput];
[m_videoInput release];
@@ -389,30 +382,25 @@ void AVFCameraSession::attachVideoInputDevice()
}
AVCaptureDevice *videoDevice = createVideoCaptureDevice();
- if (videoDevice) {
- NSError *error = nil;
- m_videoInput = [AVCaptureDeviceInput
- deviceInputWithDevice:videoDevice
- error:&error];
-
- if (!m_videoInput) {
- qWarning() << "Failed to create video device input";
- } else {
- if ([m_captureSession canAddInput:m_videoInput]) {
- [m_videoInput retain];
- [m_captureSession addInput:m_videoInput];
- } else {
- qWarning() << "Failed to connect video device input";
- m_activeCameraDevice = QCameraDevice();
- }
- }
+ if (!videoDevice)
+ return;
+
+ m_videoInput = [AVCaptureDeviceInput
+ deviceInputWithDevice:videoDevice
+ error:nil];
+ if (m_videoInput && [m_captureSession canAddInput:m_videoInput]) {
+ [m_videoInput retain];
+ [m_captureSession addInput:m_videoInput];
} else {
- m_activeCameraDevice = QCameraDevice();
+ qWarning() << "Failed to create video device input";
}
}
void AVFCameraSession::attachAudioInputDevice()
{
+ if (m_microphoneAuthorizationStatus != AVAuthorizationStatusAuthorized)
+ return;
+
if (m_audioInput) {
[m_captureSession removeInput:m_audioInput];
[m_audioInput release];
@@ -420,22 +408,18 @@ void AVFCameraSession::attachAudioInputDevice()
}
AVCaptureDevice *audioDevice = createAudioCaptureDevice();
- if (audioDevice) {
- NSError *error = nil;
- m_audioInput = [AVCaptureDeviceInput
- deviceInputWithDevice:audioDevice
- error:&error];
-
- if (!m_audioInput) {
- qWarning() << "Failed to create audio device input";
- } else {
- if ([m_captureSession canAddInput:m_audioInput]) {
- [m_audioInput retain];
- [m_captureSession addInput:m_audioInput];
- } else {
- qWarning() << "Failed to connect audio device input";
- }
- }
+ if (!audioDevice)
+ return;
+
+ m_audioInput = [AVCaptureDeviceInput
+ deviceInputWithDevice:audioDevice
+ error:nil];
+
+ if (m_audioInput && [m_captureSession canAddInput:m_audioInput]) {
+ [m_audioInput retain];
+ [m_captureSession addInput:m_audioInput];
+ } else {
+ qWarning() << "Failed to create audio device input";
}
}
@@ -472,8 +456,37 @@ void AVFCameraSession::setVideoSink(QVideoSink *sink)
updateVideoOutput();
}
+void AVFCameraSession::updateVideoInput()
+{
+ auto recorder = m_service->recorderControl();
+ if (recorder && recorder->state() == QMediaRecorder::RecordingState)
+ recorder->toggleRecord(false);
+
+ [m_captureSession beginConfiguration];
+
+ attachVideoInputDevice();
+ if (!m_activeCameraDevice.isNull() && !m_videoOutput) {
+ setVideoOutput(new AVFCameraRenderer(this));
+ connect(m_videoOutput, &AVFCameraRenderer::newViewfinderFrame,
+ this, &AVFCameraSession::newViewfinderFrame);
+ updateVideoOutput();
+ }
+ if (m_videoOutput)
+ m_videoOutput->deviceOrientationChanged();
+
+ [m_captureSession commitConfiguration];
+
+ if (recorder && recorder->state() == QMediaRecorder::RecordingState)
+ recorder->toggleRecord(true);
+ Q_EMIT readyToConfigureConnections();
+}
+
void AVFCameraSession::updateAudioInput()
{
+ requestMicrophonePermissionIfNeeded();
+ if (m_microphoneAuthorizationStatus != AVAuthorizationStatusAuthorized)
+ return;
+
auto recorder = m_service->recorderControl();
if (recorder && recorder->state() == QMediaRecorder::RecordingState)
recorder->toggleRecord(false);
@@ -519,4 +532,93 @@ void AVFCameraSession::updateVideoOutput()
}
}
+void AVFCameraSession::requestCameraPermissionIfNeeded()
+{
+ if (m_cameraAuthorizationStatus == AVAuthorizationStatusAuthorized)
+ return;
+
+ switch ([AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo])
+ {
+ case AVAuthorizationStatusAuthorized:
+ {
+ m_cameraAuthorizationStatus = AVAuthorizationStatusAuthorized;
+ break;
+ }
+ case AVAuthorizationStatusNotDetermined:
+ {
+ m_cameraAuthorizationStatus = AVAuthorizationStatusNotDetermined;
+ QPointer<AVFCameraSession> guard(this);
+ [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ if (guard)
+ cameraAuthorizationChanged(granted);
+ });
+ }];
+ break;
+ }
+ case AVAuthorizationStatusDenied:
+ case AVAuthorizationStatusRestricted:
+ {
+ m_cameraAuthorizationStatus = AVAuthorizationStatusDenied;
+ return;
+ }
+ }
+}
+
+void AVFCameraSession::requestMicrophonePermissionIfNeeded()
+{
+ if (m_microphoneAuthorizationStatus == AVAuthorizationStatusAuthorized)
+ return;
+
+ switch ([AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio])
+ {
+ case AVAuthorizationStatusAuthorized:
+ {
+ m_microphoneAuthorizationStatus = AVAuthorizationStatusAuthorized;
+ break;
+ }
+ case AVAuthorizationStatusNotDetermined:
+ {
+ m_microphoneAuthorizationStatus = AVAuthorizationStatusNotDetermined;
+ QPointer<AVFCameraSession> guard(this);
+ [AVCaptureDevice requestAccessForMediaType:AVMediaTypeAudio completionHandler:^(BOOL granted) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ if (guard)
+ microphoneAuthorizationChanged(granted);
+ });
+ }];
+ break;
+ }
+ case AVAuthorizationStatusDenied:
+ case AVAuthorizationStatusRestricted:
+ {
+ m_microphoneAuthorizationStatus = AVAuthorizationStatusDenied;
+ return;
+ }
+ }
+}
+
+void AVFCameraSession::cameraAuthorizationChanged(bool authorized)
+{
+ if (authorized) {
+ m_cameraAuthorizationStatus = AVAuthorizationStatusAuthorized;
+ updateVideoInput();
+ updateCameraFormat(m_cameraFormat);
+ } else {
+ m_cameraAuthorizationStatus = AVAuthorizationStatusDenied;
+ qWarning() << "User has denied access to camera";
+ }
+}
+
+void AVFCameraSession::microphoneAuthorizationChanged(bool authorized)
+{
+ if (authorized) {
+ m_microphoneAuthorizationStatus = AVAuthorizationStatusAuthorized;
+ updateAudioInput();
+ } else {
+ m_microphoneAuthorizationStatus = AVAuthorizationStatusDenied;
+ qWarning() << "User has denied access to microphone";
+ }
+}
+
#include "moc_avfcamerasession_p.cpp"
diff --git a/src/multimedia/platform/darwin/camera/avfcamerasession_p.h b/src/multimedia/platform/darwin/camera/avfcamerasession_p.h
index e461b809c..05ddf3373 100644
--- a/src/multimedia/platform/darwin/camera/avfcamerasession_p.h
+++ b/src/multimedia/platform/darwin/camera/avfcamerasession_p.h
@@ -85,7 +85,6 @@ public:
AVCaptureAudioDataOutput *audioOutput() const { return m_audioOutput; }
AVFAudioPreviewDelegate *audioPreviewDelegate() const { return m_audioPreviewDelegate; }
-
AVCaptureSession *captureSession() const { return m_captureSession; }
AVCaptureDevice *videoCaptureDevice() const;
AVCaptureDevice *audioCaptureDevice() const;
@@ -99,6 +98,8 @@ public:
void setVideoSink(QVideoSink *sink);
+ void updateVideoInput();
+
void updateAudioInput();
void updateAudioOutput();
@@ -114,6 +115,9 @@ public Q_SLOTS:
void processSessionStarted();
void processSessionStopped();
+ void cameraAuthorizationChanged(bool authorized);
+ void microphoneAuthorizationChanged(bool authorized);
+
Q_SIGNALS:
void readyToConfigureConnections();
void activeChanged(bool);
@@ -121,6 +125,8 @@ Q_SIGNALS:
void newViewfinderFrame(const QVideoFrame &frame);
private:
+ void updateCameraFormat(const QCameraFormat &format);
+
void setVideoOutput(AVFCameraRenderer *output);
void updateVideoOutput();
@@ -130,6 +136,8 @@ private:
AVCaptureDevice *createAudioCaptureDevice();
void attachVideoInputDevice();
void attachAudioInputDevice();
+ void requestCameraPermissionIfNeeded();
+ void requestMicrophonePermissionIfNeeded();
bool applyImageEncoderSettings();
@@ -155,6 +163,9 @@ private:
bool m_inputMuted = false;
FourCharCode m_defaultCodec;
+
+ AVAuthorizationStatus m_cameraAuthorizationStatus = AVAuthorizationStatusDenied;
+ AVAuthorizationStatus m_microphoneAuthorizationStatus = AVAuthorizationStatusDenied;
};
QT_END_NAMESPACE
diff --git a/src/multimedia/platform/darwin/camera/avfmediaassetwriter.mm b/src/multimedia/platform/darwin/camera/avfmediaassetwriter.mm
index ed90dbd07..586e1a60e 100644
--- a/src/multimedia/platform/darwin/camera/avfmediaassetwriter.mm
+++ b/src/multimedia/platform/darwin/camera/avfmediaassetwriter.mm
@@ -62,6 +62,9 @@ bool qt_capture_session_isValid(AVFCameraService *service)
if (!session->captureSession())
return false;
+ if (!session->videoInput() && !session->audioInput())
+ return false;
+
return true;
}
@@ -171,7 +174,7 @@ using AVFAtomicInt64 = QAtomicInteger<qint64>;
return false;
}
- if (session->videoOutput() && session->videoOutput()->videoDataOutput()) {
+ if (session->videoInput() && session->videoOutput() && session->videoOutput()->videoDataOutput()) {
m_videoQueue.reset(dispatch_queue_create("video-output-queue", DISPATCH_QUEUE_SERIAL));
if (!m_videoQueue) {
qDebugCamera() << Q_FUNC_INFO << "failed to create video queue";
@@ -197,10 +200,6 @@ using AVFAtomicInt64 = QAtomicInteger<qint64>;
return false;
}
- bool audioCaptureOn = false;
- if (m_audioQueue)
- audioCaptureOn = session->audioOutput() != nil;
-
if (!m_videoQueue)
m_writeFirstAudioBuffer = true;
@@ -492,16 +491,12 @@ using AVFAtomicInt64 = QAtomicInteger<qint64>;
if (m_videoQueue)
{
- Q_ASSERT(session->videoOutput() && session->videoOutput()->videoDataOutput());
+ Q_ASSERT(session->videoCaptureDevice() && session->videoOutput() && session->videoOutput()->videoDataOutput());
m_cameraWriterInput.reset([[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeVideo
outputSettings:m_videoSettings
sourceFormatHint:session->videoCaptureDevice().activeFormat.formatDescription]);
- if (!m_cameraWriterInput) {
- qDebugCamera() << Q_FUNC_INFO << "failed to create camera writer input";
- return false;
- }
- if ([m_assetWriter canAddInput:m_cameraWriterInput]) {
+ if (m_cameraWriterInput && [m_assetWriter canAddInput:m_cameraWriterInput]) {
[m_assetWriter addInput:m_cameraWriterInput];
} else {
qDebugCamera() << Q_FUNC_INFO << "failed to add camera writer input";