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<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;
|
||||
|
||||
@@ -99,6 +99,8 @@ public:
|
||||
void emitError(int errorCode, const QString &errorString);
|
||||
bool lockFocus();
|
||||
bool unlockFocus();
|
||||
void frameMapped();
|
||||
void frameUnmapped();
|
||||
|
||||
private slots:
|
||||
void onBufferRequested();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user