diff options
author | Liang Qi <liang.qi@qt.io> | 2017-10-19 13:25:35 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2017-10-19 13:39:16 +0200 |
commit | 66c0334a3c4cb8deb63c67aa70da3f4ed94f89a4 (patch) | |
tree | caf62f9e6a8486862216306f62bf1ff4627df9f7 /src/plugins/winrt | |
parent | acc49e582abf76c962851f53cbd66134812f6a1f (diff) | |
parent | 6b5b4d4ab4806812eaa4f6ddc78831ad31d0e7d9 (diff) |
Merge remote-tracking branch 'origin/5.10' into dev
Conflicts:
src/plugins/qnx/mediaplayer/mmreventmediaplayercontrol.h
Change-Id: Ic6e27742ef6d1af0532ad05902a1431ebd5f449d
Diffstat (limited to 'src/plugins/winrt')
-rw-r--r-- | src/plugins/winrt/qwinrtabstractvideorenderercontrol.cpp | 14 | ||||
-rw-r--r-- | src/plugins/winrt/qwinrtabstractvideorenderercontrol.h | 16 | ||||
-rw-r--r-- | src/plugins/winrt/qwinrtcameracontrol.cpp | 298 | ||||
-rw-r--r-- | src/plugins/winrt/qwinrtcameracontrol.h | 2 |
4 files changed, 178 insertions, 152 deletions
diff --git a/src/plugins/winrt/qwinrtabstractvideorenderercontrol.cpp b/src/plugins/winrt/qwinrtabstractvideorenderercontrol.cpp index 433601477..3544031a7 100644 --- a/src/plugins/winrt/qwinrtabstractvideorenderercontrol.cpp +++ b/src/plugins/winrt/qwinrtabstractvideorenderercontrol.cpp @@ -43,6 +43,7 @@ #include <QtCore/QGlobalStatic> #include <QtCore/QLoggingCategory> #include <QtCore/QMetaMethod> +#include <QtCore/QMutexLocker> #include <QtCore/QPointer> #include <QtGui/QOpenGLContext> #include <QtGui/QOpenGLTexture> @@ -198,7 +199,7 @@ public: QThread renderThread; bool active; QWinRTAbstractVideoRendererControl::BlitMode blitMode; - CRITICAL_SECTION mutex; + QMutex mutex; }; ID3D11Device *QWinRTAbstractVideoRendererControl::d3dDevice() @@ -232,7 +233,6 @@ QWinRTAbstractVideoRendererControl::QWinRTAbstractVideoRendererControl(const QSi d->eglSurface = EGL_NO_SURFACE; d->active = false; d->blitMode = DirectVideo; - InitializeCriticalSectionEx(&d->mutex, 0, 0); connect(&d->renderThread, &QThread::started, this, &QWinRTAbstractVideoRendererControl::syncAndRender, @@ -243,9 +243,9 @@ QWinRTAbstractVideoRendererControl::~QWinRTAbstractVideoRendererControl() { qCDebug(lcMMVideoRender) << __FUNCTION__; Q_D(QWinRTAbstractVideoRendererControl); - CriticalSectionLocker locker(&d->mutex); + QMutexLocker locker(&d->mutex); shutdown(); - DeleteCriticalSection(&d->mutex); + locker.unlock(); eglDestroySurface(d->eglDisplay, d->eglSurface); } @@ -272,7 +272,7 @@ void QWinRTAbstractVideoRendererControl::syncAndRender() if (currentThread->isInterruptionRequested()) break; { - CriticalSectionLocker lock(&d->mutex); + QMutexLocker lock(&d->mutex); HRESULT hr; if (d->dirtyState == TextureDirty) { CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, d->format.frameWidth(), d->format.frameHeight(), 1, 1); @@ -359,7 +359,7 @@ void QWinRTAbstractVideoRendererControl::setActive(bool active) // This only happens for quick restart scenarios, for instance // when switching cameras. if (d->renderThread.isRunning() && d->renderThread.isInterruptionRequested()) { - CriticalSectionLocker lock(&d->mutex); + QMutexLocker lock(&d->mutex); d->renderThread.wait(); } @@ -385,7 +385,7 @@ QWinRTAbstractVideoRendererControl::BlitMode QWinRTAbstractVideoRendererControl: void QWinRTAbstractVideoRendererControl::setBlitMode(QWinRTAbstractVideoRendererControl::BlitMode mode) { Q_D(QWinRTAbstractVideoRendererControl); - CriticalSectionLocker lock(&d->mutex); + QMutexLocker lock(&d->mutex); if (d->blitMode == mode) return; diff --git a/src/plugins/winrt/qwinrtabstractvideorenderercontrol.h b/src/plugins/winrt/qwinrtabstractvideorenderercontrol.h index 8231fe9ab..e190c8c4a 100644 --- a/src/plugins/winrt/qwinrtabstractvideorenderercontrol.h +++ b/src/plugins/winrt/qwinrtabstractvideorenderercontrol.h @@ -96,22 +96,6 @@ private: Q_DECLARE_PRIVATE(QWinRTAbstractVideoRendererControl) }; -class CriticalSectionLocker -{ -public: - CriticalSectionLocker(CRITICAL_SECTION *section) - : m_section(section) - { - EnterCriticalSection(m_section); - } - ~CriticalSectionLocker() - { - LeaveCriticalSection(m_section); - } -private: - CRITICAL_SECTION *m_section; -}; - QT_END_NAMESPACE #endif // QWINRTABSTRACTVIDEORENDERERCONTROL_H diff --git a/src/plugins/winrt/qwinrtcameracontrol.cpp b/src/plugins/winrt/qwinrtcameracontrol.cpp index 5a14059c4..4c515bc3d 100644 --- a/src/plugins/winrt/qwinrtcameracontrol.cpp +++ b/src/plugins/winrt/qwinrtcameracontrol.cpp @@ -47,6 +47,7 @@ #include "qwinrtcameralockscontrol.h" #include <QtCore/qfunctions_winrt.h> +#include <QtCore/QMutex> #include <QtCore/QPointer> #include <QtGui/QGuiApplication> #include <private/qeventdispatcher_winrt_p.h> @@ -227,8 +228,6 @@ public: { Q_ASSERT(m_videoRenderer); - InitializeCriticalSectionEx(&m_mutex, 0, 0); - HRESULT hr; hr = MFCreateEventQueue(&m_eventQueue); Q_ASSERT_SUCCEEDED(hr); @@ -238,9 +237,8 @@ public: ~MediaStream() { - CriticalSectionLocker locker(&m_mutex); + QMutexLocker locker(&m_mutex); m_eventQueue->Shutdown(); - DeleteCriticalSection(&m_mutex); } HRESULT RequestSample() @@ -254,30 +252,30 @@ public: HRESULT __stdcall GetEvent(DWORD flags, IMFMediaEvent **event) override { - EnterCriticalSection(&m_mutex); + QMutexLocker locker(&m_mutex); // Create an extra reference to avoid deadlock ComPtr<IMFMediaEventQueue> eventQueue = m_eventQueue; - LeaveCriticalSection(&m_mutex); + locker.unlock(); return eventQueue->GetEvent(flags, event); } HRESULT __stdcall BeginGetEvent(IMFAsyncCallback *callback, IUnknown *state) override { - CriticalSectionLocker locker(&m_mutex); + QMutexLocker locker(&m_mutex); HRESULT hr = m_eventQueue->BeginGetEvent(callback, state); return hr; } HRESULT __stdcall EndGetEvent(IMFAsyncResult *result, IMFMediaEvent **event) override { - CriticalSectionLocker locker(&m_mutex); + QMutexLocker locker(&m_mutex); return m_eventQueue->EndGetEvent(result, event); } HRESULT __stdcall QueueEvent(MediaEventType eventType, const GUID &extendedType, HRESULT status, const PROPVARIANT *value) override { - CriticalSectionLocker locker(&m_mutex); + QMutexLocker locker(&m_mutex); return m_eventQueue->QueueEventParamVar(eventType, extendedType, status, value); } @@ -372,7 +370,7 @@ public: } private: - CRITICAL_SECTION m_mutex; + QMutex m_mutex; ComPtr<IMFMediaType> m_type; IMFMediaSink *m_sink; ComPtr<IMFMediaEventQueue> m_eventQueue; @@ -560,6 +558,10 @@ public: QPointer<QWinRTCameraLocksControl> cameraLocksControl; QAtomicInt framesMapped; QEventLoop *delayClose; + + bool initializing = false; + bool initialized = false; + HANDLE initializationCompleteEvent; }; QWinRTCameraControl::QWinRTCameraControl(QObject *parent) @@ -584,6 +586,8 @@ QWinRTCameraControl::QWinRTCameraControl(QObject *parent) d->cameraFocusControl = new QWinRTCameraFocusControl(this); d->cameraLocksControl = new QWinRTCameraLocksControl(this); + d->initializationCompleteEvent = CreateEvent(NULL, false, false, NULL); + if (qGuiApp) { connect(qGuiApp, &QGuiApplication::applicationStateChanged, this, &QWinRTCameraControl::onApplicationStateChanged); @@ -614,8 +618,23 @@ void QWinRTCameraControl::setState(QCamera::State state) case QCamera::ActiveState: { // Capture has not been created or initialized if (d->state == QCamera::UnloadedState) { - hr = initialize(); - RETURN_VOID_AND_EMIT_ERROR("Failed to initialize media capture"); + if (!d->initialized) { + if (!d->initializing) { + hr = initialize(); + RETURN_VOID_AND_EMIT_ERROR("Failed to initialize media capture"); + } + DWORD waitResult = WaitForSingleObjectEx(d->initializationCompleteEvent, 30000, FALSE); + if (waitResult != WAIT_OBJECT_0) { + RETURN_VOID_AND_EMIT_ERROR("Failed to initialize camera control."); + return; + } + } + + d->state = QCamera::LoadedState; + emit stateChanged(d->state); + + d->status = QCamera::LoadedStatus; + emit statusChanged(d->status); } Q_ASSERT(d->state == QCamera::LoadedState); @@ -654,8 +673,23 @@ void QWinRTCameraControl::setState(QCamera::State state) case QCamera::LoadedState: { // If moving from unloaded, initialize the camera if (d->state == QCamera::UnloadedState) { - hr = initialize(); - RETURN_VOID_AND_EMIT_ERROR("Failed to initialize media capture"); + if (!d->initialized) { + if (!d->initializing) { + hr = initialize(); + RETURN_VOID_AND_EMIT_ERROR("Failed to initialize media capture"); + } + DWORD waitResult = WaitForSingleObjectEx(d->initializationCompleteEvent, 30000, FALSE); + if (waitResult != WAIT_OBJECT_0) { + RETURN_VOID_AND_EMIT_ERROR("Failed to initialize camera control."); + return; + } + } + + d->state = QCamera::LoadedState; + emit stateChanged(d->state); + + d->status = QCamera::LoadedStatus; + emit statusChanged(d->status); } // fall through } @@ -745,6 +779,7 @@ void QWinRTCameraControl::setState(QCamera::State state) d->status = QCamera::UnloadedStatus; emit statusChanged(d->status); } + d->initialized = false; } break; } @@ -884,8 +919,7 @@ HRESULT QWinRTCameraControl::initialize() emit statusChanged(d->status); } - boolean isFocusSupported; - HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([this, d, &isFocusSupported]() { + HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([this, d]() { HRESULT hr; ComPtr<IInspectable> capture; hr = RoActivateInstance(Wrappers::HString::MakeReference(RuntimeClass_Windows_Media_Capture_MediaCapture).Get(), @@ -935,121 +969,11 @@ HRESULT QWinRTCameraControl::initialize() ComPtr<IAsyncAction> 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<IVideoDeviceController> videoDeviceController; - hr = d->capture->get_VideoDeviceController(&videoDeviceController); - ComPtr<IAdvancedVideoCaptureDeviceController2> advancedVideoDeviceController; - hr = videoDeviceController.As(&advancedVideoDeviceController); - Q_ASSERT_SUCCEEDED(hr); - hr = advancedVideoDeviceController->get_FocusControl(&d->focusControl); - Q_ASSERT_SUCCEEDED(hr); - - d->cameraFlashControl->initialize(advancedVideoDeviceController); - - hr = d->focusControl->get_Supported(&isFocusSupported); - Q_ASSERT_SUCCEEDED(hr); - if (isFocusSupported) { - hr = advancedVideoDeviceController->get_RegionsOfInterestControl(&d->regionsOfInterestControl); - if (FAILED(hr)) - qCDebug(lcMMCamera) << "Focus supported, but no control for regions of interest available"; - hr = initializeFocus(); - Q_ASSERT_SUCCEEDED(hr); - } - - Q_ASSERT_SUCCEEDED(hr); - ComPtr<IMediaDeviceController> deviceController; - hr = videoDeviceController.As(&deviceController); - Q_ASSERT_SUCCEEDED(hr); - - // Get preview stream properties. - ComPtr<IVectorView<IMediaEncodingProperties *>> previewPropertiesList; - QVector<QSize> 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<IVectorView<IMediaEncodingProperties *>> capturePropertiesList; - QVector<QSize> 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<IMediaEncodingProperties> 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); - - // Set preview resolution. - QVector<QSize> filtered; - const float captureAspectRatio = float(captureResolution.width()) / captureResolution.height(); - for (const QSize &resolution : qAsConst(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<IMediaEncodingProperties> 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<IVideoEncodingProperties> 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); - + hr = op.Get()->put_Completed(Callback<IAsyncActionCompletedHandler>( + this, &QWinRTCameraControl::onInitializationCompleted).Get()); + RETURN_HR_IF_FAILED("Failed to register initialization callback"); return S_OK; }); - - if (!isFocusSupported) { - d->cameraFocusControl->setSupportedFocusMode(0); - d->cameraFocusControl->setSupportedFocusPointMode(QSet<QCameraFocus::FocusPointMode>()); - } - d->cameraLocksControl->initialize(); - - if (SUCCEEDED(hr) && d->state != QCamera::LoadedState) { - d->state = QCamera::LoadedState; - emit stateChanged(d->state); - } - if (SUCCEEDED(hr) && d->status != QCamera::LoadedStatus) { - d->status = QCamera::LoadedStatus; - emit statusChanged(d->status); - } return hr; } @@ -1413,6 +1337,122 @@ HRESULT QWinRTCameraControl::onRecordLimitationExceeded(IMediaCapture *) return S_OK; } +HRESULT QWinRTCameraControl::onInitializationCompleted(IAsyncAction *, AsyncStatus status) +{ + qCDebug(lcMMCamera) << __FUNCTION__; + Q_D(QWinRTCameraControl); + + if (status != Completed) { + d->initializing = false; + d->initialized = true; + return S_OK; + } + + ComPtr<IVideoDeviceController> videoDeviceController; + HRESULT hr = d->capture->get_VideoDeviceController(&videoDeviceController); + ComPtr<IAdvancedVideoCaptureDeviceController2> advancedVideoDeviceController; + hr = videoDeviceController.As(&advancedVideoDeviceController); + Q_ASSERT_SUCCEEDED(hr); + hr = advancedVideoDeviceController->get_FocusControl(&d->focusControl); + Q_ASSERT_SUCCEEDED(hr); + + d->cameraFlashControl->initialize(advancedVideoDeviceController); + + boolean isFocusSupported; + hr = d->focusControl->get_Supported(&isFocusSupported); + Q_ASSERT_SUCCEEDED(hr); + if (isFocusSupported) { + hr = advancedVideoDeviceController->get_RegionsOfInterestControl(&d->regionsOfInterestControl); + if (FAILED(hr)) + qCDebug(lcMMCamera) << "Focus supported, but no control for regions of interest available"; + hr = initializeFocus(); + Q_ASSERT_SUCCEEDED(hr); + } + + Q_ASSERT_SUCCEEDED(hr); + ComPtr<IMediaDeviceController> deviceController; + hr = videoDeviceController.As(&deviceController); + Q_ASSERT_SUCCEEDED(hr); + + // Get preview stream properties. + ComPtr<IVectorView<IMediaEncodingProperties *>> previewPropertiesList; + QVector<QSize> 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<IVectorView<IMediaEncodingProperties *>> capturePropertiesList; + QVector<QSize> 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<IMediaEncodingProperties> captureProperties; + hr = capturePropertiesList->GetAt(captureResolutionIndex, &captureProperties); + Q_ASSERT_SUCCEEDED(hr); + ComPtr<IAsyncAction> op; + hr = deviceController->SetMediaStreamPropertiesAsync(mediaStreamType, captureProperties.Get(), &op); + Q_ASSERT_SUCCEEDED(hr); + hr = QWinRTFunctions::await(op); + Q_ASSERT_SUCCEEDED(hr); + + // Set preview resolution. + QVector<QSize> filtered; + const float captureAspectRatio = float(captureResolution.width()) / captureResolution.height(); + for (const QSize &resolution : qAsConst(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<IMediaEncodingProperties> 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<IVideoEncodingProperties> 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); + + if (!isFocusSupported) { + d->cameraFocusControl->setSupportedFocusMode(0); + d->cameraFocusControl->setSupportedFocusPointMode(QSet<QCameraFocus::FocusPointMode>()); + } + d->cameraLocksControl->initialize(); + + d->initializing = false; + d->initialized = true; + SetEvent(d->initializationCompleteEvent); + return S_OK; +} + void QWinRTCameraControl::emitError(int errorCode, const QString &errorString) { qCDebug(lcMMCamera) << __FUNCTION__ << errorString << errorCode; diff --git a/src/plugins/winrt/qwinrtcameracontrol.h b/src/plugins/winrt/qwinrtcameracontrol.h index a24cd462c..c46921a9c 100644 --- a/src/plugins/winrt/qwinrtcameracontrol.h +++ b/src/plugins/winrt/qwinrtcameracontrol.h @@ -123,6 +123,8 @@ private: HRESULT onCaptureFailed(ABI::Windows::Media::Capture::IMediaCapture *, ABI::Windows::Media::Capture::IMediaCaptureFailedEventArgs *); HRESULT onRecordLimitationExceeded(ABI::Windows::Media::Capture::IMediaCapture *); + HRESULT onInitializationCompleted(ABI::Windows::Foundation::IAsyncAction *, + ABI::Windows::Foundation::AsyncStatus); QScopedPointer<QWinRTCameraControlPrivate> d_ptr; Q_DECLARE_PRIVATE(QWinRTCameraControl) |