6#include <avfvideosink_p.h>
7#include <camera/avfcamera_p.h>
8#include <camera/avfcameraservice_p.h>
9#include <camera/avfcamerarenderer_p.h>
10#include <camera/avfimagecapture_p.h>
11#include <camera/avfmediaencoder_p.h>
13#include <QtMultimedia/private/qavfcameradebug_p.h>
14#include <QtMultimedia/private/qavfcamerautility_p.h>
15#include <QtMultimedia/private/qplatformaudioinput_p.h>
16#include <QtMultimedia/private/qplatformaudiooutput_p.h>
17#include <QtCore/qcoreapplication.h>
18#include <QtCore/qdatetime.h>
19#include <QtCore/qdebug.h>
20#include <QtCore/qelapsedtimer.h>
21#include <QtCore/qpermissions.h>
22#include <QtCore/qpointer.h>
23#include <QtCore/qurl.h>
25#import <CoreFoundation/CoreFoundation.h>
26#import <Foundation/Foundation.h>
30@interface AVFCameraSessionObserver : NSObject
32- (AVFCameraSessionObserver *) initWithCameraSession:(AVFCameraSession*)session;
33- (
void) processRuntimeError:(NSNotification *)notification;
34- (
void) processSessionStarted:(NSNotification *)notification;
35- (
void) processSessionStopped:(NSNotification *)notification;
39@implementation AVFCameraSessionObserver
42 AVFCameraSession *m_session;
43 AVCaptureSession *m_captureSession;
46- (AVFCameraSessionObserver *) initWithCameraSession:(AVFCameraSession*)session
48 if (!(self = [super init]))
51 self->m_session = session;
52 self->m_captureSession = session->captureSession();
54 [m_captureSession retain];
55 [[NSNotificationCenter defaultCenter] addObserver:self
56 selector:@selector(processRuntimeError:)
57 name:AVCaptureSessionRuntimeErrorNotification
58 object:m_captureSession];
60 [[NSNotificationCenter defaultCenter] addObserver:self
61 selector:@selector(processSessionStarted:)
62 name:AVCaptureSessionDidStartRunningNotification
63 object:m_captureSession];
65 [[NSNotificationCenter defaultCenter] addObserver:self
66 selector:@selector(processSessionStopped:)
67 name:AVCaptureSessionDidStopRunningNotification
68 object:m_captureSession];
75 [[NSNotificationCenter defaultCenter] removeObserver:self
76 name:AVCaptureSessionRuntimeErrorNotification
77 object:m_captureSession];
79 [[NSNotificationCenter defaultCenter] removeObserver:self
80 name:AVCaptureSessionDidStartRunningNotification
81 object:m_captureSession];
83 [[NSNotificationCenter defaultCenter] removeObserver:self
84 name:AVCaptureSessionDidStopRunningNotification
85 object:m_captureSession];
86 [m_captureSession release];
90- (
void) processRuntimeError:(NSNotification *)notification
92 Q_UNUSED(notification);
93 QMetaObject::invokeMethod(m_session,
"processRuntimeError", Qt::AutoConnection);
96- (
void) processSessionStarted:(NSNotification *)notification
98 Q_UNUSED(notification);
99 QMetaObject::invokeMethod(m_session,
"processSessionStarted", Qt::AutoConnection);
102- (
void) processSessionStopped:(NSNotification *)notification
104 Q_UNUSED(notification);
105 QMetaObject::invokeMethod(m_session,
"processSessionStopped", Qt::AutoConnection);
110AVFCameraSession::AVFCameraSession(AVFCameraService *service, QObject *parent)
115 m_captureSession = [[AVCaptureSession alloc] init];
116 m_observer = [[AVFCameraSessionObserver alloc] initWithCameraSession:
this];
122 [m_captureSession removeInput:m_videoInput];
123 [m_videoInput release];
127 [m_captureSession removeInput:m_audioInput];
128 [m_audioInput release];
132 [m_captureSession removeOutput:m_audioOutput];
133 [m_audioOutput release];
136 delete m_videoOutput;
138 [m_observer release];
139 [m_captureSession release];
144 if (m_activeCameraDevice != info) {
145 m_activeCameraDevice = info;
147 if (checkCameraPermission())
154 if (m_cameraFormat == format)
157 updateCameraFormat(format);
162 return m_cameraFormat;
167 m_cameraFormat = format;
169 AVCaptureDevice *captureDevice = videoCaptureDevice();
173 AVCaptureDeviceFormat *newFormat = qt_convert_to_capture_device_format(captureDevice, format);
175 qt_set_active_format(captureDevice, newFormat,
false);
180 if (m_videoOutput == output)
183 delete m_videoOutput;
184 m_videoOutput = output;
191 if (!m_audioOutput) {
192 m_audioOutput = [[AVCaptureAudioDataOutput alloc] init];
193 if (m_audioOutput && [m_captureSession canAddOutput:m_audioOutput]) {
194 [m_captureSession addOutput:m_audioOutput];
196 qWarning() << Q_FUNC_INFO <<
"failed to add audio output";
204 return m_videoInput.device;
212 return m_audioInput.device;
219 m_inputVolume = volume;
225 AVCaptureConnection *audioInputConnection = [m_audioOutput connectionWithMediaType:AVMediaTypeAudio];
226 NSArray<AVCaptureAudioChannel *> *audioChannels = audioInputConnection.audioChannels;
228 for (AVCaptureAudioChannel *channel in audioChannels) {
229 channel.volume = volume;
237 m_inputMuted = muted;
243 if (m_audioPreviewDelegate)
244 [m_audioPreviewDelegate setVolume:volume];
249 if (m_audioPreviewDelegate)
250 [m_audioPreviewDelegate setMuted:muted];
260 if (m_active == active)
265 qCDebug(qLcCamera) << Q_FUNC_INFO << m_active <<
" -> " << active;
268 if (!m_activeCameraDevice.isNull()) {
269 Q_EMIT readyToConfigureConnections();
274 applyImageEncoderSettings();
279 [videoCaptureDevice() lockForConfiguration:nil];
280 [m_captureSession startRunning];
281 [videoCaptureDevice() unlockForConfiguration];
283 [m_captureSession stopRunning];
289 qWarning() << tr(
"Runtime camera error");
291 Q_EMIT error(QCamera::CameraError, tr(
"Runtime camera error"));
296 qCDebug(qLcCamera) << Q_FUNC_INFO;
299 Q_EMIT activeChanged(m_active);
305 qCDebug(qLcCamera) << Q_FUNC_INFO;
308 Q_EMIT activeChanged(m_active);
314 AVCaptureDevice *device =
nullptr;
316 QByteArray deviceId = m_activeCameraDevice.id();
317 if (!deviceId.isEmpty()) {
318 device = [AVCaptureDevice deviceWithUniqueID:
319 [NSString stringWithUTF8String:
320 deviceId.constData()]];
328 AVCaptureDevice *device =
nullptr;
330 QByteArray deviceId = m_service->audioInput() ? m_service->audioInput()->device.id()
332 if (!deviceId.isEmpty())
333 device = [AVCaptureDevice deviceWithUniqueID: [NSString stringWithUTF8String:deviceId.constData()]];
340 if (!checkCameraPermission())
344 [m_captureSession removeInput:m_videoInput];
345 [m_videoInput release];
346 m_videoInput =
nullptr;
349 AVCaptureDevice *videoDevice = createVideoCaptureDevice();
353 m_videoInput = [AVCaptureDeviceInput
354 deviceInputWithDevice:videoDevice
356 if (m_videoInput && [m_captureSession canAddInput:m_videoInput]) {
357 [m_videoInput retain];
358 [m_captureSession addInput:m_videoInput];
360 qWarning() <<
"Failed to create video device input";
367 [m_captureSession removeInput:m_audioInput];
368 [m_audioInput release];
369 m_audioInput =
nullptr;
372 AVCaptureDevice *audioDevice = createAudioCaptureDevice();
376 m_audioInput = [AVCaptureDeviceInput
377 deviceInputWithDevice:audioDevice
380 if (m_audioInput && [m_captureSession canAddInput:m_audioInput]) {
381 [m_audioInput retain];
382 [m_captureSession addInput:m_audioInput];
384 qWarning() <<
"Failed to create audio device input";
398 if (!m_defaultCodec) {
399 if (AVCaptureDevice *device = videoCaptureDevice()) {
400 AVCaptureDeviceFormat *format = device.activeFormat;
401 if (!format || !format.formatDescription)
402 return m_defaultCodec;
403 m_defaultCodec = CMVideoFormatDescriptionGetCodecType(format.formatDescription);
406 return m_defaultCodec;
411 auto *videoSink = sink ?
static_cast<
AVFVideoSink *>(sink->platformVideoSink()) :
nullptr;
413 if (m_videoSink == videoSink)
416 m_videoSink = videoSink;
424 if (recorder && recorder->state() == QMediaRecorder::RecordingState)
427 [m_captureSession beginConfiguration];
429 attachVideoInputDevice();
430 if (!m_activeCameraDevice.isNull() && !m_videoOutput) {
431 setVideoOutput(
new AVFCameraRenderer(
this));
432 connect(m_videoOutput, &AVFCameraRenderer::newViewfinderFrame,
433 this, &AVFCameraSession::newViewfinderFrame);
437 m_videoOutput->deviceOrientationChanged();
439 [m_captureSession commitConfiguration];
441 if (recorder && recorder->state() == QMediaRecorder::RecordingState)
443 Q_EMIT readyToConfigureConnections();
448 if (!checkMicrophonePermission())
452 if (recorder && recorder->state() == QMediaRecorder::RecordingState)
455 [m_captureSession beginConfiguration];
457 AVCaptureConnection *lastConnection = [m_audioOutput connectionWithMediaType:AVMediaTypeAudio];
458 [m_captureSession removeConnection:lastConnection];
460 attachAudioInputDevice();
463 [m_captureSession commitConfiguration];
465 if (recorder && recorder->state() == QMediaRecorder::RecordingState)
471 QByteArray deviceId = m_service->audioOutput()
472 ? m_service->audioOutput()->device.id()
475 [m_audioPreviewDelegate release];
476 m_audioPreviewDelegate = nil;
477 if (!deviceId.isEmpty()) {
478 m_audioPreviewDelegate = [[AVFAudioPreviewDelegate alloc] init];
479 [m_audioPreviewDelegate setupWithCaptureSession:
this
480 audioOutputDevice:[NSString stringWithUTF8String:
481 deviceId.constData()]];
493 const QCameraPermission permission;
494 const bool granted = qApp->checkPermission(permission) == Qt::PermissionStatus::Granted;
496 qWarning() <<
"Access to camera not granted";
503 const QMicrophonePermission permission;
504 const bool granted = qApp->checkPermission(permission) == Qt::PermissionStatus::Granted;
506 qWarning() <<
"Access to microphone not granted";
511#include "moc_avfcamerasession_p.cpp"
void configureAVCaptureSession(AVFCameraSession *cameraSession)
AVFMediaEncoder * recorderControl() const
AVFImageCapture * avfImageCaptureControl() const
void processSessionStopped()
void setCameraFormat(const QCameraFormat &format)
AVCaptureDevice * videoCaptureDevice() const
void setAudioOutputMuted(bool muted)
QCameraFormat cameraFormat() const
~AVFCameraSession() override
void setActiveCamera(const QCameraDevice &info)
void setAudioInputVolume(float volume)
AVCaptureDevice * audioCaptureDevice() const
void setVideoSink(QVideoSink *sink)
FourCharCode defaultCodec()
void processSessionStarted()
void setAudioOutputVolume(float volume)
void processRuntimeError()
void setAudioInputMuted(bool muted)
void setVideoSink(AVFVideoSink *sink)