diff options
author | Peng Wu <peng.wu@intopalo.com> | 2015-07-29 13:00:03 +0300 |
---|---|---|
committer | Andrew Knight <andrew.knight@intopalo.com> | 2015-08-10 12:12:52 +0000 |
commit | 129b06ba77e451c08778badcd54cbaf193d195bc (patch) | |
tree | 052b20dca9571bb5291445378d0a4ff29c8874a2 /src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp | |
parent | 5cec451c10e73785c95fb236cbae7205a9a661d0 (diff) |
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>
Diffstat (limited to 'src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp')
-rw-r--r-- | src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp | 152 |
1 files changed, 142 insertions, 10 deletions
diff --git a/src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp b/src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp index 4878c55c9..6c5575a17 100644 --- a/src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp +++ b/src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp @@ -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 |