diff options
author | Samuel Nevala <samuel.nevala@intopalo.com> | 2015-10-14 10:48:00 +0300 |
---|---|---|
committer | Samuel Nevala <samuel.nevala@intopalo.com> | 2015-10-15 06:19:14 +0000 |
commit | 787dcd9e4d40d9d59b90544e4c4bdea13ef532b8 (patch) | |
tree | 0650f73eaa9794265c43e69c38ce899e91b8cfcc /src | |
parent | d50a09965ae53e02caabdbcf4994ed9bc0ea3293 (diff) |
winrt: Prevent camera device from being suspended.
On certain Lumia devices video buffer gets page locked when camera
is stopped. Subsequent call to video frame map/unmap leads to camera
device suspension. As a fix delay camera unload until all mapped
video frames are unmapped and return early from video frame map when
camera is not active.
Task-Id: QTBUG-48672
Change-Id: If547b9d430727bbe0e12cd8c07a30aeff81d13e3
Reviewed-by: Andrew Knight <andrew.knight@intopalo.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/plugins/winrt/qwinrtcameracontrol.cpp | 26 | ||||
-rw-r--r-- | src/plugins/winrt/qwinrtcameracontrol.h | 2 | ||||
-rw-r--r-- | src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp | 21 |
3 files changed, 45 insertions, 4 deletions
diff --git a/src/plugins/winrt/qwinrtcameracontrol.cpp b/src/plugins/winrt/qwinrtcameracontrol.cpp index 3489048d8..0db4cdb0d 100644 --- a/src/plugins/winrt/qwinrtcameracontrol.cpp +++ b/src/plugins/winrt/qwinrtcameracontrol.cpp @@ -524,6 +524,8 @@ public: QPointer<QWinRTImageEncoderControl> imageEncoderControl; QPointer<QWinRTCameraFocusControl> cameraFocusControl; QPointer<QWinRTCameraLocksControl> cameraLocksControl; + QAtomicInt framesMapped; + QEventLoop *delayClose; }; QWinRTCameraControl::QWinRTCameraControl(QObject *parent) @@ -531,6 +533,7 @@ QWinRTCameraControl::QWinRTCameraControl(QObject *parent) { Q_D(QWinRTCameraControl); + d->delayClose = nullptr; d->state = QCamera::UnloadedState; d->status = QCamera::UnloadedStatus; d->captureMode = QCamera::CaptureStillImage; @@ -612,6 +615,14 @@ void QWinRTCameraControl::setState(QCamera::State state) case QCamera::UnloadedState: { // Stop the camera if it is running (transition to LoadedState) if (d->status == QCamera::ActiveStatus) { + 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 = d->capturePreview->StopPreviewAsync(&op); RETURN_VOID_AND_EMIT_ERROR("Failed to stop camera preview"); @@ -1208,6 +1219,21 @@ bool QWinRTCameraControl::unlockFocus() #endif // !Q_OS_WINPHONE +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) { HRESULT hr; diff --git a/src/plugins/winrt/qwinrtcameracontrol.h b/src/plugins/winrt/qwinrtcameracontrol.h index ac1c922a4..758ecb556 100644 --- a/src/plugins/winrt/qwinrtcameracontrol.h +++ b/src/plugins/winrt/qwinrtcameracontrol.h @@ -99,6 +99,8 @@ public: void emitError(int errorCode, const QString &errorString); bool lockFocus(); bool unlockFocus(); + void frameMapped(); + void frameUnmapped(); private slots: void onBufferRequested(); diff --git a/src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp b/src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp index 7afef7669..7313ae7a2 100644 --- a/src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp +++ b/src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp @@ -38,6 +38,7 @@ #include <QtCore/qfunctions_winrt.h> #include <QtCore/QSize> +#include <QtCore/QPointer> #include <QtCore/QVector> #include <QVideoFrame> @@ -45,6 +46,8 @@ #include <mfapi.h> #include <wrl.h> +#include "qwinrtcameracontrol.h" + #ifdef Q_OS_WINPHONE #include <Windows.Security.ExchangeActiveSyncProvisioning.h> using namespace ABI::Windows::Security::ExchangeActiveSyncProvisioning; @@ -68,12 +71,14 @@ static bool blacklisted(const wchar_t (&blackListName)[n], const HString &device class QWinRTCameraVideoBuffer : public QAbstractVideoBuffer { public: - QWinRTCameraVideoBuffer(IMF2DBuffer *buffer, int size) + QWinRTCameraVideoBuffer(IMF2DBuffer *buffer, int size, QWinRTCameraControl *control) : QAbstractVideoBuffer(NoHandle) , currentMode(NotMapped) , buffer(buffer) , size(size) + , control(control) { + Q_ASSERT(control); } ~QWinRTCameraVideoBuffer() @@ -88,13 +93,14 @@ public: uchar *map(MapMode mode, int *numBytes, int *bytesPerLine) Q_DECL_OVERRIDE { - if (currentMode != NotMapped || mode == NotMapped) + if (currentMode != NotMapped || mode == NotMapped || control && control->state() != QCamera::ActiveState) return nullptr; BYTE *bytes; LONG stride; HRESULT hr = buffer->Lock2D(&bytes, &stride); RETURN_IF_FAILED("Failed to lock camera frame buffer", nullptr); + control->frameMapped(); if (bytesPerLine) *bytesPerLine = stride; @@ -111,12 +117,15 @@ public: HRESULT hr = buffer->Unlock2D(); RETURN_VOID_IF_FAILED("Failed to unlock camera frame buffer"); currentMode = NotMapped; + if (control) + control->frameUnmapped(); } private: ComPtr<IMF2DBuffer> buffer; MapMode currentMode; int size; + QPointer<QWinRTCameraControl> control; }; class D3DVideoBlitter @@ -331,7 +340,9 @@ bool QWinRTCameraVideoRendererControl::dequeueFrame(QVideoFrame *frame) return false; } - QWinRTCameraVideoBuffer *videoBuffer = new QWinRTCameraVideoBuffer(buffer.Get(), d->cameraSampleSize); + QWinRTCameraVideoBuffer *videoBuffer = new QWinRTCameraVideoBuffer(buffer.Get(), + d->cameraSampleSize, + static_cast<QWinRTCameraControl *>(parent())); *frame = QVideoFrame(videoBuffer, size(), d->cameraSampleformat); emit bufferRequested(); @@ -350,7 +361,9 @@ void QWinRTCameraVideoRendererControl::queueBuffer(IMF2DBuffer *buffer) } if (d->videoProbesCounter > 0 && d->cameraSampleformat != QVideoFrame::Format_Invalid) { - QWinRTCameraVideoBuffer *videoBuffer = new QWinRTCameraVideoBuffer(buffer, d->cameraSampleSize); + QWinRTCameraVideoBuffer *videoBuffer = new QWinRTCameraVideoBuffer(buffer, + d->cameraSampleSize, + static_cast<QWinRTCameraControl *>(parent())); QVideoFrame frame(videoBuffer, size(), d->cameraSampleformat); emit videoFrameProbed(frame); } |