diff options
author | Liang Qi <liang.qi@qt.io> | 2016-05-10 19:26:21 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2016-05-10 19:26:21 +0200 |
commit | 08e13bfcdb23eabfbc47bca7499b0b8aadce0ac7 (patch) | |
tree | 406ffa7e3ae0a346a14175ccccb8ac7e596d8f8f /src/plugins/avfoundation/camera | |
parent | fa9fe9ff8c3aba25fbae4f8f32588dd6477d6df8 (diff) | |
parent | f0e0d5d901d4e28fff9f29caf86ada84906b3db4 (diff) | |
download | qtmultimedia-08e13bfcdb23eabfbc47bca7499b0b8aadce0ac7.tar.gz |
Merge remote-tracking branch 'origin/5.6' into 5.7
Conflicts:
src/plugins/winrt/qwinrtcameracontrol.cpp
Change-Id: I45d3042adf19577a72794610fa1c310cb22e26c4
Diffstat (limited to 'src/plugins/avfoundation/camera')
7 files changed, 86 insertions, 113 deletions
diff --git a/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm b/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm index fb02a7d09..e4f234b7e 100644 --- a/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm +++ b/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm @@ -66,11 +66,14 @@ public: && CVPixelBufferGetPixelFormatType(buffer) == kCVPixelFormatType_32BGRA ? GLTextureHandle : NoHandle) , m_texture(0) + , m_renderer(renderer) #endif , m_buffer(buffer) - , m_renderer(renderer) , m_mode(NotMapped) { +#ifndef Q_OS_IOS + Q_UNUSED(renderer) +#endif // Q_OS_IOS CVPixelBufferRetain(m_buffer); } @@ -200,9 +203,9 @@ public: private: #ifdef Q_OS_IOS mutable CVOpenGLESTextureRef m_texture; + AVFCameraRendererControl *m_renderer; #endif CVImageBufferRef m_buffer; - AVFCameraRendererControl *m_renderer; MapMode m_mode; }; diff --git a/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm b/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm index d2ae2af05..924b0d76a 100644 --- a/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm +++ b/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm @@ -345,7 +345,7 @@ QList<QCameraViewfinderSettings> AVFCameraViewfinderSettingsControl2::supportedV QCameraViewfinderSettings AVFCameraViewfinderSettingsControl2::viewfinderSettings() const { - QCameraViewfinderSettings settings; + QCameraViewfinderSettings settings = m_settings; AVCaptureDevice *captureDevice = m_service->session()->videoCaptureDevice(); if (!captureDevice) { @@ -353,6 +353,11 @@ QCameraViewfinderSettings AVFCameraViewfinderSettingsControl2::viewfinderSetting return settings; } + if (m_service->session()->state() != QCamera::LoadedState && + m_service->session()->state() != QCamera::ActiveState) { + 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 (!captureDevice.activeFormat) { diff --git a/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm b/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm index dea407e3b..6465e69e3 100644 --- a/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm +++ b/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm @@ -40,6 +40,7 @@ #include "avfcameradebug.h" #include "avfimagecapturecontrol.h" #include "avfcameraservice.h" +#include "avfcamerautility.h" #include "avfcameracontrol.h" #include <QtCore/qurl.h> @@ -214,6 +215,8 @@ void AVFImageCaptureControl::updateCaptureConnection() if (![captureSession.outputs containsObject:m_stillImageOutput]) { if ([captureSession canAddOutput:m_stillImageOutput]) { + // Lock the video capture device to make sure the active format is not reset + const AVFConfigurationLock lock(m_session->videoCaptureDevice()); [captureSession addOutput:m_stillImageOutput]; m_videoConnection = [m_stillImageOutput connectionWithMediaType:AVMediaTypeVideo]; updateReadyStatus(); diff --git a/src/plugins/avfoundation/camera/avfmediaassetwriter.h b/src/plugins/avfoundation/camera/avfmediaassetwriter.h index 7cb6f9e44..c70deea10 100644 --- a/src/plugins/avfoundation/camera/avfmediaassetwriter.h +++ b/src/plugins/avfoundation/camera/avfmediaassetwriter.h @@ -50,19 +50,9 @@ QT_BEGIN_NAMESPACE +class AVFMediaRecorderControlIOS; class AVFCameraService; -class AVFMediaAssetWriterDelegate -{ -public: - virtual ~AVFMediaAssetWriterDelegate(); - - virtual void assetWriterStarted() = 0; - virtual void assetWriterFailedToStart() = 0; - virtual void assetWriterFailedToStop() = 0; - virtual void assetWriterFinished() = 0; -}; - typedef QAtomicInteger<bool> AVFAtomicBool; typedef QAtomicInteger<qint64> AVFAtomicInt64; @@ -86,18 +76,15 @@ QT_END_NAMESPACE // Serial queue for audio output: QT_PREPEND_NAMESPACE(AVFScopedPointer)<dispatch_queue_t> m_audioQueue; // Queue to write sample buffers: - __weak dispatch_queue_t m_writerQueue; + QT_PREPEND_NAMESPACE(AVFScopedPointer)<dispatch_queue_t> m_writerQueue; QT_PREPEND_NAMESPACE(AVFScopedPointer)<AVAssetWriter> m_assetWriter; - // Delegate's queue. - __weak dispatch_queue_t m_delegateQueue; - // TODO: QPointer?? - QT_PREPEND_NAMESPACE(AVFMediaAssetWriterDelegate) *m_delegate; + + QT_PREPEND_NAMESPACE(AVFMediaRecorderControlIOS) *m_delegate; bool m_setStartTime; QT_PREPEND_NAMESPACE(AVFAtomicBool) m_stopped; - bool m_stoppedInternal; - bool m_aborted; + QT_PREPEND_NAMESPACE(AVFAtomicBool) m_aborted; QT_PREPEND_NAMESPACE(QMutex) m_writerMutex; @public @@ -108,8 +95,7 @@ QT_END_NAMESPACE } - (id)initWithQueue:(dispatch_queue_t)writerQueue - delegate:(QT_PREPEND_NAMESPACE(AVFMediaAssetWriterDelegate) *)delegate - delegateQueue:(dispatch_queue_t)delegateQueue; + delegate:(QT_PREPEND_NAMESPACE(AVFMediaRecorderControlIOS) *)delegate; - (bool)setupWithFileURL:(NSURL *)fileURL cameraService:(QT_PREPEND_NAMESPACE(AVFCameraService) *)service; diff --git a/src/plugins/avfoundation/camera/avfmediaassetwriter.mm b/src/plugins/avfoundation/camera/avfmediaassetwriter.mm index 88c4914aa..1b8c253e2 100644 --- a/src/plugins/avfoundation/camera/avfmediaassetwriter.mm +++ b/src/plugins/avfoundation/camera/avfmediaassetwriter.mm @@ -38,6 +38,7 @@ ****************************************************************************/ #include "avfaudioinputselectorcontrol.h" +#include "avfmediarecordercontrol_ios.h" #include "avfcamerarenderercontrol.h" #include "avfmediaassetwriter.h" #include "avfcameraservice.h" @@ -45,6 +46,7 @@ #include "avfcameradebug.h" //#include <QtCore/qmutexlocker.h> +#include <QtCore/qmetaobject.h> #include <QtCore/qsysinfo.h> QT_USE_NAMESPACE @@ -71,11 +73,7 @@ bool qt_camera_service_isValid(AVFCameraService *service) return true; } -} - -AVFMediaAssetWriterDelegate::~AVFMediaAssetWriterDelegate() -{ -} +} // unnamed namespace @interface QT_MANGLE_NAMESPACE(AVFMediaAssetWriter) (PrivateAPI) - (bool)addAudioCapture; @@ -89,21 +87,20 @@ AVFMediaAssetWriterDelegate::~AVFMediaAssetWriterDelegate() @implementation QT_MANGLE_NAMESPACE(AVFMediaAssetWriter) - (id)initWithQueue:(dispatch_queue_t)writerQueue - delegate:(AVFMediaAssetWriterDelegate *)delegate - delegateQueue:(dispatch_queue_t)delegateQueue + delegate:(AVFMediaRecorderControlIOS *)delegate { Q_ASSERT(writerQueue); Q_ASSERT(delegate); - Q_ASSERT(delegateQueue); if (self = [super init]) { - m_writerQueue = writerQueue; + // "Shared" queue: + dispatch_retain(writerQueue); + m_writerQueue.reset(writerQueue); + m_delegate = delegate; - m_delegateQueue = delegateQueue; m_setStartTime = true; m_stopped.store(true); - m_stoppedInternal = false; - m_aborted = false; + m_aborted.store(false); m_startTime = kCMTimeInvalid; m_lastTimeStamp = kCMTimeInvalid; m_durationInMs.store(0); @@ -166,14 +163,13 @@ AVFMediaAssetWriterDelegate::~AVFMediaAssetWriterDelegate() { // To be executed on a writer's queue. const QMutexLocker lock(&m_writerMutex); - if (m_aborted) + if (m_aborted.load()) return; [self setQueues]; m_setStartTime = true; m_stopped.store(false); - m_stoppedInternal = false; [m_assetWriter startWriting]; AVCaptureSession *session = m_service->session()->captureSession(); if (!session.running) @@ -183,40 +179,41 @@ AVFMediaAssetWriterDelegate::~AVFMediaAssetWriterDelegate() - (void)stop { // To be executed on a writer's queue. + { const QMutexLocker lock(&m_writerMutex); - if (m_aborted) + if (m_aborted.load()) return; - if (m_stopped.load()) { - // Should never happen, but ... - // if something went wrong in a recorder control - // and we set state stopped without starting first ... - // m_stoppedIntenal will be false, but m_stopped - true. + if (m_stopped.load()) return; - } m_stopped.store(true); - m_stoppedInternal = true; + } + [m_assetWriter finishWritingWithCompletionHandler:^{ - // TODO: make sure the session exist and we can call stop/remove on it. + // This block is async, so by the time it's executed, + // it's possible that render control was deleted already ... + const QMutexLocker lock(&m_writerMutex); + if (m_aborted.load()) + return; + AVCaptureSession *session = m_service->session()->captureSession(); [session stopRunning]; [session removeOutput:m_audioOutput]; [session removeInput:m_audioInput]; - dispatch_async(m_delegateQueue, ^{ - m_delegate->assetWriterFinished(); - }); + QMetaObject::invokeMethod(m_delegate, "assetWriterFinished", Qt::QueuedConnection); }]; } - (void)abort { - // To be executed on any thread, prevents writer from - // accessing any external object (probably deleted by this time) + // To be executed on any thread (presumably, it's the main thread), + // prevents writer from accessing any shared object. const QMutexLocker lock(&m_writerMutex); - m_aborted = true; + m_aborted.store(true); if (m_stopped.load()) return; + [m_assetWriter finishWritingWithCompletionHandler:^{ }]; } @@ -227,9 +224,11 @@ AVFMediaAssetWriterDelegate::~AVFMediaAssetWriterDelegate() Q_ASSERT(m_setStartTime); Q_ASSERT(sampleBuffer); - dispatch_async(m_delegateQueue, ^{ - m_delegate->assetWriterStarted(); - }); + const QMutexLocker lock(&m_writerMutex); + if (m_aborted.load() || m_stopped.load()) + return; + + QMetaObject::invokeMethod(m_delegate, "assetWriterStarted", Qt::QueuedConnection); m_durationInMs.store(0); m_startTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer); @@ -242,22 +241,18 @@ AVFMediaAssetWriterDelegate::~AVFMediaAssetWriterDelegate() { Q_ASSERT(sampleBuffer); - // This code is executed only on a writer's queue, but - // it can access potentially deleted objects, so we - // need a lock and m_aborted flag test. - { - const QMutexLocker lock(&m_writerMutex); - if (!m_aborted && !m_stoppedInternal) { - if (m_setStartTime) - [self setStartTimeFrom:sampleBuffer]; - - if (m_cameraWriterInput.data().readyForMoreMediaData) { - [self updateDuration:CMSampleBufferGetPresentationTimeStamp(sampleBuffer)]; - [m_cameraWriterInput appendSampleBuffer:sampleBuffer]; - } + // This code is executed only on a writer's queue. + if (!m_aborted.load() && !m_stopped.load()) { + if (m_setStartTime) + [self setStartTimeFrom:sampleBuffer]; + + if (m_cameraWriterInput.data().readyForMoreMediaData) { + [self updateDuration:CMSampleBufferGetPresentationTimeStamp(sampleBuffer)]; + [m_cameraWriterInput appendSampleBuffer:sampleBuffer]; } } + CFRelease(sampleBuffer); } @@ -267,16 +262,13 @@ AVFMediaAssetWriterDelegate::~AVFMediaAssetWriterDelegate() // it does not touch any shared/external data. Q_ASSERT(sampleBuffer); - { - const QMutexLocker lock(&m_writerMutex); - if (!m_aborted && !m_stoppedInternal) { - if (m_setStartTime) - [self setStartTimeFrom:sampleBuffer]; - - if (m_audioWriterInput.data().readyForMoreMediaData) { - [self updateDuration:CMSampleBufferGetPresentationTimeStamp(sampleBuffer)]; - [m_audioWriterInput appendSampleBuffer:sampleBuffer]; - } + if (!m_aborted.load() && !m_stopped.load()) { + if (m_setStartTime) + [self setStartTimeFrom:sampleBuffer]; + + if (m_audioWriterInput.data().readyForMoreMediaData) { + [self updateDuration:CMSampleBufferGetPresentationTimeStamp(sampleBuffer)]; + [m_audioWriterInput appendSampleBuffer:sampleBuffer]; } } @@ -289,13 +281,12 @@ AVFMediaAssetWriterDelegate::~AVFMediaAssetWriterDelegate() { Q_UNUSED(connection) - // This method can be called on either video or audio queue, never on a writer's - // queue - it does not access any shared data except this atomic flag below. + // This method can be called on either video or audio queue, + // never on a writer's queue, it needs access to a shared data, so + // lock is required. if (m_stopped.load()) return; - // Even if we are stopped now, we still do not access any data. - if (!CMSampleBufferDataIsReady(sampleBuffer)) { qDebugCamera() << Q_FUNC_INFO << "sample buffer is not ready, skipping."; return; @@ -304,21 +295,18 @@ AVFMediaAssetWriterDelegate::~AVFMediaAssetWriterDelegate() CFRetain(sampleBuffer); if (captureOutput != m_audioOutput.data()) { - { - const QMutexLocker lock(&m_writerMutex); - if (m_aborted || m_stoppedInternal) { - CFRelease(sampleBuffer); - return; - } - - // Find renderercontrol's delegate and invoke its method to - // show updated viewfinder's frame. - if (m_service && m_service->videoOutput()) { - NSObject<AVCaptureVideoDataOutputSampleBufferDelegate> *vfDelegate = - (NSObject<AVCaptureVideoDataOutputSampleBufferDelegate> *)m_service->videoOutput()->captureDelegate(); - if (vfDelegate) - [vfDelegate captureOutput:nil didOutputSampleBuffer:sampleBuffer fromConnection:nil]; - } + const QMutexLocker lock(&m_writerMutex); + if (m_aborted.load() || m_stopped.load()) { + CFRelease(sampleBuffer); + return; + } + // Find renderercontrol's delegate and invoke its method to + // show updated viewfinder's frame. + if (m_service && m_service->videoOutput()) { + NSObject<AVCaptureVideoDataOutputSampleBufferDelegate> *vfDelegate = + (NSObject<AVCaptureVideoDataOutputSampleBufferDelegate> *)m_service->videoOutput()->captureDelegate(); + if (vfDelegate) + [vfDelegate captureOutput:nil didOutputSampleBuffer:sampleBuffer fromConnection:nil]; } dispatch_async(m_writerQueue, ^{ diff --git a/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.h b/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.h index 59af1d4bf..c3fe02c44 100644 --- a/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.h +++ b/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.h @@ -57,7 +57,7 @@ class AVFCameraService; class QString; class QUrl; -class AVFMediaRecorderControlIOS : public QMediaRecorderControl, public AVFMediaAssetWriterDelegate +class AVFMediaRecorderControlIOS : public QMediaRecorderControl { Q_OBJECT public: @@ -82,13 +82,10 @@ public Q_SLOTS: void setMuted(bool muted) Q_DECL_OVERRIDE; void setVolume(qreal volume) Q_DECL_OVERRIDE; - // Writer delegate: private: - void assetWriterStarted() Q_DECL_OVERRIDE; - void assetWriterFailedToStart() Q_DECL_OVERRIDE; - void assetWriterFailedToStop() Q_DECL_OVERRIDE; - void assetWriterFinished() Q_DECL_OVERRIDE; + Q_INVOKABLE void assetWriterStarted(); + Q_INVOKABLE void assetWriterFinished(); private Q_SLOTS: void captureModeChanged(QCamera::CaptureModes); diff --git a/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.mm b/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.mm index 470cc8034..72386eeda 100644 --- a/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.mm +++ b/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.mm @@ -92,8 +92,7 @@ AVFMediaRecorderControlIOS::AVFMediaRecorderControlIOS(AVFCameraService *service return; } - m_writer.reset([[QT_MANGLE_NAMESPACE(AVFMediaAssetWriter) alloc] initWithQueue:m_writerQueue - delegate:this delegateQueue:dispatch_get_main_queue()]); + m_writer.reset([[QT_MANGLE_NAMESPACE(AVFMediaAssetWriter) alloc] initWithQueue:m_writerQueue delegate:this]); if (!m_writer) { qDebugCamera() << Q_FUNC_INFO << "failed to create an asset writer"; return; @@ -265,14 +264,6 @@ void AVFMediaRecorderControlIOS::assetWriterStarted() Q_EMIT statusChanged(QMediaRecorder::RecordingStatus); } -void AVFMediaRecorderControlIOS::assetWriterFailedToStart() -{ -} - -void AVFMediaRecorderControlIOS::assetWriterFailedToStop() -{ -} - void AVFMediaRecorderControlIOS::assetWriterFinished() { AVFCameraControl *cameraControl = m_service->cameraControl(); |