summaryrefslogtreecommitdiffstats
path: root/src/plugins/avfoundation
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@qt.io>2016-05-10 19:26:21 +0200
committerLiang Qi <liang.qi@qt.io>2016-05-10 19:26:21 +0200
commit08e13bfcdb23eabfbc47bca7499b0b8aadce0ac7 (patch)
tree406ffa7e3ae0a346a14175ccccb8ac7e596d8f8f /src/plugins/avfoundation
parentfa9fe9ff8c3aba25fbae4f8f32588dd6477d6df8 (diff)
parentf0e0d5d901d4e28fff9f29caf86ada84906b3db4 (diff)
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')
-rw-r--r--src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm7
-rw-r--r--src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm7
-rw-r--r--src/plugins/avfoundation/camera/avfimagecapturecontrol.mm3
-rw-r--r--src/plugins/avfoundation/camera/avfmediaassetwriter.h26
-rw-r--r--src/plugins/avfoundation/camera/avfmediaassetwriter.mm136
-rw-r--r--src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.h9
-rw-r--r--src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.mm11
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();