diff options
Diffstat (limited to 'src/plugins/winrt/qwinrtcameraimagecapturecontrol.cpp')
-rw-r--r-- | src/plugins/winrt/qwinrtcameraimagecapturecontrol.cpp | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/src/plugins/winrt/qwinrtcameraimagecapturecontrol.cpp b/src/plugins/winrt/qwinrtcameraimagecapturecontrol.cpp new file mode 100644 index 000000000..f5151c619 --- /dev/null +++ b/src/plugins/winrt/qwinrtcameraimagecapturecontrol.cpp @@ -0,0 +1,280 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwinrtcameraimagecapturecontrol.h" +#include "qwinrtcameracontrol.h" + +#include <QtCore/QCoreApplication> +#include <QtCore/QDir> +#include <QtCore/QFileInfo> +#include <QtCore/QGlobalStatic> +#include <QtCore/QPointer> +#include <QtCore/QStandardPaths> +#include <QtCore/QVector> +#include <QtCore/qfunctions_winrt.h> +#include <QtMultimedia/private/qmediastoragelocation_p.h> + +#include <wrl.h> +#include <windows.media.capture.h> +#include <windows.media.devices.h> +#include <windows.media.mediaproperties.h> +#include <windows.storage.streams.h> +#include <windows.graphics.imaging.h> +#include <robuffer.h> + +using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Media::Capture; +using namespace ABI::Windows::Media::Devices; +using namespace ABI::Windows::Media::MediaProperties; +using namespace ABI::Windows::Storage::Streams; +using namespace ABI::Windows::Graphics::Imaging; + +QT_USE_NAMESPACE + +#define wchar(str) reinterpret_cast<const wchar_t *>(str.utf16()) + +struct QWinRTCameraImageCaptureControlGlobal +{ + QWinRTCameraImageCaptureControlGlobal() + { + HRESULT hr; + hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Media_MediaProperties_ImageEncodingProperties).Get(), + &encodingPropertiesFactory); + Q_ASSERT_SUCCEEDED(hr); + + hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(), + &bufferFactory); + Q_ASSERT_SUCCEEDED(hr); + + hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_DataReader).Get(), + &dataReaderFactory); + } + + ComPtr<IImageEncodingPropertiesStatics2> encodingPropertiesFactory; + ComPtr<IBufferFactory> bufferFactory; + ComPtr<IDataReaderFactory> dataReaderFactory; +}; +Q_GLOBAL_STATIC(QWinRTCameraImageCaptureControlGlobal, g) + +struct CaptureRequest +{ + quint16 id; + QString fileName; + ComPtr<IImageEncodingProperties> imageFormat; + ComPtr<IRandomAccessStream> stream; + ComPtr<IAsyncAction> op; +}; + +class QWinRTCameraImageCaptureControlPrivate +{ +public: + QPointer<QWinRTCameraControl> cameraControl; + QHash<IAsyncAction *, CaptureRequest> requests; + quint16 currentCaptureId; + QMediaStorageLocation location; + + void onCameraStateChanged() + { + + } +}; + +QWinRTCameraImageCaptureControl::QWinRTCameraImageCaptureControl(QWinRTCameraControl *parent) + : QCameraImageCaptureControl(parent), d_ptr(new QWinRTCameraImageCaptureControlPrivate) +{ + Q_D(QWinRTCameraImageCaptureControl); + + d->cameraControl = parent; + connect(d->cameraControl, &QCameraControl::stateChanged, + this, &QWinRTCameraImageCaptureControl::readyForCaptureChanged); + d->currentCaptureId = 0; +} + +bool QWinRTCameraImageCaptureControl::isReadyForCapture() const +{ + Q_D(const QWinRTCameraImageCaptureControl); + return d->cameraControl->state() == QCamera::ActiveState; +} + +QCameraImageCapture::DriveMode QWinRTCameraImageCaptureControl::driveMode() const +{ + return QCameraImageCapture::SingleImageCapture; +} + +void QWinRTCameraImageCaptureControl::setDriveMode(QCameraImageCapture::DriveMode mode) +{ + Q_UNUSED(mode); +} + +int QWinRTCameraImageCaptureControl::capture(const QString &fileName) +{ + Q_D(QWinRTCameraImageCaptureControl); + + ++d->currentCaptureId; + IMediaCapture *capture = d->cameraControl->handle(); + if (!capture) { + emit error(d->currentCaptureId, QCameraImageCapture::NotReadyError, tr("Camera not ready")); + return -1; + } + + CaptureRequest request = { + d->currentCaptureId, + d->location.generateFileName(fileName, QMediaStorageLocation::Pictures, QStringLiteral("IMG_"), + 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); + + hr = g->encodingPropertiesFactory->CreateBmp(&request.imageFormat); + Q_ASSERT_SUCCEEDED(hr); + + const QSize imageSize = d->cameraControl->imageSize(); + 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); + d->requests.insert(request.op.Get(), request); + + hr = request.op->put_Completed(Callback<IAsyncActionCompletedHandler>( + this, &QWinRTCameraImageCaptureControl::onCaptureCompleted).Get()); + Q_ASSERT_SUCCEEDED(hr); + + return request.id; +} + +void QWinRTCameraImageCaptureControl::cancelCapture() +{ + Q_D(QWinRTCameraImageCaptureControl); + + QHash<IAsyncAction *, CaptureRequest>::iterator it = d->requests.begin(); + while (it != d->requests.end()) { + ComPtr<IAsyncInfo> info; + it->op.As(&info); + info->Cancel(); + it = d->requests.erase(it); + } +} + +HRESULT QWinRTCameraImageCaptureControl::onCaptureCompleted(IAsyncAction *asyncInfo, AsyncStatus status) +{ + Q_D(QWinRTCameraImageCaptureControl); + + if (status == Canceled || !d->requests.contains(asyncInfo)) + return S_OK; + + CaptureRequest request = d->requests.take(asyncInfo); + + HRESULT hr; + if (status == Error) { + hr = asyncInfo->GetResults(); + emit error(request.id, QCameraImageCapture::ResourceError, qt_error_string(hr)); + return S_OK; + } + + quint64 dataLength; + hr = request.stream->get_Size(&dataLength); + Q_ASSERT_SUCCEEDED(hr); + if (dataLength == 0 || dataLength > INT_MAX) { + emit error(request.id, QCameraImageCapture::FormatError, tr("Invalid photo data length.")); + return S_OK; + } + + ComPtr<IBitmapDecoderStatics> bitmapFactory; + hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Graphics_Imaging_BitmapDecoder).Get(), + &bitmapFactory); + Q_ASSERT_SUCCEEDED(hr); + + ComPtr<IAsyncOperation<BitmapDecoder *>> op; + hr = bitmapFactory->CreateAsync(request.stream.Get(), &op); + Q_ASSERT_SUCCEEDED(hr); + ComPtr<IBitmapDecoder> decoder; + hr = QWinRTFunctions::await(op, decoder.GetAddressOf()); + Q_ASSERT_SUCCEEDED(hr); + + ComPtr<IAsyncOperation<BitmapFrame *>> op2; + hr = decoder->GetFrameAsync(0, &op2); + Q_ASSERT_SUCCEEDED(hr); + ComPtr<IBitmapFrame> frame; + hr = QWinRTFunctions::await(op2, frame.GetAddressOf()); + Q_ASSERT_SUCCEEDED(hr); + + ComPtr<IBitmapTransform> transform; + hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Graphics_Imaging_BitmapTransform).Get(), + &transform); + Q_ASSERT_SUCCEEDED(hr); + + ComPtr<IAsyncOperation<PixelDataProvider *>> op3; + hr = frame->GetPixelDataTransformedAsync(BitmapPixelFormat_Rgba8, BitmapAlphaMode_Straight, + transform.Get(), ExifOrientationMode_IgnoreExifOrientation, + ColorManagementMode_DoNotColorManage, &op3); + Q_ASSERT_SUCCEEDED(hr); + ComPtr<IPixelDataProvider> pixelDataProvider; + hr = QWinRTFunctions::await(op3, pixelDataProvider.GetAddressOf()); + Q_ASSERT_SUCCEEDED(hr); + + UINT32 pixelDataSize; + BYTE *pixelData; + hr = pixelDataProvider->DetachPixelData(&pixelDataSize, &pixelData); + + UINT32 pixelHeight; + hr = frame->get_PixelHeight(&pixelHeight); + Q_ASSERT_SUCCEEDED(hr); + UINT32 pixelWidth; + hr = frame->get_PixelWidth(&pixelWidth); + Q_ASSERT_SUCCEEDED(hr); + const QImage image(pixelData, pixelWidth, pixelHeight, QImage::Format_RGBA8888, + reinterpret_cast<QImageCleanupFunction>(&CoTaskMemFree), pixelData); + emit imageCaptured(request.id, image); + if (image.save(request.fileName)) + emit imageSaved(request.id, request.fileName); + else + emit error(request.id, QCameraImageCapture::ResourceError, tr("Image saving failed")); + + return S_OK; +} |