summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYoann Lopes <yoann.lopes@qt.io>2016-08-01 11:52:05 +0200
committerYoann Lopes <yoann.lopes@qt.io>2016-08-01 11:52:05 +0200
commit339944b284e9dd11302dd013f9d9a10ad0d9055a (patch)
treec2952d186b1dbc6f2380448fa2cfd9ec55043da6
parent53d0a1e5454f4e5beecdea19acb9df11c87cc375 (diff)
parentd7d31d63db5f0029a4a5e24d998601baee8bade0 (diff)
downloadqtmultimedia-339944b284e9dd11302dd013f9d9a10ad0d9055a.tar.gz
Merge remote-tracking branch 'origin/5.6' into 5.7
Change-Id: Ic29cb09048003f18ff86d4546cd547be715eaec8
-rw-r--r--src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtSurfaceTextureListener.java10
-rw-r--r--src/plugins/android/src/common/qandroidvideooutput.cpp8
-rw-r--r--src/plugins/android/src/mediacapture/qandroidcamerasession.cpp15
-rw-r--r--src/plugins/android/src/qandroidmediaserviceplugin.cpp5
-rw-r--r--src/plugins/android/src/wrappers/jni/androidsurfacetexture.cpp42
-rw-r--r--src/plugins/android/src/wrappers/jni/androidsurfacetexture.h4
-rw-r--r--src/plugins/avfoundation/camera/avfmediaassetwriter.h19
-rw-r--r--src/plugins/avfoundation/camera/avfmediaassetwriter.mm114
-rw-r--r--src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.h2
-rw-r--r--src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.mm26
-rw-r--r--src/plugins/directshow/player/directshowplayerservice.cpp2
-rw-r--r--src/plugins/directshow/player/directshowvideorenderercontrol.cpp24
-rw-r--r--src/plugins/directshow/player/directshowvideorenderercontrol.h6
-rw-r--r--src/plugins/gstreamer/camerabin/camerabinv4limageprocessing.cpp5
-rw-r--r--src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp7
-rw-r--r--src/plugins/winrt/qwinrtcameracontrol.cpp3
-rw-r--r--tests/auto/integration/qsoundeffect/BLACKLIST8
-rw-r--r--tests/auto/integration/qsoundeffect/tst_qsoundeffect.cpp6
18 files changed, 184 insertions, 122 deletions
diff --git a/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtSurfaceTextureListener.java b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtSurfaceTextureListener.java
index 0404e2d75..a997dde90 100644
--- a/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtSurfaceTextureListener.java
+++ b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtSurfaceTextureListener.java
@@ -43,18 +43,18 @@ import android.graphics.SurfaceTexture;
public class QtSurfaceTextureListener implements SurfaceTexture.OnFrameAvailableListener
{
- private final int texID;
+ private final long m_id;
- public QtSurfaceTextureListener(int texName)
+ public QtSurfaceTextureListener(long id)
{
- texID = texName;
+ m_id = id;
}
@Override
public void onFrameAvailable(SurfaceTexture surfaceTexture)
{
- notifyFrameAvailable(texID);
+ notifyFrameAvailable(m_id);
}
- private static native void notifyFrameAvailable(int id);
+ private static native void notifyFrameAvailable(long id);
}
diff --git a/src/plugins/android/src/common/qandroidvideooutput.cpp b/src/plugins/android/src/common/qandroidvideooutput.cpp
index 5c804ccc4..a5cd3580b 100644
--- a/src/plugins/android/src/common/qandroidvideooutput.cpp
+++ b/src/plugins/android/src/common/qandroidvideooutput.cpp
@@ -147,7 +147,13 @@ public:
delete m_program;
}
- void setTexture(quint32 id) { m_textureID = id; }
+ void setTexture(quint32 id) {
+ if (m_textureID)
+ glDeleteTextures(1, &m_textureID);
+
+ m_textureID = id;
+ }
+
void setFbo(QOpenGLFramebufferObject *fbo) { m_fbo = fbo; }
void setShaderProgram(QOpenGLShaderProgram *prog) { m_program = prog; }
diff --git a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp
index 9137fbc05..0b082b02b 100644
--- a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp
+++ b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp
@@ -295,16 +295,27 @@ void QAndroidCameraSession::applyViewfinderSettings(const QSize &captureSize, bo
adjustedViewfinderResolution = vfRes;
} else if (validCaptureSize) {
// search for viewfinder resolution with the same aspect ratio
+ qreal minAspectDiff = 1;
+ QSize closestResolution;
for (int i = previewSizes.count() - 1; i >= 0; --i) {
const QSize &size = previewSizes.at(i);
- if (qAbs(captureAspectRatio - (qreal(size.width()) / size.height())) < 0.01) {
+ const qreal sizeAspect = qreal(size.width()) / size.height();
+ if (qFuzzyCompare(captureAspectRatio, sizeAspect)) {
adjustedViewfinderResolution = size;
break;
+ } else if (minAspectDiff > qAbs(sizeAspect - captureAspectRatio)) {
+ closestResolution = size;
+ minAspectDiff = qAbs(sizeAspect - captureAspectRatio);
}
}
if (!adjustedViewfinderResolution.isValid()) {
qWarning("Cannot find a viewfinder resolution matching the capture aspect ratio.");
- return;
+ if (closestResolution.isValid()) {
+ adjustedViewfinderResolution = closestResolution;
+ qWarning("Using closest viewfinder resolution.");
+ } else {
+ return;
+ }
}
} else {
adjustedViewfinderResolution = previewSizes.last();
diff --git a/src/plugins/android/src/qandroidmediaserviceplugin.cpp b/src/plugins/android/src/qandroidmediaserviceplugin.cpp
index 87de7d561..0de231c9d 100644
--- a/src/plugins/android/src/qandroidmediaserviceplugin.cpp
+++ b/src/plugins/android/src/qandroidmediaserviceplugin.cpp
@@ -150,6 +150,11 @@ QT_END_NAMESPACE
Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void * /*reserved*/)
{
+ static bool initialized = false;
+ if (initialized)
+ return JNI_VERSION_1_6;
+ initialized = true;
+
QT_USE_NAMESPACE
typedef union {
JNIEnv *nativeEnvironment;
diff --git a/src/plugins/android/src/wrappers/jni/androidsurfacetexture.cpp b/src/plugins/android/src/wrappers/jni/androidsurfacetexture.cpp
index 82a8bffe3..df09d0819 100644
--- a/src/plugins/android/src/wrappers/jni/androidsurfacetexture.cpp
+++ b/src/plugins/android/src/wrappers/jni/androidsurfacetexture.cpp
@@ -40,24 +40,32 @@
#include "androidsurfacetexture.h"
#include <QtCore/private/qjni_p.h>
#include <QtCore/private/qjnihelpers_p.h>
+#include <QtCore/qmutex.h>
QT_BEGIN_NAMESPACE
static const char QtSurfaceTextureListenerClassName[] = "org/qtproject/qt5/android/multimedia/QtSurfaceTextureListener";
-static QMap<int, AndroidSurfaceTexture*> g_objectMap;
+typedef QVector<jlong> SurfaceTextures;
+Q_GLOBAL_STATIC(SurfaceTextures, g_surfaceTextures);
+Q_GLOBAL_STATIC(QMutex, g_textureMutex);
// native method for QtSurfaceTexture.java
-static void notifyFrameAvailable(JNIEnv* , jobject, int id)
+static void notifyFrameAvailable(JNIEnv* , jobject, jlong id)
{
- AndroidSurfaceTexture *obj = g_objectMap.value(id, 0);
+ const QMutexLocker lock(g_textureMutex);
+ const int idx = g_surfaceTextures->indexOf(id);
+ if (idx == -1)
+ return;
+
+ AndroidSurfaceTexture *obj = reinterpret_cast<AndroidSurfaceTexture *>(g_surfaceTextures->at(idx));
if (obj)
Q_EMIT obj->frameAvailable();
}
AndroidSurfaceTexture::AndroidSurfaceTexture(unsigned int texName)
: QObject()
- , m_texID(int(texName))
{
+ Q_STATIC_ASSERT(sizeof (jlong) >= sizeof (void *));
// API level 11 or higher is required
if (QtAndroidPrivate::androidSdkVersion() < 11) {
qWarning("Camera preview and video playback require Android 3.0 (API level 11) or later.");
@@ -73,13 +81,13 @@ AndroidSurfaceTexture::AndroidSurfaceTexture(unsigned int texName)
env->ExceptionClear();
}
- if (m_surfaceTexture.isValid())
- g_objectMap.insert(int(texName), this);
+ if (!m_surfaceTexture.isValid())
+ return;
- QJNIObjectPrivate listener(QtSurfaceTextureListenerClassName, "(I)V", jint(texName));
- m_surfaceTexture.callMethod<void>("setOnFrameAvailableListener",
- "(Landroid/graphics/SurfaceTexture$OnFrameAvailableListener;)V",
- listener.object());
+ const QMutexLocker lock(g_textureMutex);
+ g_surfaceTextures->append(jlong(this));
+ QJNIObjectPrivate listener(QtSurfaceTextureListenerClassName, "(J)V", jlong(this));
+ setOnFrameAvailableListener(listener);
}
AndroidSurfaceTexture::~AndroidSurfaceTexture()
@@ -89,7 +97,10 @@ AndroidSurfaceTexture::~AndroidSurfaceTexture()
if (m_surfaceTexture.isValid()) {
release();
- g_objectMap.remove(m_texID);
+ const QMutexLocker lock(g_textureMutex);
+ const int idx = g_surfaceTextures->indexOf(jlong(this));
+ if (idx != -1)
+ g_surfaceTextures->remove(idx);
}
}
@@ -178,7 +189,7 @@ bool AndroidSurfaceTexture::initJNI(JNIEnv *env)
env);
static const JNINativeMethod methods[] = {
- {"notifyFrameAvailable", "(I)V", (void *)notifyFrameAvailable}
+ {"notifyFrameAvailable", "(J)V", (void *)notifyFrameAvailable}
};
if (clazz && env->RegisterNatives(clazz,
@@ -190,4 +201,11 @@ bool AndroidSurfaceTexture::initJNI(JNIEnv *env)
return true;
}
+void AndroidSurfaceTexture::setOnFrameAvailableListener(const QJNIObjectPrivate &listener)
+{
+ m_surfaceTexture.callMethod<void>("setOnFrameAvailableListener",
+ "(Landroid/graphics/SurfaceTexture$OnFrameAvailableListener;)V",
+ listener.object());
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/android/src/wrappers/jni/androidsurfacetexture.h b/src/plugins/android/src/wrappers/jni/androidsurfacetexture.h
index b45ee384c..0a271287a 100644
--- a/src/plugins/android/src/wrappers/jni/androidsurfacetexture.h
+++ b/src/plugins/android/src/wrappers/jni/androidsurfacetexture.h
@@ -54,7 +54,6 @@ public:
explicit AndroidSurfaceTexture(unsigned int texName);
~AndroidSurfaceTexture();
- int textureID() const { return m_texID; }
jobject surfaceTexture();
jobject surface();
jobject surfaceHolder();
@@ -73,7 +72,8 @@ Q_SIGNALS:
void frameAvailable();
private:
- int m_texID;
+ void setOnFrameAvailableListener(const QJNIObjectPrivate &listener);
+
QJNIObjectPrivate m_surfaceTexture;
QJNIObjectPrivate m_surface;
QJNIObjectPrivate m_surfaceHolder;
diff --git a/src/plugins/avfoundation/camera/avfmediaassetwriter.h b/src/plugins/avfoundation/camera/avfmediaassetwriter.h
index fa1ec46a2..624906c85 100644
--- a/src/plugins/avfoundation/camera/avfmediaassetwriter.h
+++ b/src/plugins/avfoundation/camera/avfmediaassetwriter.h
@@ -44,7 +44,6 @@
#include <QtCore/qglobal.h>
#include <QtCore/qatomic.h>
-#include <QtCore/qmutex.h>
#include <AVFoundation/AVFoundation.h>
@@ -53,13 +52,10 @@ QT_BEGIN_NAMESPACE
class AVFMediaRecorderControlIOS;
class AVFCameraService;
-typedef QAtomicInteger<bool> AVFAtomicBool;
typedef QAtomicInteger<qint64> AVFAtomicInt64;
QT_END_NAMESPACE
-// TODO: any reasonable error handling requires smart pointers, otherwise it's getting crappy immediately.
-
@interface QT_MANGLE_NAMESPACE(AVFMediaAssetWriter) : NSObject<AVCaptureVideoDataOutputSampleBufferDelegate,
AVCaptureAudioDataOutputSampleBufferDelegate>
{
@@ -72,22 +68,20 @@ QT_END_NAMESPACE
QT_PREPEND_NAMESPACE(AVFScopedPointer)<AVAssetWriterInput> m_audioWriterInput;
AVCaptureDevice *m_audioCaptureDevice;
+ // Queue to write sample buffers:
+ QT_PREPEND_NAMESPACE(AVFScopedPointer)<dispatch_queue_t> m_writerQueue;
// High priority serial queue for video output:
QT_PREPEND_NAMESPACE(AVFScopedPointer)<dispatch_queue_t> m_videoQueue;
// Serial queue for audio output:
QT_PREPEND_NAMESPACE(AVFScopedPointer)<dispatch_queue_t> m_audioQueue;
- // Queue to write sample buffers:
- QT_PREPEND_NAMESPACE(AVFScopedPointer)<dispatch_queue_t> m_writerQueue;
QT_PREPEND_NAMESPACE(AVFScopedPointer)<AVAssetWriter> m_assetWriter;
QT_PREPEND_NAMESPACE(AVFMediaRecorderControlIOS) *m_delegate;
bool m_setStartTime;
- QT_PREPEND_NAMESPACE(AVFAtomicBool) m_stopped;
- QT_PREPEND_NAMESPACE(AVFAtomicBool) m_aborted;
- QT_PREPEND_NAMESPACE(QMutex) m_writerMutex;
+ QT_PREPEND_NAMESPACE(QAtomicInt) m_state;
@public
QT_PREPEND_NAMESPACE(AVFAtomicInt64) m_durationInMs;
@private
@@ -98,8 +92,7 @@ QT_END_NAMESPACE
NSDictionary *m_videoSettings;
}
-- (id)initWithQueue:(dispatch_queue_t)writerQueue
- delegate:(QT_PREPEND_NAMESPACE(AVFMediaRecorderControlIOS) *)delegate;
+- (id)initWithDelegate:(QT_PREPEND_NAMESPACE(AVFMediaRecorderControlIOS) *)delegate;
- (bool)setupWithFileURL:(NSURL *)fileURL
cameraService:(QT_PREPEND_NAMESPACE(AVFCameraService) *)service
@@ -107,10 +100,10 @@ QT_END_NAMESPACE
videoSettings:(NSDictionary *)videoSettings
transform:(CGAffineTransform)transform;
+// This to be called from the recorder control's thread:
- (void)start;
- (void)stop;
-// This to be called if control's dtor gets called,
-// on the control's thread.
+// This to be called from the recorder control's dtor:
- (void)abort;
@end
diff --git a/src/plugins/avfoundation/camera/avfmediaassetwriter.mm b/src/plugins/avfoundation/camera/avfmediaassetwriter.mm
index 98c8f99ff..28735bc6a 100644
--- a/src/plugins/avfoundation/camera/avfmediaassetwriter.mm
+++ b/src/plugins/avfoundation/camera/avfmediaassetwriter.mm
@@ -46,7 +46,6 @@
#include "avfcameradebug.h"
#include "avfmediacontainercontrol.h"
-//#include <QtCore/qmutexlocker.h>
#include <QtCore/qmetaobject.h>
#include <QtCore/qsysinfo.h>
@@ -74,6 +73,13 @@ bool qt_camera_service_isValid(AVFCameraService *service)
return true;
}
+enum WriterState
+{
+ WriterStateIdle,
+ WriterStateActive,
+ WriterStateAborted
+};
+
} // unnamed namespace
@interface QT_MANGLE_NAMESPACE(AVFMediaAssetWriter) (PrivateAPI)
@@ -85,21 +91,14 @@ bool qt_camera_service_isValid(AVFCameraService *service)
@implementation QT_MANGLE_NAMESPACE(AVFMediaAssetWriter)
-- (id)initWithQueue:(dispatch_queue_t)writerQueue
- delegate:(AVFMediaRecorderControlIOS *)delegate
+- (id)initWithDelegate:(AVFMediaRecorderControlIOS *)delegate
{
- Q_ASSERT(writerQueue);
Q_ASSERT(delegate);
if (self = [super init]) {
- // "Shared" queue:
- dispatch_retain(writerQueue);
- m_writerQueue.reset(writerQueue);
-
m_delegate = delegate;
m_setStartTime = true;
- m_stopped.store(true);
- m_aborted.store(false);
+ m_state.store(WriterStateIdle);
m_startTime = kCMTimeInvalid;
m_lastTimeStamp = kCMTimeInvalid;
m_durationInMs.store(0);
@@ -127,6 +126,12 @@ bool qt_camera_service_isValid(AVFCameraService *service)
m_audioSettings = audioSettings;
m_videoSettings = videoSettings;
+ m_writerQueue.reset(dispatch_queue_create("asset-writer-queue", DISPATCH_QUEUE_SERIAL));
+ if (!m_writerQueue) {
+ qDebugCamera() << Q_FUNC_INFO << "failed to create an asset writer's queue";
+ return false;
+ }
+
m_videoQueue.reset(dispatch_queue_create("video-output-queue", DISPATCH_QUEUE_SERIAL));
if (!m_videoQueue) {
qDebugCamera() << Q_FUNC_INFO << "failed to create video queue";
@@ -173,15 +178,12 @@ bool qt_camera_service_isValid(AVFCameraService *service)
- (void)start
{
- // To be executed on a writer's queue.
- const QMutexLocker lock(&m_writerMutex);
- if (m_aborted.load())
- return;
-
[self setQueues];
m_setStartTime = true;
- m_stopped.store(false);
+
+ m_state.storeRelease(WriterStateActive);
+
[m_assetWriter startWriting];
AVCaptureSession *session = m_service->session()->captureSession();
if (!session.running)
@@ -190,27 +192,36 @@ bool qt_camera_service_isValid(AVFCameraService *service)
- (void)stop
{
- // To be executed on a writer's queue.
- {
- const QMutexLocker lock(&m_writerMutex);
- if (m_aborted.load())
+ if (m_state.loadAcquire() != WriterStateActive)
return;
- if (m_stopped.load())
+ if ([m_assetWriter status] != AVAssetWriterStatusWriting)
return;
- m_stopped.store(true);
- }
-
+ // Do this here so that -
+ // 1. '-abort' should not try calling finishWriting again and
+ // 2. async block (see below) will know if recorder control was deleted
+ // before the block's execution:
+ m_state.storeRelease(WriterStateIdle);
+ // Now, since we have to ensure no sample buffers are
+ // appended after a call to finishWriting, we must
+ // ensure writer's queue sees this change in m_state
+ // _before_ we call finishWriting:
+ dispatch_sync(m_writerQueue, ^{});
+ // Done, but now we also want to prevent video queue
+ // from updating our viewfinder:
+ dispatch_sync(m_videoQueue, ^{});
+
+ // Now we're safe to stop:
[m_assetWriter finishWritingWithCompletionHandler:^{
// 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())
+ if (m_state.loadAcquire() == WriterStateAborted)
return;
AVCaptureSession *session = m_service->session()->captureSession();
- [session stopRunning];
+ if (session.running)
+ [session stopRunning];
[session removeOutput:m_audioOutput];
[session removeInput:m_audioInput];
QMetaObject::invokeMethod(m_delegate, "assetWriterFinished", Qt::QueuedConnection);
@@ -219,12 +230,26 @@ bool qt_camera_service_isValid(AVFCameraService *service)
- (void)abort
{
- // 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.store(true);
- if (m_stopped.load())
+ // -abort is to be called from recorder control's dtor.
+
+ if (m_state.fetchAndStoreRelease(WriterStateAborted) != WriterStateActive) {
+ // Not recording, nothing to stop.
return;
+ }
+
+ // From Apple's docs:
+ // "To guarantee that all sample buffers are successfully written,
+ // you must ensure that all calls to appendSampleBuffer: and
+ // appendPixelBuffer:withPresentationTime: have returned before
+ // invoking this method."
+ //
+ // The only way we can ensure this is:
+ dispatch_sync(m_writerQueue, ^{});
+ // At this point next block (if any) on the writer's queue
+ // will see m_state preventing it from any further processing.
+ dispatch_sync(m_videoQueue, ^{});
+ // After this point video queue will not try to modify our
+ // viewfider, so we're safe to delete now.
[m_assetWriter finishWritingWithCompletionHandler:^{
}];
@@ -236,13 +261,12 @@ bool qt_camera_service_isValid(AVFCameraService *service)
Q_ASSERT(m_setStartTime);
Q_ASSERT(sampleBuffer);
- const QMutexLocker lock(&m_writerMutex);
- if (m_aborted.load() || m_stopped.load())
+ if (m_state.loadAcquire() != WriterStateActive)
return;
QMetaObject::invokeMethod(m_delegate, "assetWriterStarted", Qt::QueuedConnection);
- m_durationInMs.store(0);
+ m_durationInMs.storeRelease(0);
m_startTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
m_lastTimeStamp = m_startTime;
[m_assetWriter startSessionAtSourceTime:m_startTime];
@@ -251,10 +275,10 @@ bool qt_camera_service_isValid(AVFCameraService *service)
- (void)writeVideoSampleBuffer:(CMSampleBufferRef)sampleBuffer
{
+ // This code is executed only on a writer's queue.
Q_ASSERT(sampleBuffer);
- // This code is executed only on a writer's queue.
- if (!m_aborted.load() && !m_stopped.load()) {
+ if (m_state.loadAcquire() == WriterStateActive) {
if (m_setStartTime)
[self setStartTimeFrom:sampleBuffer];
@@ -264,17 +288,15 @@ bool qt_camera_service_isValid(AVFCameraService *service)
}
}
-
CFRelease(sampleBuffer);
}
- (void)writeAudioSampleBuffer:(CMSampleBufferRef)sampleBuffer
{
- // This code is executed only on a writer's queue.
- // it does not touch any shared/external data.
Q_ASSERT(sampleBuffer);
- if (!m_aborted.load() && !m_stopped.load()) {
+ // This code is executed only on a writer's queue.
+ if (m_state.loadAcquire() == WriterStateActive) {
if (m_setStartTime)
[self setStartTimeFrom:sampleBuffer];
@@ -293,10 +315,7 @@ bool qt_camera_service_isValid(AVFCameraService *service)
{
Q_UNUSED(connection)
- // 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())
+ if (m_state.loadAcquire() != WriterStateActive)
return;
if (!CMSampleBufferDataIsReady(sampleBuffer)) {
@@ -307,8 +326,7 @@ bool qt_camera_service_isValid(AVFCameraService *service)
CFRetain(sampleBuffer);
if (captureOutput != m_audioOutput.data()) {
- const QMutexLocker lock(&m_writerMutex);
- if (m_aborted.load() || m_stopped.load()) {
+ if (m_state.load() != WriterStateActive) {
CFRelease(sampleBuffer);
return;
}
@@ -447,7 +465,7 @@ bool qt_camera_service_isValid(AVFCameraService *service)
if (!CMTimeCompare(duration, kCMTimeInvalid))
return;
- m_durationInMs.store(CMTimeGetSeconds(duration) * 1000);
+ m_durationInMs.storeRelease(CMTimeGetSeconds(duration) * 1000);
m_lastTimeStamp = newTimeStamp;
}
}
diff --git a/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.h b/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.h
index 6736f4639..a0967efa3 100644
--- a/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.h
+++ b/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.h
@@ -97,8 +97,6 @@ private:
void stopWriter();
AVFCameraService *m_service;
-
- AVFScopedPointer<dispatch_queue_t> m_writerQueue;
AVFScopedPointer<QT_MANGLE_NAMESPACE(AVFMediaAssetWriter)> m_writer;
QUrl m_outputLocation;
diff --git a/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.mm b/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.mm
index 7c8725260..5f604e9a0 100644
--- a/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.mm
+++ b/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.mm
@@ -92,13 +92,7 @@ AVFMediaRecorderControlIOS::AVFMediaRecorderControlIOS(AVFCameraService *service
{
Q_ASSERT(service);
- m_writerQueue.reset(dispatch_queue_create("asset-writer-queue", DISPATCH_QUEUE_SERIAL));
- if (!m_writerQueue) {
- qDebugCamera() << Q_FUNC_INFO << "failed to create an asset writer's queue";
- return;
- }
-
- m_writer.reset([[QT_MANGLE_NAMESPACE(AVFMediaAssetWriter) alloc] initWithQueue:m_writerQueue delegate:this]);
+ m_writer.reset([[QT_MANGLE_NAMESPACE(AVFMediaAssetWriter) alloc] initWithDelegate:this]);
if (!m_writer) {
qDebugCamera() << Q_FUNC_INFO << "failed to create an asset writer";
return;
@@ -295,9 +289,15 @@ void AVFMediaRecorderControlIOS::setState(QMediaRecorder::State state)
Q_EMIT stateChanged(m_state);
Q_EMIT statusChanged(m_lastStatus);
- dispatch_async(m_writerQueue, ^{
- [m_writer start];
- });
+ // Apple recommends to call startRunning and do all
+ // setup on a special queue, and that's what we had
+ // initially (dispatch_async to writerQueue). Unfortunately,
+ // writer's queue is not the only queue/thread that can
+ // access/modify the session, and as a result we have
+ // all possible data/race-conditions with Obj-C exceptions
+ // at best and something worse in general.
+ // Now we try to only modify session on the same thread.
+ [m_writer start];
} else {
[session startRunning];
Q_EMIT error(QMediaRecorder::FormatError, tr("Failed to start recording"));
@@ -324,7 +324,7 @@ void AVFMediaRecorderControlIOS::setMuted(bool muted)
void AVFMediaRecorderControlIOS::setVolume(qreal volume)
{
- Q_UNUSED(volume);
+ Q_UNUSED(volume)
qDebugCamera() << Q_FUNC_INFO << "not implemented";
}
@@ -409,9 +409,7 @@ void AVFMediaRecorderControlIOS::stopWriter()
Q_EMIT stateChanged(m_state);
Q_EMIT statusChanged(m_lastStatus);
- dispatch_async(m_writerQueue, ^{
- [m_writer stop];
- });
+ [m_writer stop];
}
}
diff --git a/src/plugins/directshow/player/directshowplayerservice.cpp b/src/plugins/directshow/player/directshowplayerservice.cpp
index fa5ce3d55..ccc25d30b 100644
--- a/src/plugins/directshow/player/directshowplayerservice.cpp
+++ b/src/plugins/directshow/player/directshowplayerservice.cpp
@@ -552,8 +552,6 @@ void DirectShowPlayerService::doRender(QMutexLocker *locker)
m_executedTasks |= Render;
}
-
- m_loop->wake();
}
void DirectShowPlayerService::doFinalizeLoad(QMutexLocker *locker)
diff --git a/src/plugins/directshow/player/directshowvideorenderercontrol.cpp b/src/plugins/directshow/player/directshowvideorenderercontrol.cpp
index e08ac1f9d..b86125df9 100644
--- a/src/plugins/directshow/player/directshowvideorenderercontrol.cpp
+++ b/src/plugins/directshow/player/directshowvideorenderercontrol.cpp
@@ -52,11 +52,20 @@ DirectShowVideoRendererControl::DirectShowVideoRendererControl(DirectShowEventLo
, m_loop(loop)
, m_surface(0)
, m_filter(0)
+#ifdef HAVE_EVR
+ , m_evrPresenter(0)
+#endif
{
}
DirectShowVideoRendererControl::~DirectShowVideoRendererControl()
{
+#ifdef HAVE_EVR
+ if (m_evrPresenter) {
+ m_evrPresenter->setSurface(Q_NULLPTR);
+ m_evrPresenter->Release();
+ }
+#endif
if (m_filter)
m_filter->Release();
}
@@ -71,6 +80,14 @@ void DirectShowVideoRendererControl::setSurface(QAbstractVideoSurface *surface)
if (m_surface == surface)
return;
+#ifdef HAVE_EVR
+ if (m_evrPresenter) {
+ m_evrPresenter->setSurface(Q_NULLPTR);
+ m_evrPresenter->Release();
+ m_evrPresenter = 0;
+ }
+#endif
+
if (m_filter) {
m_filter->Release();
m_filter = 0;
@@ -81,12 +98,13 @@ void DirectShowVideoRendererControl::setSurface(QAbstractVideoSurface *surface)
if (m_surface) {
#ifdef HAVE_EVR
m_filter = com_new<IBaseFilter>(clsid_EnhancedVideoRenderer);
- EVRCustomPresenter *evrPresenter = new EVRCustomPresenter(m_surface);
- if (!evrPresenter->isValid() || !qt_evr_setCustomPresenter(m_filter, evrPresenter)) {
+ m_evrPresenter = new EVRCustomPresenter(m_surface);
+ if (!m_evrPresenter->isValid() || !qt_evr_setCustomPresenter(m_filter, m_evrPresenter)) {
m_filter->Release();
m_filter = 0;
+ m_evrPresenter->Release();
+ m_evrPresenter = 0;
}
- evrPresenter->Release();
if (!m_filter)
#endif
diff --git a/src/plugins/directshow/player/directshowvideorenderercontrol.h b/src/plugins/directshow/player/directshowvideorenderercontrol.h
index 17dd4705b..9d1a23933 100644
--- a/src/plugins/directshow/player/directshowvideorenderercontrol.h
+++ b/src/plugins/directshow/player/directshowvideorenderercontrol.h
@@ -45,6 +45,9 @@
#include "qvideorenderercontrol.h"
class DirectShowEventLoop;
+#ifdef HAVE_EVR
+class EVRCustomPresenter;
+#endif
QT_USE_NAMESPACE
@@ -67,6 +70,9 @@ private:
DirectShowEventLoop *m_loop;
QAbstractVideoSurface *m_surface;
IBaseFilter *m_filter;
+#ifdef HAVE_EVR
+ EVRCustomPresenter *m_evrPresenter;
+#endif
};
#endif
diff --git a/src/plugins/gstreamer/camerabin/camerabinv4limageprocessing.cpp b/src/plugins/gstreamer/camerabin/camerabinv4limageprocessing.cpp
index d2be15e71..6ca1dbe94 100644
--- a/src/plugins/gstreamer/camerabin/camerabinv4limageprocessing.cpp
+++ b/src/plugins/gstreamer/camerabin/camerabinv4limageprocessing.cpp
@@ -200,8 +200,10 @@ void CameraBinV4LImageProcessing::setParameter(
const QCameraImageProcessing::WhiteBalanceMode m =
value.value<QCameraImageProcessing::WhiteBalanceMode>();
if (m != QCameraImageProcessing::WhiteBalanceAuto
- && m != QCameraImageProcessing::WhiteBalanceManual)
+ && m != QCameraImageProcessing::WhiteBalanceManual) {
+ qt_safe_close(fd);
return;
+ }
control.value = (m == QCameraImageProcessing::WhiteBalanceAuto) ? true : false;
}
@@ -220,6 +222,7 @@ void CameraBinV4LImageProcessing::setParameter(
break;
default:
+ qt_safe_close(fd);
return;
}
diff --git a/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp b/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp
index 87c2c26dc..5cd3bc3d2 100644
--- a/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp
+++ b/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp
@@ -346,6 +346,8 @@ void MmRendererMediaPlayerControl::setState(QMediaPlayer::State state)
void MmRendererMediaPlayerControl::stopInternal(StopCommand stopCommand)
{
+ setPosition(0);
+
if (m_state != QMediaPlayer::StoppedState) {
if (stopCommand == StopMmRenderer) {
@@ -355,11 +357,6 @@ void MmRendererMediaPlayerControl::stopInternal(StopCommand stopCommand)
setState(QMediaPlayer::StoppedState);
}
-
- if (m_position != 0) {
- m_position = 0;
- emit positionChanged(0);
- }
}
void MmRendererMediaPlayerControl::setVolume(int volume)
diff --git a/src/plugins/winrt/qwinrtcameracontrol.cpp b/src/plugins/winrt/qwinrtcameracontrol.cpp
index 390364eb8..6ce502b88 100644
--- a/src/plugins/winrt/qwinrtcameracontrol.cpp
+++ b/src/plugins/winrt/qwinrtcameracontrol.cpp
@@ -942,7 +942,8 @@ HRESULT QWinRTCameraControl::initialize()
Q_ASSERT_SUCCEEDED(hr);
if (isFocusSupported) {
hr = advancedVideoDeviceController->get_RegionsOfInterestControl(&d->regionsOfInterestControl);
- Q_ASSERT_SUCCEEDED(hr);
+ if (FAILED(hr))
+ qCDebug(lcMMCamera) << "Focus supported, but no control for regions of interest available";
hr = initializeFocus();
Q_ASSERT_SUCCEEDED(hr);
} else {
diff --git a/tests/auto/integration/qsoundeffect/BLACKLIST b/tests/auto/integration/qsoundeffect/BLACKLIST
deleted file mode 100644
index 3a358789a..000000000
--- a/tests/auto/integration/qsoundeffect/BLACKLIST
+++ /dev/null
@@ -1,8 +0,0 @@
-# QTBUG-46689
-
-[testLooping]
-ubuntu-14.04 64bit
-redhatenterpriselinuxworkstation-6.6
-rhel-7.1
-opensuse-13.1
-rhel-7.2
diff --git a/tests/auto/integration/qsoundeffect/tst_qsoundeffect.cpp b/tests/auto/integration/qsoundeffect/tst_qsoundeffect.cpp
index dd486a1a3..5be889096 100644
--- a/tests/auto/integration/qsoundeffect/tst_qsoundeffect.cpp
+++ b/tests/auto/integration/qsoundeffect/tst_qsoundeffect.cpp
@@ -183,7 +183,7 @@ void tst_QSoundEffect::testLooping()
// wait for all the loops to be completed
QTRY_COMPARE(sound->loopsRemaining(), 0);
- QVERIFY(readSignal_Remaining.count() >= 6);
+ QTRY_VERIFY(readSignal_Remaining.count() >= 6);
QTRY_VERIFY(!sound->isPlaying());
}
@@ -198,7 +198,7 @@ void tst_QSoundEffect::testLooping()
QCOMPARE(readSignal_Remaining.count(), 0);
sound->play();
- QCOMPARE(sound->loopsRemaining(), int(QSoundEffect::Infinite));
+ QTRY_COMPARE(sound->loopsRemaining(), int(QSoundEffect::Infinite));
QCOMPARE(readSignal_Remaining.count(), 1);
QTest::qWait(1500);
@@ -214,7 +214,7 @@ void tst_QSoundEffect::testLooping()
QCOMPARE(readSignal_Remaining.count(), 1);
QTRY_COMPARE(sound->loopsRemaining(), 0);
- QVERIFY(readSignal_Remaining.count() >= 2);
+ QTRY_VERIFY(readSignal_Remaining.count() >= 2);
QTRY_VERIFY(!sound->isPlaying());
}
}