diff options
author | Yoann Lopes <yoann.lopes@theqtcompany.com> | 2015-11-27 11:56:50 +0100 |
---|---|---|
committer | Yoann Lopes <yoann.lopes@theqtcompany.com> | 2016-01-12 15:51:32 +0000 |
commit | c7397523e77578cf8f09ba3258791f68c34e2e5f (patch) | |
tree | 9c293c768038f74564d411cd27cff5ce22ed46ac | |
parent | 36549dbe148055d6ecf98952b05b4ff2310fe491 (diff) |
Windows: Improve EVR presenter.
Removed hard dependency to Angle; it's now required only when rendering
to a texture. If Angle is not used, the buffers are now mappable to
system memory.
This enables HW-accelerated video decoding in QML for non-ANGLE
builds. Note that the frame data have to do a round-trip through system
memory, which is not ideal but still faster than SW decoding.
Task-number: QTBUG-45593
Change-Id: Icc3503142df4e8dbb53b4e11f409b161fd2f9bde
Reviewed-by: Christian Stromme <christian.stromme@theqtcompany.com>
-rw-r--r-- | src/plugins/common/evr.pri | 26 | ||||
-rw-r--r-- | src/plugins/common/evr/evrcustompresenter.cpp | 310 | ||||
-rw-r--r-- | src/plugins/common/evr/evrcustompresenter.h | 40 | ||||
-rw-r--r-- | src/plugins/common/evr/evrd3dpresentengine.cpp | 741 | ||||
-rw-r--r-- | src/plugins/common/evr/evrd3dpresentengine.h | 69 | ||||
-rw-r--r-- | src/plugins/common/evr/evrhelpers.cpp | 73 | ||||
-rw-r--r-- | src/plugins/common/evr/evrhelpers.h | 6 | ||||
-rw-r--r-- | src/plugins/directshow/player/directshowvideorenderercontrol.cpp | 58 | ||||
-rw-r--r-- | src/plugins/directshow/player/directshowvideorenderercontrol.h | 9 | ||||
-rw-r--r-- | src/plugins/wmf/player/mfvideorenderercontrol.cpp | 43 | ||||
-rw-r--r-- | src/plugins/wmf/player/mfvideorenderercontrol.h | 4 |
11 files changed, 716 insertions, 663 deletions
diff --git a/src/plugins/common/evr.pri b/src/plugins/common/evr.pri index aa272adab..2a1b383df 100644 --- a/src/plugins/common/evr.pri +++ b/src/plugins/common/evr.pri @@ -1,28 +1,20 @@ INCLUDEPATH += $$PWD/evr qtHaveModule(widgets): QT += widgets +QT += gui-private + +LIBS += -lmf -lmfplat -lmfuuid -ld3d9 -ldxva2 -lwinmm -levr HEADERS += \ $$PWD/evr/evrvideowindowcontrol.h \ + $$PWD/evr/evrcustompresenter.h \ + $$PWD/evr/evrd3dpresentengine.h \ + $$PWD/evr/evrhelpers.h \ $$PWD/evr/evrdefs.h SOURCES += \ $$PWD/evr/evrvideowindowcontrol.cpp \ + $$PWD/evr/evrcustompresenter.cpp \ + $$PWD/evr/evrd3dpresentengine.cpp \ + $$PWD/evr/evrhelpers.cpp \ $$PWD/evr/evrdefs.cpp - -contains(QT_CONFIG, angle)|contains(QT_CONFIG, dynamicgl) { - LIBS += -lmf -lmfplat -lmfuuid -ld3d9 -ldxva2 -lwinmm -levr - QT += gui-private - - DEFINES += CUSTOM_EVR_PRESENTER - - HEADERS += \ - $$PWD/evr/evrcustompresenter.h \ - $$PWD/evr/evrd3dpresentengine.h \ - $$PWD/evr/evrhelpers.h - - SOURCES += \ - $$PWD/evr/evrcustompresenter.cpp \ - $$PWD/evr/evrd3dpresentengine.cpp \ - $$PWD/evr/evrhelpers.cpp -} diff --git a/src/plugins/common/evr/evrcustompresenter.cpp b/src/plugins/common/evr/evrcustompresenter.cpp index 969dd1415..73d032aa6 100644 --- a/src/plugins/common/evr/evrcustompresenter.cpp +++ b/src/plugins/common/evr/evrcustompresenter.cpp @@ -56,7 +56,6 @@ static const LONG ONE_MSEC = 1000; static HRESULT setDesiredSampleTime(IMFSample *sample, const LONGLONG& hnsSampleTime, const LONGLONG& hnsDuration); static HRESULT clearDesiredSampleTime(IMFSample *sample); static HRESULT setMixerSourceRect(IMFTransform *mixer, const MFVideoNormalizedRect& nrcSource); -static DWORD getFourCCFromPixelFormat(QVideoFrame::PixelFormat pixelFormat); static QVideoFrame::PixelFormat pixelFormatFromMediaType(IMFMediaType *type); static inline LONG MFTimeToMsec(const LONGLONG& time) @@ -80,9 +79,32 @@ bool qt_evr_setCustomPresenter(IUnknown *evr, EVRCustomPresenter *presenter) return result == S_OK; } -Scheduler::Scheduler() - : m_clock(NULL) - , m_CB(NULL) +class PresentSampleEvent : public QEvent +{ +public: + PresentSampleEvent(IMFSample *sample) + : QEvent(QEvent::Type(EVRCustomPresenter::PresentSample)) + , m_sample(sample) + { + if (m_sample) + m_sample->AddRef(); + } + + ~PresentSampleEvent() + { + if (m_sample) + m_sample->Release(); + } + + IMFSample *sample() const { return m_sample; } + +private: + IMFSample *m_sample; +}; + +Scheduler::Scheduler(EVRCustomPresenter *presenter) + : m_presenter(presenter) + , m_clock(NULL) , m_threadID(0) , m_schedulerThread(0) , m_threadReadyEvent(0) @@ -228,9 +250,6 @@ HRESULT Scheduler::flush() HRESULT Scheduler::scheduleSample(IMFSample *sample, bool presentNow) { - if (!m_CB) - return MF_E_NOT_INITIALIZED; - if (!m_schedulerThread) return MF_E_NOT_INITIALIZED; @@ -242,13 +261,7 @@ HRESULT Scheduler::scheduleSample(IMFSample *sample, bool presentNow) return E_FAIL; if (presentNow || !m_clock) { - // Present the sample immediately. - sample->AddRef(); - QMetaObject::invokeMethod(m_CB, - "presentSample", - Qt::QueuedConnection, - Q_ARG(void*, sample), - Q_ARG(qint64, 0)); + m_presenter->presentSample(sample); } else { // Queue the sample and ask the scheduler thread to wake up. m_mutex.lock(); @@ -344,12 +357,7 @@ HRESULT Scheduler::processSample(IMFSample *sample, LONG *pNextSleep) } if (presentNow) { - sample->AddRef(); - QMetaObject::invokeMethod(m_CB, - "presentSample", - Qt::QueuedConnection, - Q_ARG(void*, sample), - Q_ARG(qint64, hnsPresentationTime)); + m_presenter->presentSample(sample); } else { // The sample is not ready yet. Return it to the queue. m_mutex.lock(); @@ -538,24 +546,27 @@ HRESULT SamplePool::clear() } -EVRCustomPresenter::EVRCustomPresenter() +EVRCustomPresenter::EVRCustomPresenter(QAbstractVideoSurface *surface) : QObject() , m_sampleFreeCB(this, &EVRCustomPresenter::onSampleFree) , m_refCount(1) , m_renderState(RenderShutdown) , m_mutex(QMutex::Recursive) + , m_scheduler(this) , m_tokenCounter(0) , m_sampleNotify(false) , m_repaint(false) , m_prerolled(false) , m_endStreaming(false) , m_playbackRate(1.0f) - , m_D3DPresentEngine(0) + , m_presentEngine(new D3DPresentEngine) , m_clock(0) , m_mixer(0) , m_mediaEventSink(0) , m_mediaType(0) , m_surface(0) + , m_canRenderToSurface(false) + , m_sampleToPresent(0) { // Initial source rectangle = (0,0,1,1) m_sourceRect.top = 0; @@ -563,18 +574,21 @@ EVRCustomPresenter::EVRCustomPresenter() m_sourceRect.bottom = 1; m_sourceRect.right = 1; - m_D3DPresentEngine = new D3DPresentEngine; - m_scheduler.setCallback(m_D3DPresentEngine); + setSurface(surface); } EVRCustomPresenter::~EVRCustomPresenter() { + m_scheduler.flush(); + m_scheduler.stopScheduler(); + m_samplePool.clear(); + qt_evr_safe_release(&m_clock); qt_evr_safe_release(&m_mixer); qt_evr_safe_release(&m_mediaEventSink); qt_evr_safe_release(&m_mediaType); - m_D3DPresentEngine->deleteLater(); + delete m_presentEngine; } HRESULT EVRCustomPresenter::QueryInterface(REFIID riid, void ** ppvObject) @@ -628,7 +642,7 @@ HRESULT EVRCustomPresenter::GetService(REFGUID guidService, REFIID riid, LPVOID return MF_E_UNSUPPORTED_SERVICE; // First try to get the service interface from the D3DPresentEngine object. - hr = m_D3DPresentEngine->getService(guidService, riid, ppvObject); + hr = m_presentEngine->getService(guidService, riid, ppvObject); if (FAILED(hr)) // Next, check if this object supports the interface. hr = QueryInterface(riid, ppvObject); @@ -725,6 +739,11 @@ HRESULT EVRCustomPresenter::ReleaseServicePointers() return S_OK; } +bool EVRCustomPresenter::isValid() const +{ + return m_presentEngine->isValid() && m_canRenderToSurface; +} + HRESULT EVRCustomPresenter::ProcessMessage(MFVP_MESSAGE_TYPE message, ULONG_PTR param) { HRESULT hr = S_OK; @@ -837,11 +856,7 @@ HRESULT EVRCustomPresenter::OnClockStart(MFTIME, LONGLONG clockStartOffset) return hr; } - // Start the video surface in the main thread - if (thread() == QThread::currentThread()) - startSurface(); - else - QMetaObject::invokeMethod(this, "startSurface", Qt::QueuedConnection); + startSurface(); // Now try to get new output samples from the mixer. processOutputLoop(); @@ -890,11 +905,7 @@ HRESULT EVRCustomPresenter::OnClockStop(MFTIME) cancelFrameStep(); } - // Stop the video surface in the main thread - if (thread() == QThread::currentThread()) - stopSurface(); - else - QMetaObject::invokeMethod(this, "stopSurface", Qt::QueuedConnection); + stopSurface(); return S_OK; } @@ -1021,16 +1032,27 @@ void EVRCustomPresenter::supportedFormatsChanged() { QMutexLocker locker(&m_mutex); - m_supportedGLFormats.clear(); - if (!m_surface) - return; + m_canRenderToSurface = false; + m_presentEngine->setHint(D3DPresentEngine::RenderToTexture, false); - QList<QVideoFrame::PixelFormat> formats = m_surface->supportedPixelFormats(QAbstractVideoBuffer::GLTextureHandle); - for (int i = 0; i < formats.size(); ++i) { - DWORD fourCC = getFourCCFromPixelFormat(formats.at(i)); - if (fourCC) - m_supportedGLFormats.append(fourCC); + // check if we can render to the surface (compatible formats) + if (m_surface) { + QList<QVideoFrame::PixelFormat> formats = m_surface->supportedPixelFormats(QAbstractVideoBuffer::GLTextureHandle); + if (m_presentEngine->supportsTextureRendering() && formats.contains(QVideoFrame::Format_RGB32)) { + m_presentEngine->setHint(D3DPresentEngine::RenderToTexture, true); + m_canRenderToSurface = true; + } else { + formats = m_surface->supportedPixelFormats(QAbstractVideoBuffer::NoHandle); + Q_FOREACH (QVideoFrame::PixelFormat format, formats) { + if (SUCCEEDED(m_presentEngine->checkFormat(qt_evr_D3DFormatFromPixelFormat(format)))) { + m_canRenderToSurface = true; + break; + } + } + } } + + // TODO: if media type already set, renegotiate? } void EVRCustomPresenter::setSurface(QAbstractVideoSurface *surface) @@ -1044,9 +1066,6 @@ void EVRCustomPresenter::setSurface(QAbstractVideoSurface *surface) m_surface = surface; - if (m_D3DPresentEngine) - m_D3DPresentEngine->setSurface(surface); - if (m_surface) { connect(m_surface, &QAbstractVideoSurface::supportedFormatsChanged, this, &EVRCustomPresenter::supportedFormatsChanged); @@ -1140,11 +1159,7 @@ HRESULT EVRCustomPresenter::flush() if (m_renderState == RenderStopped) { // Repaint with black. - QMetaObject::invokeMethod(m_D3DPresentEngine, - "presentSample", - Qt::QueuedConnection, - Q_ARG(void*, 0), - Q_ARG(qint64, 0)); + presentSample(NULL); } return S_OK; @@ -1401,7 +1416,6 @@ HRESULT EVRCustomPresenter::setMediaType(IMFMediaType *mediaType) if (!mediaType) { qt_evr_safe_release(&m_mediaType); releaseResources(); - m_D3DPresentEngine->setSurfaceFormat(QVideoSurfaceFormat()); return S_OK; } @@ -1410,11 +1424,6 @@ HRESULT EVRCustomPresenter::setMediaType(IMFMediaType *mediaType) IMFSample *sample = NULL; - QVideoSurfaceFormat surfaceFormat; - UINT64 size; - int width; - int height; - // Cannot set the media type after shutdown. HRESULT hr = checkShutdown(); if (FAILED(hr)) @@ -1432,7 +1441,7 @@ HRESULT EVRCustomPresenter::setMediaType(IMFMediaType *mediaType) // Initialize the presenter engine with the new media type. // The presenter engine allocates the samples. - hr = m_D3DPresentEngine->createVideoSamples(mediaType, sampleQueue); + hr = m_presentEngine->createVideoSamples(mediaType, sampleQueue); if (FAILED(hr)) goto done; @@ -1465,15 +1474,6 @@ HRESULT EVRCustomPresenter::setMediaType(IMFMediaType *mediaType) m_mediaType = mediaType; m_mediaType->AddRef(); - // Create the surface format - hr = m_mediaType->GetUINT64(MF_MT_FRAME_SIZE, &size); - width = int(HI32(size)); - height = int(LO32(size)); - surfaceFormat = QVideoSurfaceFormat(QSize(width, height), - pixelFormatFromMediaType(m_mediaType), - QAbstractVideoBuffer::GLTextureHandle); - m_D3DPresentEngine->setSurfaceFormat(surfaceFormat); - done: if (FAILED(hr)) releaseResources(); @@ -1493,9 +1493,16 @@ HRESULT EVRCustomPresenter::isMediaTypeSupported(IMFMediaType *proposed) if (FAILED(hr)) return hr; - // Only accept pixel formats supported by the video surface - if (!m_supportedGLFormats.contains((DWORD)d3dFormat)) + QVideoFrame::PixelFormat pixelFormat = pixelFormatFromMediaType(proposed); + if (pixelFormat == QVideoFrame::Format_Invalid) + return MF_E_INVALIDMEDIATYPE; + + // When not rendering to texture, only accept pixel formats supported by the video surface + if (!m_presentEngine->isTextureRenderingEnabled() + && m_surface + && !m_surface->supportedPixelFormats().contains(pixelFormat)) { return MF_E_INVALIDMEDIATYPE; + } // Reject compressed media types. hr = proposed->IsCompressedFormat(&compressed); @@ -1505,9 +1512,8 @@ HRESULT EVRCustomPresenter::isMediaTypeSupported(IMFMediaType *proposed) if (compressed) return MF_E_INVALIDMEDIATYPE; - // The D3DPresentEngine checks whether the format can be used as - // the back-buffer format for the swap chains. - hr = m_D3DPresentEngine->checkFormat(d3dFormat); + // The D3DPresentEngine checks whether surfaces can be created using this format + hr = m_presentEngine->checkFormat(d3dFormat); if (FAILED(hr)) return hr; @@ -1788,7 +1794,7 @@ void EVRCustomPresenter::releaseResources() m_samplePool.clear(); - m_D3DPresentEngine->releaseResources(); + m_presentEngine->releaseResources(); } HRESULT EVRCustomPresenter::onSampleFree(IMFAsyncResult *result) @@ -1853,18 +1859,6 @@ done: return hr; } -void EVRCustomPresenter::startSurface() -{ - if (m_D3DPresentEngine) - m_D3DPresentEngine->start(); -} - -void EVRCustomPresenter::stopSurface() -{ - if (m_D3DPresentEngine) - m_D3DPresentEngine->stop(); -} - float EVRCustomPresenter::getMaxRate(bool thin) { // Non-thinned: @@ -1880,7 +1874,7 @@ float EVRCustomPresenter::getMaxRate(bool thin) if (!thin && m_mediaType) { qt_evr_getFrameRate(m_mediaType, &fps); - monitorRateHz = m_D3DPresentEngine->refreshRate(); + monitorRateHz = m_presentEngine->refreshRate(); if (fps.Denominator && fps.Numerator && monitorRateHz) { // Max Rate = Refresh Rate / Frame Rate @@ -1891,6 +1885,74 @@ float EVRCustomPresenter::getMaxRate(bool thin) return maxRate; } +bool EVRCustomPresenter::event(QEvent *e) +{ + if (e->type() == StartSurface) { + startSurface(); + return true; + } else if (e->type() == StopSurface) { + stopSurface(); + return true; + } else if (e->type() == PresentSample) { + PresentSampleEvent *ev = static_cast<PresentSampleEvent *>(e); + presentSample(ev->sample()); + return true; + } + + return QObject::event(e); +} + +void EVRCustomPresenter::startSurface() +{ + if (thread() != QThread::currentThread()) { + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(StartSurface))); + return; + } + + if (!m_surface || m_surface->isActive()) + return; + + QVideoSurfaceFormat format = m_presentEngine->videoSurfaceFormat(); + if (!format.isValid()) + return; + + m_surface->start(format); +} + +void EVRCustomPresenter::stopSurface() +{ + if (thread() != QThread::currentThread()) { + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(StopSurface))); + return; + } + + if (!m_surface || !m_surface->isActive()) + return; + + m_surface->stop(); +} + +void EVRCustomPresenter::presentSample(IMFSample *sample) +{ + if (thread() != QThread::currentThread()) { + QCoreApplication::postEvent(this, new PresentSampleEvent(sample)); + return; + } + + if (!m_surface || !m_surface->isActive() || !m_presentEngine->videoSurfaceFormat().isValid()) + return; + + QVideoFrame frame = m_presentEngine->makeVideoFrame(sample); + + if (m_surface->isActive() && m_surface->surfaceFormat() != m_presentEngine->videoSurfaceFormat()) { + m_surface->stop(); + if (!m_surface->start(m_presentEngine->videoSurfaceFormat())) + return; + } + + m_surface->present(frame); +} + HRESULT setDesiredSampleTime(IMFSample *sample, const LONGLONG &sampleTime, const LONGLONG &duration) { if (!sample) @@ -1925,8 +1987,6 @@ HRESULT clearDesiredSampleTime(IMFSample *sample) UINT32 counter = MFGetAttributeUINT32(sample, MFSamplePresenter_SampleCounter, (UINT32)-1); - sample->GetUnknown(MFSamplePresenter_SampleSwapChain, IID_IUnknown, (void**)&unkSwapChain); - hr = sample->QueryInterface(IID_PPV_ARGS(&desired)); if (SUCCEEDED(hr)) { desired->Clear(); @@ -1934,12 +1994,6 @@ HRESULT clearDesiredSampleTime(IMFSample *sample) hr = sample->SetUINT32(MFSamplePresenter_SampleCounter, counter); if (FAILED(hr)) goto done; - - if (unkSwapChain) { - hr = sample->SetUnknown(MFSamplePresenter_SampleSwapChain, unkSwapChain); - if (FAILED(hr)) - goto done; - } } done: @@ -1963,48 +2017,6 @@ HRESULT setMixerSourceRect(IMFTransform *mixer, const MFVideoNormalizedRect &sou return hr; } -DWORD getFourCCFromPixelFormat(QVideoFrame::PixelFormat pixelFormat) -{ - DWORD fourCC = 0; - switch (pixelFormat) { - case QVideoFrame::Format_ARGB32: - case QVideoFrame::Format_ARGB32_Premultiplied: - fourCC = MFVideoFormat_ARGB32.Data1; - break; - case QVideoFrame::Format_RGB32: - fourCC = MFVideoFormat_RGB32.Data1; - break; - case QVideoFrame::Format_RGB24: - fourCC = MFVideoFormat_RGB24.Data1; - break; - case QVideoFrame::Format_RGB565: - fourCC = MFVideoFormat_RGB565.Data1; - break; - case QVideoFrame::Format_RGB555: - fourCC = MFVideoFormat_RGB555.Data1; - break; - case QVideoFrame::Format_AYUV444: - case QVideoFrame::Format_AYUV444_Premultiplied: - fourCC = MFVideoFormat_AYUV.Data1; - break; - case QVideoFrame::Format_YUV420P: - fourCC = MFVideoFormat_I420.Data1; - break; - case QVideoFrame::Format_UYVY: - fourCC = MFVideoFormat_UYVY.Data1; - break; - case QVideoFrame::Format_YV12: - fourCC = MFVideoFormat_YV12.Data1; - break; - case QVideoFrame::Format_NV12: - fourCC = MFVideoFormat_NV12.Data1; - break; - default: - break; - } - return fourCC; -} - static QVideoFrame::PixelFormat pixelFormatFromMediaType(IMFMediaType *type) { GUID majorType; @@ -2013,12 +2025,30 @@ static QVideoFrame::PixelFormat pixelFormatFromMediaType(IMFMediaType *type) if (majorType != MFMediaType_Video) return QVideoFrame::Format_Invalid; - GUID subType; - if (FAILED(type->GetGUID(MF_MT_SUBTYPE, &subType))) + GUID subtype; + if (FAILED(type->GetGUID(MF_MT_SUBTYPE, &subtype))) return QVideoFrame::Format_Invalid; - if (subType == MFVideoFormat_RGB32) + if (subtype == MFVideoFormat_RGB32) return QVideoFrame::Format_RGB32; + else if (subtype == MFVideoFormat_ARGB32) + return QVideoFrame::Format_ARGB32; + else if (subtype == MFVideoFormat_RGB24) + return QVideoFrame::Format_RGB24; + else if (subtype == MFVideoFormat_RGB565) + return QVideoFrame::Format_RGB565; + else if (subtype == MFVideoFormat_RGB555) + return QVideoFrame::Format_RGB555; + else if (subtype == MFVideoFormat_AYUV) + return QVideoFrame::Format_AYUV444; + else if (subtype == MFVideoFormat_I420) + return QVideoFrame::Format_YUV420P; + else if (subtype == MFVideoFormat_UYVY) + return QVideoFrame::Format_UYVY; + else if (subtype == MFVideoFormat_YV12) + return QVideoFrame::Format_YV12; + else if (subtype == MFVideoFormat_NV12) + return QVideoFrame::Format_NV12; return QVideoFrame::Format_Invalid; } diff --git a/src/plugins/common/evr/evrcustompresenter.h b/src/plugins/common/evr/evrcustompresenter.h index b9067d9ae..e25780140 100644 --- a/src/plugins/common/evr/evrcustompresenter.h +++ b/src/plugins/common/evr/evrcustompresenter.h @@ -37,13 +37,19 @@ #include <QObject> #include <qmutex.h> #include <qqueue.h> +#include <qevent.h> +#include <qvideosurfaceformat.h> #include "evrdefs.h" +QT_BEGIN_NAMESPACE +class QAbstractVideoSurface; +QT_END_NAMESPACE + QT_USE_NAMESPACE +class EVRCustomPresenter; class D3DPresentEngine; -class QAbstractVideoSurface; template<class T> class AsyncCallback : public IMFAsyncCallback @@ -108,13 +114,9 @@ public: Flush = WM_USER + 2 }; - Scheduler(); + Scheduler(EVRCustomPresenter *presenter); ~Scheduler(); - void setCallback(QObject *cb) { - m_CB = cb; - } - void setFrameRate(const MFRatio &fps); void setClockRate(float rate) { m_playbackRate = rate; } @@ -135,10 +137,11 @@ public: private: DWORD schedulerThreadProcPrivate(); + EVRCustomPresenter *m_presenter; + QQueue<IMFSample*> m_scheduledSamples; // Samples waiting to be presented. IMFClock *m_clock; // Presentation clock. Can be NULL. - QObject *m_CB; // Weak reference; do not delete. DWORD m_threadID; HANDLE m_schedulerThread; @@ -181,8 +184,6 @@ class EVRCustomPresenter , public IMFGetService , public IMFTopologyServiceLookupClient { - Q_OBJECT - public: // Defines the state of the presenter. enum RenderState @@ -203,9 +204,18 @@ public: FrameStepComplete // Sample was rendered. }; - EVRCustomPresenter(); + enum PresenterEvents + { + StartSurface = QEvent::User, + StopSurface = QEvent::User + 1, + PresentSample = QEvent::User + 2 + }; + + EVRCustomPresenter(QAbstractVideoSurface *surface = 0); ~EVRCustomPresenter(); + bool isValid() const; + // IUnknown methods STDMETHODIMP QueryInterface(REFIID riid, void ** ppv); STDMETHODIMP_(ULONG) AddRef(); @@ -240,9 +250,11 @@ public: void supportedFormatsChanged(); void setSurface(QAbstractVideoSurface *surface); -private Q_SLOTS: void startSurface(); void stopSurface(); + void presentSample(IMFSample *sample); + + bool event(QEvent *); private: HRESULT checkShutdown() const @@ -342,7 +354,7 @@ private: MFVideoNormalizedRect m_sourceRect; float m_playbackRate; - D3DPresentEngine *m_D3DPresentEngine; // Rendering engine. (Never null if the constructor succeeds.) + D3DPresentEngine *m_presentEngine; // Rendering engine. (Never null if the constructor succeeds.) IMFClock *m_clock; // The EVR's clock. IMFTransform *m_mixer; // The EVR's mixer. @@ -350,7 +362,9 @@ private: IMFMediaType *m_mediaType; // Output media type QAbstractVideoSurface *m_surface; - QList<DWORD> m_supportedGLFormats; + bool m_canRenderToSurface; + + IMFSample *m_sampleToPresent; }; bool qt_evr_setCustomPresenter(IUnknown *evr, EVRCustomPresenter *presenter); diff --git a/src/plugins/common/evr/evrd3dpresentengine.cpp b/src/plugins/common/evr/evrd3dpresentengine.cpp index 61cee88d7..77cd7e0c8 100644 --- a/src/plugins/common/evr/evrd3dpresentengine.cpp +++ b/src/plugins/common/evr/evrd3dpresentengine.cpp @@ -35,48 +35,23 @@ #include "evrhelpers.h" -#include <qtgui/qguiapplication.h> -#include <qpa/qplatformnativeinterface.h> -#include <qtgui/qopenglcontext.h> #include <qabstractvideobuffer.h> #include <QAbstractVideoSurface> #include <qvideoframe.h> #include <QDebug> -#include <qopenglcontext.h> -#include <qopenglfunctions.h> -#include <qwindow.h> - -#include <EGL/egl.h> -#include <EGL/eglext.h> -#include <d3d9.h> -#include <dxva2api.h> -#include <WinUser.h> -#include <evr.h> +#include <qthread.h> +#include <private/qmediaopenglhelper_p.h> + +#ifdef MAYBE_ANGLE +# include <qtgui/qguiapplication.h> +# include <qpa/qplatformnativeinterface.h> +# include <qopenglfunctions.h> +# include <EGL/eglext.h> +#endif static const int PRESENTER_BUFFER_COUNT = 3; -class TextureVideoBuffer : public QAbstractVideoBuffer -{ -public: - TextureVideoBuffer(GLuint textureId) - : QAbstractVideoBuffer(GLTextureHandle) - , m_textureId(textureId) - {} - - ~TextureVideoBuffer() {} - - MapMode mapMode() const { return NotMapped; } - uchar *map(MapMode, int*, int*) { return 0; } - void unmap() {} - - QVariant handle() const - { - return QVariant::fromValue<unsigned int>(m_textureId); - } - -private: - GLuint m_textureId; -}; +#ifdef MAYBE_ANGLE EGLWrapper::EGLWrapper() { @@ -140,22 +115,160 @@ EGLBoolean EGLWrapper::releaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLin return m_eglReleaseTexImage(dpy, surface, buffer); } + +class OpenGLResources : public QObject +{ +public: + OpenGLResources() + : egl(new EGLWrapper) + , eglDisplay(0) + , eglSurface(0) + , glTexture(0) + {} + + void release() + { + if (thread() == QThread::currentThread()) + delete this; + else + deleteLater(); + } + + EGLWrapper *egl; + EGLDisplay *eglDisplay; + EGLSurface eglSurface; + unsigned int glTexture; + +private: + ~OpenGLResources() + { + Q_ASSERT(QOpenGLContext::currentContext() != NULL); + + if (eglSurface && egl) { + egl->releaseTexImage(eglDisplay, eglSurface, EGL_BACK_BUFFER); + egl->destroySurface(eglDisplay, eglSurface); + } + if (glTexture) + QOpenGLContext::currentContext()->functions()->glDeleteTextures(1, &glTexture); + + delete egl; + } +}; + +#endif // MAYBE_ANGLE + + +class IMFSampleVideoBuffer: public QAbstractVideoBuffer +{ +public: + IMFSampleVideoBuffer(D3DPresentEngine *engine, IMFSample *sample, QAbstractVideoBuffer::HandleType handleType) + : QAbstractVideoBuffer(handleType) + , m_engine(engine) + , m_sample(sample) + , m_surface(0) + , m_mapMode(NotMapped) + , m_textureUpdated(false) + { + if (m_sample) { + m_sample->AddRef(); + + IMFMediaBuffer *buffer; + if (SUCCEEDED(m_sample->GetBufferByIndex(0, &buffer))) { + MFGetService(buffer, + mr_BUFFER_SERVICE, + iid_IDirect3DSurface9, + reinterpret_cast<void **>(&m_surface)); + buffer->Release(); + } + } + } + + ~IMFSampleVideoBuffer() + { + if (m_surface) { + if (m_mapMode != NotMapped) + m_surface->UnlockRect(); + m_surface->Release(); + } + if (m_sample) + m_sample->Release(); + } + + QVariant handle() const; + + MapMode mapMode() const { return m_mapMode; } + uchar *map(MapMode, int*, int*); + void unmap(); + +private: + mutable D3DPresentEngine *m_engine; + IMFSample *m_sample; + IDirect3DSurface9 *m_surface; + MapMode m_mapMode; + mutable bool m_textureUpdated; +}; + +uchar *IMFSampleVideoBuffer::map(MapMode mode, int *numBytes, int *bytesPerLine) +{ + if (!m_surface || m_mapMode != NotMapped) + return 0; + + D3DSURFACE_DESC desc; + if (FAILED(m_surface->GetDesc(&desc))) + return 0; + + D3DLOCKED_RECT rect; + if (FAILED(m_surface->LockRect(&rect, NULL, mode == ReadOnly ? D3DLOCK_READONLY : 0))) + return 0; + + m_mapMode = mode; + + if (numBytes) + *numBytes = (int)(rect.Pitch * desc.Height); + + if (bytesPerLine) + *bytesPerLine = (int)rect.Pitch; + + return reinterpret_cast<uchar *>(rect.pBits); +} + +void IMFSampleVideoBuffer::unmap() +{ + if (m_mapMode == NotMapped) + return; + + m_mapMode = NotMapped; + m_surface->UnlockRect(); +} + +QVariant IMFSampleVideoBuffer::handle() const +{ + QVariant handle; + +#ifdef MAYBE_ANGLE + if (handleType() != GLTextureHandle) + return handle; + + if (m_textureUpdated || m_engine->updateTexture(m_surface)) { + m_textureUpdated = true; + handle = QVariant::fromValue<unsigned int>(m_engine->m_glResources->glTexture); + } +#endif + + return handle; +} + + D3DPresentEngine::D3DPresentEngine() - : QObject() - , m_mutex(QMutex::Recursive) - , m_deviceResetToken(0) + : m_deviceResetToken(0) , m_D3D9(0) , m_device(0) , m_deviceManager(0) - , m_surface(0) - , m_glContext(0) - , m_offscreenSurface(0) - , m_eglDisplay(0) - , m_eglConfig(0) - , m_eglSurface(0) - , m_glTexture(0) + , m_useTextureRendering(false) +#ifdef MAYBE_ANGLE + , m_glResources(0) , m_texture(0) - , m_egl(0) +#endif { ZeroMemory(&m_displayMode, sizeof(m_displayMode)); @@ -172,47 +285,110 @@ D3DPresentEngine::D3DPresentEngine() D3DPresentEngine::~D3DPresentEngine() { - qt_evr_safe_release(&m_texture); + releaseResources(); + qt_evr_safe_release(&m_device); qt_evr_safe_release(&m_deviceManager); qt_evr_safe_release(&m_D3D9); +} - if (m_eglSurface) { - m_egl->releaseTexImage(m_eglDisplay, m_eglSurface, EGL_BACK_BUFFER); - m_egl->destroySurface(m_eglDisplay, m_eglSurface); - m_eglSurface = NULL; - } - if (m_glTexture) { - if (QOpenGLContext *current = QOpenGLContext::currentContext()) - current->functions()->glDeleteTextures(1, &m_glTexture); - else - qWarning() << "D3DPresentEngine: Cannot obtain GL context, unable to delete textures"; - } +HRESULT D3DPresentEngine::initializeD3D() +{ + HRESULT hr = Direct3DCreate9Ex(D3D_SDK_VERSION, &m_D3D9); - delete m_glContext; - delete m_offscreenSurface; - delete m_egl; + if (SUCCEEDED(hr)) + hr = DXVA2CreateDirect3DDeviceManager9(&m_deviceResetToken, &m_deviceManager); + + return hr; } -void D3DPresentEngine::start() +HRESULT D3DPresentEngine::createD3DDevice() { - QMutexLocker locker(&m_mutex); + HRESULT hr = S_OK; + HWND hwnd = NULL; + UINT uAdapterID = D3DADAPTER_DEFAULT; + DWORD vp = 0; - if (!m_surfaceFormat.isValid()) - return; + D3DCAPS9 ddCaps; + ZeroMemory(&ddCaps, sizeof(ddCaps)); + + IDirect3DDevice9Ex* device = NULL; + + if (!m_D3D9 || !m_deviceManager) + return MF_E_NOT_INITIALIZED; + + hwnd = ::GetShellWindow(); + + D3DPRESENT_PARAMETERS pp; + ZeroMemory(&pp, sizeof(pp)); + + pp.BackBufferWidth = 1; + pp.BackBufferHeight = 1; + pp.BackBufferFormat = D3DFMT_UNKNOWN; + pp.BackBufferCount = 1; + pp.Windowed = TRUE; + pp.SwapEffect = D3DSWAPEFFECT_DISCARD; + pp.BackBufferFormat = D3DFMT_UNKNOWN; + pp.hDeviceWindow = hwnd; + pp.Flags = D3DPRESENTFLAG_VIDEO; + pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; - if (!m_texture) - createOffscreenTexture(); + hr = m_D3D9->GetDeviceCaps(uAdapterID, D3DDEVTYPE_HAL, &ddCaps); + if (FAILED(hr)) + goto done; + + if (ddCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) + vp = D3DCREATE_HARDWARE_VERTEXPROCESSING; + else + vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING; - if (m_surface && !m_surface->isActive()) - m_surface->start(m_surfaceFormat); + hr = m_D3D9->CreateDeviceEx( + uAdapterID, + D3DDEVTYPE_HAL, + pp.hDeviceWindow, + vp | D3DCREATE_NOWINDOWCHANGES | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE, + &pp, + NULL, + &device + ); + if (FAILED(hr)) + goto done; + + hr = m_D3D9->GetAdapterDisplayMode(uAdapterID, &m_displayMode); + if (FAILED(hr)) + goto done; + + hr = m_deviceManager->ResetDevice(device, m_deviceResetToken); + if (FAILED(hr)) + goto done; + + qt_evr_safe_release(&m_device); + + m_device = device; + m_device->AddRef(); + +done: + qt_evr_safe_release(&device); + return hr; } -void D3DPresentEngine::stop() +bool D3DPresentEngine::isValid() const { - QMutexLocker locker(&m_mutex); - if (m_surface && m_surface->isActive()) - m_surface->stop(); + return m_device != NULL; +} + +void D3DPresentEngine::releaseResources() +{ + m_surfaceFormat = QVideoSurfaceFormat(); + +#ifdef MAYBE_ANGLE + qt_evr_safe_release(&m_texture); + + if (m_glResources) { + m_glResources->release(); // deleted in GL thread + m_glResources = NULL; + } +#endif } HRESULT D3DPresentEngine::getService(REFGUID, REFIID riid, void** ppv) @@ -235,33 +411,52 @@ HRESULT D3DPresentEngine::getService(REFGUID, REFIID riid, void** ppv) HRESULT D3DPresentEngine::checkFormat(D3DFORMAT format) { - HRESULT hr = S_OK; + if (!m_D3D9 || !m_device) + return E_FAIL; - UINT uAdapter = D3DADAPTER_DEFAULT; - D3DDEVTYPE type = D3DDEVTYPE_HAL; + HRESULT hr = S_OK; D3DDISPLAYMODE mode; D3DDEVICE_CREATION_PARAMETERS params; - // Our shared D3D/EGL surface only supports RGB32, - // reject all other formats - if (format != D3DFMT_X8R8G8B8) - return MF_E_INVALIDMEDIATYPE; - - if (m_device) { - hr = m_device->GetCreationParameters(¶ms); - if (FAILED(hr)) - return hr; + hr = m_device->GetCreationParameters(¶ms); + if (FAILED(hr)) + return hr; - uAdapter = params.AdapterOrdinal; - type = params.DeviceType; - } + UINT uAdapter = params.AdapterOrdinal; + D3DDEVTYPE type = params.DeviceType; hr = m_D3D9->GetAdapterDisplayMode(uAdapter, &mode); if (FAILED(hr)) return hr; - return m_D3D9->CheckDeviceType(uAdapter, type, mode.Format, format, TRUE); + hr = m_D3D9->CheckDeviceFormat(uAdapter, type, mode.Format, + D3DUSAGE_RENDERTARGET, + D3DRTYPE_SURFACE, + format); + + if (m_useTextureRendering && format != D3DFMT_X8R8G8B8 && format != D3DFMT_A8R8G8B8) { + // The texture is always in RGB32 so the d3d driver must support conversion from the + // requested format to RGB32. + hr = m_D3D9->CheckDeviceFormatConversion(uAdapter, type, format, D3DFMT_X8R8G8B8); + } + + return hr; +} + +bool D3DPresentEngine::supportsTextureRendering() const +{ +#ifdef MAYBE_ANGLE + return QMediaOpenGLHelper::isANGLE(); +#else + return false; +#endif +} + +void D3DPresentEngine::setHint(Hint hint, bool enable) +{ + if (hint == RenderToTexture) + m_useTextureRendering = enable && supportsTextureRendering(); } HRESULT D3DPresentEngine::createVideoSamples(IMFMediaType *format, QList<IMFSample*> &videoSampleQueue) @@ -270,211 +465,148 @@ HRESULT D3DPresentEngine::createVideoSamples(IMFMediaType *format, QList<IMFSamp return MF_E_UNEXPECTED; HRESULT hr = S_OK; - D3DPRESENT_PARAMETERS pp; - IDirect3DSwapChain9 *swapChain = NULL; + IDirect3DSurface9 *surface = NULL; IMFSample *videoSample = NULL; - QMutexLocker locker(&m_mutex); - releaseResources(); - // Get the swap chain parameters from the media type. - hr = getSwapChainPresentParameters(format, &pp); + UINT32 width = 0, height = 0; + hr = MFGetAttributeSize(format, MF_MT_FRAME_SIZE, &width, &height); if (FAILED(hr)) - goto done; + return hr; + + DWORD d3dFormat = 0; + hr = qt_evr_getFourCC(format, &d3dFormat); + if (FAILED(hr)) + return hr; // Create the video samples. for (int i = 0; i < PRESENTER_BUFFER_COUNT; i++) { - // Create a new swap chain. - hr = m_device->CreateAdditionalSwapChain(&pp, &swapChain); + hr = m_device->CreateRenderTarget(width, height, + (D3DFORMAT)d3dFormat, + D3DMULTISAMPLE_NONE, + 0, + TRUE, + &surface, NULL); if (FAILED(hr)) goto done; - // Create the video sample from the swap chain. - hr = createD3DSample(swapChain, &videoSample); + hr = MFCreateVideoSampleFromSurface(surface, &videoSample); if (FAILED(hr)) goto done; - // Add it to the list. videoSample->AddRef(); videoSampleQueue.append(videoSample); - // Set the swap chain pointer as a custom attribute on the sample. This keeps - // a reference count on the swap chain, so that the swap chain is kept alive - // for the duration of the sample's lifetime. - hr = videoSample->SetUnknown(MFSamplePresenter_SampleSwapChain, swapChain); - if (FAILED(hr)) - goto done; - qt_evr_safe_release(&videoSample); - qt_evr_safe_release(&swapChain); + qt_evr_safe_release(&surface); } done: - if (FAILED(hr)) + if (SUCCEEDED(hr)) { + m_surfaceFormat = QVideoSurfaceFormat(QSize(width, height), + m_useTextureRendering ? QVideoFrame::Format_RGB32 + : qt_evr_pixelFormatFromD3DFormat((D3DFORMAT)d3dFormat), + m_useTextureRendering ? QAbstractVideoBuffer::GLTextureHandle + : QAbstractVideoBuffer::NoHandle); + } else { releaseResources(); + } - qt_evr_safe_release(&swapChain); qt_evr_safe_release(&videoSample); + qt_evr_safe_release(&surface); return hr; } -void D3DPresentEngine::releaseResources() +QVideoFrame D3DPresentEngine::makeVideoFrame(IMFSample *sample) { -} + if (!sample) + return QVideoFrame(); -void D3DPresentEngine::presentSample(void *opaque, qint64) -{ - HRESULT hr = S_OK; + QVideoFrame frame(new IMFSampleVideoBuffer(this, sample, m_surfaceFormat.handleType()), + m_surfaceFormat.frameSize(), + m_surfaceFormat.pixelFormat()); - IMFSample *sample = reinterpret_cast<IMFSample*>(opaque); - IMFMediaBuffer* buffer = NULL; - IDirect3DSurface9* surface = NULL; - - if (m_surface && m_surface->isActive()) { - if (sample) { - // Get the buffer from the sample. - hr = sample->GetBufferByIndex(0, &buffer); - if (FAILED(hr)) - goto done; - - // Get the surface from the buffer. - hr = MFGetService(buffer, mr_BUFFER_SERVICE, IID_PPV_ARGS(&surface)); - if (FAILED(hr)) - goto done; - } + // WMF uses 100-nanosecond units, Qt uses microseconds + LONGLONG startTime = -1; + if (SUCCEEDED(sample->GetSampleTime(&startTime))) { + frame.setStartTime(startTime * 0.1); - if (surface && updateTexture(surface)) { - QVideoFrame frame = QVideoFrame(new TextureVideoBuffer(m_glTexture), - m_surfaceFormat.frameSize(), - m_surfaceFormat.pixelFormat()); - - // WMF uses 100-nanosecond units, Qt uses microseconds - LONGLONG startTime = -1; - if (SUCCEEDED(sample->GetSampleTime(&startTime))) { - frame.setStartTime(startTime * 0.1); - - LONGLONG duration = -1; - if (SUCCEEDED(sample->GetSampleDuration(&duration))) - frame.setEndTime((startTime + duration) * 0.1); - } - - m_surface->present(frame); - } + LONGLONG duration = -1; + if (SUCCEEDED(sample->GetSampleDuration(&duration))) + frame.setEndTime((startTime + duration) * 0.1); } -done: - qt_evr_safe_release(&surface); - qt_evr_safe_release(&buffer); - qt_evr_safe_release(&sample); + return frame; } -void D3DPresentEngine::setSurface(QAbstractVideoSurface *surface) -{ - QMutexLocker locker(&m_mutex); - m_surface = surface; -} +#ifdef MAYBE_ANGLE -void D3DPresentEngine::setSurfaceFormat(const QVideoSurfaceFormat &format) +bool D3DPresentEngine::createRenderTexture() { - QMutexLocker locker(&m_mutex); - m_surfaceFormat = format; -} + if (m_texture) + return true; -void D3DPresentEngine::createOffscreenTexture() -{ - // First, check if we have a context on this thread - QOpenGLContext *currentContext = QOpenGLContext::currentContext(); - - if (!currentContext) { - //Create OpenGL context and set share context from surface - QOpenGLContext *shareContext = qobject_cast<QOpenGLContext*>(m_surface->property("GLContext").value<QObject*>()); - if (!shareContext) - return; - - m_offscreenSurface = new QWindow; - m_offscreenSurface->setSurfaceType(QWindow::OpenGLSurface); - //Needs geometry to be a valid surface, but size is not important - m_offscreenSurface->setGeometry(-1, -1, 1, 1); - m_offscreenSurface->create(); - - m_glContext = new QOpenGLContext; - m_glContext->setFormat(m_offscreenSurface->requestedFormat()); - m_glContext->setShareContext(shareContext); - - if (!m_glContext->create()) { - delete m_glContext; - delete m_offscreenSurface; - m_glContext = 0; - m_offscreenSurface = 0; - return; - } - - currentContext = m_glContext; - } + Q_ASSERT(QOpenGLContext::currentContext() != NULL); - if (m_glContext) - m_glContext->makeCurrent(m_offscreenSurface); + if (!m_glResources) + m_glResources = new OpenGLResources; - if (!m_egl) - m_egl = new EGLWrapper; + QOpenGLContext *currentContext = QOpenGLContext::currentContext(); + if (!currentContext) + return false; QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface(); - m_eglDisplay = static_cast<EGLDisplay*>( + m_glResources->eglDisplay = static_cast<EGLDisplay*>( nativeInterface->nativeResourceForContext("eglDisplay", currentContext)); - m_eglConfig = static_cast<EGLConfig*>( + EGLConfig *eglConfig = static_cast<EGLConfig*>( nativeInterface->nativeResourceForContext("eglConfig", currentContext)); - currentContext->functions()->glGenTextures(1, &m_glTexture); + currentContext->functions()->glGenTextures(1, &m_glResources->glTexture); - int w = m_surfaceFormat.frameWidth(); - int h = m_surfaceFormat.frameHeight(); bool hasAlpha = currentContext->format().hasAlpha(); EGLint attribs[] = { - EGL_WIDTH, w, - EGL_HEIGHT, h, + EGL_WIDTH, m_surfaceFormat.frameWidth(), + EGL_HEIGHT, m_surfaceFormat.frameHeight(), EGL_TEXTURE_FORMAT, hasAlpha ? EGL_TEXTURE_RGBA : EGL_TEXTURE_RGB, EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, EGL_NONE }; - EGLSurface pbuffer = m_egl->createPbufferSurface(m_eglDisplay, m_eglConfig, attribs); + EGLSurface pbuffer = m_glResources->egl->createPbufferSurface(m_glResources->eglDisplay, eglConfig, attribs); HANDLE share_handle = 0; PFNEGLQUERYSURFACEPOINTERANGLEPROC eglQuerySurfacePointerANGLE = - reinterpret_cast<PFNEGLQUERYSURFACEPOINTERANGLEPROC>(m_egl->getProcAddress("eglQuerySurfacePointerANGLE")); + reinterpret_cast<PFNEGLQUERYSURFACEPOINTERANGLEPROC>(m_glResources->egl->getProcAddress("eglQuerySurfacePointerANGLE")); Q_ASSERT(eglQuerySurfacePointerANGLE); eglQuerySurfacePointerANGLE( - m_eglDisplay, + m_glResources->eglDisplay, pbuffer, EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, &share_handle); - m_device->CreateTexture(w, h, 1, + m_device->CreateTexture(m_surfaceFormat.frameWidth(), m_surfaceFormat.frameHeight(), 1, D3DUSAGE_RENDERTARGET, hasAlpha ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &m_texture, &share_handle); - m_eglSurface = pbuffer; + m_glResources->eglSurface = pbuffer; + + QOpenGLContext::currentContext()->functions()->glBindTexture(GL_TEXTURE_2D, m_glResources->glTexture); + m_glResources->egl->bindTexImage(m_glResources->eglDisplay, m_glResources->eglSurface, EGL_BACK_BUFFER); - if (m_glContext) - m_glContext->doneCurrent(); + return m_texture != NULL; } bool D3DPresentEngine::updateTexture(IDirect3DSurface9 *src) { - if (!m_texture) + if (!m_texture && !createRenderTexture()) return false; - if (m_glContext) - m_glContext->makeCurrent(m_offscreenSurface); - - QOpenGLContext::currentContext()->functions()->glBindTexture(GL_TEXTURE_2D, m_glTexture); - IDirect3DSurface9 *dest = NULL; // Copy the sample surface to the shared D3D/EGL surface @@ -483,173 +615,24 @@ bool D3DPresentEngine::updateTexture(IDirect3DSurface9 *src) goto done; hr = m_device->StretchRect(src, NULL, dest, NULL, D3DTEXF_NONE); - if (FAILED(hr)) + if (FAILED(hr)) { qWarning("Failed to copy D3D surface"); - - if (hr == S_OK) - m_egl->bindTexImage(m_eglDisplay, m_eglSurface, EGL_BACK_BUFFER); + } else { + // Shared surfaces are not synchronized, there's no guarantee that + // StretchRect is complete when the texture is later rendered by Qt. + // To make sure the next rendered frame is up to date, flush the command pipeline + // using an event query. + IDirect3DQuery9 *eventQuery = NULL; + m_device->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery); + eventQuery->Issue(D3DISSUE_END); + while (eventQuery->GetData(NULL, 0, D3DGETDATA_FLUSH) == S_FALSE); + eventQuery->Release(); + } done: qt_evr_safe_release(&dest); - if (m_glContext) - m_glContext->doneCurrent(); - return SUCCEEDED(hr); } -HRESULT D3DPresentEngine::initializeD3D() -{ - HRESULT hr = Direct3DCreate9Ex(D3D_SDK_VERSION, &m_D3D9); - - if (SUCCEEDED(hr)) - hr = DXVA2CreateDirect3DDeviceManager9(&m_deviceResetToken, &m_deviceManager); - - return hr; -} - -HRESULT D3DPresentEngine::createD3DDevice() -{ - HRESULT hr = S_OK; - HWND hwnd = NULL; - UINT uAdapterID = D3DADAPTER_DEFAULT; - DWORD vp = 0; - - D3DCAPS9 ddCaps; - ZeroMemory(&ddCaps, sizeof(ddCaps)); - - IDirect3DDevice9Ex* device = NULL; - - // Hold the lock because we might be discarding an existing device. - QMutexLocker locker(&m_mutex); - - if (!m_D3D9 || !m_deviceManager) - return MF_E_NOT_INITIALIZED; - - hwnd = ::GetShellWindow(); - - // Note: The presenter creates additional swap chains to present the - // video frames. Therefore, it does not use the device's implicit - // swap chain, so the size of the back buffer here is 1 x 1. - - D3DPRESENT_PARAMETERS pp; - ZeroMemory(&pp, sizeof(pp)); - - pp.BackBufferWidth = 1; - pp.BackBufferHeight = 1; - pp.BackBufferFormat = D3DFMT_UNKNOWN; - pp.BackBufferCount = 1; - pp.Windowed = TRUE; - pp.SwapEffect = D3DSWAPEFFECT_DISCARD; - pp.BackBufferFormat = D3DFMT_UNKNOWN; - pp.hDeviceWindow = hwnd; - pp.Flags = D3DPRESENTFLAG_VIDEO; - pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; - - hr = m_D3D9->GetDeviceCaps(uAdapterID, D3DDEVTYPE_HAL, &ddCaps); - if (FAILED(hr)) - goto done; - - if (ddCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) - vp = D3DCREATE_HARDWARE_VERTEXPROCESSING; - else - vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING; - - hr = m_D3D9->CreateDeviceEx( - uAdapterID, - D3DDEVTYPE_HAL, - pp.hDeviceWindow, - vp | D3DCREATE_NOWINDOWCHANGES | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE, - &pp, - NULL, - &device - ); - if (FAILED(hr)) - goto done; - - hr = m_D3D9->GetAdapterDisplayMode(uAdapterID, &m_displayMode); - if (FAILED(hr)) - goto done; - - hr = m_deviceManager->ResetDevice(device, m_deviceResetToken); - if (FAILED(hr)) - goto done; - - qt_evr_safe_release(&m_device); - - m_device = device; - m_device->AddRef(); - -done: - qt_evr_safe_release(&device); - return hr; -} - -HRESULT D3DPresentEngine::createD3DSample(IDirect3DSwapChain9 *swapChain, IMFSample **videoSample) -{ - D3DCOLOR clrBlack = D3DCOLOR_ARGB(0xFF, 0x00, 0x00, 0x00); - - IDirect3DSurface9* surface = NULL; - IMFSample* sample = NULL; - - // Get the back buffer surface. - HRESULT hr = swapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &surface); - if (FAILED(hr)) - goto done; - - // Fill it with black. - hr = m_device->ColorFill(surface, NULL, clrBlack); - if (FAILED(hr)) - goto done; - - hr = MFCreateVideoSampleFromSurface(surface, &sample); - if (FAILED(hr)) - goto done; - - *videoSample = sample; - (*videoSample)->AddRef(); - -done: - qt_evr_safe_release(&surface); - qt_evr_safe_release(&sample); - return hr; -} - -HRESULT D3DPresentEngine::getSwapChainPresentParameters(IMFMediaType *type, D3DPRESENT_PARAMETERS* pp) -{ - ZeroMemory(pp, sizeof(D3DPRESENT_PARAMETERS)); - - // Get some information about the video format. - - UINT32 width = 0, height = 0; - - HRESULT hr = MFGetAttributeSize(type, MF_MT_FRAME_SIZE, &width, &height); - if (FAILED(hr)) - return hr; - - DWORD d3dFormat = 0; - - hr = qt_evr_getFourCC(type, &d3dFormat); - if (FAILED(hr)) - return hr; - - ZeroMemory(pp, sizeof(D3DPRESENT_PARAMETERS)); - pp->BackBufferWidth = width; - pp->BackBufferHeight = height; - pp->Windowed = TRUE; - pp->SwapEffect = D3DSWAPEFFECT_DISCARD; - pp->BackBufferFormat = (D3DFORMAT)d3dFormat; - pp->hDeviceWindow = ::GetShellWindow(); - pp->Flags = D3DPRESENTFLAG_VIDEO; - pp->PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; - - D3DDEVICE_CREATION_PARAMETERS params; - hr = m_device->GetCreationParameters(¶ms); - if (FAILED(hr)) - return hr; - - if (params.DeviceType != D3DDEVTYPE_HAL) - pp->Flags |= D3DPRESENTFLAG_LOCKABLE_BACKBUFFER; - - return S_OK; -} +#endif // MAYBE_ANGLE diff --git a/src/plugins/common/evr/evrd3dpresentengine.h b/src/plugins/common/evr/evrd3dpresentengine.h index df695a5dd..f3bbb8b3e 100644 --- a/src/plugins/common/evr/evrd3dpresentengine.h +++ b/src/plugins/common/evr/evrd3dpresentengine.h @@ -34,33 +34,36 @@ #ifndef EVRD3DPRESENTENGINE_H #define EVRD3DPRESENTENGINE_H -#include <QObject> #include <EGL/egl.h> #include <QMutex> #include <d3d9types.h> #include <QVideoSurfaceFormat> +#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) +#define MAYBE_ANGLE +#endif + +QT_BEGIN_NAMESPACE +class QAbstractVideoSurface; +QT_END_NAMESPACE + struct IDirect3D9Ex; -struct IDirect3DDevice9; struct IDirect3DDevice9Ex; struct IDirect3DDeviceManager9; struct IDirect3DSurface9; struct IDirect3DTexture9; struct IMFSample; struct IMFMediaType; -struct IDirect3DSwapChain9; // Randomly generated GUIDs static const GUID MFSamplePresenter_SampleCounter = { 0xb0bb83cc, 0xf10f, 0x4e2e, { 0xaa, 0x2b, 0x29, 0xea, 0x5e, 0x92, 0xef, 0x85 } }; -static const GUID MFSamplePresenter_SampleSwapChain = -{ 0xad885bd1, 0x7def, 0x414a, { 0xb5, 0xb0, 0xd3, 0xd2, 0x63, 0xd6, 0xe9, 0x6d } }; - QT_USE_NAMESPACE -class QAbstractVideoSurface; -class QOpenGLContext; +#ifdef MAYBE_ANGLE + +class OpenGLResources; class EGLWrapper { @@ -87,40 +90,39 @@ private: EglReleaseTexImage m_eglReleaseTexImage; }; -class D3DPresentEngine : public QObject +#endif // MAYBE_ANGLE + +class D3DPresentEngine { - Q_OBJECT public: + enum Hint + { + RenderToTexture + }; + D3DPresentEngine(); virtual ~D3DPresentEngine(); - void start(); - void stop(); + bool isValid() const; + void setHint(Hint hint, bool enable = true); HRESULT getService(REFGUID guidService, REFIID riid, void** ppv); HRESULT checkFormat(D3DFORMAT format); - - HRESULT createVideoSamples(IMFMediaType *format, QList<IMFSample*>& videoSampleQueue); - void releaseResources(); - UINT refreshRate() const { return m_displayMode.RefreshRate; } - void setSurface(QAbstractVideoSurface *surface); - void setSurfaceFormat(const QVideoSurfaceFormat &format); + bool supportsTextureRendering() const; + bool isTextureRenderingEnabled() const { return m_useTextureRendering; } - void createOffscreenTexture(); - bool updateTexture(IDirect3DSurface9 *src); + HRESULT createVideoSamples(IMFMediaType *format, QList<IMFSample*>& videoSampleQueue); + QVideoSurfaceFormat videoSurfaceFormat() const { return m_surfaceFormat; } + QVideoFrame makeVideoFrame(IMFSample* sample); -public Q_SLOTS: - void presentSample(void* sample, qint64 llTarget); + void releaseResources(); private: HRESULT initializeD3D(); - HRESULT getSwapChainPresentParameters(IMFMediaType *type, D3DPRESENT_PARAMETERS *pp); HRESULT createD3DDevice(); - HRESULT createD3DSample(IDirect3DSwapChain9 *swapChain, IMFSample **videoSample); - QMutex m_mutex; UINT m_deviceResetToken; D3DDISPLAYMODE m_displayMode; @@ -130,17 +132,18 @@ private: IDirect3DDeviceManager9 *m_deviceManager; QVideoSurfaceFormat m_surfaceFormat; - QAbstractVideoSurface *m_surface; - QOpenGLContext *m_glContext; - QWindow *m_offscreenSurface; + bool m_useTextureRendering; + +#ifdef MAYBE_ANGLE + bool createRenderTexture(); + bool updateTexture(IDirect3DSurface9 *src); - EGLDisplay *m_eglDisplay; - EGLConfig *m_eglConfig; - EGLSurface m_eglSurface; - unsigned int m_glTexture; + OpenGLResources *m_glResources; IDirect3DTexture9 *m_texture; - EGLWrapper *m_egl; +#endif + + friend class IMFSampleVideoBuffer; }; #endif // EVRD3DPRESENTENGINE_H diff --git a/src/plugins/common/evr/evrhelpers.cpp b/src/plugins/common/evr/evrhelpers.cpp index ae289de3a..2338d40fc 100644 --- a/src/plugins/common/evr/evrhelpers.cpp +++ b/src/plugins/common/evr/evrhelpers.cpp @@ -33,6 +33,13 @@ #include "evrhelpers.h" +#ifndef D3DFMT_YV12 +#define D3DFMT_YV12 (D3DFORMAT)MAKEFOURCC ('Y', 'V', '1', '2') +#endif +#ifndef D3DFMT_NV12 +#define D3DFMT_NV12 (D3DFORMAT)MAKEFOURCC ('N', 'V', '1', '2') +#endif + HRESULT qt_evr_getFourCC(IMFMediaType *type, DWORD *fourCC) { if (!fourCC) @@ -101,3 +108,69 @@ bool qt_evr_isSampleTimePassed(IMFClock *clock, IMFSample *sample) return false; } + +QVideoFrame::PixelFormat qt_evr_pixelFormatFromD3DFormat(D3DFORMAT format) +{ + switch (format) { + case D3DFMT_R8G8B8: + return QVideoFrame::Format_RGB24; + case D3DFMT_A8R8G8B8: + return QVideoFrame::Format_ARGB32; + case D3DFMT_X8R8G8B8: + return QVideoFrame::Format_RGB32; + case D3DFMT_R5G6B5: + return QVideoFrame::Format_RGB565; + case D3DFMT_X1R5G5B5: + return QVideoFrame::Format_RGB555; + case D3DFMT_A8: + return QVideoFrame::Format_Y8; + case D3DFMT_A8B8G8R8: + return QVideoFrame::Format_BGRA32; + case D3DFMT_X8B8G8R8: + return QVideoFrame::Format_BGR32; + case D3DFMT_UYVY: + return QVideoFrame::Format_UYVY; + case D3DFMT_YUY2: + return QVideoFrame::Format_YUYV; + case D3DFMT_NV12: + return QVideoFrame::Format_NV12; + case D3DFMT_YV12: + return QVideoFrame::Format_YV12; + case D3DFMT_UNKNOWN: + default: + return QVideoFrame::Format_Invalid; + } +} + +D3DFORMAT qt_evr_D3DFormatFromPixelFormat(QVideoFrame::PixelFormat format) +{ + switch (format) { + case QVideoFrame::Format_RGB24: + return D3DFMT_R8G8B8; + case QVideoFrame::Format_ARGB32: + return D3DFMT_A8R8G8B8; + case QVideoFrame::Format_RGB32: + return D3DFMT_X8R8G8B8; + case QVideoFrame::Format_RGB565: + return D3DFMT_R5G6B5; + case QVideoFrame::Format_RGB555: + return D3DFMT_X1R5G5B5; + case QVideoFrame::Format_Y8: + return D3DFMT_A8; + case QVideoFrame::Format_BGRA32: + return D3DFMT_A8B8G8R8; + case QVideoFrame::Format_BGR32: + return D3DFMT_X8B8G8R8; + case QVideoFrame::Format_UYVY: + return D3DFMT_UYVY; + case QVideoFrame::Format_YUYV: + return D3DFMT_YUY2; + case QVideoFrame::Format_NV12: + return D3DFMT_NV12; + case QVideoFrame::Format_YV12: + return D3DFMT_YV12; + case QVideoFrame::Format_Invalid: + default: + return D3DFMT_UNKNOWN; + } +} diff --git a/src/plugins/common/evr/evrhelpers.h b/src/plugins/common/evr/evrhelpers.h index 3883379a0..1b1f64194 100644 --- a/src/plugins/common/evr/evrhelpers.h +++ b/src/plugins/common/evr/evrhelpers.h @@ -35,6 +35,9 @@ #define EVRHELPERS_H #include "evrdefs.h" +#include <qvideoframe.h> + +QT_USE_NAMESPACE template<class T> static inline void qt_evr_safe_release(T **unk) @@ -81,5 +84,8 @@ inline HRESULT qt_evr_getFrameRate(IMFMediaType *pType, MFRatio *pRatio) return MFGetAttributeRatio(pType, MF_MT_FRAME_RATE, (UINT32*)&pRatio->Numerator, (UINT32*)&pRatio->Denominator); } +QVideoFrame::PixelFormat qt_evr_pixelFormatFromD3DFormat(D3DFORMAT format); +D3DFORMAT qt_evr_D3DFormatFromPixelFormat(QVideoFrame::PixelFormat format); + #endif // EVRHELPERS_H diff --git a/src/plugins/directshow/player/directshowvideorenderercontrol.cpp b/src/plugins/directshow/player/directshowvideorenderercontrol.cpp index 6754c1852..027d2ce55 100644 --- a/src/plugins/directshow/player/directshowvideorenderercontrol.cpp +++ b/src/plugins/directshow/player/directshowvideorenderercontrol.cpp @@ -35,21 +35,17 @@ #include "videosurfacefilter.h" -#ifdef CUSTOM_EVR_PRESENTER +#ifdef HAVE_EVR #include "evrcustompresenter.h" #endif #include <qabstractvideosurface.h> -#include <QtMultimedia/private/qmediaopenglhelper_p.h> DirectShowVideoRendererControl::DirectShowVideoRendererControl(DirectShowEventLoop *loop, QObject *parent) : QVideoRendererControl(parent) , m_loop(loop) , m_surface(0) , m_filter(0) -#ifdef CUSTOM_EVR_PRESENTER - , m_evrPresenter(0) -#endif { } @@ -57,10 +53,6 @@ DirectShowVideoRendererControl::~DirectShowVideoRendererControl() { if (m_filter) m_filter->Release(); -#ifdef CUSTOM_EVR_PRESENTER - if (m_evrPresenter) - m_evrPresenter->Release(); -#endif } QAbstractVideoSurface *DirectShowVideoRendererControl::surface() const @@ -70,38 +62,34 @@ QAbstractVideoSurface *DirectShowVideoRendererControl::surface() const void DirectShowVideoRendererControl::setSurface(QAbstractVideoSurface *surface) { - if (surface != m_surface) { - m_surface = surface; + if (m_surface == surface) + return; - IBaseFilter *currentFilter = m_filter; + if (m_filter) { + m_filter->Release(); m_filter = 0; + } - if (surface) { -#ifdef CUSTOM_EVR_PRESENTER - if (!surface->supportedPixelFormats(QAbstractVideoBuffer::GLTextureHandle).isEmpty() - && QMediaOpenGLHelper::isANGLE()) { - m_evrPresenter = new EVRCustomPresenter; - m_evrPresenter->setSurface(surface); - m_filter = com_new<IBaseFilter>(clsid_EnhancedVideoRenderer); - if (!qt_evr_setCustomPresenter(m_filter, m_evrPresenter)) { - m_evrPresenter->Release(); - m_evrPresenter = 0; - m_filter->Release(); - m_filter = 0; - } - } - if (!m_filter) -#endif - { - m_filter = new VideoSurfaceFilter(surface, m_loop); - } - } + m_surface = surface; - emit filterChanged(); + if (m_surface) { +#ifdef HAVE_EVR + m_filter = com_new<IBaseFilter>(clsid_EnhancedVideoRenderer); + EVRCustomPresenter *evrPresenter = new EVRCustomPresenter(m_surface); + if (!evrPresenter->isValid() || !qt_evr_setCustomPresenter(m_filter, evrPresenter)) { + m_filter->Release(); + m_filter = 0; + } + evrPresenter->Release(); - if (currentFilter) - currentFilter->Release(); + if (!m_filter) +#endif + { + m_filter = new VideoSurfaceFilter(m_surface, m_loop); + } } + + emit filterChanged(); } IBaseFilter *DirectShowVideoRendererControl::filter() diff --git a/src/plugins/directshow/player/directshowvideorenderercontrol.h b/src/plugins/directshow/player/directshowvideorenderercontrol.h index e6f0bb3af..484fda263 100644 --- a/src/plugins/directshow/player/directshowvideorenderercontrol.h +++ b/src/plugins/directshow/player/directshowvideorenderercontrol.h @@ -39,11 +39,6 @@ #include <dshow.h> class DirectShowEventLoop; -class VideoSurfaceFilter; - -#ifdef CUSTOM_EVR_PRESENTER -class EVRCustomPresenter; -#endif QT_USE_NAMESPACE @@ -66,10 +61,6 @@ private: DirectShowEventLoop *m_loop; QAbstractVideoSurface *m_surface; IBaseFilter *m_filter; - -#ifdef CUSTOM_EVR_PRESENTER - EVRCustomPresenter *m_evrPresenter; -#endif }; #endif diff --git a/src/plugins/wmf/player/mfvideorenderercontrol.cpp b/src/plugins/wmf/player/mfvideorenderercontrol.cpp index 365cf537d..766b4b0d9 100644 --- a/src/plugins/wmf/player/mfvideorenderercontrol.cpp +++ b/src/plugins/wmf/player/mfvideorenderercontrol.cpp @@ -34,9 +34,7 @@ #include "mfvideorenderercontrol.h" #include "mfactivate.h" -#ifdef CUSTOM_EVR_PRESENTER #include "evrcustompresenter.h" -#endif #include <qabstractvideosurface.h> #include <qvideosurfaceformat.h> @@ -2222,7 +2220,6 @@ namespace }; } -#ifdef CUSTOM_EVR_PRESENTER class EVRCustomPresenterActivate : public MFAbstractActivate { @@ -2243,16 +2240,13 @@ private: QMutex m_mutex; }; -#endif // CUSTOM_EVR_PRESENTER MFVideoRendererControl::MFVideoRendererControl(QObject *parent) : QVideoRendererControl(parent) , m_surface(0) , m_currentActivate(0) , m_callback(0) -#ifdef CUSTOM_EVR_PRESENTER , m_presenterActivate(0) -#endif { } @@ -2266,13 +2260,11 @@ void MFVideoRendererControl::clear() if (m_surface) m_surface->stop(); -#ifdef CUSTOM_EVR_PRESENTER if (m_presenterActivate) { m_presenterActivate->ShutdownObject(); m_presenterActivate->Release(); m_presenterActivate = NULL; } -#endif if (m_currentActivate) { m_currentActivate->ShutdownObject(); @@ -2301,21 +2293,16 @@ void MFVideoRendererControl::setSurface(QAbstractVideoSurface *surface) connect(m_surface, SIGNAL(supportedFormatsChanged()), this, SLOT(supportedFormatsChanged())); } -#ifdef CUSTOM_EVR_PRESENTER if (m_presenterActivate) m_presenterActivate->setSurface(m_surface); - else -#endif - if (m_currentActivate) + else if (m_currentActivate) static_cast<VideoRendererActivate*>(m_currentActivate)->setSurface(m_surface); } void MFVideoRendererControl::customEvent(QEvent *event) { -#ifdef CUSTOM_EVR_PRESENTER if (m_presenterActivate) return; -#endif if (!m_currentActivate) return; @@ -2346,16 +2333,17 @@ void MFVideoRendererControl::customEvent(QEvent *event) void MFVideoRendererControl::supportedFormatsChanged() { + if (m_presenterActivate) + return; + if (m_currentActivate) static_cast<VideoRendererActivate*>(m_currentActivate)->supportedFormatsChanged(); } void MFVideoRendererControl::present() { -#ifdef CUSTOM_EVR_PRESENTER if (m_presenterActivate) return; -#endif if (m_currentActivate) static_cast<VideoRendererActivate*>(m_currentActivate)->present(); @@ -2367,28 +2355,19 @@ IMFActivate* MFVideoRendererControl::createActivate() clear(); -#ifdef CUSTOM_EVR_PRESENTER - // We can use the EVR with our custom presenter only if the surface supports OpenGL - // texture handles. We also require ANGLE (due to the D3D interop). - if (!m_surface->supportedPixelFormats(QAbstractVideoBuffer::GLTextureHandle).isEmpty() - && QMediaOpenGLHelper::isANGLE()) { - // Create the EVR media sink, but replace the presenter with our own - if (SUCCEEDED(MFCreateVideoRendererActivate(::GetShellWindow(), &m_currentActivate))) { - m_presenterActivate = new EVRCustomPresenterActivate; - m_currentActivate->SetUnknown(MF_ACTIVATE_CUSTOM_VIDEO_PRESENTER_ACTIVATE, m_presenterActivate); - } - } -#endif - - if (!m_currentActivate) + // Create the EVR media sink, but replace the presenter with our own + if (SUCCEEDED(MFCreateVideoRendererActivate(::GetShellWindow(), &m_currentActivate))) { + m_presenterActivate = new EVRCustomPresenterActivate; + m_currentActivate->SetUnknown(MF_ACTIVATE_CUSTOM_VIDEO_PRESENTER_ACTIVATE, m_presenterActivate); + } else { m_currentActivate = new VideoRendererActivate(this); + } setSurface(m_surface); return m_currentActivate; } -#ifdef CUSTOM_EVR_PRESENTER EVRCustomPresenterActivate::EVRCustomPresenterActivate() : MFAbstractActivate() @@ -2438,7 +2417,5 @@ void EVRCustomPresenterActivate::setSurface(QAbstractVideoSurface *surface) m_presenter->setSurface(surface); } -#endif // CUSTOM_EVR_PRESENTER - #include "moc_mfvideorenderercontrol.cpp" #include "mfvideorenderercontrol.moc" diff --git a/src/plugins/wmf/player/mfvideorenderercontrol.h b/src/plugins/wmf/player/mfvideorenderercontrol.h index 8ef4feeef..224fcea51 100644 --- a/src/plugins/wmf/player/mfvideorenderercontrol.h +++ b/src/plugins/wmf/player/mfvideorenderercontrol.h @@ -40,9 +40,7 @@ QT_USE_NAMESPACE -#ifdef CUSTOM_EVR_PRESENTER class EVRCustomPresenterActivate; -#endif class MFVideoRendererControl : public QVideoRendererControl { @@ -71,9 +69,7 @@ private: IMFActivate *m_currentActivate; IMFSampleGrabberSinkCallback *m_callback; -#ifdef CUSTOM_EVR_PRESENTER EVRCustomPresenterActivate *m_presenterActivate; -#endif }; #endif |