winrt: Add camera video probe controls

[ChangLog][multimedia][winrt] The WinRT backend now supports QVideoProbes
on camera objects.

Task-number: QTBUG-46228
Change-Id: I7850c5ec6f61e5824064d4be8afc8a0b55d05806
Reviewed-by: Andrew Knight <andrew.knight@intopalo.com>
This commit is contained in:
Peng Wu
2015-07-29 13:00:03 +03:00
committed by Andrew Knight
parent 5cec451c10
commit 129b06ba77
7 changed files with 271 additions and 13 deletions

View File

@@ -630,6 +630,7 @@ void QWinRTCameraControl::setState(QCamera::State state)
emit stateChanged(d->state);
d->status = QCamera::ActiveStatus;
emit statusChanged(d->status);
d->mediaSink->RequestSample();
break;
}
case QCamera::LoadedState: {

View File

@@ -37,6 +37,8 @@
#include "qwinrtcameraservice.h"
#include "qwinrtcameracontrol.h"
#include "qwinrtcamerainfocontrol.h"
#include "qwinrtvideoprobecontrol.h"
#include "qwinrtcameravideorenderercontrol.h"
#include <QtCore/QCoreApplication>
#include <QtCore/qfunctions_winrt.h>
@@ -47,6 +49,7 @@
#include <QtMultimedia/QImageEncoderControl>
#include <QtMultimedia/QCameraFocusControl>
#include <QtMultimedia/QCameraLocksControl>
#include <QtMultimedia/QMediaVideoProbeControl>
QT_BEGIN_NAMESPACE
@@ -98,12 +101,17 @@ QMediaControl *QWinRTCameraService::requestControl(const char *name)
if (qstrcmp(name, QCameraLocksControl_iid) == 0)
return d->cameraControl->cameraLocksControl();
if (qstrcmp(name, QMediaVideoProbeControl_iid) == 0)
return new QWinRTVideoProbeControl(qobject_cast<QWinRTCameraVideoRendererControl *>(d->cameraControl->videoRenderer()));
return nullptr;
}
void QWinRTCameraService::releaseControl(QMediaControl *control)
{
Q_UNUSED(control);
Q_ASSERT(control);
if (QWinRTVideoProbeControl *videoProbe = qobject_cast<QWinRTVideoProbeControl *>(control))
videoProbe->deleteLater();
}
QT_END_NAMESPACE

View File

@@ -39,6 +39,7 @@
#include <QtCore/qfunctions_winrt.h>
#include <QtCore/QSize>
#include <QtCore/QVector>
#include <QVideoFrame>
#include <d3d11.h>
#include <mfapi.h>
@@ -47,6 +48,60 @@ using namespace Microsoft::WRL;
QT_BEGIN_NAMESPACE
class QWinRTCameraVideoBuffer : public QAbstractVideoBuffer
{
public:
QWinRTCameraVideoBuffer(IMF2DBuffer *buffer, int size)
: QAbstractVideoBuffer(NoHandle)
, currentMode(NotMapped)
, buffer(buffer)
, size(size)
{
}
~QWinRTCameraVideoBuffer()
{
unmap();
}
MapMode mapMode() const Q_DECL_OVERRIDE
{
return currentMode;
}
uchar *map(MapMode mode, int *numBytes, int *bytesPerLine) Q_DECL_OVERRIDE
{
if (currentMode != NotMapped || mode == NotMapped)
return nullptr;
BYTE *bytes;
LONG stride;
HRESULT hr = buffer->Lock2D(&bytes, &stride);
RETURN_IF_FAILED("Failed to lock camera frame buffer", nullptr);
if (bytesPerLine)
*bytesPerLine = stride;
if (numBytes)
*numBytes = size;
currentMode = mode;
return bytes;
}
void unmap() Q_DECL_OVERRIDE
{
if (currentMode == NotMapped)
return;
HRESULT hr = buffer->Unlock2D();
RETURN_VOID_IF_FAILED("Failed to unlock camera frame buffer");
currentMode = NotMapped;
}
private:
ComPtr<IMF2DBuffer> buffer;
MapMode currentMode;
int size;
};
class D3DVideoBlitter
{
public:
@@ -143,11 +198,52 @@ public:
ComPtr<IMF2DBuffer> buffers[CAMERA_SAMPLE_QUEUE_SIZE];
QAtomicInteger<quint16> writeIndex;
QAtomicInteger<quint16> readIndex;
QVideoFrame::PixelFormat cameraSampleformat;
int cameraSampleSize;
uint videoProbesCounter;
bool getCameraSampleInfo(const ComPtr<IMF2DBuffer> &buffer);
ComPtr<IMF2DBuffer> dequeueBuffer();
};
bool QWinRTCameraVideoRendererControlPrivate::getCameraSampleInfo(const ComPtr<IMF2DBuffer> &buffer)
{
ComPtr<ID3D11Texture2D> sourceTexture;
ComPtr<IMFDXGIBuffer> dxgiBuffer;
HRESULT hr = buffer.As(&dxgiBuffer);
Q_ASSERT_SUCCEEDED(hr);
hr = dxgiBuffer->GetResource(IID_PPV_ARGS(&sourceTexture));
if (FAILED(hr)) {
qErrnoWarning(hr, "The video frame does not support texture output");
cameraSampleformat = QVideoFrame::Format_Invalid;
return false;
}
D3D11_TEXTURE2D_DESC desc;
sourceTexture->GetDesc(&desc);
switch (desc.Format) {
case DXGI_FORMAT_R8G8B8A8_TYPELESS:
cameraSampleformat = QVideoFrame::Format_ARGB32;
break;
case DXGI_FORMAT_NV12:
cameraSampleformat = QVideoFrame::Format_NV12;
break;
default:
cameraSampleformat = QVideoFrame::Format_Invalid;
qErrnoWarning("Unsupported camera probe format.");
return false;
}
DWORD pcbLength;
hr = buffer->GetContiguousLength(&pcbLength);
Q_ASSERT_SUCCEEDED(hr);
cameraSampleSize = pcbLength;
return true;
}
QWinRTCameraVideoRendererControl::QWinRTCameraVideoRendererControl(const QSize &size, QObject *parent)
: QWinRTAbstractVideoRendererControl(size, parent), d_ptr(new QWinRTCameraVideoRendererControlPrivate)
{
Q_D(QWinRTCameraVideoRendererControl);
d->cameraSampleformat = QVideoFrame::Format_User;
d->videoProbesCounter = 0;
}
QWinRTCameraVideoRendererControl::~QWinRTCameraVideoRendererControl()
@@ -158,22 +254,15 @@ QWinRTCameraVideoRendererControl::~QWinRTCameraVideoRendererControl()
bool QWinRTCameraVideoRendererControl::render(ID3D11Texture2D *target)
{
Q_D(QWinRTCameraVideoRendererControl);
const quint16 readIndex = d->readIndex;
if (readIndex == d->writeIndex) {
ComPtr<IMF2DBuffer> buffer = d->dequeueBuffer();
if (!buffer) {
emit bufferRequested();
return false;
}
HRESULT hr;
ComPtr<IMF2DBuffer> buffer = d->buffers[readIndex];
Q_ASSERT(buffer);
d->buffers[readIndex].Reset();
d->readIndex = (readIndex + 1) % CAMERA_SAMPLE_QUEUE_SIZE;
ComPtr<ID3D11Texture2D> sourceTexture;
ComPtr<IMFDXGIBuffer> dxgiBuffer;
hr = buffer.As(&dxgiBuffer);
HRESULT hr = buffer.As(&dxgiBuffer);
Q_ASSERT_SUCCEEDED(hr);
hr = dxgiBuffer->GetResource(IID_PPV_ARGS(&sourceTexture));
if (FAILED(hr)) {
@@ -196,11 +285,41 @@ void QWinRTCameraVideoRendererControl::queueBuffer(IMF2DBuffer *buffer)
{
Q_D(QWinRTCameraVideoRendererControl);
Q_ASSERT(buffer);
if (d->videoProbesCounter > 0) {
if (d->cameraSampleformat == QVideoFrame::Format_User)
d->getCameraSampleInfo(buffer);
if (d->cameraSampleformat != QVideoFrame::Format_Invalid) {
QWinRTCameraVideoBuffer *videoBuffer = new QWinRTCameraVideoBuffer(buffer, d->cameraSampleSize);
QVideoFrame frame(videoBuffer, size(), d->cameraSampleformat);
emit videoFrameProbed(frame);
}
}
const quint16 writeIndex = (d->writeIndex + 1) % CAMERA_SAMPLE_QUEUE_SIZE;
if (d->readIndex == writeIndex) // Drop new sample if queue is full
return;
d->buffers[d->writeIndex] = buffer;
d->writeIndex = writeIndex;
if (!surface()) {
d->dequeueBuffer();
emit bufferRequested();
}
}
ComPtr<IMF2DBuffer> QWinRTCameraVideoRendererControlPrivate::dequeueBuffer()
{
const quint16 currentReadIndex = readIndex;
if (currentReadIndex == writeIndex)
return nullptr;
ComPtr<IMF2DBuffer> buffer = buffers[currentReadIndex];
Q_ASSERT(buffer);
buffers[currentReadIndex].Reset();
readIndex = (currentReadIndex + 1) % CAMERA_SAMPLE_QUEUE_SIZE;
return buffer;
}
void QWinRTCameraVideoRendererControl::discardBuffers()
@@ -211,4 +330,17 @@ void QWinRTCameraVideoRendererControl::discardBuffers()
buffer.Reset();
}
void QWinRTCameraVideoRendererControl::incrementProbe()
{
Q_D(QWinRTCameraVideoRendererControl);
++d->videoProbesCounter;
}
void QWinRTCameraVideoRendererControl::decrementProbe()
{
Q_D(QWinRTCameraVideoRendererControl);
Q_ASSERT(d->videoProbesCounter > 0);
--d->videoProbesCounter;
}
QT_END_NAMESPACE

View File

@@ -39,10 +39,13 @@
#include "qwinrtabstractvideorenderercontrol.h"
#include <QVideoFrame>
struct IMF2DBuffer;
QT_BEGIN_NAMESPACE
class QWinRTVideoProbeControl;
class QVideoSurfaceFormat;
class QWinRTCameraVideoRendererControlPrivate;
class QWinRTCameraVideoRendererControl : public QWinRTAbstractVideoRendererControl
@@ -55,9 +58,12 @@ public:
bool render(ID3D11Texture2D *texture) Q_DECL_OVERRIDE;
void queueBuffer(IMF2DBuffer *buffer);
void discardBuffers();
void incrementProbe();
void decrementProbe();
signals:
void bufferRequested();
void videoFrameProbed(const QVideoFrame &frame);
private:
QScopedPointer<QWinRTCameraVideoRendererControlPrivate> d_ptr;

View File

@@ -0,0 +1,55 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies).
** Contact: http://www.qt.io/licensing/
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL3$
** 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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://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.LGPLv3 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.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 later 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 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qwinrtvideoprobecontrol.h"
#include "qwinrtcameravideorenderercontrol.h"
QT_BEGIN_NAMESPACE
QWinRTVideoProbeControl::QWinRTVideoProbeControl(QWinRTCameraVideoRendererControl *parent)
: QMediaVideoProbeControl(parent)
{
QObject::connect(parent, &QWinRTCameraVideoRendererControl::videoFrameProbed,
this, &QMediaVideoProbeControl::videoFrameProbed, Qt::QueuedConnection);
parent->incrementProbe();
}
QWinRTVideoProbeControl::~QWinRTVideoProbeControl()
{
if (QWinRTCameraVideoRendererControl *renderer = qobject_cast<QWinRTCameraVideoRendererControl *>(parent()))
renderer->decrementProbe();
}
QT_END_NAMESPACE

View File

@@ -0,0 +1,54 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies).
** Contact: http://www.qt.io/licensing/
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL3$
** 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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://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.LGPLv3 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.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 later 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 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QWINRTVIDEOPROBECONTROL_H
#define QWINRTVIDEOPROBECONTROL_H
#include <qmediavideoprobecontrol.h>
QT_BEGIN_NAMESPACE
class QWinRTCameraVideoRendererControl;
class QWinRTVideoProbeControl : public QMediaVideoProbeControl
{
Q_OBJECT
public:
explicit QWinRTVideoProbeControl(QWinRTCameraVideoRendererControl *parent);
~QWinRTVideoProbeControl();
};
QT_END_NAMESPACE
#endif // QWINRTVIDEOPROBECONTROL_H

View File

@@ -21,7 +21,8 @@ HEADERS += \
qwinrtmediaplayerservice.h \
qwinrtplayerrenderercontrol.h \
qwinrtserviceplugin.h \
qwinrtvideodeviceselectorcontrol.h
qwinrtvideodeviceselectorcontrol.h \
qwinrtvideoprobecontrol.h
SOURCES += \
qwinrtabstractvideorenderercontrol.cpp \
@@ -37,7 +38,8 @@ SOURCES += \
qwinrtmediaplayerservice.cpp \
qwinrtplayerrenderercontrol.cpp \
qwinrtserviceplugin.cpp \
qwinrtvideodeviceselectorcontrol.cpp
qwinrtvideodeviceselectorcontrol.cpp \
qwinrtvideoprobecontrol.cpp
OTHER_FILES += \
winrt.json