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>
This commit is contained in:
@@ -524,6 +524,8 @@ public:
|
|||||||
QPointer<QWinRTImageEncoderControl> imageEncoderControl;
|
QPointer<QWinRTImageEncoderControl> imageEncoderControl;
|
||||||
QPointer<QWinRTCameraFocusControl> cameraFocusControl;
|
QPointer<QWinRTCameraFocusControl> cameraFocusControl;
|
||||||
QPointer<QWinRTCameraLocksControl> cameraLocksControl;
|
QPointer<QWinRTCameraLocksControl> cameraLocksControl;
|
||||||
|
QAtomicInt framesMapped;
|
||||||
|
QEventLoop *delayClose;
|
||||||
};
|
};
|
||||||
|
|
||||||
QWinRTCameraControl::QWinRTCameraControl(QObject *parent)
|
QWinRTCameraControl::QWinRTCameraControl(QObject *parent)
|
||||||
@@ -531,6 +533,7 @@ QWinRTCameraControl::QWinRTCameraControl(QObject *parent)
|
|||||||
{
|
{
|
||||||
Q_D(QWinRTCameraControl);
|
Q_D(QWinRTCameraControl);
|
||||||
|
|
||||||
|
d->delayClose = nullptr;
|
||||||
d->state = QCamera::UnloadedState;
|
d->state = QCamera::UnloadedState;
|
||||||
d->status = QCamera::UnloadedStatus;
|
d->status = QCamera::UnloadedStatus;
|
||||||
d->captureMode = QCamera::CaptureStillImage;
|
d->captureMode = QCamera::CaptureStillImage;
|
||||||
@@ -612,6 +615,14 @@ void QWinRTCameraControl::setState(QCamera::State state)
|
|||||||
case QCamera::UnloadedState: {
|
case QCamera::UnloadedState: {
|
||||||
// Stop the camera if it is running (transition to LoadedState)
|
// Stop the camera if it is running (transition to LoadedState)
|
||||||
if (d->status == QCamera::ActiveStatus) {
|
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;
|
ComPtr<IAsyncAction> op;
|
||||||
hr = d->capturePreview->StopPreviewAsync(&op);
|
hr = d->capturePreview->StopPreviewAsync(&op);
|
||||||
RETURN_VOID_AND_EMIT_ERROR("Failed to stop camera preview");
|
RETURN_VOID_AND_EMIT_ERROR("Failed to stop camera preview");
|
||||||
@@ -1208,6 +1219,21 @@ bool QWinRTCameraControl::unlockFocus()
|
|||||||
|
|
||||||
#endif // !Q_OS_WINPHONE
|
#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 QWinRTCameraControl::onCaptureFailed(IMediaCapture *, IMediaCaptureFailedEventArgs *args)
|
||||||
{
|
{
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|||||||
@@ -99,6 +99,8 @@ public:
|
|||||||
void emitError(int errorCode, const QString &errorString);
|
void emitError(int errorCode, const QString &errorString);
|
||||||
bool lockFocus();
|
bool lockFocus();
|
||||||
bool unlockFocus();
|
bool unlockFocus();
|
||||||
|
void frameMapped();
|
||||||
|
void frameUnmapped();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onBufferRequested();
|
void onBufferRequested();
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
|
|
||||||
#include <QtCore/qfunctions_winrt.h>
|
#include <QtCore/qfunctions_winrt.h>
|
||||||
#include <QtCore/QSize>
|
#include <QtCore/QSize>
|
||||||
|
#include <QtCore/QPointer>
|
||||||
#include <QtCore/QVector>
|
#include <QtCore/QVector>
|
||||||
#include <QVideoFrame>
|
#include <QVideoFrame>
|
||||||
|
|
||||||
@@ -45,6 +46,8 @@
|
|||||||
#include <mfapi.h>
|
#include <mfapi.h>
|
||||||
#include <wrl.h>
|
#include <wrl.h>
|
||||||
|
|
||||||
|
#include "qwinrtcameracontrol.h"
|
||||||
|
|
||||||
#ifdef Q_OS_WINPHONE
|
#ifdef Q_OS_WINPHONE
|
||||||
#include <Windows.Security.ExchangeActiveSyncProvisioning.h>
|
#include <Windows.Security.ExchangeActiveSyncProvisioning.h>
|
||||||
using namespace ABI::Windows::Security::ExchangeActiveSyncProvisioning;
|
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
|
class QWinRTCameraVideoBuffer : public QAbstractVideoBuffer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QWinRTCameraVideoBuffer(IMF2DBuffer *buffer, int size)
|
QWinRTCameraVideoBuffer(IMF2DBuffer *buffer, int size, QWinRTCameraControl *control)
|
||||||
: QAbstractVideoBuffer(NoHandle)
|
: QAbstractVideoBuffer(NoHandle)
|
||||||
, currentMode(NotMapped)
|
, currentMode(NotMapped)
|
||||||
, buffer(buffer)
|
, buffer(buffer)
|
||||||
, size(size)
|
, size(size)
|
||||||
|
, control(control)
|
||||||
{
|
{
|
||||||
|
Q_ASSERT(control);
|
||||||
}
|
}
|
||||||
|
|
||||||
~QWinRTCameraVideoBuffer()
|
~QWinRTCameraVideoBuffer()
|
||||||
@@ -88,13 +93,14 @@ public:
|
|||||||
|
|
||||||
uchar *map(MapMode mode, int *numBytes, int *bytesPerLine) Q_DECL_OVERRIDE
|
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;
|
return nullptr;
|
||||||
|
|
||||||
BYTE *bytes;
|
BYTE *bytes;
|
||||||
LONG stride;
|
LONG stride;
|
||||||
HRESULT hr = buffer->Lock2D(&bytes, &stride);
|
HRESULT hr = buffer->Lock2D(&bytes, &stride);
|
||||||
RETURN_IF_FAILED("Failed to lock camera frame buffer", nullptr);
|
RETURN_IF_FAILED("Failed to lock camera frame buffer", nullptr);
|
||||||
|
control->frameMapped();
|
||||||
|
|
||||||
if (bytesPerLine)
|
if (bytesPerLine)
|
||||||
*bytesPerLine = stride;
|
*bytesPerLine = stride;
|
||||||
@@ -111,12 +117,15 @@ public:
|
|||||||
HRESULT hr = buffer->Unlock2D();
|
HRESULT hr = buffer->Unlock2D();
|
||||||
RETURN_VOID_IF_FAILED("Failed to unlock camera frame buffer");
|
RETURN_VOID_IF_FAILED("Failed to unlock camera frame buffer");
|
||||||
currentMode = NotMapped;
|
currentMode = NotMapped;
|
||||||
|
if (control)
|
||||||
|
control->frameUnmapped();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ComPtr<IMF2DBuffer> buffer;
|
ComPtr<IMF2DBuffer> buffer;
|
||||||
MapMode currentMode;
|
MapMode currentMode;
|
||||||
int size;
|
int size;
|
||||||
|
QPointer<QWinRTCameraControl> control;
|
||||||
};
|
};
|
||||||
|
|
||||||
class D3DVideoBlitter
|
class D3DVideoBlitter
|
||||||
@@ -331,7 +340,9 @@ bool QWinRTCameraVideoRendererControl::dequeueFrame(QVideoFrame *frame)
|
|||||||
return false;
|
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);
|
*frame = QVideoFrame(videoBuffer, size(), d->cameraSampleformat);
|
||||||
|
|
||||||
emit bufferRequested();
|
emit bufferRequested();
|
||||||
@@ -350,7 +361,9 @@ void QWinRTCameraVideoRendererControl::queueBuffer(IMF2DBuffer *buffer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (d->videoProbesCounter > 0 && d->cameraSampleformat != QVideoFrame::Format_Invalid) {
|
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);
|
QVideoFrame frame(videoBuffer, size(), d->cameraSampleformat);
|
||||||
emit videoFrameProbed(frame);
|
emit videoFrameProbed(frame);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user