4#include <QtMultimedia/private/qavfcameradebug_p.h>
11#include <QtMultimedia/private/qavfcamerautility_p.h>
12#include <avfvideosink_p.h>
14#include <CoreFoundation/CoreFoundation.h>
15#include <Foundation/Foundation.h>
17#include <QtCore/qcoreapplication.h>
18#include <QtCore/qdatetime.h>
19#include <QtCore/qurl.h>
20#include <QtCore/qelapsedtimer.h>
21#include <QtCore/qpermissions.h>
22#include <QtCore/qpointer.h>
24#include <private/qplatformaudioinput_p.h>
25#include <private/qplatformaudiooutput_p.h>
27#include <QtCore/qdebug.h>
31@interface AVFCameraSessionObserver : NSObject
33- (AVFCameraSessionObserver *) initWithCameraSession:(AVFCameraSession*)session;
34- (
void) processRuntimeError:(NSNotification *)notification;
35- (
void) processSessionStarted:(NSNotification *)notification;
36- (
void) processSessionStopped:(NSNotification *)notification;
40@implementation AVFCameraSessionObserver
43 AVFCameraSession *m_session;
44 AVCaptureSession *m_captureSession;
47- (AVFCameraSessionObserver *) initWithCameraSession:(AVFCameraSession*)session
49 if (!(self = [super init]))
52 self->m_session = session;
53 self->m_captureSession = session->captureSession();
55 [m_captureSession retain];
56 [[NSNotificationCenter defaultCenter] addObserver:self
57 selector:@selector(processRuntimeError:)
58 name:AVCaptureSessionRuntimeErrorNotification
59 object:m_captureSession];
61 [[NSNotificationCenter defaultCenter] addObserver:self
62 selector:@selector(processSessionStarted:)
63 name:AVCaptureSessionDidStartRunningNotification
64 object:m_captureSession];
66 [[NSNotificationCenter defaultCenter] addObserver:self
67 selector:@selector(processSessionStopped:)
68 name:AVCaptureSessionDidStopRunningNotification
69 object:m_captureSession];
76 [[NSNotificationCenter defaultCenter] removeObserver:self
77 name:AVCaptureSessionRuntimeErrorNotification
78 object:m_captureSession];
80 [[NSNotificationCenter defaultCenter] removeObserver:self
81 name:AVCaptureSessionDidStartRunningNotification
82 object:m_captureSession];
84 [[NSNotificationCenter defaultCenter] removeObserver:self
85 name:AVCaptureSessionDidStopRunningNotification
86 object:m_captureSession];
87 [m_captureSession release];
91- (
void) processRuntimeError:(NSNotification *)notification
93 Q_UNUSED(notification);
94 QMetaObject::invokeMethod(m_session,
"processRuntimeError", Qt::AutoConnection);
97- (
void) processSessionStarted:(NSNotification *)notification
99 Q_UNUSED(notification);
100 QMetaObject::invokeMethod(m_session,
"processSessionStarted", Qt::AutoConnection);
103- (
void) processSessionStopped:(NSNotification *)notification
105 Q_UNUSED(notification);
106 QMetaObject::invokeMethod(m_session,
"processSessionStopped", Qt::AutoConnection);
111AVFCameraSession::AVFCameraSession(AVFCameraService *service, QObject *parent)
116 m_captureSession = [[AVCaptureSession alloc] init];
117 m_observer = [[AVFCameraSessionObserver alloc] initWithCameraSession:
this];
123 [m_captureSession removeInput:m_videoInput];
124 [m_videoInput release];
128 [m_captureSession removeInput:m_audioInput];
129 [m_audioInput release];
133 [m_captureSession removeOutput:m_audioOutput];
134 [m_audioOutput release];
137 delete m_videoOutput;
139 [m_observer release];
140 [m_captureSession release];
145 if (m_activeCameraDevice != info) {
146 m_activeCameraDevice = info;
148 if (checkCameraPermission())
155 if (m_cameraFormat == format)
158 updateCameraFormat(format);
163 return m_cameraFormat;
168 m_cameraFormat = format;
170 AVCaptureDevice *captureDevice = videoCaptureDevice();
174 AVCaptureDeviceFormat *newFormat = qt_convert_to_capture_device_format(captureDevice, format);
176 qt_set_active_format(captureDevice, newFormat,
false);
181 if (m_videoOutput == output)
184 delete m_videoOutput;
185 m_videoOutput = output;
192 if (!m_audioOutput) {
193 m_audioOutput = [[AVCaptureAudioDataOutput alloc] init];
194 if (m_audioOutput && [m_captureSession canAddOutput:m_audioOutput]) {
195 [m_captureSession addOutput:m_audioOutput];
197 qWarning() << Q_FUNC_INFO <<
"failed to add audio output";
205 return m_videoInput.device;
213 return m_audioInput.device;
220 m_inputVolume = volume;
226 AVCaptureConnection *audioInputConnection = [m_audioOutput connectionWithMediaType:AVMediaTypeAudio];
227 NSArray<AVCaptureAudioChannel *> *audioChannels = audioInputConnection.audioChannels;
229 for (AVCaptureAudioChannel *channel in audioChannels) {
230 channel.volume = volume;
238 m_inputMuted = muted;
244 if (m_audioPreviewDelegate)
245 [m_audioPreviewDelegate setVolume:volume];
250 if (m_audioPreviewDelegate)
251 [m_audioPreviewDelegate setMuted:muted];
261 if (m_active == active)
266 qCDebug(qLcCamera) << Q_FUNC_INFO << m_active <<
" -> " << active;
269 if (!m_activeCameraDevice.isNull()) {
270 Q_EMIT readyToConfigureConnections();
275 applyImageEncoderSettings();
280 [videoCaptureDevice() lockForConfiguration:nil];
281 [m_captureSession startRunning];
282 [videoCaptureDevice() unlockForConfiguration];
284 [m_captureSession stopRunning];
290 qWarning() << tr(
"Runtime camera error");
292 Q_EMIT error(QCamera::CameraError, tr(
"Runtime camera error"));
297 qCDebug(qLcCamera) << Q_FUNC_INFO;
300 Q_EMIT activeChanged(m_active);
306 qCDebug(qLcCamera) << Q_FUNC_INFO;
309 Q_EMIT activeChanged(m_active);
315 AVCaptureDevice *device =
nullptr;
317 QByteArray deviceId = m_activeCameraDevice.id();
318 if (!deviceId.isEmpty()) {
319 device = [AVCaptureDevice deviceWithUniqueID:
320 [NSString stringWithUTF8String:
321 deviceId.constData()]];
329 AVCaptureDevice *device =
nullptr;
331 QByteArray deviceId = m_service->audioInput() ? m_service->audioInput()->device.id()
333 if (!deviceId.isEmpty())
334 device = [AVCaptureDevice deviceWithUniqueID: [NSString stringWithUTF8String:deviceId.constData()]];
341 if (!checkCameraPermission())
345 [m_captureSession removeInput:m_videoInput];
346 [m_videoInput release];
347 m_videoInput =
nullptr;
350 AVCaptureDevice *videoDevice = createVideoCaptureDevice();
354 m_videoInput = [AVCaptureDeviceInput
355 deviceInputWithDevice:videoDevice
357 if (m_videoInput && [m_captureSession canAddInput:m_videoInput]) {
358 [m_videoInput retain];
359 [m_captureSession addInput:m_videoInput];
361 qWarning() <<
"Failed to create video device input";
368 [m_captureSession removeInput:m_audioInput];
369 [m_audioInput release];
370 m_audioInput =
nullptr;
373 AVCaptureDevice *audioDevice = createAudioCaptureDevice();
377 m_audioInput = [AVCaptureDeviceInput
378 deviceInputWithDevice:audioDevice
381 if (m_audioInput && [m_captureSession canAddInput:m_audioInput]) {
382 [m_audioInput retain];
383 [m_captureSession addInput:m_audioInput];
385 qWarning() <<
"Failed to create audio device input";
399 if (!m_defaultCodec) {
400 if (AVCaptureDevice *device = videoCaptureDevice()) {
401 AVCaptureDeviceFormat *format = device.activeFormat;
402 if (!format || !format.formatDescription)
403 return m_defaultCodec;
404 m_defaultCodec = CMVideoFormatDescriptionGetCodecType(format.formatDescription);
407 return m_defaultCodec;
412 auto *videoSink = sink ?
static_cast<
AVFVideoSink *>(sink->platformVideoSink()) :
nullptr;
414 if (m_videoSink == videoSink)
417 m_videoSink = videoSink;
425 if (recorder && recorder->state() == QMediaRecorder::RecordingState)
428 [m_captureSession beginConfiguration];
430 attachVideoInputDevice();
431 if (!m_activeCameraDevice.isNull() && !m_videoOutput) {
432 setVideoOutput(
new AVFCameraRenderer(
this));
433 connect(m_videoOutput, &AVFCameraRenderer::newViewfinderFrame,
434 this, &AVFCameraSession::newViewfinderFrame);
438 m_videoOutput->deviceOrientationChanged();
440 [m_captureSession commitConfiguration];
442 if (recorder && recorder->state() == QMediaRecorder::RecordingState)
444 Q_EMIT readyToConfigureConnections();
449 if (!checkMicrophonePermission())
453 if (recorder && recorder->state() == QMediaRecorder::RecordingState)
456 [m_captureSession beginConfiguration];
458 AVCaptureConnection *lastConnection = [m_audioOutput connectionWithMediaType:AVMediaTypeAudio];
459 [m_captureSession removeConnection:lastConnection];
461 attachAudioInputDevice();
464 [m_captureSession commitConfiguration];
466 if (recorder && recorder->state() == QMediaRecorder::RecordingState)
472 QByteArray deviceId = m_service->audioOutput()
473 ? m_service->audioOutput()->device.id()
476 [m_audioPreviewDelegate release];
477 m_audioPreviewDelegate = nil;
478 if (!deviceId.isEmpty()) {
479 m_audioPreviewDelegate = [[AVFAudioPreviewDelegate alloc] init];
480 [m_audioPreviewDelegate setupWithCaptureSession:
this
481 audioOutputDevice:[NSString stringWithUTF8String:
482 deviceId.constData()]];
494 const QCameraPermission permission;
495 const bool granted = qApp->checkPermission(permission) == Qt::PermissionStatus::Granted;
497 qWarning() <<
"Access to camera not granted";
504 const QMicrophonePermission permission;
505 const bool granted = qApp->checkPermission(permission) == Qt::PermissionStatus::Granted;
507 qWarning() <<
"Access to microphone not granted";
512#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)