From 40924657e9e5a8f40182be784cc07a70302e1824 Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Fri, 8 Apr 2016 09:07:49 +0200 Subject: tests: skip tst_qaudiodecoderbackend when no audio decoding support Task-number: QTBUG-46331 Change-Id: I9168ae7d89869cc0811394fc4091a5e44c136b9b Reviewed-by: Christian Stromme --- .../integration/qaudiodecoderbackend/BLACKLIST | 41 ---------------------- .../tst_qaudiodecoderbackend.cpp | 8 +++++ 2 files changed, 8 insertions(+), 41 deletions(-) delete mode 100644 tests/auto/integration/qaudiodecoderbackend/BLACKLIST diff --git a/tests/auto/integration/qaudiodecoderbackend/BLACKLIST b/tests/auto/integration/qaudiodecoderbackend/BLACKLIST deleted file mode 100644 index 038b89022..000000000 --- a/tests/auto/integration/qaudiodecoderbackend/BLACKLIST +++ /dev/null @@ -1,41 +0,0 @@ -# QTBUG-46331 - -[fileTest] -opensuse-13.1 64bit -redhatenterpriselinuxworkstation-6.6 -osx-10.8 -osx-10.9 -osx-10.10 -osx-10.11 -windows 32bit developer-build -windows 64bit developer-build - -[unsupportedFileTest] -opensuse-13.1 64bit -redhatenterpriselinuxworkstation-6.6 -osx-10.8 -osx-10.9 -osx-10.10 -osx-10.11 -windows 32bit developer-build -windows 64bit developer-build - -[corruptedFileTest] -opensuse-13.1 64bit -redhatenterpriselinuxworkstation-6.6 -osx-10.8 -osx-10.9 -osx-10.10 -osx-10.11 -windows 32bit developer-build -windows 64bit developer-build - -[deviceTest] -opensuse-13.1 64bit -redhatenterpriselinuxworkstation-6.6 -osx-10.8 -osx-10.9 -osx-10.10 -osx-10.11 -windows 32bit developer-build -windows 64bit developer-build diff --git a/tests/auto/integration/qaudiodecoderbackend/tst_qaudiodecoderbackend.cpp b/tests/auto/integration/qaudiodecoderbackend/tst_qaudiodecoderbackend.cpp index a52324d1a..562fe7ada 100644 --- a/tests/auto/integration/qaudiodecoderbackend/tst_qaudiodecoderbackend.cpp +++ b/tests/auto/integration/qaudiodecoderbackend/tst_qaudiodecoderbackend.cpp @@ -78,6 +78,8 @@ void tst_QAudioDecoderBackend::cleanup() void tst_QAudioDecoderBackend::fileTest() { QAudioDecoder d; + if (d.error() == QAudioDecoder::ServiceMissingError) + QSKIP("There is no audio decoding support on this platform."); QAudioBuffer buffer; quint64 duration = 0; int byteCount = 0; @@ -260,6 +262,8 @@ void tst_QAudioDecoderBackend::fileTest() void tst_QAudioDecoderBackend::unsupportedFileTest() { QAudioDecoder d; + if (d.error() == QAudioDecoder::ServiceMissingError) + QSKIP("There is no audio decoding support on this platform."); QAudioBuffer buffer; QVERIFY(d.state() == QAudioDecoder::StoppedState); @@ -336,6 +340,8 @@ void tst_QAudioDecoderBackend::unsupportedFileTest() void tst_QAudioDecoderBackend::corruptedFileTest() { QAudioDecoder d; + if (d.error() == QAudioDecoder::ServiceMissingError) + QSKIP("There is no audio decoding support on this platform."); QAudioBuffer buffer; QVERIFY(d.state() == QAudioDecoder::StoppedState); @@ -408,6 +414,8 @@ void tst_QAudioDecoderBackend::corruptedFileTest() void tst_QAudioDecoderBackend::deviceTest() { QAudioDecoder d; + if (d.error() == QAudioDecoder::ServiceMissingError) + QSKIP("There is no audio decoding support on this platform."); QAudioBuffer buffer; quint64 duration = 0; int sampleCount = 0; -- cgit v1.2.3 From c8090b79520bd7834954a743d64c0c5eecf01c23 Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Fri, 11 Mar 2016 15:34:13 +0100 Subject: AVFoundation: return correct viewfinder settings. When the camera is unloaded, return the requested settings. Change-Id: If39e158cd8d0fd8d4bbd7cf6cd48226cdefc1272 Reviewed-by: Christian Stromme --- .../avfoundation/camera/avfcameraviewfindersettingscontrol.mm | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm b/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm index 3c20801e5..472e84ed1 100644 --- a/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm +++ b/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm @@ -339,7 +339,7 @@ QList AVFCameraViewfinderSettingsControl2::supportedV QCameraViewfinderSettings AVFCameraViewfinderSettingsControl2::viewfinderSettings() const { - QCameraViewfinderSettings settings; + QCameraViewfinderSettings settings = m_settings; AVCaptureDevice *captureDevice = m_service->session()->videoCaptureDevice(); if (!captureDevice) { @@ -347,6 +347,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) { -- cgit v1.2.3 From b5a184ec2da2c17d2a6d03b416130bf300614664 Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Fri, 11 Mar 2016 15:40:57 +0100 Subject: AVFoundation: fix switching to still image capture mode. It would reset the active format on the capture device. The patch prevents that. Change-Id: I97c192c064bf3c6ed4ba1f8d78768196927819a7 Reviewed-by: Christian Stromme --- src/plugins/avfoundation/camera/avfimagecapturecontrol.mm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm b/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm index edaaf8ce3..3e6b6c778 100644 --- a/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm +++ b/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm @@ -34,6 +34,7 @@ #include "avfcameradebug.h" #include "avfimagecapturecontrol.h" #include "avfcameraservice.h" +#include "avfcamerautility.h" #include "avfcameracontrol.h" #include @@ -208,6 +209,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(); -- cgit v1.2.3 From 9047d9b84e9d94d193e77abd81f5980eff77d73a Mon Sep 17 00:00:00 2001 From: Stephen Hurd Date: Thu, 14 Apr 2016 19:11:01 -0700 Subject: ALSA: Call snd_pcm_drain() on suspend The ALSA plugin previously didn't suspend the ALSA device when the ::suspend() method is called. This results in underrun errors when it's resumed. In ALSA, stopping a pcm doesn't close it, so the ALSA stop/start functions map to the QAudioInput suspend/resume functions. Change-Id: I2507065a1b7472af29eef70c531b9f6e8e5b3072 Reviewed-by: Christian Stromme --- src/plugins/alsa/qalsaaudioinput.cpp | 1 + src/plugins/alsa/qalsaaudiooutput.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/plugins/alsa/qalsaaudioinput.cpp b/src/plugins/alsa/qalsaaudioinput.cpp index d9c775148..5f7a788a6 100644 --- a/src/plugins/alsa/qalsaaudioinput.cpp +++ b/src/plugins/alsa/qalsaaudioinput.cpp @@ -701,6 +701,7 @@ qint64 QAlsaAudioInput::processedUSecs() const void QAlsaAudioInput::suspend() { if(deviceState == QAudio::ActiveState||resuming) { + snd_pcm_drain(handle); timer->stop(); deviceState = QAudio::SuspendedState; emit stateChanged(deviceState); diff --git a/src/plugins/alsa/qalsaaudiooutput.cpp b/src/plugins/alsa/qalsaaudiooutput.cpp index 5702cfc78..02681a4df 100644 --- a/src/plugins/alsa/qalsaaudiooutput.cpp +++ b/src/plugins/alsa/qalsaaudiooutput.cpp @@ -673,6 +673,7 @@ QAudioFormat QAlsaAudioOutput::format() const void QAlsaAudioOutput::suspend() { if(deviceState == QAudio::ActiveState || deviceState == QAudio::IdleState || resuming) { + snd_pcm_drain(handle); timer->stop(); deviceState = QAudio::SuspendedState; errorState = QAudio::NoError; -- cgit v1.2.3 From 2170a3b0fcda613daf76a337fa45cb97e0714cdf Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Tue, 19 Apr 2016 12:50:12 +0200 Subject: AVFFoundation - fix a compilation error (iOS, XCode 7.3) __weak previously was a simple noop, but now it ends up in a compilation error in non-ARC'ed source code ('declaration uses __weak, but ARC is disabled'). Task-number: QTBUG-52671 Change-Id: I574519f892ba1d5f71488c5cc26423d04d5e02cf Reviewed-by: Yoann Lopes --- src/plugins/avfoundation/camera/avfmediaassetwriter.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/avfoundation/camera/avfmediaassetwriter.h b/src/plugins/avfoundation/camera/avfmediaassetwriter.h index 4759ae0a7..de8126295 100644 --- a/src/plugins/avfoundation/camera/avfmediaassetwriter.h +++ b/src/plugins/avfoundation/camera/avfmediaassetwriter.h @@ -80,12 +80,12 @@ QT_END_NAMESPACE // Serial queue for audio output: QT_PREPEND_NAMESPACE(AVFScopedPointer) m_audioQueue; // Queue to write sample buffers: - __weak dispatch_queue_t m_writerQueue; + dispatch_queue_t m_writerQueue; QT_PREPEND_NAMESPACE(AVFScopedPointer) m_assetWriter; // Delegate's queue. - __weak dispatch_queue_t m_delegateQueue; - // TODO: QPointer?? + dispatch_queue_t m_delegateQueue; + QT_PREPEND_NAMESPACE(AVFMediaAssetWriterDelegate) *m_delegate; bool m_setStartTime; -- cgit v1.2.3 From ffe61fd5169b5dd6f2a475ddccbf3679696d380f Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Thu, 21 Apr 2016 10:23:18 +0200 Subject: winrt: Remove capability specification This is handled with 34e0e908c896126138a95abdeba7456499d0fb68 in qtbase. Change-Id: I41cf27690189aefb3000de90df4a518d8dd449f0 Reviewed-by: Oliver Wolff --- examples/multimedia/declarative-camera/declarative-camera.pro | 3 --- 1 file changed, 3 deletions(-) diff --git a/examples/multimedia/declarative-camera/declarative-camera.pro b/examples/multimedia/declarative-camera/declarative-camera.pro index f977e1cb3..71d4f68b0 100644 --- a/examples/multimedia/declarative-camera/declarative-camera.pro +++ b/examples/multimedia/declarative-camera/declarative-camera.pro @@ -9,6 +9,3 @@ RESOURCES += declarative-camera.qrc target.path = $$[QT_INSTALL_EXAMPLES]/multimedia/declarative-camera INSTALLS += target -winrt { - WINRT_MANIFEST.capabilities_device += webcam microphone -} -- cgit v1.2.3 From f97e1988a6f76d46d551678666a96fa5f36a92f7 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Tue, 19 Apr 2016 15:21:50 +0200 Subject: AVFMediaAssetWriter - fix potential race condition(s) 1. m_writerQueue is now shared by recorder control and asset writer to ensure it lives long enough. 2. m_delegate->method() calls from async block can be dangerous, since by the time this block is actually executed, delegate can be deleted already. This fix uses Q_INVOKABLE and invokeMethod with QueuedConnection instead. 3. -finishWritingWithCompletionHandler: is async and when the block finally gets executed, lock and 'if aborted' test are still needed. 4. Simplify the logic and reduce locking. Change-Id: If23daf2fe22043244033427a7f6517a0fe3f23d1 Reviewed-by: Yoann Lopes --- .../avfoundation/camera/avfmediaassetwriter.h | 24 +--- .../avfoundation/camera/avfmediaassetwriter.mm | 136 ++++++++++----------- .../camera/avfmediarecordercontrol_ios.h | 9 +- .../camera/avfmediarecordercontrol_ios.mm | 11 +- 4 files changed, 71 insertions(+), 109 deletions(-) diff --git a/src/plugins/avfoundation/camera/avfmediaassetwriter.h b/src/plugins/avfoundation/camera/avfmediaassetwriter.h index de8126295..21915e9ee 100644 --- a/src/plugins/avfoundation/camera/avfmediaassetwriter.h +++ b/src/plugins/avfoundation/camera/avfmediaassetwriter.h @@ -44,19 +44,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 AVFAtomicBool; typedef QAtomicInteger AVFAtomicInt64; @@ -80,18 +70,15 @@ QT_END_NAMESPACE // Serial queue for audio output: QT_PREPEND_NAMESPACE(AVFScopedPointer) m_audioQueue; // Queue to write sample buffers: - dispatch_queue_t m_writerQueue; + QT_PREPEND_NAMESPACE(AVFScopedPointer) m_writerQueue; QT_PREPEND_NAMESPACE(AVFScopedPointer) m_assetWriter; - // Delegate's queue. - dispatch_queue_t m_delegateQueue; - 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 @@ -102,8 +89,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 37004c1db..a541956a8 100644 --- a/src/plugins/avfoundation/camera/avfmediaassetwriter.mm +++ b/src/plugins/avfoundation/camera/avfmediaassetwriter.mm @@ -32,6 +32,7 @@ ****************************************************************************/ #include "avfaudioinputselectorcontrol.h" +#include "avfmediarecordercontrol_ios.h" #include "avfcamerarenderercontrol.h" #include "avfmediaassetwriter.h" #include "avfcameraservice.h" @@ -39,6 +40,7 @@ #include "avfcameradebug.h" //#include +#include #include QT_USE_NAMESPACE @@ -65,11 +67,7 @@ bool qt_camera_service_isValid(AVFCameraService *service) return true; } -} - -AVFMediaAssetWriterDelegate::~AVFMediaAssetWriterDelegate() -{ -} +} // unnamed namespace @interface QT_MANGLE_NAMESPACE(AVFMediaAssetWriter) (PrivateAPI) - (bool)addAudioCapture; @@ -83,21 +81,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); @@ -160,14 +157,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) @@ -177,40 +173,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:^{ }]; } @@ -221,9 +218,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); @@ -236,22 +235,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); } @@ -261,16 +256,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]; } } @@ -283,13 +275,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; @@ -298,21 +289,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 *vfDelegate = - (NSObject *)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 *vfDelegate = + (NSObject *)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 785769486..a055e54f6 100644 --- a/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.h +++ b/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.h @@ -51,7 +51,7 @@ class AVFCameraService; class QString; class QUrl; -class AVFMediaRecorderControlIOS : public QMediaRecorderControl, public AVFMediaAssetWriterDelegate +class AVFMediaRecorderControlIOS : public QMediaRecorderControl { Q_OBJECT public: @@ -76,13 +76,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 b763dbcce..73e19e683 100644 --- a/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.mm +++ b/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.mm @@ -86,8 +86,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; @@ -259,14 +258,6 @@ void AVFMediaRecorderControlIOS::assetWriterStarted() Q_EMIT statusChanged(QMediaRecorder::RecordingStatus); } -void AVFMediaRecorderControlIOS::assetWriterFailedToStart() -{ -} - -void AVFMediaRecorderControlIOS::assetWriterFailedToStop() -{ -} - void AVFMediaRecorderControlIOS::assetWriterFinished() { AVFCameraControl *cameraControl = m_service->cameraControl(); -- cgit v1.2.3 From 5206d3783645ad4caf189ab77ce82f360d1e45bc Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Thu, 14 Apr 2016 10:45:21 +0200 Subject: winrt: Use ComPtr for better ref count tracking Just forwarding the content of a ComPtr is potentially dangerous. Change-Id: I4f3dfa04a5844d299a5653e31a4a0d1e1b86f9b5 Reviewed-by: Oliver Wolff --- src/plugins/winrt/qwinrtcameracontrol.cpp | 4 ++-- src/plugins/winrt/qwinrtcameracontrol.h | 4 +++- src/plugins/winrt/qwinrtcameraimagecapturecontrol.cpp | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/plugins/winrt/qwinrtcameracontrol.cpp b/src/plugins/winrt/qwinrtcameracontrol.cpp index 19b718cdd..b0446cd57 100644 --- a/src/plugins/winrt/qwinrtcameracontrol.cpp +++ b/src/plugins/winrt/qwinrtcameracontrol.cpp @@ -775,10 +775,10 @@ QCameraLocksControl *QWinRTCameraControl::cameraLocksControl() const return d->cameraLocksControl; } -IMediaCapture *QWinRTCameraControl::handle() const +Microsoft::WRL::ComPtr QWinRTCameraControl::handle() const { Q_D(const QWinRTCameraControl); - return d->capture.Get(); + return d->capture; } void QWinRTCameraControl::onBufferRequested() diff --git a/src/plugins/winrt/qwinrtcameracontrol.h b/src/plugins/winrt/qwinrtcameracontrol.h index b3c86adf9..1c0cbd808 100644 --- a/src/plugins/winrt/qwinrtcameracontrol.h +++ b/src/plugins/winrt/qwinrtcameracontrol.h @@ -40,6 +40,8 @@ #include #include +#include + namespace ABI { namespace Windows { namespace Media { @@ -90,7 +92,7 @@ public: QCameraFocusControl *cameraFocusControl() const; QCameraLocksControl *cameraLocksControl() const; - ABI::Windows::Media::Capture::IMediaCapture *handle() const; + Microsoft::WRL::ComPtr handle() const; bool setFocus(QCameraFocus::FocusModes mode); bool setFocusPoint(const QPointF &point); diff --git a/src/plugins/winrt/qwinrtcameraimagecapturecontrol.cpp b/src/plugins/winrt/qwinrtcameraimagecapturecontrol.cpp index ae67e33f4..67f12f264 100644 --- a/src/plugins/winrt/qwinrtcameraimagecapturecontrol.cpp +++ b/src/plugins/winrt/qwinrtcameraimagecapturecontrol.cpp @@ -147,7 +147,7 @@ int QWinRTCameraImageCaptureControl::capture(const QString &fileName) Q_D(QWinRTCameraImageCaptureControl); ++d->currentCaptureId; - IMediaCapture *capture = d->cameraControl->handle(); + ComPtr capture = d->cameraControl->handle(); if (!capture) { emit error(d->currentCaptureId, QCameraImageCapture::NotReadyError, tr("Camera not ready")); return -1; -- cgit v1.2.3 From 65c9e24c10c7fe715c897572d8f3e5210ea13e07 Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Fri, 15 Apr 2016 07:36:34 +0200 Subject: winrt: Add categorized logging to camera control Change-Id: I6d823ac07950212d766905c9409469f2b1b84954 Reviewed-by: Oliver Wolff Reviewed-by: Yoann Lopes --- src/plugins/winrt/qwinrtcameracontrol.cpp | 10 ++++++++++ src/plugins/winrt/qwinrtcameracontrol.h | 3 +++ src/plugins/winrt/qwinrtcameraimagecapturecontrol.cpp | 4 ++++ 3 files changed, 17 insertions(+) diff --git a/src/plugins/winrt/qwinrtcameracontrol.cpp b/src/plugins/winrt/qwinrtcameracontrol.cpp index b0446cd57..63428fd84 100644 --- a/src/plugins/winrt/qwinrtcameracontrol.cpp +++ b/src/plugins/winrt/qwinrtcameracontrol.cpp @@ -81,6 +81,8 @@ QT_BEGIN_NAMESPACE #define FOCUS_RECT_POSITION_MAX 0.995f // FOCUS_RECT_BOUNDARY - FOCUS_RECT_HALF_SIZE #define ASPECTRATIO_EPSILON 0.01f +Q_LOGGING_CATEGORY(lcMMCamera, "qt.mm.camera") + HRESULT getMediaStreamResolutions(IMediaDeviceController *device, MediaStreamType type, IVectorView **propertiesList, @@ -532,6 +534,7 @@ public: QWinRTCameraControl::QWinRTCameraControl(QObject *parent) : QCameraControl(parent), d_ptr(new QWinRTCameraControlPrivate) { + qCDebug(lcMMCamera) << __FUNCTION__ << parent; Q_D(QWinRTCameraControl); d->delayClose = nullptr; @@ -568,6 +571,7 @@ QCamera::State QWinRTCameraControl::state() const void QWinRTCameraControl::setState(QCamera::State state) { + qCDebug(lcMMCamera) << __FUNCTION__ << state; Q_D(QWinRTCameraControl); if (d->state == state) @@ -713,6 +717,7 @@ QCamera::CaptureModes QWinRTCameraControl::captureMode() const void QWinRTCameraControl::setCaptureMode(QCamera::CaptureModes mode) { + qCDebug(lcMMCamera) << __FUNCTION__ << mode; Q_D(QWinRTCameraControl); if (d->captureMode == mode) @@ -791,6 +796,7 @@ void QWinRTCameraControl::onBufferRequested() void QWinRTCameraControl::onApplicationStateChanged(Qt::ApplicationState state) { + qCDebug(lcMMCamera) << __FUNCTION__ << state; Q_D(QWinRTCameraControl); static QCamera::State savedState = d->state; switch (state) { @@ -810,6 +816,7 @@ void QWinRTCameraControl::onApplicationStateChanged(Qt::ApplicationState state) HRESULT QWinRTCameraControl::initialize() { + qCDebug(lcMMCamera) << __FUNCTION__; Q_D(QWinRTCameraControl); if (d->status != QCamera::LoadingStatus) { @@ -1284,6 +1291,7 @@ void QWinRTCameraControl::frameUnmapped() HRESULT QWinRTCameraControl::onCaptureFailed(IMediaCapture *, IMediaCaptureFailedEventArgs *args) { + qCDebug(lcMMCamera) << __FUNCTION__ << args; HRESULT hr; UINT32 code; hr = args->get_Code(&code); @@ -1300,6 +1308,7 @@ HRESULT QWinRTCameraControl::onCaptureFailed(IMediaCapture *, IMediaCaptureFaile HRESULT QWinRTCameraControl::onRecordLimitationExceeded(IMediaCapture *) { + qCDebug(lcMMCamera) << __FUNCTION__; emit error(QCamera::CameraError, QStringLiteral("Recording limit exceeded.")); setState(QCamera::LoadedState); return S_OK; @@ -1307,6 +1316,7 @@ HRESULT QWinRTCameraControl::onRecordLimitationExceeded(IMediaCapture *) void QWinRTCameraControl::emitError(int errorCode, const QString &errorString) { + qCDebug(lcMMCamera) << __FUNCTION__ << errorString << errorCode; emit error(errorCode, errorString); } diff --git a/src/plugins/winrt/qwinrtcameracontrol.h b/src/plugins/winrt/qwinrtcameracontrol.h index 1c0cbd808..c657d5935 100644 --- a/src/plugins/winrt/qwinrtcameracontrol.h +++ b/src/plugins/winrt/qwinrtcameracontrol.h @@ -38,6 +38,7 @@ #define QWINRTCAMERACONTROL_H #include +#include #include #include @@ -59,6 +60,8 @@ namespace ABI { QT_BEGIN_NAMESPACE +Q_DECLARE_LOGGING_CATEGORY(lcMMCamera) + class QVideoRendererControl; class QVideoDeviceSelectorControl; class QCameraImageCaptureControl; diff --git a/src/plugins/winrt/qwinrtcameraimagecapturecontrol.cpp b/src/plugins/winrt/qwinrtcameraimagecapturecontrol.cpp index 67f12f264..8ae7f37a9 100644 --- a/src/plugins/winrt/qwinrtcameraimagecapturecontrol.cpp +++ b/src/plugins/winrt/qwinrtcameraimagecapturecontrol.cpp @@ -118,6 +118,7 @@ public: QWinRTCameraImageCaptureControl::QWinRTCameraImageCaptureControl(QWinRTCameraControl *parent) : QCameraImageCaptureControl(parent), d_ptr(new QWinRTCameraImageCaptureControlPrivate) { + qCDebug(lcMMCamera) << __FUNCTION__ << parent; Q_D(QWinRTCameraImageCaptureControl); d->cameraControl = parent; @@ -144,6 +145,7 @@ void QWinRTCameraImageCaptureControl::setDriveMode(QCameraImageCapture::DriveMod int QWinRTCameraImageCaptureControl::capture(const QString &fileName) { + qCDebug(lcMMCamera) << __FUNCTION__ << fileName; Q_D(QWinRTCameraImageCaptureControl); ++d->currentCaptureId; @@ -191,6 +193,7 @@ int QWinRTCameraImageCaptureControl::capture(const QString &fileName) void QWinRTCameraImageCaptureControl::cancelCapture() { + qCDebug(lcMMCamera) << __FUNCTION__; Q_D(QWinRTCameraImageCaptureControl); QHash::iterator it = d->requests.begin(); @@ -205,6 +208,7 @@ void QWinRTCameraImageCaptureControl::cancelCapture() HRESULT QWinRTCameraImageCaptureControl::onCaptureCompleted(IAsyncAction *asyncInfo, AsyncStatus status) { + qCDebug(lcMMCamera) << __FUNCTION__; Q_D(QWinRTCameraImageCaptureControl); if (status == Canceled || !d->requests.contains(asyncInfo)) -- cgit v1.2.3 From a0a20157efab21c07f327c70bd8603b5973f9a39 Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Fri, 15 Apr 2016 08:33:42 +0200 Subject: winrt: fix camera control after move to xaml thread Camera control management has to happen inside the xaml thread, otherwise the behavior is undefined. This results in ie. the first capture not working due to synchronization issues. When (de-)activating the videoRenderer we have to switch to the UI thread first. In addition add focus for Windows 10 (Mobile), previously it was compiled for Windows Phone 8.1 only. On desktop this might return no focus mode to be supported, but API-wise this is available. Task-number: QTBUG-47803 Change-Id: I9b345ebc82502fc6e00aede43b9096893cd0ad53 Reviewed-by: Oliver Wolff --- .../winrt/qwinrtabstractvideorenderercontrol.h | 5 +- src/plugins/winrt/qwinrtcameracontrol.cpp | 358 +++++++++++---------- .../winrt/qwinrtcameraimagecapturecontrol.cpp | 52 +-- .../winrt/qwinrtcameravideorenderercontrol.cpp | 6 +- .../winrt/qwinrtvideodeviceselectorcontrol.cpp | 2 +- 5 files changed, 230 insertions(+), 193 deletions(-) diff --git a/src/plugins/winrt/qwinrtabstractvideorenderercontrol.h b/src/plugins/winrt/qwinrtabstractvideorenderercontrol.h index 70227c53c..bfef55fc7 100644 --- a/src/plugins/winrt/qwinrtabstractvideorenderercontrol.h +++ b/src/plugins/winrt/qwinrtabstractvideorenderercontrol.h @@ -68,8 +68,6 @@ public: void setScanLineDirection(QVideoSurfaceFormat::Direction direction); - void setActive(bool active); - BlitMode blitMode() const; void setBlitMode(BlitMode mode); @@ -78,6 +76,9 @@ public: static ID3D11Device *d3dDevice(); +public slots: + void setActive(bool active); + protected: void shutdown(); diff --git a/src/plugins/winrt/qwinrtcameracontrol.cpp b/src/plugins/winrt/qwinrtcameracontrol.cpp index 63428fd84..b6068594a 100644 --- a/src/plugins/winrt/qwinrtcameracontrol.cpp +++ b/src/plugins/winrt/qwinrtcameracontrol.cpp @@ -45,7 +45,9 @@ #include #include #include +#include +#include #include #include #include @@ -446,7 +448,7 @@ public: HRESULT __stdcall Shutdown() Q_DECL_OVERRIDE { m_stream->Flush(); - m_videoRenderer->setActive(false); + scheduleSetActive(false); return m_presentationClock ? m_presentationClock->Stop() : S_OK; } @@ -455,7 +457,7 @@ public: Q_UNUSED(systemTime); Q_UNUSED(clockStartOffset); - m_videoRenderer->setActive(true); + scheduleSetActive(true); return S_OK; } @@ -464,7 +466,7 @@ public: { Q_UNUSED(systemTime); - m_videoRenderer->setActive(false); + scheduleSetActive(false); return m_stream->QueueEvent(MEStreamSinkStopped, GUID_NULL, S_OK, Q_NULLPTR); } @@ -473,7 +475,7 @@ public: { Q_UNUSED(systemTime); - m_videoRenderer->setActive(false); + scheduleSetActive(false); return m_stream->QueueEvent(MEStreamSinkPaused, GUID_NULL, S_OK, Q_NULLPTR); } @@ -482,7 +484,7 @@ public: { Q_UNUSED(systemTime); - m_videoRenderer->setActive(true); + scheduleSetActive(true); return m_stream->QueueEvent(MEStreamSinkStarted, GUID_NULL, S_OK, Q_NULLPTR); } @@ -495,6 +497,12 @@ public: } private: + + inline void scheduleSetActive(bool active) + { + QMetaObject::invokeMethod(m_videoRenderer, "setActive", Qt::QueuedConnection, Q_ARG(bool, active)); + } + ComPtr m_stream; ComPtr m_presentationClock; @@ -587,16 +595,21 @@ void QWinRTCameraControl::setState(QCamera::State state) } Q_ASSERT(d->state == QCamera::LoadedState); - d->mediaSink = Make(d->encodingProfile.Get(), d->videoRenderer); ComPtr op; - hr = d->capturePreview->StartPreviewToCustomSinkAsync(d->encodingProfile.Get(), d->mediaSink.Get(), &op); - RETURN_VOID_AND_EMIT_ERROR("Failed to initiate capture"); + hr = QEventDispatcherWinRT::runOnXamlThread([d, &op]() { + d->mediaSink = Make(d->encodingProfile.Get(), d->videoRenderer); + HRESULT hr = d->capturePreview->StartPreviewToCustomSinkAsync(d->encodingProfile.Get(), d->mediaSink.Get(), &op); + return hr; + }); + RETURN_VOID_AND_EMIT_ERROR("Failed to initiate capture."); if (d->status != QCamera::StartingStatus) { d->status = QCamera::StartingStatus; emit statusChanged(d->status); } - hr = QWinRTFunctions::await(op); + hr = QEventDispatcherWinRT::runOnXamlThread([&op]() { + return QWinRTFunctions::await(op); + }); if (FAILED(hr)) { emit error(QCamera::CameraError, qt_error_string(hr)); setState(QCamera::UnloadedState); // Unload everything, as initialize() will need be called again @@ -611,7 +624,7 @@ void QWinRTCameraControl::setState(QCamera::State state) emit stateChanged(d->state); d->status = QCamera::ActiveStatus; emit statusChanged(d->status); - d->mediaSink->RequestSample(); + QEventDispatcherWinRT::runOnXamlThread([d]() { d->mediaSink->RequestSample(); return S_OK;}); break; } case QCamera::LoadedState: { @@ -639,20 +652,28 @@ void QWinRTCameraControl::setState(QCamera::State state) } ComPtr op; - hr = d->capturePreview->StopPreviewAsync(&op); + hr = QEventDispatcherWinRT::runOnXamlThread([d, &op]() { + HRESULT hr = d->capturePreview->StopPreviewAsync(&op); + return hr; + }); RETURN_VOID_AND_EMIT_ERROR("Failed to stop camera preview"); if (d->status != QCamera::StoppingStatus) { d->status = QCamera::StoppingStatus; emit statusChanged(d->status); } Q_ASSERT_SUCCEEDED(hr); - hr = QWinRTFunctions::await(op); // Synchronize unloading + hr = QEventDispatcherWinRT::runOnXamlThread([&op]() { + return QWinRTFunctions::await(op); // Synchronize unloading + }); if (FAILED(hr)) emit error(QCamera::InvalidRequestError, qt_error_string(hr)); if (d->mediaSink) { + hr = QEventDispatcherWinRT::runOnXamlThread([d]() { d->mediaSink->Shutdown(); d->mediaSink.Reset(); + return S_OK; + }); } d->state = QCamera::LoadedState; @@ -671,22 +692,27 @@ void QWinRTCameraControl::setState(QCamera::State state) emit statusChanged(d->status); } - if (d->capture && d->captureFailedCookie.value) { - hr = d->capture->remove_Failed(d->captureFailedCookie); - Q_ASSERT_SUCCEEDED(hr); - d->captureFailedCookie.value = 0; - } - if (d->capture && d->recordLimitationCookie.value) { - d->capture->remove_RecordLimitationExceeded(d->recordLimitationCookie); + hr = QEventDispatcherWinRT::runOnXamlThread([d]() { + HRESULT hr; + if (d->capture && d->captureFailedCookie.value) { + hr = d->capture->remove_Failed(d->captureFailedCookie); + Q_ASSERT_SUCCEEDED(hr); + d->captureFailedCookie.value = 0; + } + if (d->capture && d->recordLimitationCookie.value) { + d->capture->remove_RecordLimitationExceeded(d->recordLimitationCookie); + Q_ASSERT_SUCCEEDED(hr); + d->recordLimitationCookie.value = 0; + } + ComPtr capture; + hr = d->capture.As(&capture); Q_ASSERT_SUCCEEDED(hr); - d->recordLimitationCookie.value = 0; - } - ComPtr capture; - hr = d->capture.As(&capture); - Q_ASSERT_SUCCEEDED(hr); - hr = capture->Close(); + hr = capture->Close(); + RETURN_HR_IF_FAILED(""); + d->capture.Reset(); + return hr; + }); RETURN_VOID_AND_EMIT_ERROR("Failed to close the capture manger"); - d->capture.Reset(); if (d->state != QCamera::UnloadedState) { d->state = QCamera::UnloadedState; emit stateChanged(d->state); @@ -824,154 +850,158 @@ HRESULT QWinRTCameraControl::initialize() emit statusChanged(d->status); } - HRESULT hr; - ComPtr capture; - hr = RoActivateInstance(Wrappers::HString::MakeReference(RuntimeClass_Windows_Media_Capture_MediaCapture).Get(), - &capture); - Q_ASSERT_SUCCEEDED(hr); - hr = capture.As(&d->capture); - Q_ASSERT_SUCCEEDED(hr); - hr = d->capture.As(&d->capturePreview); - Q_ASSERT_SUCCEEDED(hr); - hr = d->capture->add_Failed(Callback(this, &QWinRTCameraControl::onCaptureFailed).Get(), - &d->captureFailedCookie); - Q_ASSERT_SUCCEEDED(hr); - hr = d->capture->add_RecordLimitationExceeded(Callback(this, &QWinRTCameraControl::onRecordLimitationExceeded).Get(), - &d->recordLimitationCookie); - Q_ASSERT_SUCCEEDED(hr); - hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Media_MediaProperties_MediaEncodingProfile).Get(), - IID_PPV_ARGS(&d->encodingProfileFactory)); - Q_ASSERT_SUCCEEDED(hr); + HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([this, d]() { + HRESULT hr; + ComPtr capture; + hr = RoActivateInstance(Wrappers::HString::MakeReference(RuntimeClass_Windows_Media_Capture_MediaCapture).Get(), + &capture); + Q_ASSERT_SUCCEEDED(hr); + hr = capture.As(&d->capture); + Q_ASSERT_SUCCEEDED(hr); + hr = d->capture.As(&d->capturePreview); + Q_ASSERT_SUCCEEDED(hr); + hr = d->capture->add_Failed(Callback(this, &QWinRTCameraControl::onCaptureFailed).Get(), + &d->captureFailedCookie); + Q_ASSERT_SUCCEEDED(hr); + hr = d->capture->add_RecordLimitationExceeded(Callback(this, &QWinRTCameraControl::onRecordLimitationExceeded).Get(), + &d->recordLimitationCookie); + Q_ASSERT_SUCCEEDED(hr); + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Media_MediaProperties_MediaEncodingProfile).Get(), + IID_PPV_ARGS(&d->encodingProfileFactory)); + Q_ASSERT_SUCCEEDED(hr); - int deviceIndex = d->videoDeviceSelector->selectedDevice(); - if (deviceIndex < 0) - deviceIndex = d->videoDeviceSelector->defaultDevice(); + int deviceIndex = d->videoDeviceSelector->selectedDevice(); + if (deviceIndex < 0) + deviceIndex = d->videoDeviceSelector->defaultDevice(); - const QString deviceName = d->videoDeviceSelector->deviceName(deviceIndex); - if (deviceName.isEmpty()) { - qWarning("No video device available or selected."); - return E_FAIL; - } + const QString deviceName = d->videoDeviceSelector->deviceName(deviceIndex); + if (deviceName.isEmpty()) { + qWarning("No video device available or selected."); + return E_FAIL; + } - const QCamera::Position position = d->videoDeviceSelector->cameraPosition(deviceName); - d->videoRenderer->setScanLineDirection(position == QCamera::BackFace ? QVideoSurfaceFormat::TopToBottom - : QVideoSurfaceFormat::BottomToTop); - ComPtr settings; - hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Media_Capture_MediaCaptureInitializationSettings).Get(), - &settings); - Q_ASSERT_SUCCEEDED(hr); - HStringReference deviceId(reinterpret_cast(deviceName.utf16()), deviceName.length()); - hr = settings->put_VideoDeviceId(deviceId.Get()); - Q_ASSERT_SUCCEEDED(hr); + const QCamera::Position position = d->videoDeviceSelector->cameraPosition(deviceName); + d->videoRenderer->setScanLineDirection(position == QCamera::BackFace ? QVideoSurfaceFormat::TopToBottom + : QVideoSurfaceFormat::BottomToTop); + ComPtr settings; + hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Media_Capture_MediaCaptureInitializationSettings).Get(), + &settings); + Q_ASSERT_SUCCEEDED(hr); + HStringReference deviceId(reinterpret_cast(deviceName.utf16()), deviceName.length()); + hr = settings->put_VideoDeviceId(deviceId.Get()); + Q_ASSERT_SUCCEEDED(hr); - hr = settings->put_StreamingCaptureMode(StreamingCaptureMode_Video); - Q_ASSERT_SUCCEEDED(hr); + hr = settings->put_StreamingCaptureMode(StreamingCaptureMode_Video); + Q_ASSERT_SUCCEEDED(hr); - hr = settings->put_PhotoCaptureSource(PhotoCaptureSource_Auto); - Q_ASSERT_SUCCEEDED(hr); + hr = settings->put_PhotoCaptureSource(PhotoCaptureSource_Auto); + Q_ASSERT_SUCCEEDED(hr); - ComPtr op; - hr = d->capture->InitializeWithSettingsAsync(settings.Get(), &op); - RETURN_HR_IF_FAILED("Failed to begin initialization of media capture manager"); - hr = QWinRTFunctions::await(op, QWinRTFunctions::ProcessThreadEvents); - if (hr == E_ACCESSDENIED) { - qWarning("Access denied when initializing the media capture manager. " - "Check your manifest settings for microphone and webcam access."); - } - RETURN_HR_IF_FAILED("Failed to initialize media capture manager"); - - ComPtr videoDeviceController; - hr = d->capture->get_VideoDeviceController(&videoDeviceController); - ComPtr advancedVideoDeviceController; - hr = videoDeviceController.As(&advancedVideoDeviceController); - Q_ASSERT_SUCCEEDED(hr); - hr = advancedVideoDeviceController->get_FocusControl(&d->focusControl); - Q_ASSERT_SUCCEEDED(hr); + ComPtr op; + hr = d->capture->InitializeWithSettingsAsync(settings.Get(), &op); + RETURN_HR_IF_FAILED("Failed to begin initialization of media capture manager"); + hr = QWinRTFunctions::await(op, QWinRTFunctions::ProcessThreadEvents); + if (hr == E_ACCESSDENIED) { + qWarning("Access denied when initializing the media capture manager. " + "Check your manifest settings for microphone and webcam access."); + } + RETURN_HR_IF_FAILED("Failed to initialize media capture manager"); - boolean isFocusSupported; - hr = d->focusControl->get_Supported(&isFocusSupported); - Q_ASSERT_SUCCEEDED(hr); - if (isFocusSupported) { - hr = advancedVideoDeviceController->get_RegionsOfInterestControl(&d->regionsOfInterestControl); + ComPtr videoDeviceController; + hr = d->capture->get_VideoDeviceController(&videoDeviceController); + ComPtr advancedVideoDeviceController; + hr = videoDeviceController.As(&advancedVideoDeviceController); Q_ASSERT_SUCCEEDED(hr); - hr = initializeFocus(); + hr = advancedVideoDeviceController->get_FocusControl(&d->focusControl); Q_ASSERT_SUCCEEDED(hr); - } else { - d->cameraFocusControl->setSupportedFocusMode(0); - d->cameraFocusControl->setSupportedFocusPointMode(QSet()); - } - d->cameraLocksControl->initialize(); - Q_ASSERT_SUCCEEDED(hr); - ComPtr deviceController; - hr = videoDeviceController.As(&deviceController); - Q_ASSERT_SUCCEEDED(hr); + boolean isFocusSupported; + hr = d->focusControl->get_Supported(&isFocusSupported); + Q_ASSERT_SUCCEEDED(hr); + if (isFocusSupported) { + hr = advancedVideoDeviceController->get_RegionsOfInterestControl(&d->regionsOfInterestControl); + Q_ASSERT_SUCCEEDED(hr); + hr = initializeFocus(); + Q_ASSERT_SUCCEEDED(hr); + } else { + d->cameraFocusControl->setSupportedFocusMode(0); + d->cameraFocusControl->setSupportedFocusPointMode(QSet()); + } + d->cameraLocksControl->initialize(); - // Get preview stream properties. - ComPtr> previewPropertiesList; - QVector previewResolutions; - hr = getMediaStreamResolutions(deviceController.Get(), - MediaStreamType_VideoPreview, - &previewPropertiesList, - &previewResolutions); - RETURN_HR_IF_FAILED("Failed to find a suitable video format"); - - MediaStreamType mediaStreamType = - d->captureMode == QCamera::CaptureVideo ? MediaStreamType_VideoRecord : MediaStreamType_Photo; - - // Get capture stream properties. - ComPtr> capturePropertiesList; - QVector captureResolutions; - hr = getMediaStreamResolutions(deviceController.Get(), - mediaStreamType, - &capturePropertiesList, - &captureResolutions); - RETURN_HR_IF_FAILED("Failed to find a suitable video format"); - - // Set capture resolutions. - d->imageEncoderControl->setSupportedResolutionsList(captureResolutions.toList()); - const QSize captureResolution = d->imageEncoderControl->imageSettings().resolution(); - const quint32 captureResolutionIndex = captureResolutions.indexOf(captureResolution); - ComPtr captureProperties; - hr = capturePropertiesList->GetAt(captureResolutionIndex, &captureProperties); - Q_ASSERT_SUCCEEDED(hr); - hr = deviceController->SetMediaStreamPropertiesAsync(mediaStreamType, captureProperties.Get(), &op); - Q_ASSERT_SUCCEEDED(hr); - hr = QWinRTFunctions::await(op); - Q_ASSERT_SUCCEEDED(hr); + Q_ASSERT_SUCCEEDED(hr); + ComPtr deviceController; + hr = videoDeviceController.As(&deviceController); + Q_ASSERT_SUCCEEDED(hr); - // Set preview resolution. - QVector filtered; - const float captureAspectRatio = float(captureResolution.width()) / captureResolution.height(); - foreach (const QSize &resolution, previewResolutions) { - const float aspectRatio = float(resolution.width()) / resolution.height(); - if (qAbs(aspectRatio - captureAspectRatio) <= ASPECTRATIO_EPSILON) - filtered.append(resolution); - } - qSort(filtered.begin(), - filtered.end(), - [](QSize size1, QSize size2) { return size1.width() * size1.height() < size2.width() * size2.height(); }); - - const QSize &viewfinderResolution = filtered.first(); - const quint32 viewfinderResolutionIndex = previewResolutions.indexOf(viewfinderResolution); - hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Media_MediaProperties_MediaEncodingProfile).Get(), - &d->encodingProfile); - Q_ASSERT_SUCCEEDED(hr); - ComPtr previewProperties; - hr = previewPropertiesList->GetAt(viewfinderResolutionIndex, &previewProperties); - Q_ASSERT_SUCCEEDED(hr); - hr = deviceController->SetMediaStreamPropertiesAsync(MediaStreamType_VideoPreview, previewProperties.Get(), &op); - Q_ASSERT_SUCCEEDED(hr); - hr = QWinRTFunctions::await(op); - Q_ASSERT_SUCCEEDED(hr); - ComPtr videoPreviewProperties; - hr = previewProperties.As(&videoPreviewProperties); - Q_ASSERT_SUCCEEDED(hr); - hr = d->encodingProfile->put_Video(videoPreviewProperties.Get()); - Q_ASSERT_SUCCEEDED(hr); + // Get preview stream properties. + ComPtr> previewPropertiesList; + QVector previewResolutions; + hr = getMediaStreamResolutions(deviceController.Get(), + MediaStreamType_VideoPreview, + &previewPropertiesList, + &previewResolutions); + RETURN_HR_IF_FAILED("Failed to find a suitable video format"); + + MediaStreamType mediaStreamType = + d->captureMode == QCamera::CaptureVideo ? MediaStreamType_VideoRecord : MediaStreamType_Photo; + + // Get capture stream properties. + ComPtr> capturePropertiesList; + QVector captureResolutions; + hr = getMediaStreamResolutions(deviceController.Get(), + mediaStreamType, + &capturePropertiesList, + &captureResolutions); + RETURN_HR_IF_FAILED("Failed to find a suitable video format"); + + // Set capture resolutions. + d->imageEncoderControl->setSupportedResolutionsList(captureResolutions.toList()); + const QSize captureResolution = d->imageEncoderControl->imageSettings().resolution(); + const quint32 captureResolutionIndex = captureResolutions.indexOf(captureResolution); + ComPtr captureProperties; + hr = capturePropertiesList->GetAt(captureResolutionIndex, &captureProperties); + Q_ASSERT_SUCCEEDED(hr); + hr = deviceController->SetMediaStreamPropertiesAsync(mediaStreamType, captureProperties.Get(), &op); + Q_ASSERT_SUCCEEDED(hr); + hr = QWinRTFunctions::await(op); + Q_ASSERT_SUCCEEDED(hr); - if (d->videoRenderer) - d->videoRenderer->setSize(viewfinderResolution); + // Set preview resolution. + QVector filtered; + const float captureAspectRatio = float(captureResolution.width()) / captureResolution.height(); + foreach (const QSize &resolution, previewResolutions) { + const float aspectRatio = float(resolution.width()) / resolution.height(); + if (qAbs(aspectRatio - captureAspectRatio) <= ASPECTRATIO_EPSILON) + filtered.append(resolution); + } + qSort(filtered.begin(), + filtered.end(), + [](QSize size1, QSize size2) { return size1.width() * size1.height() < size2.width() * size2.height(); }); + + const QSize &viewfinderResolution = filtered.first(); + const quint32 viewfinderResolutionIndex = previewResolutions.indexOf(viewfinderResolution); + hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Media_MediaProperties_MediaEncodingProfile).Get(), + &d->encodingProfile); + Q_ASSERT_SUCCEEDED(hr); + ComPtr previewProperties; + hr = previewPropertiesList->GetAt(viewfinderResolutionIndex, &previewProperties); + Q_ASSERT_SUCCEEDED(hr); + hr = deviceController->SetMediaStreamPropertiesAsync(MediaStreamType_VideoPreview, previewProperties.Get(), &op); + Q_ASSERT_SUCCEEDED(hr); + hr = QWinRTFunctions::await(op); + Q_ASSERT_SUCCEEDED(hr); + ComPtr videoPreviewProperties; + hr = previewProperties.As(&videoPreviewProperties); + Q_ASSERT_SUCCEEDED(hr); + hr = d->encodingProfile->put_Video(videoPreviewProperties.Get()); + Q_ASSERT_SUCCEEDED(hr); + + if (d->videoRenderer) + d->videoRenderer->setSize(viewfinderResolution); + + return S_OK; + }); if (SUCCEEDED(hr) && d->state != QCamera::LoadedState) { d->state = QCamera::LoadedState; @@ -984,7 +1014,7 @@ HRESULT QWinRTCameraControl::initialize() return hr; } -#ifdef Q_OS_WINPHONE +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) HRESULT QWinRTCameraControl::initializeFocus() { @@ -1231,7 +1261,7 @@ bool QWinRTCameraControl::unlockFocus() return QWinRTFunctions::await(op) == S_OK; } -#else // Q_OS_WINPHONE +#else // !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) HRESULT QWinRTCameraControl::initializeFocus() { @@ -1272,7 +1302,7 @@ bool QWinRTCameraControl::unlockFocus() return false; } -#endif // !Q_OS_WINPHONE +#endif // !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) void QWinRTCameraControl::frameMapped() { diff --git a/src/plugins/winrt/qwinrtcameraimagecapturecontrol.cpp b/src/plugins/winrt/qwinrtcameraimagecapturecontrol.cpp index 8ae7f37a9..07ec0b40d 100644 --- a/src/plugins/winrt/qwinrtcameraimagecapturecontrol.cpp +++ b/src/plugins/winrt/qwinrtcameraimagecapturecontrol.cpp @@ -46,8 +46,10 @@ #include #include #include +#include #include +#include #include #include #include @@ -161,33 +163,37 @@ int QWinRTCameraImageCaptureControl::capture(const QString &fileName) fileName.isEmpty() ? QStringLiteral("jpg") : QFileInfo(fileName).suffix()) }; - HRESULT hr; - hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_InMemoryRandomAccessStream).Get(), - &request.stream); - Q_ASSERT_SUCCEEDED(hr); + HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([this, d, capture, &request]() { + HRESULT hr; + hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_InMemoryRandomAccessStream).Get(), + &request.stream); + Q_ASSERT_SUCCEEDED(hr); - hr = g->encodingPropertiesFactory->CreateBmp(&request.imageFormat); - Q_ASSERT_SUCCEEDED(hr); + hr = g->encodingPropertiesFactory->CreateBmp(&request.imageFormat); + Q_ASSERT_SUCCEEDED(hr); - const QSize imageSize = static_cast(d->cameraControl->imageEncoderControl())->imageSettings().resolution(); - hr = request.imageFormat->put_Width(imageSize.width()); - Q_ASSERT_SUCCEEDED(hr); - hr = request.imageFormat->put_Height(imageSize.height()); - Q_ASSERT_SUCCEEDED(hr); + const QSize imageSize = static_cast(d->cameraControl->imageEncoderControl())->imageSettings().resolution(); + hr = request.imageFormat->put_Width(imageSize.width()); + Q_ASSERT_SUCCEEDED(hr); + hr = request.imageFormat->put_Height(imageSize.height()); + Q_ASSERT_SUCCEEDED(hr); - hr = capture->CapturePhotoToStreamAsync(request.imageFormat.Get(), request.stream.Get(), &request.op); - Q_ASSERT_SUCCEEDED(hr); - if (!request.op) { - qErrnoWarning("Camera photo capture failed."); + hr = capture->CapturePhotoToStreamAsync(request.imageFormat.Get(), request.stream.Get(), &request.op); + Q_ASSERT_SUCCEEDED(hr); + if (!request.op) { + qErrnoWarning("Camera photo capture failed."); + return E_FAIL; + } + emit captureQueueChanged(false); + d->requests.insert(request.op.Get(), request); + + hr = request.op->put_Completed(Callback( + this, &QWinRTCameraImageCaptureControl::onCaptureCompleted).Get()); + Q_ASSERT_SUCCEEDED(hr); + return hr; + }); + if (FAILED(hr)) return -1; - } - emit captureQueueChanged(false); - d->requests.insert(request.op.Get(), request); - - hr = request.op->put_Completed(Callback( - this, &QWinRTCameraImageCaptureControl::onCaptureCompleted).Get()); - Q_ASSERT_SUCCEEDED(hr); - return request.id; } diff --git a/src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp b/src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp index fe07581c9..796a36f55 100644 --- a/src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp +++ b/src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp @@ -48,7 +48,7 @@ #include "qwinrtcameracontrol.h" -#ifdef Q_OS_WINPHONE +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) #include using namespace ABI::Windows::Security::ExchangeActiveSyncProvisioning; #endif @@ -58,7 +58,7 @@ using namespace Microsoft::WRL::Wrappers; QT_BEGIN_NAMESPACE -#ifdef Q_OS_WINPHONE +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) template static bool blacklisted(const wchar_t (&blackListName)[n], const HString &deviceModel) { @@ -282,7 +282,7 @@ QWinRTCameraVideoRendererControl::QWinRTCameraVideoRendererControl(const QSize & d->cameraSampleformat = QVideoFrame::Format_User; d->videoProbesCounter = 0; -#ifdef Q_OS_WINPHONE +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) // Workaround for certain devices which fail to blit. ComPtr deviceInfo; HRESULT hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Security_ExchangeActiveSyncProvisioning_EasClientDeviceInformation).Get(), diff --git a/src/plugins/winrt/qwinrtvideodeviceselectorcontrol.cpp b/src/plugins/winrt/qwinrtvideodeviceselectorcontrol.cpp index 8e806dcbf..cd3a7fa04 100644 --- a/src/plugins/winrt/qwinrtvideodeviceselectorcontrol.cpp +++ b/src/plugins/winrt/qwinrtvideodeviceselectorcontrol.cpp @@ -332,7 +332,7 @@ QCamera::Position QWinRTVideoDeviceSelectorControl::cameraPosition(const QString int QWinRTVideoDeviceSelectorControl::cameraOrientation(const QString &deviceName) { -#ifdef Q_OS_WINPHONE +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) switch (cameraPosition(deviceName)) { case QCamera::FrontFace: case QCamera::BackFace: -- cgit v1.2.3 From a75f8fd0bb19b76a7577c695208b385381a35278 Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Tue, 19 Apr 2016 12:26:45 +0200 Subject: winrt: Fix device watcher handling When device watcher has been started it can have the enumerationComplete state in addition to started. Hence only start the watcher if none of those two states is present. This fixes an assert where starting an already started watcher failed. Change-Id: Idc3af256845f0993a26e8d186b499ef1c7e7dacc Reviewed-by: Oliver Wolff --- src/plugins/winrt/qwinrtvideodeviceselectorcontrol.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/winrt/qwinrtvideodeviceselectorcontrol.cpp b/src/plugins/winrt/qwinrtvideodeviceselectorcontrol.cpp index cd3a7fa04..24a3a911a 100644 --- a/src/plugins/winrt/qwinrtvideodeviceselectorcontrol.cpp +++ b/src/plugins/winrt/qwinrtvideodeviceselectorcontrol.cpp @@ -204,7 +204,8 @@ public: DeviceWatcherStatus status; hr = deviceWatcher->get_Status(&status); Q_ASSERT_SUCCEEDED(hr); - if (status != DeviceWatcherStatus_Started) { + if (status != DeviceWatcherStatus_Started && + status != DeviceWatcherStatus_EnumerationCompleted) { // We can't immediately Start() if we have just called Stop() while (status == DeviceWatcherStatus_Stopping) { QThread::yieldCurrentThread(); -- cgit v1.2.3 From 7553a0521356d0b28bacb8c8d07a25e4ba26097e Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Fri, 22 Apr 2016 11:02:13 +0200 Subject: winrt: Disable camera deactivation automation in debug mode Camera control reacts to an application becoming inactive and turns off the camera. However, when debugging or watching internals inside an IDE this feature breaks the state of the application as the IDE gets focus and hence camera is turned off. Change-Id: I6f80476592c0faa32e9da11401f699c6211d226a Reviewed-by: Oliver Wolff --- src/plugins/winrt/qwinrtcameracontrol.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/plugins/winrt/qwinrtcameracontrol.cpp b/src/plugins/winrt/qwinrtcameracontrol.cpp index b6068594a..effddafe3 100644 --- a/src/plugins/winrt/qwinrtcameracontrol.cpp +++ b/src/plugins/winrt/qwinrtcameracontrol.cpp @@ -823,6 +823,9 @@ void QWinRTCameraControl::onBufferRequested() void QWinRTCameraControl::onApplicationStateChanged(Qt::ApplicationState state) { qCDebug(lcMMCamera) << __FUNCTION__ << state; +#ifdef _DEBUG + return; +#else // !_DEBUG Q_D(QWinRTCameraControl); static QCamera::State savedState = d->state; switch (state) { @@ -838,6 +841,7 @@ void QWinRTCameraControl::onApplicationStateChanged(Qt::ApplicationState state) default: break; } +#endif // _DEBUG } HRESULT QWinRTCameraControl::initialize() -- cgit v1.2.3 From eabe79f9fdeae9caf4bcbd91928f316707d36544 Mon Sep 17 00:00:00 2001 From: Christian Stromme Date: Wed, 20 Apr 2016 01:32:27 +0200 Subject: Fix property attributes. A property can't be both constant and writable at the same time. Change-Id: Ie1f81fdf10eba7fe84f98f7c34f829cdac654e75 Reviewed-by: Yoann Lopes --- src/imports/audioengine/qdeclarative_attenuationmodel_p.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/imports/audioengine/qdeclarative_attenuationmodel_p.h b/src/imports/audioengine/qdeclarative_attenuationmodel_p.h index d4d12df04..a710cb4d6 100644 --- a/src/imports/audioengine/qdeclarative_attenuationmodel_p.h +++ b/src/imports/audioengine/qdeclarative_attenuationmodel_p.h @@ -79,8 +79,8 @@ private: class QDeclarativeAttenuationModelLinear : public QDeclarativeAttenuationModel { Q_OBJECT - Q_PROPERTY(qreal start READ startDistance WRITE setStartDistance CONSTANT) - Q_PROPERTY(qreal end READ endDistance WRITE setEndDistance CONSTANT) + Q_PROPERTY(qreal start READ startDistance WRITE setStartDistance) + Q_PROPERTY(qreal end READ endDistance WRITE setEndDistance) public: QDeclarativeAttenuationModelLinear(QObject *parent = 0); @@ -104,9 +104,9 @@ private: class QDeclarativeAttenuationModelInverse : public QDeclarativeAttenuationModel { Q_OBJECT - Q_PROPERTY(qreal start READ referenceDistance WRITE setReferenceDistance CONSTANT) - Q_PROPERTY(qreal end READ maxDistance WRITE setMaxDistance CONSTANT) - Q_PROPERTY(qreal rolloff READ rolloffFactor WRITE setRolloffFactor CONSTANT) + Q_PROPERTY(qreal start READ referenceDistance WRITE setReferenceDistance) + Q_PROPERTY(qreal end READ maxDistance WRITE setMaxDistance) + Q_PROPERTY(qreal rolloff READ rolloffFactor WRITE setRolloffFactor) public: QDeclarativeAttenuationModelInverse(QObject *parent = 0); -- cgit v1.2.3 From d73812dcb699bd6b6bd99b4fee3b50573d1e7e5e Mon Sep 17 00:00:00 2001 From: Christian Stromme Date: Wed, 20 Apr 2016 01:49:03 +0200 Subject: Fix unused variable warning - warning: unused variable 'm_renderer' [-Wunused-variable] Change-Id: Ie7d8ebe35a3ab0beb66cda3448595ed952f7dea4 Reviewed-by: Yoann Lopes --- src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm b/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm index 705ec633f..39901cd48 100644 --- a/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm +++ b/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm @@ -60,11 +60,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); } @@ -194,9 +197,9 @@ public: private: #ifdef Q_OS_IOS mutable CVOpenGLESTextureRef m_texture; + AVFCameraRendererControl *m_renderer; #endif CVImageBufferRef m_buffer; - AVFCameraRendererControl *m_renderer; MapMode m_mode; }; -- cgit v1.2.3 From 80deebcee3e9b14046a042cf6a66467ff078d57b Mon Sep 17 00:00:00 2001 From: Christian Stromme Date: Wed, 20 Apr 2016 01:50:25 +0200 Subject: Fix macro redefinition warning Don't re-define APIENTRY macros unconditionally on mac. Change-Id: I894f866da0ec0d6da76a62f01c24739be92d851f Reviewed-by: Yoann Lopes --- src/multimediawidgets/qpaintervideosurface.cpp | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/multimediawidgets/qpaintervideosurface.cpp b/src/multimediawidgets/qpaintervideosurface.cpp index 5a8857b78..affcacec7 100644 --- a/src/multimediawidgets/qpaintervideosurface.cpp +++ b/src/multimediawidgets/qpaintervideosurface.cpp @@ -218,18 +218,13 @@ void QVideoSurfaceGenericPainter::updateColors(int, int, int, int) #if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) -#ifndef Q_OS_MAC -# ifndef APIENTRYP -# ifdef APIENTRY -# define APIENTRYP APIENTRY * -# else -# define APIENTRY -# define APIENTRYP * -# endif -# endif -#else -# define APIENTRY -# define APIENTRYP * +#ifndef APIENTRYP +# ifdef APIENTRY +# define APIENTRYP APIENTRY * +# else +# define APIENTRY +# define APIENTRYP * +# endif #endif #ifndef GL_TEXTURE0 -- cgit v1.2.3 From c1cfbd98d2c03a2aff305c4fc190424906d7f465 Mon Sep 17 00:00:00 2001 From: Dan Cape Date: Fri, 22 Apr 2016 14:40:23 -0400 Subject: QNX: Avoid reading frames faster than they're rendered The previous code would capture frames with a 60Hz timer into two pixmaps alternating pixmaps with each successive frame. Rendering was somewhat disconnected from this, if rendering was unable to occur at 60fps, multiple frames might be copied for each frame rendered. This meant that it might try copying a video frame into a pixmap that was currently being used by the GPU with bad effects. The primary effect being severe flicker on i.mx6 targets. The change is to ensure that we don't read the window data until we're just about to make use of it. This means we don't ever get ahead of ourselves and read the video window once for every frame rendered. The code has been significantly refactored. There is now a class that manages the pixmaps and egl images. This is created on demand and the images are created and destroyed when sizes change. Since this all now occurs in the proper thread, much of the nonsense of setting _q_GLThreadCallback to arrange a call from the render thread is avoided. Remove BlackBerry ifdefs that are no longer used. Change-Id: I4bf5efa4c39c8170e3f55499c167ee10e521e100 Reviewed-by: James McDonnell Reviewed-by: Rafael Roquetto --- src/plugins/qnx/common/windowgrabber.cpp | 362 ++++++++++----------- src/plugins/qnx/common/windowgrabber.h | 61 ++-- .../mmrendererplayervideorenderercontrol.cpp | 53 ++- .../mmrendererplayervideorenderercontrol.h | 2 +- .../qdeclarativevideooutput_render.cpp | 10 - 5 files changed, 241 insertions(+), 247 deletions(-) diff --git a/src/plugins/qnx/common/windowgrabber.cpp b/src/plugins/qnx/common/windowgrabber.cpp index 39d87c781..3fd99c319 100644 --- a/src/plugins/qnx/common/windowgrabber.cpp +++ b/src/plugins/qnx/common/windowgrabber.cpp @@ -37,47 +37,50 @@ #include #include #include +#include #include #include #include -#ifdef Q_OS_BLACKBERRY -#include -#include -#endif #include QT_BEGIN_NAMESPACE +static PFNEGLCREATEIMAGEKHRPROC s_eglCreateImageKHR; +static PFNEGLDESTROYIMAGEKHRPROC s_eglDestroyImageKHR; + WindowGrabber::WindowGrabber(QObject *parent) : QObject(parent), - m_screenBufferWidth(-1), - m_screenBufferHeight(-1), + m_screenContext(0), m_active(false), - m_screenContextInitialized(false), - m_screenPixmapBuffersInitialized(false), m_currentFrame(0), m_eglImageSupported(false), - m_eglImagesInitialized(false), m_eglImageCheck(false) { // grab the window frame with 60 frames per second m_timer.setInterval(1000/60); - connect(&m_timer, SIGNAL(timeout()), SLOT(grab())); + connect(&m_timer, SIGNAL(timeout()), SLOT(triggerUpdate())); QCoreApplication::eventDispatcher()->installNativeEventFilter(this); + + for ( int i = 0; i < 2; ++i ) + m_images[i] = 0; + + // Use of EGL images can be disabled by setting QQNX_MM_DISABLE_EGLIMAGE_SUPPORT to something + // non-zero. This is probably useful only to test that this path still works since it results + // in a high CPU load. + if (!s_eglCreateImageKHR && qgetenv("QQNX_MM_DISABLE_EGLIMAGE_SUPPORT").toInt() == 0) { + s_eglCreateImageKHR = reinterpret_cast(eglGetProcAddress("eglCreateImageKHR")); + s_eglDestroyImageKHR = reinterpret_cast(eglGetProcAddress("eglDestroyImageKHR")); + } } WindowGrabber::~WindowGrabber() { QCoreApplication::eventDispatcher()->removeNativeEventFilter(this); - if (eglImagesInitialized()) { - glDeleteTextures(2, imgTextures); - eglDestroyImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), img[0]); - eglDestroyImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), img[1]); - } + cleanup(); } void WindowGrabber::setFrameRate(int frameRate) @@ -85,36 +88,6 @@ void WindowGrabber::setFrameRate(int frameRate) m_timer.setInterval(1000/frameRate); } -void WindowGrabber::createEglImages() -{ - // Do nothing if either egl images are not supported, the screen context is not valid - // or the images are already created - if (!eglImageSupported() || !m_screenContextInitialized || eglImagesInitialized()) - return; - - glGenTextures(2, imgTextures); - glBindTexture(GL_TEXTURE_2D, imgTextures[0]); - img[0] = eglCreateImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), EGL_NO_CONTEXT, - EGL_NATIVE_PIXMAP_KHR, - m_screenPixmaps[0], - 0); - glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, img[0]); - - glBindTexture(GL_TEXTURE_2D, imgTextures[1]); - img[1] = eglCreateImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), EGL_NO_CONTEXT, - EGL_NATIVE_PIXMAP_KHR, - m_screenPixmaps[1], - 0); - - glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, img[1]); - - if (img[0] == 0 || img[1] == 0) { - qWarning() << "Failed to create KHR images" << img[0] << img[1] << strerror(errno) << errno; - m_eglImageSupported = false; - } else { - m_eglImagesInitialized = true; - } -} void WindowGrabber::setWindowId(const QByteArray &windowId) { @@ -126,107 +99,14 @@ void WindowGrabber::start() if (m_active) return; - int result = 0; - - result = screen_create_context(&m_screenContext, SCREEN_APPLICATION_CONTEXT); - if (result != 0) { - qWarning() << "WindowGrabber: cannot create screen context:" << strerror(errno); - return; - } else { - m_screenContextInitialized = true; - } - - result = screen_create_pixmap(&m_screenPixmaps[0], m_screenContext); - result = screen_create_pixmap(&m_screenPixmaps[1], m_screenContext); - if (result != 0) { - cleanup(); - qWarning() << "WindowGrabber: cannot create pixmaps:" << strerror(errno); - return; - } - - const int usage = SCREEN_USAGE_NATIVE; - result = screen_set_pixmap_property_iv(m_screenPixmaps[0], SCREEN_PROPERTY_USAGE, &usage); - result |= screen_set_pixmap_property_iv(m_screenPixmaps[1], SCREEN_PROPERTY_USAGE, &usage); - - const int format = SCREEN_FORMAT_RGBX8888; - screen_set_pixmap_property_iv(m_screenPixmaps[0], SCREEN_PROPERTY_FORMAT, &format); - screen_set_pixmap_property_iv(m_screenPixmaps[1], SCREEN_PROPERTY_FORMAT, &format); - - int size[2] = { 0, 0 }; - - result = screen_get_window_property_iv(m_window, SCREEN_PROPERTY_SOURCE_SIZE, size); - if (result != 0) { - cleanup(); - qWarning() << "WindowGrabber: cannot get window size:" << strerror(errno); - return; - } - - m_screenBufferWidth = size[0]; - m_screenBufferHeight = size[1]; - - updateFrameSize(); + if (!m_screenContext) + screen_get_window_property_pv(m_window, SCREEN_PROPERTY_CONTEXT, reinterpret_cast(&m_screenContext)); m_timer.start(); m_active = true; } -void WindowGrabber::updateFrameSize() -{ - int size[2] = { m_screenBufferWidth, m_screenBufferHeight }; - - screen_set_pixmap_property_iv(m_screenPixmaps[0], SCREEN_PROPERTY_BUFFER_SIZE, size); - if (eglImageSupported()) - screen_set_pixmap_property_iv(m_screenPixmaps[1], SCREEN_PROPERTY_BUFFER_SIZE, size); - - int result = screen_create_pixmap_buffer(m_screenPixmaps[0]); - if (eglImageSupported()) - result |= screen_create_pixmap_buffer(m_screenPixmaps[1]); - - if (result != 0) { - cleanup(); - qWarning() << "WindowGrabber: cannot create pixmap buffer:" << strerror(errno); - return; - } else { - m_screenPixmapBuffersInitialized = true; - } - - result = screen_get_pixmap_property_pv(m_screenPixmaps[0], SCREEN_PROPERTY_RENDER_BUFFERS, - (void**)&m_screenPixmapBuffers[0]); - if (eglImageSupported()) { - result |= screen_get_pixmap_property_pv(m_screenPixmaps[1], SCREEN_PROPERTY_RENDER_BUFFERS, - (void**)&m_screenPixmapBuffers[1]); - } - - if (result != 0) { - cleanup(); - qWarning() << "WindowGrabber: cannot get pixmap buffer:" << strerror(errno); - return; - } - - result = screen_get_buffer_property_pv(m_screenPixmapBuffers[0], SCREEN_PROPERTY_POINTER, - (void**)&m_screenBuffers[0]); - if (eglImageSupported()) { - result |= screen_get_buffer_property_pv(m_screenPixmapBuffers[1], SCREEN_PROPERTY_POINTER, - (void**)&m_screenBuffers[1]); - } - - if (result != 0) { - cleanup(); - qWarning() << "WindowGrabber: cannot get pixmap buffer pointer:" << strerror(errno); - return; - } - - result = screen_get_buffer_property_iv(m_screenPixmapBuffers[0], SCREEN_PROPERTY_STRIDE, - &m_screenBufferStride); - - if (result != 0) { - cleanup(); - qWarning() << "WindowGrabber: cannot get pixmap buffer stride:" << strerror(errno); - return; - } -} - void WindowGrabber::stop() { if (!m_active) @@ -288,20 +168,10 @@ bool WindowGrabber::handleScreenEvent(screen_event_t screen_event) bool WindowGrabber::nativeEventFilter(const QByteArray &eventType, void *message, long*) { -#ifdef Q_OS_BLACKBERRY - Q_UNUSED(eventType) - bps_event_t * const event = static_cast(message); - - if (event && bps_event_get_domain(event) == screen_get_domain()) { - const screen_event_t screen_event = screen_event_get_event(event); - return handleScreenEvent(screen_event); - } -#else if (eventType == "screen_event_t") { const screen_event_t event = static_cast(message); return handleScreenEvent(event); } -#endif return false; } @@ -342,7 +212,8 @@ void WindowGrabber::checkForEglImageExtension() QByteArray eglExtensions = QByteArray(eglQueryString(eglGetDisplay(EGL_DEFAULT_DISPLAY), EGL_EXTENSIONS)); m_eglImageSupported = m_context->hasExtension(QByteArrayLiteral("GL_OES_EGL_image")) - && eglExtensions.contains(QByteArrayLiteral("EGL_KHR_image")); + && eglExtensions.contains(QByteArrayLiteral("EGL_KHR_image")) + && s_eglCreateImageKHR && s_eglDestroyImageKHR; if (strstr(reinterpret_cast(glGetString(GL_VENDOR)), "VMware")) m_eglImageSupported = false; @@ -350,21 +221,11 @@ void WindowGrabber::checkForEglImageExtension() m_eglImageCheck = true; } -bool WindowGrabber::eglImagesInitialized() -{ - return m_eglImagesInitialized; -} - -void WindowGrabber::grab() +void WindowGrabber::triggerUpdate() { if (!m_eglImageCheck) // We did not check for egl images yet return; - if (eglImageSupported()) - m_currentFrame = (m_currentFrame + 1) % 2; - else - m_currentFrame = 0; - int size[2] = { 0, 0 }; int result = screen_get_window_property_iv(m_window, SCREEN_PROPERTY_SOURCE_SIZE, size); @@ -374,40 +235,173 @@ void WindowGrabber::grab() return; } - if (m_screenBufferWidth != size[0] || m_screenBufferHeight != size[1]) { - // The source viewport size changed, so we have to adapt our buffers + if (m_size.width() != size[0] || m_size.height() != size[1]) + m_size = QSize(size[0], size[1]); - if (m_screenPixmapBuffersInitialized) { - screen_destroy_pixmap_buffer(m_screenPixmaps[0]); - if (eglImageSupported()) - screen_destroy_pixmap_buffer(m_screenPixmaps[1]); - } + emit updateScene(m_size); +} - m_screenBufferWidth = size[0]; - m_screenBufferHeight = size[1]; +bool WindowGrabber::selectBuffer() +{ + // If we're using egl images we need to double buffer since the gpu may still be using the last + // video frame. If we're not, it doesn't matter since the data is immediately copied. + if (eglImageSupported()) + m_currentFrame = (m_currentFrame + 1) % 2; - updateFrameSize(); - m_eglImagesInitialized = false; + if (!m_images[m_currentFrame]) { + m_images[m_currentFrame] = new WindowGrabberImage(); + if (!m_images[m_currentFrame]->initialize(m_screenContext)) { + delete m_images[m_currentFrame]; + m_images[m_currentFrame] = 0; + return false; + } } + return true; +} - const int rect[] = { 0, 0, m_screenBufferWidth, m_screenBufferHeight }; - result = screen_read_window(m_window, m_screenPixmapBuffers[m_currentFrame], 1, rect, 0); - if (result != 0) - return; +int WindowGrabber::getNextTextureId() +{ + if (!selectBuffer()) + return 0; + return m_images[m_currentFrame]->getTexture(m_window, m_size); +} - const QImage frame((unsigned char*)m_screenBuffers[m_currentFrame], m_screenBufferWidth, - m_screenBufferHeight, m_screenBufferStride, QImage::Format_ARGB32); +QImage WindowGrabber::getNextImage() +{ + if (!selectBuffer()) + return QImage(); - emit frameGrabbed(frame, imgTextures[m_currentFrame]); + return m_images[m_currentFrame]->getImage(m_window, m_size); } void WindowGrabber::cleanup() { - //We only need to destroy the context as it frees all resources associated with it - if (m_screenContextInitialized) { - screen_destroy_context(m_screenContext); - m_screenContextInitialized = false; + for ( int i = 0; i < 2; ++i ) { + if (m_images[i]) { + m_images[i]->destroy(); + m_images[i] = 0; + } + } +} + + +WindowGrabberImage::WindowGrabberImage() + : m_pixmap(0), m_pixmapBuffer(0), m_eglImage(0), m_glTexture(0), m_bufferAddress(0), m_bufferStride(0) +{ +} + +WindowGrabberImage::~WindowGrabberImage() +{ + if (m_glTexture) + glDeleteTextures(1, &m_glTexture); + if (m_eglImage) + s_eglDestroyImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), m_eglImage); + if (m_pixmap) + screen_destroy_pixmap(m_pixmap); +} + +bool +WindowGrabberImage::initialize(screen_context_t screenContext) +{ + if (screen_create_pixmap(&m_pixmap, screenContext) != 0) { + qWarning() << "WindowGrabber: cannot create pixmap:" << strerror(errno); + return false; + } + const int usage = SCREEN_USAGE_WRITE | SCREEN_USAGE_READ | SCREEN_USAGE_NATIVE; + screen_set_pixmap_property_iv(m_pixmap, SCREEN_PROPERTY_USAGE, &usage); + + const int format = SCREEN_FORMAT_RGBX8888; + screen_set_pixmap_property_iv(m_pixmap, SCREEN_PROPERTY_FORMAT, &format); + + return true; +} + +void +WindowGrabberImage::destroy() +{ + // We want to delete in the thread we were created in since we need the thread that + // has called eglMakeCurrent on the right EGL context. This doesn't actually guarantee + // this but that would be hard to achieve and in practice it works. + if (QThread::currentThread() == thread()) + delete this; + else + deleteLater(); +} + +bool +WindowGrabberImage::resize(const QSize &newSize) +{ + if (m_pixmapBuffer) { + screen_destroy_pixmap_buffer(m_pixmap); + m_pixmapBuffer = 0; + m_bufferAddress = 0; + m_bufferStride = 0; + } + + int size[2] = { newSize.width(), newSize.height() }; + + screen_set_pixmap_property_iv(m_pixmap, SCREEN_PROPERTY_BUFFER_SIZE, size); + + if (screen_create_pixmap_buffer(m_pixmap) == 0) { + screen_get_pixmap_property_pv(m_pixmap, SCREEN_PROPERTY_RENDER_BUFFERS, + reinterpret_cast(&m_pixmapBuffer)); + screen_get_buffer_property_pv(m_pixmapBuffer, SCREEN_PROPERTY_POINTER, + reinterpret_cast(&m_bufferAddress)); + screen_get_buffer_property_iv(m_pixmapBuffer, SCREEN_PROPERTY_STRIDE, &m_bufferStride); + m_size = newSize; + + return true; + } else { + m_size = QSize(); + return false; } } +bool +WindowGrabberImage::grab(screen_window_t window) +{ + const int rect[] = { 0, 0, m_size.width(), m_size.height() }; + return screen_read_window(window, m_pixmapBuffer, 1, rect, 0) == 0; +} + +QImage +WindowGrabberImage::getImage(screen_window_t window, const QSize &size) +{ + if (size != m_size) { + if (!resize(size)) + return QImage(); + } + if (!m_bufferAddress || !grab(window)) + return QImage(); + + return QImage(m_bufferAddress, m_size.width(), m_size.height(), m_bufferStride, QImage::Format_ARGB32); +} + +GLuint +WindowGrabberImage::getTexture(screen_window_t window, const QSize &size) +{ + if (size != m_size) { + if (!m_glTexture) + glGenTextures(1, &m_glTexture); + glBindTexture(GL_TEXTURE_2D, m_glTexture); + if (m_eglImage) { + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, 0); + s_eglDestroyImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), m_eglImage); + m_eglImage = 0; + } + if (!resize(size)) + return 0; + m_eglImage = s_eglCreateImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), EGL_NO_CONTEXT, + EGL_NATIVE_PIXMAP_KHR, m_pixmap, 0); + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_eglImage); + } + + if (!m_pixmap || !grab(window)) + return 0; + + return m_glTexture; +} + + + QT_END_NAMESPACE diff --git a/src/plugins/qnx/common/windowgrabber.h b/src/plugins/qnx/common/windowgrabber.h index bcf0ce66c..06ed6f435 100644 --- a/src/plugins/qnx/common/windowgrabber.h +++ b/src/plugins/qnx/common/windowgrabber.h @@ -41,12 +41,41 @@ #include #include #include +#include #include #include QT_BEGIN_NAMESPACE +class WindowGrabberImage : public QObject +{ + Q_OBJECT + +public: + WindowGrabberImage(); + ~WindowGrabberImage(); + + bool initialize(screen_context_t screenContext); + + void destroy(); + + QImage getImage(screen_window_t window, const QSize &size); + GLuint getTexture(screen_window_t window, const QSize &size); + +private: + bool grab(screen_window_t window); + bool resize(const QSize &size); + + QSize m_size; + screen_pixmap_t m_pixmap; + screen_buffer_t m_pixmapBuffer; + EGLImageKHR m_eglImage; + GLuint m_glTexture; + unsigned char *m_bufferAddress; + int m_bufferStride; +}; + class WindowGrabber : public QObject, public QAbstractNativeEventFilter { Q_OBJECT @@ -57,8 +86,6 @@ public: void setFrameRate(int frameRate); - void createEglImages(); - void setWindowId(const QByteArray &windowId); void start(); @@ -75,17 +102,19 @@ public: bool eglImageSupported(); void checkForEglImageExtension(); - bool eglImagesInitialized(); + + int getNextTextureId(); + QImage getNextImage(); signals: - void frameGrabbed(const QImage &frame, int); + void updateScene(const QSize &size); private slots: - void grab(); + void triggerUpdate(); private: + bool selectBuffer(); void cleanup(); - void updateFrameSize(); QTimer m_timer; @@ -93,24 +122,14 @@ private: screen_window_t m_window; screen_context_t m_screenContext; - screen_pixmap_t m_screenPixmaps[2]; - screen_buffer_t m_screenPixmapBuffers[2]; - - char *m_screenBuffers[2]; - int m_screenBufferWidth; - int m_screenBufferHeight; - int m_screenBufferStride; + WindowGrabberImage *m_images[2]; + QSize m_size; - bool m_active : 1; - bool m_screenContextInitialized : 1; - bool m_screenPixmapBuffersInitialized : 1; + bool m_active; int m_currentFrame; - EGLImageKHR img[2]; - GLuint imgTextures[2]; - bool m_eglImageSupported : 1; - bool m_eglImagesInitialized : 1; - bool m_eglImageCheck : 1; // We must not send a grabed frame before this is true + bool m_eglImageSupported; + bool m_eglImageCheck; // We must not send a grabed frame before this is true }; QT_END_NAMESPACE diff --git a/src/plugins/qnx/mediaplayer/mmrendererplayervideorenderercontrol.cpp b/src/plugins/qnx/mediaplayer/mmrendererplayervideorenderercontrol.cpp index 9e83ba2b2..5483e1423 100644 --- a/src/plugins/qnx/mediaplayer/mmrendererplayervideorenderercontrol.cpp +++ b/src/plugins/qnx/mediaplayer/mmrendererplayervideorenderercontrol.cpp @@ -52,7 +52,7 @@ MmRendererPlayerVideoRendererControl::MmRendererPlayerVideoRendererControl(QObje , m_context(0) , m_videoId(-1) { - connect(m_windowGrabber, SIGNAL(frameGrabbed(QImage, int)), SLOT(frameGrabbed(QImage, int))); + connect(m_windowGrabber, SIGNAL(updateScene(const QSize &)), SLOT(updateScene(const QSize &))); } MmRendererPlayerVideoRendererControl::~MmRendererPlayerVideoRendererControl() @@ -136,13 +136,14 @@ void MmRendererPlayerVideoRendererControl::resume() m_windowGrabber->resume(); } -class BBTextureBuffer : public QAbstractVideoBuffer +class QnxTextureBuffer : public QAbstractVideoBuffer { public: - BBTextureBuffer(int handle) : + QnxTextureBuffer(WindowGrabber *windowGrabber) : QAbstractVideoBuffer(QAbstractVideoBuffer::GLTextureHandle) { - m_handle = handle; + m_windowGrabber = windowGrabber; + m_handle = 0; } MapMode mapMode() const { return QAbstractVideoBuffer::ReadWrite; @@ -157,54 +158,46 @@ public: return 0; } QVariant handle() const { + if (!m_handle) { + const_cast(this)->m_handle = m_windowGrabber->getNextTextureId(); + } return m_handle; } private: + WindowGrabber *m_windowGrabber; int m_handle; }; -void MmRendererPlayerVideoRendererControl::frameGrabbed(const QImage &frame, int handle) +void MmRendererPlayerVideoRendererControl::updateScene(const QSize &size) { if (m_surface) { if (!m_surface->isActive()) { if (m_windowGrabber->eglImageSupported()) { - if (QOpenGLContext::currentContext()) - m_windowGrabber->createEglImages(); - else - m_surface->setProperty("_q_GLThreadCallback", QVariant::fromValue(this)); - - m_surface->start(QVideoSurfaceFormat(frame.size(), QVideoFrame::Format_BGR32, - QAbstractVideoBuffer::GLTextureHandle)); + m_surface->start(QVideoSurfaceFormat(size, QVideoFrame::Format_BGR32, + QAbstractVideoBuffer::GLTextureHandle)); } else { - m_surface->start(QVideoSurfaceFormat(frame.size(), QVideoFrame::Format_ARGB32)); + m_surface->start(QVideoSurfaceFormat(size, QVideoFrame::Format_ARGB32)); } } else { - if (m_surface->surfaceFormat().frameSize() != frame.size()) { - QAbstractVideoBuffer::HandleType type = m_surface->surfaceFormat().handleType(); + if (m_surface->surfaceFormat().frameSize() != size) { m_surface->stop(); - if (type != QAbstractVideoBuffer::NoHandle) { - m_surface->setProperty("_q_GLThreadCallback", QVariant::fromValue(this)); - m_surface->start(QVideoSurfaceFormat(frame.size(), QVideoFrame::Format_BGR32, - QAbstractVideoBuffer::GLTextureHandle)); + if (m_windowGrabber->eglImageSupported()) { + m_surface->start(QVideoSurfaceFormat(size, QVideoFrame::Format_BGR32, + QAbstractVideoBuffer::GLTextureHandle)); } else { - m_surface->start(QVideoSurfaceFormat(frame.size(), QVideoFrame::Format_ARGB32)); + m_surface->start(QVideoSurfaceFormat(size, QVideoFrame::Format_ARGB32)); } } } // Depending on the support of EGL images on the current platform we either pass a texture // handle or a copy of the image data - if (m_surface->surfaceFormat().handleType() != QAbstractVideoBuffer::NoHandle) { - if (m_windowGrabber->eglImagesInitialized() && - m_surface->property("_q_GLThreadCallback") != 0) - m_surface->setProperty("_q_GLThreadCallback", 0); - - - BBTextureBuffer *textBuffer = new BBTextureBuffer(handle); - QVideoFrame actualFrame(textBuffer, frame.size(), QVideoFrame::Format_BGR32); + if (m_windowGrabber->eglImageSupported()) { + QnxTextureBuffer *textBuffer = new QnxTextureBuffer(m_windowGrabber); + QVideoFrame actualFrame(textBuffer, size, QVideoFrame::Format_BGR32); m_surface->present(actualFrame); } else { - m_surface->present(frame.copy()); + m_surface->present(m_windowGrabber->getNextImage().copy()); } } } @@ -214,8 +207,6 @@ void MmRendererPlayerVideoRendererControl::customEvent(QEvent *e) // This is running in the render thread (OpenGL enabled) if (e->type() == QEvent::User) m_windowGrabber->checkForEglImageExtension(); - else if (e->type() == QEvent::User + 1) - m_windowGrabber->createEglImages(); } QT_END_NAMESPACE diff --git a/src/plugins/qnx/mediaplayer/mmrendererplayervideorenderercontrol.h b/src/plugins/qnx/mediaplayer/mmrendererplayervideorenderercontrol.h index 22833040c..c63d88f4d 100644 --- a/src/plugins/qnx/mediaplayer/mmrendererplayervideorenderercontrol.h +++ b/src/plugins/qnx/mediaplayer/mmrendererplayervideorenderercontrol.h @@ -62,7 +62,7 @@ public: void customEvent(QEvent *) Q_DECL_OVERRIDE; private Q_SLOTS: - void frameGrabbed(const QImage &frame, int); + void updateScene(const QSize &size); private: QPointer m_surface; diff --git a/src/qtmultimediaquicktools/qdeclarativevideooutput_render.cpp b/src/qtmultimediaquicktools/qdeclarativevideooutput_render.cpp index 70d48dd97..fbe8a62f9 100644 --- a/src/qtmultimediaquicktools/qdeclarativevideooutput_render.cpp +++ b/src/qtmultimediaquicktools/qdeclarativevideooutput_render.cpp @@ -282,16 +282,6 @@ QSGNode *QDeclarativeVideoRendererBackend::updatePaintNode(QSGNode *oldNode, obj->event(&ev); } } -#if defined (Q_OS_QNX) // On QNX we need to be called back again for creating the egl images - else { - // Internal mechanism to call back the surface renderer from the QtQuick render thread - QObject *obj = m_surface->property("_q_GLThreadCallback").value(); - if (obj) { - QEvent ev(static_cast(QEvent::User + 1)); - obj->event(&ev); - } - } -#endif bool isFrameModified = false; if (m_frameChanged) { -- cgit v1.2.3 From cf44daa75499eecfee8f614837908d722d8741f3 Mon Sep 17 00:00:00 2001 From: Dyami Caliri Date: Fri, 22 Apr 2016 17:00:31 -0700 Subject: CoreAudio: use AudioComponent instead of deprecated Carbon Component OS X 10.11 generates a warning when the code uses the Carbon Component Manager to locate audio devices. The new AudioComponent interface has been available since 10.7. Change-Id: I46ecbcd62871ecc46ce3ebd9ea2a37a9e1342f41 Task-number: QTBUG-48828 Reviewed-by: Yoann Lopes --- src/plugins/coreaudio/coreaudioinput.mm | 33 ++++++-------------------------- src/plugins/coreaudio/coreaudiooutput.mm | 32 +++++-------------------------- 2 files changed, 11 insertions(+), 54 deletions(-) diff --git a/src/plugins/coreaudio/coreaudioinput.mm b/src/plugins/coreaudio/coreaudioinput.mm index e0cedb1b9..b5be71166 100644 --- a/src/plugins/coreaudio/coreaudioinput.mm +++ b/src/plugins/coreaudio/coreaudioinput.mm @@ -36,7 +36,7 @@ #include "coreaudioutils.h" #if defined(Q_OS_OSX) -# include +# include #endif #if defined(Q_OS_IOS) @@ -480,31 +480,15 @@ bool CoreAudioInput::open() if (m_isOpen) return true; -#if defined(Q_OS_OSX) UInt32 size = 0; - ComponentDescription componentDescription; - componentDescription.componentType = kAudioUnitType_Output; - componentDescription.componentSubType = kAudioUnitSubType_HALOutput; - componentDescription.componentManufacturer = kAudioUnitManufacturer_Apple; - componentDescription.componentFlags = 0; - componentDescription.componentFlagsMask = 0; - - // Open - Component component = FindNextComponent(NULL, &componentDescription); - if (component == 0) { - qWarning() << "QAudioInput: Failed to find HAL Output component"; - return false; - } - - if (OpenAComponent(component, &m_audioUnit) != noErr) { - qWarning() << "QAudioInput: Unable to Open Output Component"; - return false; - } -#else //iOS AudioComponentDescription componentDescription; componentDescription.componentType = kAudioUnitType_Output; +#if defined(Q_OS_OSX) + componentDescription.componentSubType = kAudioUnitSubType_HALOutput; +#else componentDescription.componentSubType = kAudioUnitSubType_RemoteIO; +#endif componentDescription.componentManufacturer = kAudioUnitManufacturer_Apple; componentDescription.componentFlags = 0; componentDescription.componentFlagsMask = 0; @@ -519,7 +503,7 @@ bool CoreAudioInput::open() qWarning() << "QAudioInput: Unable to Open Output Component"; return false; } -#endif + // Set mode // switch to input mode UInt32 enable = 1; @@ -687,12 +671,7 @@ void CoreAudioInput::close() if (m_audioUnit != 0) { AudioOutputUnitStop(m_audioUnit); AudioUnitUninitialize(m_audioUnit); -#if defined(Q_OS_OSX) - CloseComponent(m_audioUnit); -#else //iOS AudioComponentInstanceDispose(m_audioUnit); -#endif - } delete m_audioBuffer; diff --git a/src/plugins/coreaudio/coreaudiooutput.mm b/src/plugins/coreaudio/coreaudiooutput.mm index 2db26297a..8c3760a39 100644 --- a/src/plugins/coreaudio/coreaudiooutput.mm +++ b/src/plugins/coreaudio/coreaudiooutput.mm @@ -42,7 +42,7 @@ #include #include #if defined(Q_OS_OSX) -# include +# include #endif #if defined(Q_OS_IOS) @@ -543,30 +543,13 @@ bool CoreAudioOutput::open() if (m_isOpen) return true; -#if defined(Q_OS_OSX) - ComponentDescription componentDescription; - componentDescription.componentType = kAudioUnitType_Output; - componentDescription.componentSubType = kAudioUnitSubType_HALOutput; - componentDescription.componentManufacturer = kAudioUnitManufacturer_Apple; - componentDescription.componentFlags = 0; - componentDescription.componentFlagsMask = 0; - - // Open - Component component = FindNextComponent(NULL, &componentDescription); - if (component == 0) { - qWarning() << "QAudioOutput: Failed to find HAL Output component"; - return false; - } - - if (OpenAComponent(component, &m_audioUnit) != noErr) { - qWarning() << "QAudioOutput: Unable to Open Output Component"; - return false; - } -#else //iOS - AudioComponentDescription componentDescription; componentDescription.componentType = kAudioUnitType_Output; +#if defined(Q_OS_OSX) + componentDescription.componentSubType = kAudioUnitSubType_HALOutput; +#else componentDescription.componentSubType = kAudioUnitSubType_RemoteIO; +#endif componentDescription.componentManufacturer = kAudioUnitManufacturer_Apple; componentDescription.componentFlags = 0; componentDescription.componentFlagsMask = 0; @@ -581,7 +564,6 @@ bool CoreAudioOutput::open() qWarning() << "QAudioOutput: Unable to Open Output Component"; return false; } -#endif // register callback AURenderCallbackStruct callback; @@ -673,11 +655,7 @@ void CoreAudioOutput::close() if (m_audioUnit != 0) { AudioOutputUnitStop(m_audioUnit); AudioUnitUninitialize(m_audioUnit); -#if defined(Q_OS_OSX) - CloseComponent(m_audioUnit); -#else //iOS AudioComponentInstanceDispose(m_audioUnit); -#endif } delete m_audioBuffer; -- cgit v1.2.3 From 20528da413e68cbff9d2eb1da3257c0e0025b4cd Mon Sep 17 00:00:00 2001 From: Zhang Xingtao Date: Tue, 12 Apr 2016 23:48:35 +0800 Subject: GStreamer camerabin: return the proper camera source - return m_cameraSrc for function cameraSource() instead of m_videoSrc. m_videoSrc is not always assigned(default 0), it will crash on: if (g_object_class_find_property( G_OBJECT_GET_CLASS(m_session->cameraSource()), "exposure-mode")) { And as the function name says, it would be better to return the value m_cameraSrc. - make sure pointers are not NULL before using them. Change-Id: I8a56db34a805724b428409b87de7d072ee7bfa57 Reviewed-by: Yoann Lopes --- src/plugins/gstreamer/camerabin/camerabinlocks.cpp | 21 ++++++++++++++++----- .../gstreamer/camerabin/camerabinsession.cpp | 3 ++- src/plugins/gstreamer/camerabin/camerabinsession.h | 2 +- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/plugins/gstreamer/camerabin/camerabinlocks.cpp b/src/plugins/gstreamer/camerabin/camerabinlocks.cpp index e6fe9a309..2f44ec057 100644 --- a/src/plugins/gstreamer/camerabin/camerabinlocks.cpp +++ b/src/plugins/gstreamer/camerabin/camerabinlocks.cpp @@ -65,9 +65,12 @@ QCamera::LockTypes CameraBinLocks::supportedLocks() const if (GstPhotography *photography = m_session->photography()) { if (gst_photography_get_capabilities(photography) & GST_PHOTOGRAPHY_CAPS_WB_MODE) locks |= QCamera::LockWhiteBalance; - if (g_object_class_find_property( - G_OBJECT_GET_CLASS(m_session->cameraSource()), "exposure-mode")) { - locks |= QCamera::LockExposure; + + if (GstElement *source = m_session->cameraSource()) { + if (g_object_class_find_property( + G_OBJECT_GET_CLASS(source), "exposure-mode")) { + locks |= QCamera::LockExposure; + } } } #endif @@ -195,9 +198,13 @@ bool CameraBinLocks::isExposureLocked() const void CameraBinLocks::lockExposure(QCamera::LockChangeReason reason) { + GstElement *source = m_session->cameraSource(); + if (!source) + return; + m_pendingLocks &= ~QCamera::LockExposure; g_object_set( - G_OBJECT(m_session->cameraSource()), + G_OBJECT(source), "exposure-mode", GST_PHOTOGRAPHY_EXPOSURE_MODE_MANUAL, NULL); @@ -206,8 +213,12 @@ void CameraBinLocks::lockExposure(QCamera::LockChangeReason reason) void CameraBinLocks::unlockExposure(QCamera::LockStatus status, QCamera::LockChangeReason reason) { + GstElement *source = m_session->cameraSource(); + if (!source) + return; + g_object_set( - G_OBJECT(m_session->cameraSource()), + G_OBJECT(source), "exposure-mode", GST_PHOTOGRAPHY_EXPOSURE_MODE_AUTO, NULL); diff --git a/src/plugins/gstreamer/camerabin/camerabinsession.cpp b/src/plugins/gstreamer/camerabin/camerabinsession.cpp index 3dd200c54..96b31e1b3 100644 --- a/src/plugins/gstreamer/camerabin/camerabinsession.cpp +++ b/src/plugins/gstreamer/camerabin/camerabinsession.cpp @@ -514,7 +514,8 @@ GstElement *CameraBinSession::buildCameraSource() if (!m_videoSrc) m_videoSrc = gst_element_factory_make("v4l2src", "camera_source"); - g_object_set(G_OBJECT(m_cameraSrc), "video-source", m_videoSrc, NULL); + if (m_videoSrc) + g_object_set(G_OBJECT(m_cameraSrc), "video-source", m_videoSrc, NULL); } if (m_videoSrc) diff --git a/src/plugins/gstreamer/camerabin/camerabinsession.h b/src/plugins/gstreamer/camerabin/camerabinsession.h index dda900a8b..ade8916ba 100644 --- a/src/plugins/gstreamer/camerabin/camerabinsession.h +++ b/src/plugins/gstreamer/camerabin/camerabinsession.h @@ -91,7 +91,7 @@ public: GstPhotography *photography(); #endif GstElement *cameraBin() { return m_camerabin; } - GstElement *cameraSource() { return m_videoSrc; } + GstElement *cameraSource() { return m_cameraSrc; } QGstreamerBusHelper *bus() { return m_busHelper; } QList< QPair > supportedFrameRates(const QSize &frameSize, bool *continuous) const; -- cgit v1.2.3 From 6dc5ff99ac02a5ed2c716a011c06eee766d125de Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 20 Apr 2016 20:46:46 +0200 Subject: fix example installs Change-Id: I9daec1e1ec1bc163d451ac03685ef6caba7dbde7 Reviewed-by: Yoann Lopes --- examples/multimedia/spectrum/3rdparty/fftreal/fftreal.pro | 1 + examples/multimedia/spectrum/app/app.pro | 2 ++ examples/multimedia/spectrum/spectrum.pro | 3 +++ examples/multimedia/video/qmlvideo/qmlvideo.pro | 3 +++ examples/multimedia/video/qmlvideofx/qmlvideofx.pro | 4 ++++ examples/multimedia/video/video.pro | 3 +++ 6 files changed, 16 insertions(+) diff --git a/examples/multimedia/spectrum/3rdparty/fftreal/fftreal.pro b/examples/multimedia/spectrum/3rdparty/fftreal/fftreal.pro index f6abeeb15..b2c96f96c 100644 --- a/examples/multimedia/spectrum/3rdparty/fftreal/fftreal.pro +++ b/examples/multimedia/spectrum/3rdparty/fftreal/fftreal.pro @@ -42,3 +42,4 @@ EXAMPLE_FILES = bwins/fftreal.def eabi/fftreal.def readme.txt license.txt target.path = $$[QT_INSTALL_EXAMPLES]/multimedia/spectrum INSTALLS += target +CONFIG += install_ok # Do not cargo-cult this! diff --git a/examples/multimedia/spectrum/app/app.pro b/examples/multimedia/spectrum/app/app.pro index 8262372c4..76aa02cdf 100644 --- a/examples/multimedia/spectrum/app/app.pro +++ b/examples/multimedia/spectrum/app/app.pro @@ -57,6 +57,8 @@ RESOURCES = spectrum.qrc target.path = $$[QT_INSTALL_EXAMPLES]/multimedia/spectrum INSTALLS += target +CONFIG += install_ok # Do not cargo-cult this! + # Deployment DESTDIR = ..$${spectrum_build_dir} diff --git a/examples/multimedia/spectrum/spectrum.pro b/examples/multimedia/spectrum/spectrum.pro index 81006a24c..0ca2ee554 100644 --- a/examples/multimedia/spectrum/spectrum.pro +++ b/examples/multimedia/spectrum/spectrum.pro @@ -10,3 +10,6 @@ SUBDIRS += app TARGET = spectrum +EXAMPLE_FILES += \ + README.txt \ + TODO.txt diff --git a/examples/multimedia/video/qmlvideo/qmlvideo.pro b/examples/multimedia/video/qmlvideo/qmlvideo.pro index 26865c59a..022835f12 100644 --- a/examples/multimedia/video/qmlvideo/qmlvideo.pro +++ b/examples/multimedia/video/qmlvideo/qmlvideo.pro @@ -16,3 +16,6 @@ include($$SNIPPETS_PATH/performancemonitor/performancemonitordeclarative.pri) target.path = $$[QT_INSTALL_EXAMPLES]/multimedia/video/qmlvideo INSTALLS += target +EXAMPLE_FILES += \ + qmlvideo.png \ + qmlvideo.svg diff --git a/examples/multimedia/video/qmlvideofx/qmlvideofx.pro b/examples/multimedia/video/qmlvideofx/qmlvideofx.pro index e9633954c..4221d157b 100644 --- a/examples/multimedia/video/qmlvideofx/qmlvideofx.pro +++ b/examples/multimedia/video/qmlvideofx/qmlvideofx.pro @@ -19,3 +19,7 @@ OTHER_FILES += \ android/AndroidManifest.xml QMAKE_INFO_PLIST = Info.plist + +EXAMPLE_FILES += \ + qmlvideofx.png \ + qmlvideofx.svg diff --git a/examples/multimedia/video/video.pro b/examples/multimedia/video/video.pro index 3127a4e49..f38cbc124 100644 --- a/examples/multimedia/video/video.pro +++ b/examples/multimedia/video/video.pro @@ -2,3 +2,6 @@ TEMPLATE = subdirs SUBDIRS += qmlvideo qmlvideofx +EXAMPLE_FILES += \ + qmlvideofilter_opencl \ # FIXME: this one should use a configure check instead + snippets -- cgit v1.2.3 From 1afe2ed975a71e72f37a34a9561dede342985be7 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 3 May 2016 10:34:42 +0200 Subject: DirectShow: Invoke IGraphBuilder::AddSourceFilter() with local file name. When possible, convert the URL to a local file name with native separators. The method seems to accept URLs with file scheme, but fails when passing UNC paths. Task-number: QTBUG-53114 Change-Id: Ib7418090080be8c1b8472e77541e686adaa3a18a Reviewed-by: Yoann Lopes --- src/plugins/directshow/player/directshowplayerservice.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/directshow/player/directshowplayerservice.cpp b/src/plugins/directshow/player/directshowplayerservice.cpp index 73279accb..57f100b9c 100644 --- a/src/plugins/directshow/player/directshowplayerservice.cpp +++ b/src/plugins/directshow/player/directshowplayerservice.cpp @@ -63,6 +63,7 @@ #include #include +#include #include #include @@ -333,8 +334,10 @@ void DirectShowPlayerService::doSetUrlSource(QMutexLocker *locker) if (!SUCCEEDED(hr)) { locker->unlock(); + const QString urlString = m_url.isLocalFile() + ? QDir::toNativeSeparators(m_url.toLocalFile()) : m_url.toString(); hr = m_graph->AddSourceFilter( - reinterpret_cast(m_url.toString().utf16()), L"Source", &source); + reinterpret_cast(urlString.utf16()), L"Source", &source); locker->relock(); } -- cgit v1.2.3 From 6f3e6a78ca885096b8864638bfb64724c486e7d1 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 3 May 2016 11:21:17 +0200 Subject: Polish the videowidget example. - Add command line parsing and file argument. - Port to Qt 5 connection syntax. - Adapt size to available geometry (for High DPI). Task-number: QTBUG-53114 Change-Id: I1c1c547ddb14210ef5900f99f4870d6d91b67088 Reviewed-by: Yoann Lopes --- examples/multimediawidgets/videowidget/main.cpp | 25 +++++++++- .../multimediawidgets/videowidget/videoplayer.cpp | 53 ++++++++++++++-------- .../multimediawidgets/videowidget/videoplayer.h | 3 ++ 3 files changed, 62 insertions(+), 19 deletions(-) diff --git a/examples/multimediawidgets/videowidget/main.cpp b/examples/multimediawidgets/videowidget/main.cpp index c9940e10e..fd726884b 100644 --- a/examples/multimediawidgets/videowidget/main.cpp +++ b/examples/multimediawidgets/videowidget/main.cpp @@ -41,13 +41,36 @@ #include "videoplayer.h" #include +#include +#include +#include +#include int main(int argc, char *argv[]) { QApplication app(argc, argv); + QCoreApplication::setApplicationName("Video Widget Example"); + QCoreApplication::setOrganizationName("QtProject"); + QGuiApplication::setApplicationDisplayName(QCoreApplication::applicationName()); + QCoreApplication::setApplicationVersion(QT_VERSION_STR); + QCommandLineParser parser; + parser.setApplicationDescription("Qt Video Widget Example"); + parser.addHelpOption(); + parser.addVersionOption(); + parser.addPositionalArgument("url", "The URL to open."); + parser.process(app); + VideoPlayer player; - player.resize(320, 240); + if (!parser.positionalArguments().isEmpty()) { + const QUrl url = + QUrl::fromUserInput(parser.positionalArguments().constFirst(), + QDir::currentPath(), QUrl::AssumeLocalFile); + player.setUrl(url); + } + + const QRect availableGeometry = QApplication::desktop()->availableGeometry(&player); + player.resize(availableGeometry.width() / 6, availableGeometry.height() / 4); player.show(); return app.exec(); diff --git a/examples/multimediawidgets/videowidget/videoplayer.cpp b/examples/multimediawidgets/videowidget/videoplayer.cpp index c3554ff04..8504746c4 100644 --- a/examples/multimediawidgets/videowidget/videoplayer.cpp +++ b/examples/multimediawidgets/videowidget/videoplayer.cpp @@ -54,20 +54,20 @@ VideoPlayer::VideoPlayer(QWidget *parent) QVideoWidget *videoWidget = new QVideoWidget; QAbstractButton *openButton = new QPushButton(tr("Open...")); - connect(openButton, SIGNAL(clicked()), this, SLOT(openFile())); + connect(openButton, &QAbstractButton::clicked, this, &VideoPlayer::openFile); playButton = new QPushButton; playButton->setEnabled(false); playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay)); - connect(playButton, SIGNAL(clicked()), - this, SLOT(play())); + connect(playButton, &QAbstractButton::clicked, + this, &VideoPlayer::play); positionSlider = new QSlider(Qt::Horizontal); positionSlider->setRange(0, 0); - connect(positionSlider, SIGNAL(sliderMoved(int)), - this, SLOT(setPosition(int))); + connect(positionSlider, &QAbstractSlider::sliderMoved, + this, &VideoPlayer::setPosition); errorLabel = new QLabel; errorLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); @@ -86,11 +86,13 @@ VideoPlayer::VideoPlayer(QWidget *parent) setLayout(layout); mediaPlayer.setVideoOutput(videoWidget); - connect(&mediaPlayer, SIGNAL(stateChanged(QMediaPlayer::State)), - this, SLOT(mediaStateChanged(QMediaPlayer::State))); - connect(&mediaPlayer, SIGNAL(positionChanged(qint64)), this, SLOT(positionChanged(qint64))); - connect(&mediaPlayer, SIGNAL(durationChanged(qint64)), this, SLOT(durationChanged(qint64))); - connect(&mediaPlayer, SIGNAL(error(QMediaPlayer::Error)), this, SLOT(handleError())); + connect(&mediaPlayer, &QMediaPlayer::stateChanged, + this, &VideoPlayer::mediaStateChanged); + connect(&mediaPlayer, &QMediaPlayer::positionChanged, this, &VideoPlayer::positionChanged); + connect(&mediaPlayer, &QMediaPlayer::durationChanged, this, &VideoPlayer::durationChanged); + typedef void (QMediaPlayer::*ErrorSignal)(QMediaPlayer::Error); + connect(&mediaPlayer, static_cast(&QMediaPlayer::error), + this, &VideoPlayer::handleError); } VideoPlayer::~VideoPlayer() @@ -99,14 +101,23 @@ VideoPlayer::~VideoPlayer() void VideoPlayer::openFile() { - errorLabel->setText(""); - - QString fileName = QFileDialog::getOpenFileName(this, tr("Open Movie"),QDir::homePath()); + QFileDialog fileDialog(this); + fileDialog.setAcceptMode(QFileDialog::AcceptOpen); + fileDialog.setWindowTitle(tr("Open Movie")); + QStringList supportedMimeTypes = mediaPlayer.supportedMimeTypes(); + if (!supportedMimeTypes.isEmpty()) + fileDialog.setMimeTypeFilters(supportedMimeTypes); + fileDialog.setDirectory(QStandardPaths::standardLocations(QStandardPaths::MoviesLocation).value(0, QDir::homePath())); + if (fileDialog.exec() == QDialog::Accepted) + setUrl(fileDialog.selectedUrls().constFirst()); +} - if (!fileName.isEmpty()) { - mediaPlayer.setMedia(QUrl::fromLocalFile(fileName)); - playButton->setEnabled(true); - } +void VideoPlayer::setUrl(const QUrl &url) +{ + errorLabel->setText(QString()); + setWindowFilePath(url.isLocalFile() ? url.toLocalFile() : QString()); + mediaPlayer.setMedia(url); + playButton->setEnabled(true); } void VideoPlayer::play() @@ -151,5 +162,11 @@ void VideoPlayer::setPosition(int position) void VideoPlayer::handleError() { playButton->setEnabled(false); - errorLabel->setText("Error: " + mediaPlayer.errorString()); + const QString errorString = mediaPlayer.errorString(); + QString message = "Error: "; + if (errorString.isEmpty()) + message += " #" + QString::number(int(mediaPlayer.error())); + else + message += errorString; + errorLabel->setText(message); } diff --git a/examples/multimediawidgets/videowidget/videoplayer.h b/examples/multimediawidgets/videowidget/videoplayer.h index 24589f542..f9f3b692b 100644 --- a/examples/multimediawidgets/videowidget/videoplayer.h +++ b/examples/multimediawidgets/videowidget/videoplayer.h @@ -50,6 +50,7 @@ QT_BEGIN_NAMESPACE class QAbstractButton; class QSlider; class QLabel; +class QUrl; QT_END_NAMESPACE class VideoPlayer : public QWidget @@ -59,6 +60,8 @@ public: VideoPlayer(QWidget *parent = 0); ~VideoPlayer(); + void setUrl(const QUrl &url); + public slots: void openFile(); void play(); -- cgit v1.2.3 From 80d8466a470565d1d823b66e3b81dcc306d04f61 Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Fri, 1 Apr 2016 14:13:38 +0200 Subject: Android: correctly use mutex for texture rendering. Some sections were not protected by the mutex, even though they should have been. An example of problem that could happen because of this was if the SurfaceTexture was reset while the render thread was rendering that texture. Change-Id: Ie95860fd4eb722bbac04cccc430cc1a8abf1df4d Reviewed-by: Christian Stromme --- src/plugins/android/src/common/qandroidvideooutput.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/plugins/android/src/common/qandroidvideooutput.cpp b/src/plugins/android/src/common/qandroidvideooutput.cpp index 82c27035d..87a725a93 100644 --- a/src/plugins/android/src/common/qandroidvideooutput.cpp +++ b/src/plugins/android/src/common/qandroidvideooutput.cpp @@ -218,6 +218,8 @@ bool QAndroidTextureVideoOutput::initSurfaceTexture() return false; } + QMutexLocker locker(&m_mutex); + m_surfaceTexture = new AndroidSurfaceTexture(m_externalTex); if (m_surfaceTexture->surfaceTexture() != 0) { @@ -235,6 +237,7 @@ bool QAndroidTextureVideoOutput::initSurfaceTexture() void QAndroidTextureVideoOutput::clearSurfaceTexture() { + QMutexLocker locker(&m_mutex); if (m_surfaceTexture) { delete m_surfaceTexture; m_surfaceTexture = 0; -- cgit v1.2.3 From 3c3ea1ca20f34fc7353fb4732c9e4ee822dd796a Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Fri, 1 Apr 2016 15:15:59 +0200 Subject: Android: detect more error cases when rendering frames to textures. Don't render the frame if the SurfaceTexture has been released or if the render size is invalid. Change-Id: I6b8bf14e023ff54a560b0a9e6027ef9d7d06ab6a Reviewed-by: Christian Stromme --- src/plugins/android/src/common/qandroidvideooutput.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/plugins/android/src/common/qandroidvideooutput.cpp b/src/plugins/android/src/common/qandroidvideooutput.cpp index 87a725a93..3a22c4e98 100644 --- a/src/plugins/android/src/common/qandroidvideooutput.cpp +++ b/src/plugins/android/src/common/qandroidvideooutput.cpp @@ -304,6 +304,9 @@ void QAndroidTextureVideoOutput::renderFrameToFbo() { QMutexLocker locker(&m_mutex); + if (!m_nativeSize.isValid() || !m_surfaceTexture) + return; + createGLResources(); m_surfaceTexture->updateTexImage(); -- cgit v1.2.3 From 37d91ff58d33a573f4d546282c0c5dfe0e5f4aa2 Mon Sep 17 00:00:00 2001 From: Ralf Nolden Date: Mon, 9 May 2016 17:07:32 +0200 Subject: Add FreeBSD define and include for where is used Compile fix: FreeBSD uses instead of the linux version , so this patch changes the include by Q_OS_FREEBSD define. Change-Id: Iafe18614ad2360dce9858039b22f9b6c2dd9caaa Reviewed-by: Thiago Macieira --- src/plugins/v4l/radio/v4lradiocontrol.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/plugins/v4l/radio/v4lradiocontrol.h b/src/plugins/v4l/radio/v4lradiocontrol.h index 3d2f21f5d..c084ec960 100644 --- a/src/plugins/v4l/radio/v4lradiocontrol.h +++ b/src/plugins/v4l/radio/v4lradiocontrol.h @@ -40,7 +40,11 @@ #include +#if defined(Q_OS_FREEBSD) +#include +#else #include +#endif #include #include #include -- cgit v1.2.3 From ba8127639857232d8a37e953c5cda84203360d97 Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Wed, 4 May 2016 15:41:32 +0200 Subject: Android: improve texture rendering on API level >= 16. Android API level 16 added SurfaceTexture::attachToGLContext(). This allows to create the OpenGL texture when the first video frame is available, rather than at initialization. This means we can do without the ugly hack that makes the render thread call us back through some custom property. Additionally, it allows to recreate a new OpenGL texture every time the SurfaceTexture is reset. Task-number: QTBUG-51911 Change-Id: I17b04524d426c42ef8aa0288b0731597bc9eba62 Reviewed-by: Christian Stromme --- .../android/src/common/qandroidvideooutput.cpp | 49 ++++++++++++++++------ .../android/src/common/qandroidvideooutput.h | 2 + .../src/wrappers/jni/androidsurfacetexture.cpp | 16 +++++++ .../src/wrappers/jni/androidsurfacetexture.h | 3 ++ 4 files changed, 57 insertions(+), 13 deletions(-) diff --git a/src/plugins/android/src/common/qandroidvideooutput.cpp b/src/plugins/android/src/common/qandroidvideooutput.cpp index 3a22c4e98..c0bd88d85 100644 --- a/src/plugins/android/src/common/qandroidvideooutput.cpp +++ b/src/plugins/android/src/common/qandroidvideooutput.cpp @@ -42,6 +42,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -159,6 +160,7 @@ QAndroidTextureVideoOutput::QAndroidTextureVideoOutput(QObject *parent) , m_fbo(0) , m_program(0) , m_glDeleter(0) + , m_surfaceTextureCanAttachToContext(QtAndroidPrivate::androidSdkVersion() >= 16) { } @@ -184,12 +186,14 @@ void QAndroidTextureVideoOutput::setSurface(QAbstractVideoSurface *surface) if (m_surface) { if (m_surface->isActive()) m_surface->stop(); - m_surface->setProperty("_q_GLThreadCallback", QVariant()); + + if (!m_surfaceTextureCanAttachToContext) + m_surface->setProperty("_q_GLThreadCallback", QVariant()); } m_surface = surface; - if (m_surface) { + if (m_surface && !m_surfaceTextureCanAttachToContext) { m_surface->setProperty("_q_GLThreadCallback", QVariant::fromValue(this)); } @@ -197,7 +201,7 @@ void QAndroidTextureVideoOutput::setSurface(QAbstractVideoSurface *surface) bool QAndroidTextureVideoOutput::isReady() { - return QOpenGLContext::currentContext() || m_externalTex; + return m_surfaceTextureCanAttachToContext || QOpenGLContext::currentContext() || m_externalTex; } bool QAndroidTextureVideoOutput::initSurfaceTexture() @@ -208,14 +212,16 @@ bool QAndroidTextureVideoOutput::initSurfaceTexture() if (!m_surface) return false; - // if we have an OpenGL context in the current thread, create a texture. Otherwise, wait - // for the GL render thread to call us back to do it. - if (QOpenGLContext::currentContext()) { - glGenTextures(1, &m_externalTex); - m_glDeleter = new OpenGLResourcesDeleter; - m_glDeleter->setTexture(m_externalTex); - } else if (!m_externalTex) { - return false; + if (!m_surfaceTextureCanAttachToContext) { + // if we have an OpenGL context in the current thread, create a texture. Otherwise, wait + // for the GL render thread to call us back to do it. + if (QOpenGLContext::currentContext()) { + glGenTextures(1, &m_externalTex); + m_glDeleter = new OpenGLResourcesDeleter; + m_glDeleter->setTexture(m_externalTex); + } else if (!m_externalTex) { + return false; + } } QMutexLocker locker(&m_mutex); @@ -227,7 +233,8 @@ bool QAndroidTextureVideoOutput::initSurfaceTexture() } else { delete m_surfaceTexture; m_surfaceTexture = 0; - m_glDeleter->deleteLater(); + if (m_glDeleter) + m_glDeleter->deleteLater(); m_externalTex = 0; m_glDeleter = 0; } @@ -242,6 +249,10 @@ void QAndroidTextureVideoOutput::clearSurfaceTexture() delete m_surfaceTexture; m_surfaceTexture = 0; } + + // Also reset the attached OpenGL texture + if (m_surfaceTextureCanAttachToContext) + m_externalTex = 0; } AndroidSurfaceTexture *QAndroidTextureVideoOutput::surfaceTexture() @@ -364,6 +375,18 @@ void QAndroidTextureVideoOutput::renderFrameToFbo() void QAndroidTextureVideoOutput::createGLResources() { + Q_ASSERT(QOpenGLContext::currentContext() != NULL); + + if (!m_glDeleter) + m_glDeleter = new OpenGLResourcesDeleter; + + if (m_surfaceTextureCanAttachToContext && !m_externalTex) { + m_surfaceTexture->detachFromGLContext(); + glGenTextures(1, &m_externalTex); + m_surfaceTexture->attachToGLContext(m_externalTex); + m_glDeleter->setTexture(m_externalTex); + } + if (!m_fbo || m_fbo->size() != m_nativeSize) { delete m_fbo; m_fbo = new QOpenGLFramebufferObject(m_nativeSize); @@ -407,7 +430,7 @@ void QAndroidTextureVideoOutput::customEvent(QEvent *e) { if (e->type() == QEvent::User) { // This is running in the render thread (OpenGL enabled) - if (!m_externalTex) { + if (!m_surfaceTextureCanAttachToContext && !m_externalTex) { glGenTextures(1, &m_externalTex); m_glDeleter = new OpenGLResourcesDeleter; // will cleanup GL resources in the correct thread m_glDeleter->setTexture(m_externalTex); diff --git a/src/plugins/android/src/common/qandroidvideooutput.h b/src/plugins/android/src/common/qandroidvideooutput.h index f4401fa1d..0068a5809 100644 --- a/src/plugins/android/src/common/qandroidvideooutput.h +++ b/src/plugins/android/src/common/qandroidvideooutput.h @@ -110,6 +110,8 @@ private: QOpenGLShaderProgram *m_program; OpenGLResourcesDeleter *m_glDeleter; + bool m_surfaceTextureCanAttachToContext; + friend class AndroidTextureVideoBuffer; }; diff --git a/src/plugins/android/src/wrappers/jni/androidsurfacetexture.cpp b/src/plugins/android/src/wrappers/jni/androidsurfacetexture.cpp index 9a25b7e28..2cea896e1 100644 --- a/src/plugins/android/src/wrappers/jni/androidsurfacetexture.cpp +++ b/src/plugins/android/src/wrappers/jni/androidsurfacetexture.cpp @@ -146,6 +146,22 @@ jobject AndroidSurfaceTexture::surfaceHolder() return m_surfaceHolder.object(); } +void AndroidSurfaceTexture::attachToGLContext(int texName) +{ + if (QtAndroidPrivate::androidSdkVersion() < 16 || !m_surfaceTexture.isValid()) + return; + + m_surfaceTexture.callMethod("attachToGLContext", "(I)V", texName); +} + +void AndroidSurfaceTexture::detachFromGLContext() +{ + if (QtAndroidPrivate::androidSdkVersion() < 16 || !m_surfaceTexture.isValid()) + return; + + m_surfaceTexture.callMethod("detachFromGLContext"); +} + bool AndroidSurfaceTexture::initJNI(JNIEnv *env) { // SurfaceTexture is available since API 11. diff --git a/src/plugins/android/src/wrappers/jni/androidsurfacetexture.h b/src/plugins/android/src/wrappers/jni/androidsurfacetexture.h index ac2af694e..a08483e5e 100644 --- a/src/plugins/android/src/wrappers/jni/androidsurfacetexture.h +++ b/src/plugins/android/src/wrappers/jni/androidsurfacetexture.h @@ -58,6 +58,9 @@ public: void release(); // API level 14 void updateTexImage(); + void attachToGLContext(int texName); // API level 16 + void detachFromGLContext(); // API level 16 + static bool initJNI(JNIEnv *env); Q_SIGNALS: -- cgit v1.2.3 From f0e0d5d901d4e28fff9f29caf86ada84906b3db4 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 3 May 2016 19:46:10 +0200 Subject: decruft project file the "created by qt creator" header is not supposed to be checked in. Change-Id: I6d8c623f41c633babe5923344c915412d3d6bcd4 Reviewed-by: Joerg Bornemann --- tests/auto/unit/qaudiobuffer/qaudiobuffer.pro | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/auto/unit/qaudiobuffer/qaudiobuffer.pro b/tests/auto/unit/qaudiobuffer/qaudiobuffer.pro index cd3b42f50..535465889 100644 --- a/tests/auto/unit/qaudiobuffer/qaudiobuffer.pro +++ b/tests/auto/unit/qaudiobuffer/qaudiobuffer.pro @@ -1,9 +1,3 @@ -#------------------------------------------------- -# -# Project created by QtCreator 2012-02-02T23:40:38 -# -#------------------------------------------------- - QT += multimedia testlib QT -= gui -- cgit v1.2.3