diff options
Diffstat (limited to 'src/plugins/winrt/qwinrtcameracontrol.cpp')
-rw-r--r-- | src/plugins/winrt/qwinrtcameracontrol.cpp | 1468 |
1 files changed, 0 insertions, 1468 deletions
diff --git a/src/plugins/winrt/qwinrtcameracontrol.cpp b/src/plugins/winrt/qwinrtcameracontrol.cpp deleted file mode 100644 index 98dd7c2f7..000000000 --- a/src/plugins/winrt/qwinrtcameracontrol.cpp +++ /dev/null @@ -1,1468 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qwinrtcameracontrol.h" -#include "qwinrtcameravideorenderercontrol.h" -#include "qwinrtvideodeviceselectorcontrol.h" -#include "qwinrtcameraimagecapturecontrol.h" -#include "qwinrtimageencodercontrol.h" -#include "qwinrtcameraflashcontrol.h" -#include "qwinrtcamerafocuscontrol.h" -#include "qwinrtcameralockscontrol.h" - -#include <QtCore/qfunctions_winrt.h> -#include <QtCore/QMutex> -#include <QtCore/QPointer> -#include <QtGui/QGuiApplication> -#include <private/qeventdispatcher_winrt_p.h> - -#include <functional> -#include <mfapi.h> -#include <mferror.h> -#include <mfidl.h> -#include <wrl.h> -#include <windows.devices.enumeration.h> -#include <windows.media.capture.h> -#include <windows.storage.streams.h> -#include <windows.media.devices.h> - -#include <algorithm> - -using namespace Microsoft::WRL; -using namespace Microsoft::WRL::Wrappers; -using namespace ABI::Windows::Devices::Enumeration; -using namespace ABI::Windows::Foundation; -using namespace ABI::Windows::Foundation::Collections; -using namespace ABI::Windows::Media; -using namespace ABI::Windows::Media::Capture; -using namespace ABI::Windows::Media::Devices; -using namespace ABI::Windows::Media::MediaProperties; -using namespace ABI::Windows::Storage::Streams; - -QT_BEGIN_NAMESPACE - -#define RETURN_VOID_AND_EMIT_ERROR(msg) \ - if (FAILED(hr)) { \ - emit error(QCamera::CameraError, qt_error_string(hr)); \ - RETURN_VOID_IF_FAILED(msg); \ - } - -#define FOCUS_RECT_SIZE 0.01f -#define FOCUS_RECT_HALF_SIZE 0.005f // FOCUS_RECT_SIZE / 2 -#define FOCUS_RECT_BOUNDARY 1.0f -#define FOCUS_RECT_POSITION_MIN 0.0f -#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<IMediaEncodingProperties *> **propertiesList, - QVector<QSize> *resolutions) -{ - HRESULT hr; - hr = device->GetAvailableMediaStreamProperties(type, propertiesList); - Q_ASSERT_SUCCEEDED(hr); - quint32 listSize; - hr = (*propertiesList)->get_Size(&listSize); - Q_ASSERT_SUCCEEDED(hr); - resolutions->reserve(int(listSize)); - for (quint32 index = 0; index < listSize; ++index) { - ComPtr<IMediaEncodingProperties> properties; - hr = (*propertiesList)->GetAt(index, &properties); - Q_ASSERT_SUCCEEDED(hr); - HString propertyType; - hr = properties->get_Type(propertyType.GetAddressOf()); - Q_ASSERT_SUCCEEDED(hr); - - const HStringReference videoRef = HString::MakeReference(L"Video"); - const HStringReference imageRef = HString::MakeReference(L"Image"); - if (propertyType == videoRef) { - ComPtr<IVideoEncodingProperties> videoProperties; - hr = properties.As(&videoProperties); - Q_ASSERT_SUCCEEDED(hr); - UINT32 width, height; - hr = videoProperties->get_Width(&width); - Q_ASSERT_SUCCEEDED(hr); - hr = videoProperties->get_Height(&height); - Q_ASSERT_SUCCEEDED(hr); - resolutions->append(QSize(int(width), int(height))); - } else if (propertyType == imageRef) { - ComPtr<IImageEncodingProperties> imageProperties; - hr = properties.As(&imageProperties); - Q_ASSERT_SUCCEEDED(hr); - UINT32 width, height; - hr = imageProperties->get_Width(&width); - Q_ASSERT_SUCCEEDED(hr); - hr = imageProperties->get_Height(&height); - Q_ASSERT_SUCCEEDED(hr); - resolutions->append(QSize(int(width), int(height))); - } - } - return resolutions->isEmpty() ? MF_E_INVALID_FORMAT : hr; -} - -template<typename T, size_t typeSize> struct CustomPropertyValue; - -inline static ComPtr<IPropertyValueStatics> propertyValueStatics() -{ - ComPtr<IPropertyValueStatics> valueStatics; - GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Foundation_PropertyValue).Get(), &valueStatics); - return valueStatics; -} - -template <typename T> -struct CustomPropertyValue<T, 4> -{ - static ComPtr<IReference<T>> create(T value) - { - ComPtr<IInspectable> propertyValueObject; - HRESULT hr = propertyValueStatics()->CreateUInt32(value, &propertyValueObject); - ComPtr<IReference<UINT32>> uint32Object; - Q_ASSERT_SUCCEEDED(hr); - hr = propertyValueObject.As(&uint32Object); - Q_ASSERT_SUCCEEDED(hr); - return reinterpret_cast<IReference<T> *>(uint32Object.Get()); - } -}; - -template <typename T> -struct CustomPropertyValue<T, 8> -{ - static ComPtr<IReference<T>> create(T value) - { - ComPtr<IInspectable> propertyValueObject; - HRESULT hr = propertyValueStatics()->CreateUInt64(value, &propertyValueObject); - ComPtr<IReference<UINT64>> uint64Object; - Q_ASSERT_SUCCEEDED(hr); - hr = propertyValueObject.As(&uint64Object); - Q_ASSERT_SUCCEEDED(hr); - return reinterpret_cast<IReference<T> *>(uint64Object.Get()); - } -}; - -// Required camera point focus -class WindowsRegionOfInterestIterableIterator : public RuntimeClass<IIterator<RegionOfInterest *>> -{ -public: - explicit WindowsRegionOfInterestIterableIterator(const ComPtr<IRegionOfInterest> &item) - { - regionOfInterest = item; - } - HRESULT __stdcall get_Current(IRegionOfInterest **current) - { - *current = regionOfInterest.Detach(); - return S_OK; - } - HRESULT __stdcall get_HasCurrent(boolean *hasCurrent) - { - *hasCurrent = true; - return S_OK; - } - HRESULT __stdcall MoveNext(boolean *hasCurrent) - { - *hasCurrent = false; - return S_OK; - } -private: - ComPtr<IRegionOfInterest> regionOfInterest; -}; - -class WindowsRegionOfInterestIterable : public RuntimeClass<IIterable<RegionOfInterest *>> -{ -public: - explicit WindowsRegionOfInterestIterable(const ComPtr<IRegionOfInterest> &item) - { - regionOfInterest = item; - } - HRESULT __stdcall First(IIterator<RegionOfInterest *> **first) - { - ComPtr<WindowsRegionOfInterestIterableIterator> iterator = Make<WindowsRegionOfInterestIterableIterator>(regionOfInterest); - *first = iterator.Detach(); - return S_OK; - } -private: - ComPtr<IRegionOfInterest> regionOfInterest; -}; - -class MediaStream : public RuntimeClass<RuntimeClassFlags<WinRtClassicComMix>, IMFStreamSink, IMFMediaEventGenerator, IMFMediaTypeHandler> -{ -public: - MediaStream(IMFMediaType *type, IMFMediaSink *mediaSink, QWinRTCameraVideoRendererControl *videoRenderer) - : m_type(type), m_sink(mediaSink), m_videoRenderer(videoRenderer) - { - Q_ASSERT(m_videoRenderer); - - HRESULT hr; - hr = MFCreateEventQueue(&m_eventQueue); - Q_ASSERT_SUCCEEDED(hr); - hr = MFAllocateSerialWorkQueue(MFASYNC_CALLBACK_QUEUE_STANDARD, &m_workQueueId); - Q_ASSERT_SUCCEEDED(hr); - } - - ~MediaStream() override - { - QMutexLocker locker(&m_mutex); - m_eventQueue->Shutdown(); - } - - HRESULT RequestSample() - { - if (m_pendingSamples.load() < 3) { - m_pendingSamples.ref(); - return QueueEvent(MEStreamSinkRequestSample, GUID_NULL, S_OK, nullptr); - } - return S_OK; - } - - HRESULT __stdcall GetEvent(DWORD flags, IMFMediaEvent **event) override - { - QMutexLocker locker(&m_mutex); - // Create an extra reference to avoid deadlock - ComPtr<IMFMediaEventQueue> eventQueue = m_eventQueue; - locker.unlock(); - - return eventQueue->GetEvent(flags, event); - } - - HRESULT __stdcall BeginGetEvent(IMFAsyncCallback *callback, IUnknown *state) override - { - QMutexLocker locker(&m_mutex); - HRESULT hr = m_eventQueue->BeginGetEvent(callback, state); - return hr; - } - - HRESULT __stdcall EndGetEvent(IMFAsyncResult *result, IMFMediaEvent **event) override - { - QMutexLocker locker(&m_mutex); - return m_eventQueue->EndGetEvent(result, event); - } - - HRESULT __stdcall QueueEvent(MediaEventType eventType, const GUID &extendedType, HRESULT status, const PROPVARIANT *value) override - { - QMutexLocker locker(&m_mutex); - return m_eventQueue->QueueEventParamVar(eventType, extendedType, status, value); - } - - HRESULT __stdcall GetMediaSink(IMFMediaSink **mediaSink) override - { - m_sink->AddRef(); - *mediaSink = m_sink; - return S_OK; - } - - HRESULT __stdcall GetIdentifier(DWORD *identifier) override - { - *identifier = 0; - return S_OK; - } - - HRESULT __stdcall GetMediaTypeHandler(IMFMediaTypeHandler **handler) override - { - return QueryInterface(IID_PPV_ARGS(handler)); - } - - HRESULT __stdcall ProcessSample(IMFSample *sample) override - { - ComPtr<IMFMediaBuffer> buffer; - HRESULT hr = sample->GetBufferByIndex(0, &buffer); - RETURN_HR_IF_FAILED("Failed to get buffer from camera sample"); - ComPtr<IMF2DBuffer> buffer2d; - hr = buffer.As(&buffer2d); - RETURN_HR_IF_FAILED("Failed to cast camera sample buffer to 2D buffer"); - - m_pendingSamples.deref(); - m_videoRenderer->queueBuffer(buffer2d.Get()); - - return hr; - } - - HRESULT __stdcall PlaceMarker(MFSTREAMSINK_MARKER_TYPE type, const PROPVARIANT *value, const PROPVARIANT *context) override - { - Q_UNUSED(type); - Q_UNUSED(value); - QueueEvent(MEStreamSinkMarker, GUID_NULL, S_OK, context); - return S_OK; - } - - HRESULT __stdcall Flush() override - { - m_videoRenderer->discardBuffers(); - m_pendingSamples.store(0); - return S_OK; - } - - HRESULT __stdcall IsMediaTypeSupported(IMFMediaType *type, IMFMediaType **) override - { - HRESULT hr; - GUID majorType; - hr = type->GetMajorType(&majorType); - Q_ASSERT_SUCCEEDED(hr); - if (!IsEqualGUID(majorType, MFMediaType_Video)) - return MF_E_INVALIDMEDIATYPE; - return S_OK; - } - - HRESULT __stdcall GetMediaTypeCount(DWORD *typeCount) override - { - *typeCount = 1; - return S_OK; - } - - HRESULT __stdcall GetMediaTypeByIndex(DWORD index, IMFMediaType **type) override - { - if (index == 0) - return m_type.CopyTo(type); - return E_BOUNDS; - } - - HRESULT __stdcall SetCurrentMediaType(IMFMediaType *type) override - { - if (FAILED(IsMediaTypeSupported(type, nullptr))) - return MF_E_INVALIDREQUEST; - - m_type = type; - return S_OK; - } - - HRESULT __stdcall GetCurrentMediaType(IMFMediaType **type) override - { - return m_type.CopyTo(type); - } - - HRESULT __stdcall GetMajorType(GUID *majorType) override - { - return m_type->GetMajorType(majorType); - } - -private: - QMutex m_mutex; - ComPtr<IMFMediaType> m_type; - IMFMediaSink *m_sink; - ComPtr<IMFMediaEventQueue> m_eventQueue; - DWORD m_workQueueId; - - QWinRTCameraVideoRendererControl *m_videoRenderer; - QAtomicInt m_pendingSamples; -}; - -class MediaSink : public RuntimeClass<RuntimeClassFlags<WinRtClassicComMix>, IMediaExtension, IMFMediaSink, IMFClockStateSink> -{ -public: - MediaSink(IMediaEncodingProfile *encodingProfile, QWinRTCameraVideoRendererControl *videoRenderer) - : m_videoRenderer(videoRenderer) - { - HRESULT hr; - ComPtr<IVideoEncodingProperties> videoProperties; - hr = encodingProfile->get_Video(&videoProperties); - RETURN_VOID_IF_FAILED("Failed to get video properties"); - ComPtr<IMFMediaType> videoType; - hr = MFCreateMediaTypeFromProperties(videoProperties.Get(), &videoType); - RETURN_VOID_IF_FAILED("Failed to create video type"); - m_stream = Make<MediaStream>(videoType.Get(), this, videoRenderer); - } - - ~MediaSink() override = default; - - HRESULT RequestSample() - { - return m_stream->RequestSample(); - } - - HRESULT __stdcall SetProperties(Collections::IPropertySet *configuration) override - { - Q_UNUSED(configuration); - return E_NOTIMPL; - } - - HRESULT __stdcall GetCharacteristics(DWORD *characteristics) override - { - *characteristics = MEDIASINK_FIXED_STREAMS | MEDIASINK_RATELESS; - return S_OK; - } - - HRESULT __stdcall AddStreamSink(DWORD streamSinkIdentifier, IMFMediaType *mediaType, IMFStreamSink **streamSink) override - { - Q_UNUSED(streamSinkIdentifier); - Q_UNUSED(mediaType); - Q_UNUSED(streamSink); - return E_NOTIMPL; - } - - HRESULT __stdcall RemoveStreamSink(DWORD streamSinkIdentifier) override - { - Q_UNUSED(streamSinkIdentifier); - return E_NOTIMPL; - } - - HRESULT __stdcall GetStreamSinkCount(DWORD *streamSinkCount) override - { - *streamSinkCount = 1; - return S_OK; - } - - HRESULT __stdcall GetStreamSinkByIndex(DWORD index, IMFStreamSink **streamSink) override - { - if (index == 0) - return m_stream.CopyTo(streamSink); - return MF_E_INVALIDINDEX; - } - - HRESULT __stdcall GetStreamSinkById(DWORD streamSinkIdentifier, IMFStreamSink **streamSink) override - { - // ID and index are always 0 - HRESULT hr = GetStreamSinkByIndex(streamSinkIdentifier, streamSink); - return hr == MF_E_INVALIDINDEX ? MF_E_INVALIDSTREAMNUMBER : hr; - } - - HRESULT __stdcall SetPresentationClock(IMFPresentationClock *presentationClock) override - { - HRESULT hr = S_OK; - m_presentationClock = presentationClock; - if (m_presentationClock) - hr = m_presentationClock->AddClockStateSink(this); - return hr; - } - - HRESULT __stdcall GetPresentationClock(IMFPresentationClock **presentationClock) override - { - return m_presentationClock.CopyTo(presentationClock); - } - - HRESULT __stdcall Shutdown() override - { - m_stream->Flush(); - scheduleSetActive(false); - return m_presentationClock ? m_presentationClock->Stop() : S_OK; - } - - HRESULT __stdcall OnClockStart(MFTIME systemTime, LONGLONG clockStartOffset) override - { - Q_UNUSED(systemTime); - Q_UNUSED(clockStartOffset); - - scheduleSetActive(true); - - return S_OK; - } - - HRESULT __stdcall OnClockStop(MFTIME systemTime) override - { - Q_UNUSED(systemTime); - - scheduleSetActive(false); - - return m_stream->QueueEvent(MEStreamSinkStopped, GUID_NULL, S_OK, nullptr); - } - - HRESULT __stdcall OnClockPause(MFTIME systemTime) override - { - Q_UNUSED(systemTime); - - scheduleSetActive(false); - - return m_stream->QueueEvent(MEStreamSinkPaused, GUID_NULL, S_OK, nullptr); - } - - HRESULT __stdcall OnClockRestart(MFTIME systemTime) override - { - Q_UNUSED(systemTime); - - scheduleSetActive(true); - - return m_stream->QueueEvent(MEStreamSinkStarted, GUID_NULL, S_OK, nullptr); - } - - HRESULT __stdcall OnClockSetRate(MFTIME systemTime, float rate) override - { - Q_UNUSED(systemTime); - Q_UNUSED(rate); - return E_NOTIMPL; - } - -private: - - inline void scheduleSetActive(bool active) - { - QMetaObject::invokeMethod(m_videoRenderer, "setActive", Qt::QueuedConnection, Q_ARG(bool, active)); - } - - ComPtr<MediaStream> m_stream; - ComPtr<IMFPresentationClock> m_presentationClock; - - QWinRTCameraVideoRendererControl *m_videoRenderer; -}; - -class QWinRTCameraControlPrivate -{ -public: - QCamera::State state; - QCamera::Status status; - QCamera::CaptureModes captureMode; - - ComPtr<IMediaCapture> capture; - ComPtr<IMediaCaptureVideoPreview> capturePreview; - EventRegistrationToken captureFailedCookie; - EventRegistrationToken recordLimitationCookie; - - ComPtr<IMediaEncodingProfileStatics> encodingProfileFactory; - - ComPtr<IMediaEncodingProfile> encodingProfile; - ComPtr<MediaSink> mediaSink; - ComPtr<IFocusControl> focusControl; - ComPtr<IRegionsOfInterestControl> regionsOfInterestControl; - ComPtr<IAsyncAction> focusOperation; - - QPointer<QWinRTCameraVideoRendererControl> videoRenderer; - QPointer<QWinRTVideoDeviceSelectorControl> videoDeviceSelector; - QPointer<QWinRTCameraImageCaptureControl> imageCaptureControl; - QPointer<QWinRTImageEncoderControl> imageEncoderControl; - QPointer<QWinRTCameraFlashControl> cameraFlashControl; - QPointer<QWinRTCameraFocusControl> cameraFocusControl; - QPointer<QWinRTCameraLocksControl> cameraLocksControl; - QAtomicInt framesMapped; - QEventLoop *delayClose; - - bool initializing = false; - bool initialized = false; - HANDLE initializationCompleteEvent; -}; - -QWinRTCameraControl::QWinRTCameraControl(QObject *parent) - : QCameraControl(parent), d_ptr(new QWinRTCameraControlPrivate) -{ - qCDebug(lcMMCamera) << __FUNCTION__ << parent; - Q_D(QWinRTCameraControl); - - d->delayClose = nullptr; - d->state = QCamera::UnloadedState; - d->status = QCamera::UnloadedStatus; - d->captureMode = QCamera::CaptureStillImage; - d->captureFailedCookie.value = 0; - d->recordLimitationCookie.value = 0; - d->videoRenderer = new QWinRTCameraVideoRendererControl(QSize(), this); - connect(d->videoRenderer, &QWinRTCameraVideoRendererControl::bufferRequested, - this, &QWinRTCameraControl::onBufferRequested); - d->videoDeviceSelector = new QWinRTVideoDeviceSelectorControl(this); - connect(d->videoDeviceSelector, QOverload<int>::of(&QWinRTVideoDeviceSelectorControl::selectedDeviceChanged), - d->videoRenderer, &QWinRTCameraVideoRendererControl::resetSampleFormat); - d->imageCaptureControl = new QWinRTCameraImageCaptureControl(this); - d->imageEncoderControl = new QWinRTImageEncoderControl(this); - d->cameraFlashControl = new QWinRTCameraFlashControl(this); - d->cameraFocusControl = new QWinRTCameraFocusControl(this); - d->cameraLocksControl = new QWinRTCameraLocksControl(this); - - d->initializationCompleteEvent = CreateEvent(nullptr, false, false, nullptr); - - if (qGuiApp) { - connect(qGuiApp, &QGuiApplication::applicationStateChanged, - this, &QWinRTCameraControl::onApplicationStateChanged); - } -} - -QWinRTCameraControl::~QWinRTCameraControl() -{ - setState(QCamera::UnloadedState); -} - -QCamera::State QWinRTCameraControl::state() const -{ - Q_D(const QWinRTCameraControl); - return d->state; -} - -void QWinRTCameraControl::setState(QCamera::State state) -{ - qCDebug(lcMMCamera) << __FUNCTION__ << state; - Q_D(QWinRTCameraControl); - - if (d->state == state) - return; - - HRESULT hr; - switch (state) { - case QCamera::ActiveState: { - // Capture has not been created or initialized - if (d->state == QCamera::UnloadedState) { - 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); - - ComPtr<IAsyncAction> op; - hr = QEventDispatcherWinRT::runOnXamlThread([d, &op]() { - d->mediaSink = Make<MediaSink>(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 = 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 - return; - } - - QCameraFocus::FocusModes focusMode = d->cameraFocusControl->focusMode(); - if (focusMode != 0 && setFocus(focusMode) && focusMode == QCameraFocus::ContinuousFocus) - focus(); - - d->state = QCamera::ActiveState; - emit stateChanged(d->state); - d->status = QCamera::ActiveStatus; - emit statusChanged(d->status); - QEventDispatcherWinRT::runOnXamlThread([d]() { d->mediaSink->RequestSample(); return S_OK;}); - break; - } - case QCamera::LoadedState: { - // If moving from unloaded, initialize the camera - if (d->state == QCamera::UnloadedState) { - 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 - } - case QCamera::UnloadedState: { - // Stop the camera if it is running (transition to LoadedState) - if (d->status == QCamera::ActiveStatus) { - HRESULT hr; - if (d->focusOperation) { - hr = QWinRTFunctions::await(d->focusOperation); - Q_ASSERT_SUCCEEDED(hr); - } - if (d->framesMapped > 0) { - qWarning("%d QVideoFrame(s) mapped when closing down camera. Camera will wait for unmap before closing down.", - d->framesMapped); - if (!d->delayClose) - d->delayClose = new QEventLoop(this); - d->delayClose->exec(); - } - - ComPtr<IAsyncAction> 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 = 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; - emit stateChanged(d->state); - - d->status = QCamera::LoadedStatus; - emit statusChanged(d->status); - } - // Completely unload if needed - if (state == QCamera::UnloadedState) { - if (!d->capture) // Already unloaded - break; - - if (d->status != QCamera::UnloadingStatus) { - d->status = QCamera::UnloadingStatus; - emit statusChanged(d->status); - } - - 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<IClosable> capture; - hr = d->capture.As(&capture); - Q_ASSERT_SUCCEEDED(hr); - hr = capture->Close(); - RETURN_HR_IF_FAILED(""); - d->capture.Reset(); - return hr; - }); - RETURN_VOID_AND_EMIT_ERROR("Failed to close the capture manger"); - if (d->state != QCamera::UnloadedState) { - d->state = QCamera::UnloadedState; - emit stateChanged(d->state); - } - if (d->status != QCamera::UnloadedStatus) { - d->status = QCamera::UnloadedStatus; - emit statusChanged(d->status); - } - d->initialized = false; - } - break; - } - default: - break; - } -} - -QCamera::Status QWinRTCameraControl::status() const -{ - Q_D(const QWinRTCameraControl); - return d->status; -} - -QCamera::CaptureModes QWinRTCameraControl::captureMode() const -{ - Q_D(const QWinRTCameraControl); - return d->captureMode; -} - -void QWinRTCameraControl::setCaptureMode(QCamera::CaptureModes mode) -{ - qCDebug(lcMMCamera) << __FUNCTION__ << mode; - Q_D(QWinRTCameraControl); - - if (d->captureMode == mode) - return; - - if (!isCaptureModeSupported(mode)) { - qWarning("Unsupported capture mode: %d", mode); - return; - } - - d->captureMode = mode; - emit captureModeChanged(d->captureMode); -} - -bool QWinRTCameraControl::isCaptureModeSupported(QCamera::CaptureModes mode) const -{ - return mode >= QCamera::CaptureViewfinder && mode <= QCamera::CaptureStillImage; -} - -bool QWinRTCameraControl::canChangeProperty(QCameraControl::PropertyChangeType changeType, QCamera::Status status) const -{ - Q_UNUSED(changeType); - - return status == QCamera::UnloadedStatus; // For now, assume shutdown is required for all property changes -} - -QVideoRendererControl *QWinRTCameraControl::videoRenderer() const -{ - Q_D(const QWinRTCameraControl); - return d->videoRenderer; -} - -QVideoDeviceSelectorControl *QWinRTCameraControl::videoDeviceSelector() const -{ - Q_D(const QWinRTCameraControl); - return d->videoDeviceSelector; -} - -QCameraImageCaptureControl *QWinRTCameraControl::imageCaptureControl() const -{ - Q_D(const QWinRTCameraControl); - return d->imageCaptureControl; -} - -QImageEncoderControl *QWinRTCameraControl::imageEncoderControl() const -{ - Q_D(const QWinRTCameraControl); - return d->imageEncoderControl; -} - -QCameraFlashControl *QWinRTCameraControl::cameraFlashControl() const -{ - Q_D(const QWinRTCameraControl); - return d->cameraFlashControl; -} - -QCameraFocusControl *QWinRTCameraControl::cameraFocusControl() const -{ - Q_D(const QWinRTCameraControl); - return d->cameraFocusControl; -} - -QCameraLocksControl *QWinRTCameraControl::cameraLocksControl() const -{ - Q_D(const QWinRTCameraControl); - return d->cameraLocksControl; -} - -Microsoft::WRL::ComPtr<ABI::Windows::Media::Capture::IMediaCapture> QWinRTCameraControl::handle() const -{ - Q_D(const QWinRTCameraControl); - return d->capture; -} - -void QWinRTCameraControl::onBufferRequested() -{ - Q_D(QWinRTCameraControl); - - if (d->mediaSink) - d->mediaSink->RequestSample(); -} - -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) { - case Qt::ApplicationInactive: - if (d->state != QCamera::UnloadedState) { - savedState = d->state; - setState(QCamera::UnloadedState); - } - break; - case Qt::ApplicationActive: - setState(QCamera::State(savedState)); - break; - default: - break; - } -#endif // _DEBUG -} - -HRESULT QWinRTCameraControl::initialize() -{ - qCDebug(lcMMCamera) << __FUNCTION__; - Q_D(QWinRTCameraControl); - - if (d->status != QCamera::LoadingStatus) { - d->status = QCamera::LoadingStatus; - emit statusChanged(d->status); - } - - HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([this, d]() { - HRESULT hr; - ComPtr<IInspectable> 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<IMediaCaptureFailedEventHandler>(this, &QWinRTCameraControl::onCaptureFailed).Get(), - &d->captureFailedCookie); - Q_ASSERT_SUCCEEDED(hr); - hr = d->capture->add_RecordLimitationExceeded(Callback<IRecordLimitationExceededEventHandler>(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(); - - const QString deviceName = d->videoDeviceSelector->deviceName(deviceIndex); - if (deviceName.isEmpty()) { - qWarning("No video device available or selected."); - return E_FAIL; - } - - d->videoRenderer->setScanLineDirection(QVideoSurfaceFormat::TopToBottom); - ComPtr<IMediaCaptureInitializationSettings> settings; - hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Media_Capture_MediaCaptureInitializationSettings).Get(), - &settings); - Q_ASSERT_SUCCEEDED(hr); - HStringReference deviceId(reinterpret_cast<LPCWSTR>(deviceName.utf16()), uint(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_PhotoCaptureSource(PhotoCaptureSource_Auto); - Q_ASSERT_SUCCEEDED(hr); - - ComPtr<IAsyncAction> op; - hr = d->capture->InitializeWithSettingsAsync(settings.Get(), &op); - RETURN_HR_IF_FAILED("Failed to begin initialization of media capture manager"); - hr = op.Get()->put_Completed(Callback<IAsyncActionCompletedHandler>( - this, &QWinRTCameraControl::onInitializationCompleted).Get()); - RETURN_HR_IF_FAILED("Failed to register initialization callback"); - return S_OK; - }); - return hr; -} - -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) - -HRESULT QWinRTCameraControl::initializeFocus() -{ - Q_D(QWinRTCameraControl); - ComPtr<IFocusControl2> focusControl2; - HRESULT hr = d->focusControl.As(&focusControl2); - Q_ASSERT_SUCCEEDED(hr); - ComPtr<IVectorView<enum FocusMode>> focusModes; - hr = focusControl2->get_SupportedFocusModes(&focusModes); - if (FAILED(hr)) { - d->cameraFocusControl->setSupportedFocusMode(nullptr); - d->cameraFocusControl->setSupportedFocusPointMode(QSet<QCameraFocus::FocusPointMode>()); - qErrnoWarning(hr, "Failed to get camera supported focus mode list"); - return hr; - } - quint32 size; - hr = focusModes->get_Size(&size); - Q_ASSERT_SUCCEEDED(hr); - QCameraFocus::FocusModes supportedModeFlag = nullptr; - for (quint32 i = 0; i < size; ++i) { - FocusMode mode; - hr = focusModes->GetAt(i, &mode); - Q_ASSERT_SUCCEEDED(hr); - switch (mode) { - case FocusMode_Continuous: - supportedModeFlag |= QCameraFocus::ContinuousFocus; - break; - case FocusMode_Single: - supportedModeFlag |= QCameraFocus::AutoFocus; - break; - default: - break; - } - } - - ComPtr<IVectorView<enum AutoFocusRange>> focusRange; - hr = focusControl2->get_SupportedFocusRanges(&focusRange); - if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to get camera supported focus range list"); - } else { - hr = focusRange->get_Size(&size); - Q_ASSERT_SUCCEEDED(hr); - for (quint32 i = 0; i < size; ++i) { - AutoFocusRange range; - hr = focusRange->GetAt(i, &range); - Q_ASSERT_SUCCEEDED(hr); - switch (range) { - case AutoFocusRange_Macro: - supportedModeFlag |= QCameraFocus::MacroFocus; - break; - case AutoFocusRange_FullRange: - supportedModeFlag |= QCameraFocus::InfinityFocus; - break; - default: - break; - } - } - } - d->cameraFocusControl->setSupportedFocusMode(supportedModeFlag); - if (!d->regionsOfInterestControl) { - d->cameraFocusControl->setSupportedFocusPointMode(QSet<QCameraFocus::FocusPointMode>()); - return S_OK; - } - boolean isRegionsfocusSupported = false; - hr = d->regionsOfInterestControl->get_AutoFocusSupported(&isRegionsfocusSupported); - Q_ASSERT_SUCCEEDED(hr); - UINT32 maxRegions; - hr = d->regionsOfInterestControl->get_MaxRegions(&maxRegions); - Q_ASSERT_SUCCEEDED(hr); - if (!isRegionsfocusSupported || maxRegions == 0) { - d->cameraFocusControl->setSupportedFocusPointMode(QSet<QCameraFocus::FocusPointMode>()); - return S_OK; - } - QSet<QCameraFocus::FocusPointMode> supportedFocusPointModes; - supportedFocusPointModes << QCameraFocus::FocusPointCustom - << QCameraFocus::FocusPointCenter - << QCameraFocus::FocusPointAuto; - d->cameraFocusControl->setSupportedFocusPointMode(supportedFocusPointModes); - return S_OK; -} - -bool QWinRTCameraControl::setFocus(QCameraFocus::FocusModes modes) -{ - Q_D(QWinRTCameraControl); - if (d->status == QCamera::UnloadedStatus) - return false; - - bool result = false; - HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([modes, &result, d, this]() { - ComPtr<IFocusSettings> focusSettings; - ComPtr<IInspectable> focusSettingsObject; - HRESULT hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Media_Devices_FocusSettings).Get(), &focusSettingsObject); - Q_ASSERT_SUCCEEDED(hr); - hr = focusSettingsObject.As(&focusSettings); - Q_ASSERT_SUCCEEDED(hr); - FocusMode mode; - if (modes.testFlag(QCameraFocus::ContinuousFocus)) { - mode = FocusMode_Continuous; - } else if (modes.testFlag(QCameraFocus::AutoFocus) - || modes.testFlag(QCameraFocus::MacroFocus) - || modes.testFlag(QCameraFocus::InfinityFocus)) { - // The Macro and infinity focus modes are only supported in auto focus mode on WinRT. - // QML camera focus doesn't support combined focus flags settings. In the case of macro - // and infinity Focus modes, the auto focus setting is applied. - mode = FocusMode_Single; - } else { - emit error(QCamera::NotSupportedFeatureError, QStringLiteral("Unsupported camera focus modes.")); - result = false; - return S_OK; - } - hr = focusSettings->put_Mode(mode); - Q_ASSERT_SUCCEEDED(hr); - AutoFocusRange range = AutoFocusRange_Normal; - if (modes.testFlag(QCameraFocus::MacroFocus)) - range = AutoFocusRange_Macro; - else if (modes.testFlag(QCameraFocus::InfinityFocus)) - range = AutoFocusRange_FullRange; - hr = focusSettings->put_AutoFocusRange(range); - Q_ASSERT_SUCCEEDED(hr); - hr = focusSettings->put_WaitForFocus(true); - Q_ASSERT_SUCCEEDED(hr); - hr = focusSettings->put_DisableDriverFallback(false); - Q_ASSERT_SUCCEEDED(hr); - - ComPtr<IFocusControl2> focusControl2; - hr = d->focusControl.As(&focusControl2); - Q_ASSERT_SUCCEEDED(hr); - hr = focusControl2->Configure(focusSettings.Get()); - result = SUCCEEDED(hr); - RETURN_OK_IF_FAILED("Failed to configure camera focus control"); - return S_OK; - }); - Q_ASSERT_SUCCEEDED(hr); - Q_UNUSED(hr); // Silence release build - return result; -} - -bool QWinRTCameraControl::setFocusPoint(const QPointF &focusPoint) -{ - Q_D(QWinRTCameraControl); - if (focusPoint.x() < double(FOCUS_RECT_POSITION_MIN) - || focusPoint.x() > double(FOCUS_RECT_BOUNDARY)) { - emit error(QCamera::CameraError, QStringLiteral("Focus horizontal location should be between 0.0 and 1.0.")); - return false; - } - - if (focusPoint.y() < double(FOCUS_RECT_POSITION_MIN) - || focusPoint.y() > double(FOCUS_RECT_BOUNDARY)) { - emit error(QCamera::CameraError, QStringLiteral("Focus vertical location should be between 0.0 and 1.0.")); - return false; - } - - ABI::Windows::Foundation::Rect rect; - rect.X = qBound<float>(FOCUS_RECT_POSITION_MIN, float(focusPoint.x() - double(FOCUS_RECT_HALF_SIZE)), FOCUS_RECT_POSITION_MAX); - rect.Y = qBound<float>(FOCUS_RECT_POSITION_MIN, float(focusPoint.y() - double(FOCUS_RECT_HALF_SIZE)), FOCUS_RECT_POSITION_MAX); - rect.Width = (rect.X + FOCUS_RECT_SIZE) < FOCUS_RECT_BOUNDARY ? FOCUS_RECT_SIZE : FOCUS_RECT_BOUNDARY - rect.X; - rect.Height = (rect.Y + FOCUS_RECT_SIZE) < FOCUS_RECT_BOUNDARY ? FOCUS_RECT_SIZE : FOCUS_RECT_BOUNDARY - rect.Y; - - ComPtr<IRegionOfInterest> regionOfInterest; - ComPtr<IInspectable> regionOfInterestObject; - HRESULT hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Media_Devices_RegionOfInterest).Get(), ®ionOfInterestObject); - Q_ASSERT_SUCCEEDED(hr); - hr = regionOfInterestObject.As(®ionOfInterest); - Q_ASSERT_SUCCEEDED(hr); - ComPtr<IRegionOfInterest2> regionOfInterest2; - hr = regionOfInterestObject.As(®ionOfInterest2); - Q_ASSERT_SUCCEEDED(hr); - hr = regionOfInterest2->put_BoundsNormalized(true); - Q_ASSERT_SUCCEEDED(hr); - hr = regionOfInterest2->put_Weight(1); - Q_ASSERT_SUCCEEDED(hr); - hr = regionOfInterest2->put_Type(RegionOfInterestType_Unknown); - Q_ASSERT_SUCCEEDED(hr); - hr = regionOfInterest->put_AutoFocusEnabled(true); - Q_ASSERT_SUCCEEDED(hr); - hr = regionOfInterest->put_Bounds(rect); - Q_ASSERT_SUCCEEDED(hr); - - ComPtr<WindowsRegionOfInterestIterable> regionOfInterestIterable = Make<WindowsRegionOfInterestIterable>(regionOfInterest); - ComPtr<IAsyncAction> op; - hr = d->regionsOfInterestControl->SetRegionsAsync(regionOfInterestIterable.Get(), &op); - Q_ASSERT_SUCCEEDED(hr); - return QWinRTFunctions::await(op) == S_OK; -} - -bool QWinRTCameraControl::focus() -{ - Q_D(QWinRTCameraControl); - HRESULT hr; - if (!d->focusControl) - return false; - - QEventDispatcherWinRT::runOnXamlThread([&d, &hr]() { - if (d->focusOperation) { - ComPtr<IAsyncInfo> info; - hr = d->focusOperation.As(&info); - Q_ASSERT_SUCCEEDED(hr); - - AsyncStatus status = AsyncStatus::Completed; - hr = info->get_Status(&status); - Q_ASSERT_SUCCEEDED(hr); - if (status == AsyncStatus::Started) - return E_ASYNC_OPERATION_NOT_STARTED; - } - - hr = d->focusControl->FocusAsync(&d->focusOperation); - Q_ASSERT_SUCCEEDED(hr); - - const long errorCode = HRESULT_CODE(hr); - if (errorCode == ERROR_OPERATION_IN_PROGRESS - || errorCode == ERROR_WRITE_PROTECT) { - return E_ASYNC_OPERATION_NOT_STARTED; - } - Q_ASSERT_SUCCEEDED(hr); - return S_OK; - }); - - return hr == S_OK; -} - -void QWinRTCameraControl::clearFocusPoint() -{ - Q_D(QWinRTCameraControl); - if (!d->focusControl) - return; - ComPtr<IAsyncAction> op; - HRESULT hr = d->regionsOfInterestControl->ClearRegionsAsync(&op); - Q_ASSERT_SUCCEEDED(hr); - hr = QWinRTFunctions::await(op); - Q_ASSERT_SUCCEEDED(hr); -} - -bool QWinRTCameraControl::lockFocus() -{ - Q_D(QWinRTCameraControl); - if (!d->focusControl) - return false; - - bool result = false; - ComPtr<IAsyncAction> op; - HRESULT hr; - hr = QEventDispatcherWinRT::runOnXamlThread([d, &result, &op]() { - ComPtr<IFocusControl2> focusControl2; - HRESULT hr = d->focusControl.As(&focusControl2); - Q_ASSERT_SUCCEEDED(hr); - hr = focusControl2->LockAsync(&op); - if (HRESULT_CODE(hr) == ERROR_WRITE_PROTECT) - return S_OK; - Q_ASSERT_SUCCEEDED(hr); - result = true; - return hr; - }); - return result ? (QWinRTFunctions::await(op) == S_OK) : false; -} - -bool QWinRTCameraControl::unlockFocus() -{ - Q_D(QWinRTCameraControl); - if (!d->focusControl) - return false; - - bool result = false; - ComPtr<IAsyncAction> op; - HRESULT hr; - hr = QEventDispatcherWinRT::runOnXamlThread([d, &result, &op]() { - ComPtr<IFocusControl2> focusControl2; - HRESULT hr = d->focusControl.As(&focusControl2); - Q_ASSERT_SUCCEEDED(hr); - hr = focusControl2->UnlockAsync(&op); - if (HRESULT_CODE(hr) == ERROR_WRITE_PROTECT) - return S_OK; - Q_ASSERT_SUCCEEDED(hr); - result = true; - return hr; - }); - return result ? (QWinRTFunctions::await(op) == S_OK) : false; -} - -#else // !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) - -HRESULT QWinRTCameraControl::initializeFocus() -{ - Q_D(QWinRTCameraControl); - d->cameraFocusControl->setSupportedFocusMode(0); - d->cameraFocusControl->setSupportedFocusPointMode(QSet<QCameraFocus::FocusPointMode>()); - return S_OK; -} - -bool QWinRTCameraControl::setFocus(QCameraFocus::FocusModes modes) -{ - Q_UNUSED(modes) - return false; -} - -bool QWinRTCameraControl::setFocusPoint(const QPointF &focusPoint) -{ - Q_UNUSED(focusPoint) - return false; -} - -bool QWinRTCameraControl::focus() -{ - return false; -} - -void QWinRTCameraControl::clearFocusPoint() -{ -} - -bool QWinRTCameraControl::lockFocus() -{ - return false; -} - -bool QWinRTCameraControl::unlockFocus() -{ - return false; -} - -#endif // !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) - -void QWinRTCameraControl::frameMapped() -{ - Q_D(QWinRTCameraControl); - ++d->framesMapped; -} - -void QWinRTCameraControl::frameUnmapped() -{ - Q_D(QWinRTCameraControl); - --d->framesMapped; - Q_ASSERT(d->framesMapped >= 0); - if (!d->framesMapped && d->delayClose && d->delayClose->isRunning()) - d->delayClose->exit(); -} - -HRESULT QWinRTCameraControl::onCaptureFailed(IMediaCapture *, IMediaCaptureFailedEventArgs *args) -{ - qCDebug(lcMMCamera) << __FUNCTION__ << args; - HRESULT hr; - UINT32 code; - hr = args->get_Code(&code); - RETURN_HR_IF_FAILED("Failed to get error code"); - HString message; - args->get_Message(message.GetAddressOf()); - RETURN_HR_IF_FAILED("Failed to get error message"); - quint32 messageLength; - const wchar_t *messageBuffer = message.GetRawBuffer(&messageLength); - emit error(QCamera::CameraError, QString::fromWCharArray(messageBuffer, int(messageLength))); - setState(QCamera::LoadedState); - return S_OK; -} - -HRESULT QWinRTCameraControl::onRecordLimitationExceeded(IMediaCapture *) -{ - qCDebug(lcMMCamera) << __FUNCTION__; - emit error(QCamera::CameraError, QStringLiteral("Recording limit exceeded.")); - setState(QCamera::LoadedState); - return S_OK; -} - -HRESULT QWinRTCameraControl::onInitializationCompleted(IAsyncAction *, AsyncStatus status) -{ - qCDebug(lcMMCamera) << __FUNCTION__; - Q_D(QWinRTCameraControl); - - if (status != Completed) { - d->initializing = false; - d->initialized = false; - 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"); - - std::sort(captureResolutions.begin(), captureResolutions.end(), [](QSize size1, QSize size2) { - return size1.width() * size1.height() < size2.width() * size2.height(); - }); - - // Set capture resolutions. - d->imageEncoderControl->setSupportedResolutionsList(captureResolutions.toList()); - const QSize captureResolution = d->imageEncoderControl->imageSettings().resolution(); - const quint32 captureResolutionIndex = quint32(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. - QSize maxSize; - 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) - && (maxSize.width() * maxSize.height() < resolution.width() * resolution.height())) { - maxSize = resolution; - } - } - - const QSize &viewfinderResolution = maxSize; - const quint32 viewfinderResolutionIndex = quint32(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; - emit error(errorCode, errorString); -} - -QT_END_NAMESPACE |