diff options
Diffstat (limited to 'src/plugins/common')
-rw-r--r-- | src/plugins/common/evr.pri | 20 | ||||
-rw-r--r-- | src/plugins/common/evr/evrcustompresenter.cpp | 2062 | ||||
-rw-r--r-- | src/plugins/common/evr/evrcustompresenter.h | 377 | ||||
-rw-r--r-- | src/plugins/common/evr/evrd3dpresentengine.cpp | 413 | ||||
-rw-r--r-- | src/plugins/common/evr/evrd3dpresentengine.h | 152 | ||||
-rw-r--r-- | src/plugins/common/evr/evrdefs.cpp | 48 | ||||
-rw-r--r-- | src/plugins/common/evr/evrdefs.h | 353 | ||||
-rw-r--r-- | src/plugins/common/evr/evrhelpers.cpp | 186 | ||||
-rw-r--r-- | src/plugins/common/evr/evrhelpers.h | 101 | ||||
-rw-r--r-- | src/plugins/common/evr/evrvideowindowcontrol.cpp | 362 | ||||
-rw-r--r-- | src/plugins/common/evr/evrvideowindowcontrol.h | 109 |
11 files changed, 0 insertions, 4183 deletions
diff --git a/src/plugins/common/evr.pri b/src/plugins/common/evr.pri deleted file mode 100644 index 2a1b383df..000000000 --- a/src/plugins/common/evr.pri +++ /dev/null @@ -1,20 +0,0 @@ -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 diff --git a/src/plugins/common/evr/evrcustompresenter.cpp b/src/plugins/common/evr/evrcustompresenter.cpp deleted file mode 100644 index b2dd0426c..000000000 --- a/src/plugins/common/evr/evrcustompresenter.cpp +++ /dev/null @@ -1,2062 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 https://www.qt.io/terms-conditions. For further -** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "evrcustompresenter.h" - -#include "evrd3dpresentengine.h" -#include "evrhelpers.h" - -#include <QtCore/qmutex.h> -#include <QtCore/qvarlengtharray.h> -#include <QtCore/qrect.h> -#include <qabstractvideosurface.h> -#include <qthread.h> -#include <qcoreapplication.h> -#include <qmath.h> -#include <QtCore/qdebug.h> - -#include <mutex> - -#include <float.h> -#include <evcode.h> - -QT_BEGIN_NAMESPACE - -const static MFRatio g_DefaultFrameRate = { 30, 1 }; -static const DWORD SCHEDULER_TIMEOUT = 5000; -static const MFTIME ONE_SECOND = 10000000; -static const LONG ONE_MSEC = 1000; - -// Function declarations. -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 QVideoFrame::PixelFormat pixelFormatFromMediaType(IMFMediaType *type); - -static inline LONG MFTimeToMsec(const LONGLONG& time) -{ - return (LONG)(time / (ONE_SECOND / ONE_MSEC)); -} - -bool qt_evr_setCustomPresenter(IUnknown *evr, EVRCustomPresenter *presenter) -{ - if (!evr || !presenter) - return false; - - HRESULT result = E_FAIL; - - IMFVideoRenderer *renderer = NULL; - if (SUCCEEDED(evr->QueryInterface(IID_PPV_ARGS(&renderer)))) { - result = renderer->InitializeRenderer(NULL, presenter); - renderer->Release(); - } - - return result == S_OK; -} - -class PresentSampleEvent : public QEvent -{ -public: - PresentSampleEvent(IMFSample *sample) - : QEvent(QEvent::Type(EVRCustomPresenter::PresentSample)) - , m_sample(sample) - { - if (m_sample) - m_sample->AddRef(); - } - - ~PresentSampleEvent() override - { - 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) - , m_flushEvent(0) - , m_playbackRate(1.0f) - , m_perFrameInterval(0) - , m_perFrame_1_4th(0) - , m_lastSampleTime(0) -{ -} - -Scheduler::~Scheduler() -{ - qt_evr_safe_release(&m_clock); - for (int i = 0; i < m_scheduledSamples.size(); ++i) - m_scheduledSamples[i]->Release(); - m_scheduledSamples.clear(); -} - -void Scheduler::setFrameRate(const MFRatio& fps) -{ - UINT64 AvgTimePerFrame = 0; - - // Convert to a duration. - MFFrameRateToAverageTimePerFrame(fps.Numerator, fps.Denominator, &AvgTimePerFrame); - - m_perFrameInterval = (MFTIME)AvgTimePerFrame; - - // Calculate 1/4th of this value, because we use it frequently. - m_perFrame_1_4th = m_perFrameInterval / 4; -} - -HRESULT Scheduler::startScheduler(IMFClock *clock) -{ - if (m_schedulerThread) - return E_UNEXPECTED; - - HRESULT hr = S_OK; - DWORD dwID = 0; - HANDLE hObjects[2]; - DWORD dwWait = 0; - - if (m_clock) - m_clock->Release(); - m_clock = clock; - if (m_clock) - m_clock->AddRef(); - - // Set a high the timer resolution (ie, short timer period). - timeBeginPeriod(1); - - // Create an event to wait for the thread to start. - m_threadReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - if (!m_threadReadyEvent) { - hr = HRESULT_FROM_WIN32(GetLastError()); - goto done; - } - - // Create an event to wait for flush commands to complete. - m_flushEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - if (!m_flushEvent) { - hr = HRESULT_FROM_WIN32(GetLastError()); - goto done; - } - - // Create the scheduler thread. - m_schedulerThread = CreateThread(NULL, 0, schedulerThreadProc, (LPVOID)this, 0, &dwID); - if (!m_schedulerThread) { - hr = HRESULT_FROM_WIN32(GetLastError()); - goto done; - } - - // Wait for the thread to signal the "thread ready" event. - hObjects[0] = m_threadReadyEvent; - hObjects[1] = m_schedulerThread; - dwWait = WaitForMultipleObjects(2, hObjects, FALSE, INFINITE); // Wait for EITHER of these handles. - if (WAIT_OBJECT_0 != dwWait) { - // The thread terminated early for some reason. This is an error condition. - CloseHandle(m_schedulerThread); - m_schedulerThread = NULL; - - hr = E_UNEXPECTED; - goto done; - } - - m_threadID = dwID; - -done: - // Regardless success/failure, we are done using the "thread ready" event. - if (m_threadReadyEvent) { - CloseHandle(m_threadReadyEvent); - m_threadReadyEvent = NULL; - } - return hr; -} - -HRESULT Scheduler::stopScheduler() -{ - if (!m_schedulerThread) - return S_OK; - - // Ask the scheduler thread to exit. - PostThreadMessage(m_threadID, Terminate, 0, 0); - - // Wait for the thread to exit. - WaitForSingleObject(m_schedulerThread, INFINITE); - - // Close handles. - CloseHandle(m_schedulerThread); - m_schedulerThread = NULL; - - CloseHandle(m_flushEvent); - m_flushEvent = NULL; - - // Discard samples. - m_mutex.lock(); - for (int i = 0; i < m_scheduledSamples.size(); ++i) - m_scheduledSamples[i]->Release(); - m_scheduledSamples.clear(); - m_mutex.unlock(); - - // Restore the timer resolution. - timeEndPeriod(1); - - return S_OK; -} - -HRESULT Scheduler::flush() -{ - if (m_schedulerThread) { - // Ask the scheduler thread to flush. - PostThreadMessage(m_threadID, Flush, 0 , 0); - - // Wait for the scheduler thread to signal the flush event, - // OR for the thread to terminate. - HANDLE objects[] = { m_flushEvent, m_schedulerThread }; - - WaitForMultipleObjects(ARRAYSIZE(objects), objects, FALSE, SCHEDULER_TIMEOUT); - } - - return S_OK; -} - -bool Scheduler::areSamplesScheduled() -{ - QMutexLocker locker(&m_mutex); - return m_scheduledSamples.count() > 0; -} - -HRESULT Scheduler::scheduleSample(IMFSample *sample, bool presentNow) -{ - if (!m_schedulerThread) - return MF_E_NOT_INITIALIZED; - - HRESULT hr = S_OK; - DWORD dwExitCode = 0; - - GetExitCodeThread(m_schedulerThread, &dwExitCode); - if (dwExitCode != STILL_ACTIVE) - return E_FAIL; - - if (presentNow || !m_clock) { - m_presenter->presentSample(sample); - } else { - // Queue the sample and ask the scheduler thread to wake up. - m_mutex.lock(); - sample->AddRef(); - m_scheduledSamples.enqueue(sample); - m_mutex.unlock(); - - if (SUCCEEDED(hr)) - PostThreadMessage(m_threadID, Schedule, 0, 0); - } - - return hr; -} - -HRESULT Scheduler::processSamplesInQueue(LONG *nextSleep) -{ - HRESULT hr = S_OK; - LONG wait = 0; - IMFSample *sample = NULL; - - // Process samples until the queue is empty or until the wait time > 0. - while (!m_scheduledSamples.isEmpty()) { - m_mutex.lock(); - sample = m_scheduledSamples.dequeue(); - m_mutex.unlock(); - - // Process the next sample in the queue. If the sample is not ready - // for presentation. the value returned in wait is > 0, which - // means the scheduler should sleep for that amount of time. - - hr = processSample(sample, &wait); - qt_evr_safe_release(&sample); - - if (FAILED(hr) || wait > 0) - break; - } - - // If the wait time is zero, it means we stopped because the queue is - // empty (or an error occurred). Set the wait time to infinite; this will - // make the scheduler thread sleep until it gets another thread message. - if (wait == 0) - wait = INFINITE; - - *nextSleep = wait; - return hr; -} - -HRESULT Scheduler::processSample(IMFSample *sample, LONG *pNextSleep) -{ - HRESULT hr = S_OK; - - LONGLONG hnsPresentationTime = 0; - LONGLONG hnsTimeNow = 0; - MFTIME hnsSystemTime = 0; - - bool presentNow = true; - LONG nextSleep = 0; - - if (m_clock) { - // Get the sample's time stamp. It is valid for a sample to - // have no time stamp. - hr = sample->GetSampleTime(&hnsPresentationTime); - - // Get the clock time. (But if the sample does not have a time stamp, - // we don't need the clock time.) - if (SUCCEEDED(hr)) - hr = m_clock->GetCorrelatedTime(0, &hnsTimeNow, &hnsSystemTime); - - // Calculate the time until the sample's presentation time. - // A negative value means the sample is late. - LONGLONG hnsDelta = hnsPresentationTime - hnsTimeNow; - if (m_playbackRate < 0) { - // For reverse playback, the clock runs backward. Therefore, the - // delta is reversed. - hnsDelta = - hnsDelta; - } - - if (hnsDelta < - m_perFrame_1_4th) { - // This sample is late. - presentNow = true; - } else if (hnsDelta > (3 * m_perFrame_1_4th)) { - // This sample is still too early. Go to sleep. - nextSleep = MFTimeToMsec(hnsDelta - (3 * m_perFrame_1_4th)); - - // Adjust the sleep time for the clock rate. (The presentation clock runs - // at m_fRate, but sleeping uses the system clock.) - if (m_playbackRate != 0) - nextSleep = (LONG)(nextSleep / qFabs(m_playbackRate)); - - // Don't present yet. - presentNow = false; - } - } - - if (presentNow) { - m_presenter->presentSample(sample); - } else { - // The sample is not ready yet. Return it to the queue. - m_mutex.lock(); - sample->AddRef(); - m_scheduledSamples.prepend(sample); - m_mutex.unlock(); - } - - *pNextSleep = nextSleep; - - return hr; -} - -DWORD WINAPI Scheduler::schedulerThreadProc(LPVOID parameter) -{ - Scheduler* scheduler = reinterpret_cast<Scheduler*>(parameter); - if (!scheduler) - return -1; - return scheduler->schedulerThreadProcPrivate(); -} - -DWORD Scheduler::schedulerThreadProcPrivate() -{ - HRESULT hr = S_OK; - MSG msg; - LONG wait = INFINITE; - bool exitThread = false; - - // Force the system to create a message queue for this thread. - // (See MSDN documentation for PostThreadMessage.) - PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); - - // Signal to the scheduler that the thread is ready. - SetEvent(m_threadReadyEvent); - - while (!exitThread) { - // Wait for a thread message OR until the wait time expires. - DWORD result = MsgWaitForMultipleObjects(0, NULL, FALSE, wait, QS_POSTMESSAGE); - - if (result == WAIT_TIMEOUT) { - // If we timed out, then process the samples in the queue - hr = processSamplesInQueue(&wait); - if (FAILED(hr)) - exitThread = true; - } - - while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { - bool processSamples = true; - - switch (msg.message) { - case Terminate: - exitThread = true; - break; - case Flush: - // Flushing: Clear the sample queue and set the event. - m_mutex.lock(); - for (int i = 0; i < m_scheduledSamples.size(); ++i) - m_scheduledSamples[i]->Release(); - m_scheduledSamples.clear(); - m_mutex.unlock(); - wait = INFINITE; - SetEvent(m_flushEvent); - break; - case Schedule: - // Process as many samples as we can. - if (processSamples) { - hr = processSamplesInQueue(&wait); - if (FAILED(hr)) - exitThread = true; - processSamples = (wait != (LONG)INFINITE); - } - break; - } - } - - } - - return (SUCCEEDED(hr) ? 0 : 1); -} - - -SamplePool::SamplePool() - : m_initialized(false) -{ -} - -SamplePool::~SamplePool() -{ - clear(); -} - -HRESULT SamplePool::getSample(IMFSample **sample) -{ - QMutexLocker locker(&m_mutex); - - if (!m_initialized) - return MF_E_NOT_INITIALIZED; - - if (m_videoSampleQueue.isEmpty()) - return MF_E_SAMPLEALLOCATOR_EMPTY; - - // Get a sample from the allocated queue. - - // It doesn't matter if we pull them from the head or tail of the list, - // but when we get it back, we want to re-insert it onto the opposite end. - // (see ReturnSample) - - IMFSample *taken = m_videoSampleQueue.takeFirst(); - - // Give the sample to the caller. - *sample = taken; - (*sample)->AddRef(); - - taken->Release(); - - return S_OK; -} - -HRESULT SamplePool::returnSample(IMFSample *sample) -{ - QMutexLocker locker(&m_mutex); - - if (!m_initialized) - return MF_E_NOT_INITIALIZED; - - m_videoSampleQueue.append(sample); - sample->AddRef(); - - return S_OK; -} - -HRESULT SamplePool::initialize(QList<IMFSample*> &samples) -{ - QMutexLocker locker(&m_mutex); - - if (m_initialized) - return MF_E_INVALIDREQUEST; - - // Move these samples into our allocated queue. - for (auto sample : qAsConst(samples)) { - sample->AddRef(); - m_videoSampleQueue.append(sample); - } - - m_initialized = true; - - for (auto sample : qAsConst(samples)) - sample->Release(); - samples.clear(); - return S_OK; -} - -HRESULT SamplePool::clear() -{ - QMutexLocker locker(&m_mutex); - - for (auto sample : qAsConst(m_videoSampleQueue)) - sample->Release(); - m_videoSampleQueue.clear(); - m_initialized = false; - - return S_OK; -} - - -EVRCustomPresenter::EVRCustomPresenter(QAbstractVideoSurface *surface) - : QObject() - , m_sampleFreeCB(this, &EVRCustomPresenter::onSampleFree) - , m_refCount(1) - , m_renderState(RenderShutdown) - , m_scheduler(this) - , m_tokenCounter(0) - , m_sampleNotify(false) - , m_repaint(false) - , m_prerolled(false) - , m_endStreaming(false) - , m_playbackRate(1.0f) - , m_presentEngine(new D3DPresentEngine) - , m_clock(0) - , m_mixer(0) - , m_mediaEventSink(0) - , m_mediaType(0) - , m_surface(0) - , m_canRenderToSurface(false) - , m_positionOffset(0) -{ - // Initial source rectangle = (0,0,1,1) - m_sourceRect.top = 0; - m_sourceRect.left = 0; - m_sourceRect.bottom = 1; - m_sourceRect.right = 1; - - 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); - - delete m_presentEngine; -} - -HRESULT EVRCustomPresenter::QueryInterface(REFIID riid, void ** ppvObject) -{ - if (!ppvObject) - return E_POINTER; - if (riid == IID_IMFGetService) { - *ppvObject = static_cast<IMFGetService*>(this); - } else if (riid == IID_IMFTopologyServiceLookupClient) { - *ppvObject = static_cast<IMFTopologyServiceLookupClient*>(this); - } else if (riid == IID_IMFVideoDeviceID) { - *ppvObject = static_cast<IMFVideoDeviceID*>(this); - } else if (riid == IID_IMFVideoPresenter) { - *ppvObject = static_cast<IMFVideoPresenter*>(this); - } else if (riid == IID_IMFRateSupport) { - *ppvObject = static_cast<IMFRateSupport*>(this); - } else if (riid == IID_IUnknown) { - *ppvObject = static_cast<IUnknown*>(static_cast<IMFGetService*>(this)); - } else if (riid == IID_IMFClockStateSink) { - *ppvObject = static_cast<IMFClockStateSink*>(this); - } else { - *ppvObject = NULL; - return E_NOINTERFACE; - } - AddRef(); - return S_OK; -} - -ULONG EVRCustomPresenter::AddRef() -{ - return InterlockedIncrement(&m_refCount); -} - -ULONG EVRCustomPresenter::Release() -{ - ULONG uCount = InterlockedDecrement(&m_refCount); - if (uCount == 0) - delete this; - return uCount; -} - -HRESULT EVRCustomPresenter::GetService(REFGUID guidService, REFIID riid, LPVOID *ppvObject) -{ - HRESULT hr = S_OK; - - if (!ppvObject) - return E_POINTER; - - // The only service GUID that we support is MR_VIDEO_RENDER_SERVICE. - if (guidService != mr_VIDEO_RENDER_SERVICE) - return MF_E_UNSUPPORTED_SERVICE; - - // First try to get the service interface from the D3DPresentEngine object. - hr = m_presentEngine->getService(guidService, riid, ppvObject); - if (FAILED(hr)) - // Next, check if this object supports the interface. - hr = QueryInterface(riid, ppvObject); - - return hr; -} - -HRESULT EVRCustomPresenter::GetDeviceID(IID* deviceID) -{ - if (!deviceID) - return E_POINTER; - - *deviceID = iid_IDirect3DDevice9; - - return S_OK; -} - -HRESULT EVRCustomPresenter::InitServicePointers(IMFTopologyServiceLookup *lookup) -{ - if (!lookup) - return E_POINTER; - - HRESULT hr = S_OK; - DWORD objectCount = 0; - - const std::lock_guard<QRecursiveMutex> locker(m_mutex); - - // Do not allow initializing when playing or paused. - if (isActive()) - return MF_E_INVALIDREQUEST; - - qt_evr_safe_release(&m_clock); - qt_evr_safe_release(&m_mixer); - qt_evr_safe_release(&m_mediaEventSink); - - // Ask for the clock. Optional, because the EVR might not have a clock. - objectCount = 1; - - lookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, - mr_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&m_clock), - &objectCount - ); - - // Ask for the mixer. (Required.) - objectCount = 1; - - hr = lookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, - mr_VIDEO_MIXER_SERVICE, IID_PPV_ARGS(&m_mixer), - &objectCount - ); - - if (FAILED(hr)) - return hr; - - // Make sure that we can work with this mixer. - hr = configureMixer(m_mixer); - if (FAILED(hr)) - return hr; - - // Ask for the EVR's event-sink interface. (Required.) - objectCount = 1; - - hr = lookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, - mr_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&m_mediaEventSink), - &objectCount - ); - - if (SUCCEEDED(hr)) - m_renderState = RenderStopped; - - return hr; -} - -HRESULT EVRCustomPresenter::ReleaseServicePointers() -{ - // Enter the shut-down state. - m_mutex.lock(); - - m_renderState = RenderShutdown; - - m_mutex.unlock(); - - // Flush any samples that were scheduled. - flush(); - - // Clear the media type and release related resources. - setMediaType(NULL); - - // Release all services that were acquired from InitServicePointers. - qt_evr_safe_release(&m_clock); - qt_evr_safe_release(&m_mixer); - qt_evr_safe_release(&m_mediaEventSink); - - 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; - - const std::lock_guard<QRecursiveMutex> locker(m_mutex); - - hr = checkShutdown(); - if (FAILED(hr)) - return hr; - - switch (message) { - // Flush all pending samples. - case MFVP_MESSAGE_FLUSH: - hr = flush(); - break; - - // Renegotiate the media type with the mixer. - case MFVP_MESSAGE_INVALIDATEMEDIATYPE: - hr = renegotiateMediaType(); - break; - - // The mixer received a new input sample. - case MFVP_MESSAGE_PROCESSINPUTNOTIFY: - hr = processInputNotify(); - break; - - // Streaming is about to start. - case MFVP_MESSAGE_BEGINSTREAMING: - hr = beginStreaming(); - break; - - // Streaming has ended. (The EVR has stopped.) - case MFVP_MESSAGE_ENDSTREAMING: - hr = endStreaming(); - break; - - // All input streams have ended. - case MFVP_MESSAGE_ENDOFSTREAM: - // Set the EOS flag. - m_endStreaming = true; - // Check if it's time to send the EC_COMPLETE event to the EVR. - hr = checkEndOfStream(); - break; - - // Frame-stepping is starting. - case MFVP_MESSAGE_STEP: - hr = prepareFrameStep(DWORD(param)); - break; - - // Cancels frame-stepping. - case MFVP_MESSAGE_CANCELSTEP: - hr = cancelFrameStep(); - break; - - default: - hr = E_INVALIDARG; // Unknown message. This case should never occur. - break; - } - - return hr; -} - -HRESULT EVRCustomPresenter::GetCurrentMediaType(IMFVideoMediaType **mediaType) -{ - HRESULT hr = S_OK; - - if (!mediaType) - return E_POINTER; - - *mediaType = NULL; - - const std::lock_guard<QRecursiveMutex> locker(m_mutex); - - hr = checkShutdown(); - if (FAILED(hr)) - return hr; - - if (!m_mediaType) - return MF_E_NOT_INITIALIZED; - - return m_mediaType->QueryInterface(IID_PPV_ARGS(mediaType)); -} - -HRESULT EVRCustomPresenter::OnClockStart(MFTIME, LONGLONG clockStartOffset) -{ - const std::lock_guard<QRecursiveMutex> locker(m_mutex); - - // We cannot start after shutdown. - HRESULT hr = checkShutdown(); - if (FAILED(hr)) - return hr; - - // Check if the clock is already active (not stopped). - if (isActive()) { - m_renderState = RenderStarted; - - // If the clock position changes while the clock is active, it - // is a seek request. We need to flush all pending samples. - if (clockStartOffset != PRESENTATION_CURRENT_POSITION) - flush(); - } else { - m_renderState = RenderStarted; - - // The clock has started from the stopped state. - - // Possibly we are in the middle of frame-stepping OR have samples waiting - // in the frame-step queue. Deal with these two cases first: - hr = startFrameStep(); - if (FAILED(hr)) - return hr; - } - - // Now try to get new output samples from the mixer. - processOutputLoop(); - - return hr; -} - -HRESULT EVRCustomPresenter::OnClockRestart(MFTIME) -{ - const std::lock_guard<QRecursiveMutex> locker(m_mutex); - - HRESULT hr = checkShutdown(); - if (FAILED(hr)) - return hr; - - // The EVR calls OnClockRestart only while paused. - - m_renderState = RenderStarted; - - // Possibly we are in the middle of frame-stepping OR we have samples waiting - // in the frame-step queue. Deal with these two cases first: - hr = startFrameStep(); - if (FAILED(hr)) - return hr; - - // Now resume the presentation loop. - processOutputLoop(); - - return hr; -} - -HRESULT EVRCustomPresenter::OnClockStop(MFTIME) -{ - const std::lock_guard<QRecursiveMutex> locker(m_mutex); - - HRESULT hr = checkShutdown(); - if (FAILED(hr)) - return hr; - - if (m_renderState != RenderStopped) { - m_renderState = RenderStopped; - flush(); - - // If we are in the middle of frame-stepping, cancel it now. - if (m_frameStep.state != FrameStepNone) - cancelFrameStep(); - } - - return S_OK; -} - -HRESULT EVRCustomPresenter::OnClockPause(MFTIME) -{ - const std::lock_guard<QRecursiveMutex> locker(m_mutex); - - // We cannot pause the clock after shutdown. - HRESULT hr = checkShutdown(); - - if (SUCCEEDED(hr)) - m_renderState = RenderPaused; - - return hr; -} - -HRESULT EVRCustomPresenter::OnClockSetRate(MFTIME, float rate) -{ - // Note: - // The presenter reports its maximum rate through the IMFRateSupport interface. - // Here, we assume that the EVR honors the maximum rate. - - const std::lock_guard<QRecursiveMutex> locker(m_mutex); - - HRESULT hr = checkShutdown(); - if (FAILED(hr)) - return hr; - - // If the rate is changing from zero (scrubbing) to non-zero, cancel the - // frame-step operation. - if ((m_playbackRate == 0.0f) && (rate != 0.0f)) { - cancelFrameStep(); - for (auto sample : qAsConst(m_frameStep.samples)) - sample->Release(); - m_frameStep.samples.clear(); - } - - m_playbackRate = rate; - - // Tell the scheduler about the new rate. - m_scheduler.setClockRate(rate); - - return S_OK; -} - -HRESULT EVRCustomPresenter::GetSlowestRate(MFRATE_DIRECTION, BOOL, float *rate) -{ - if (!rate) - return E_POINTER; - - const std::lock_guard<QRecursiveMutex> locker(m_mutex); - - HRESULT hr = checkShutdown(); - - if (SUCCEEDED(hr)) { - // There is no minimum playback rate, so the minimum is zero. - *rate = 0; - } - - return S_OK; -} - -HRESULT EVRCustomPresenter::GetFastestRate(MFRATE_DIRECTION direction, BOOL thin, float *rate) -{ - if (!rate) - return E_POINTER; - - const std::lock_guard<QRecursiveMutex> locker(m_mutex); - - float maxRate = 0.0f; - - HRESULT hr = checkShutdown(); - if (FAILED(hr)) - return hr; - - // Get the maximum *forward* rate. - maxRate = getMaxRate(thin); - - // For reverse playback, it's the negative of maxRate. - if (direction == MFRATE_REVERSE) - maxRate = -maxRate; - - *rate = maxRate; - - return S_OK; -} - -HRESULT EVRCustomPresenter::IsRateSupported(BOOL thin, float rate, float *nearestSupportedRate) -{ - const std::lock_guard<QRecursiveMutex> locker(m_mutex); - - float maxRate = 0.0f; - float nearestRate = rate; // If we support rate, that is the nearest. - - HRESULT hr = checkShutdown(); - if (FAILED(hr)) - return hr; - - // Find the maximum forward rate. - // Note: We have no minimum rate (that is, we support anything down to 0). - maxRate = getMaxRate(thin); - - if (qFabs(rate) > maxRate) { - // The (absolute) requested rate exceeds the maximum rate. - hr = MF_E_UNSUPPORTED_RATE; - - // The nearest supported rate is maxRate. - nearestRate = maxRate; - if (rate < 0) { - // Negative for reverse playback. - nearestRate = -nearestRate; - } - } - - // Return the nearest supported rate. - if (nearestSupportedRate) - *nearestSupportedRate = nearestRate; - - return hr; -} - -void EVRCustomPresenter::supportedFormatsChanged() -{ - const std::lock_guard<QRecursiveMutex> locker(m_mutex); - - m_canRenderToSurface = false; - m_presentEngine->setHint(D3DPresentEngine::RenderToTexture, false); - - // 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); - for (QVideoFrame::PixelFormat format : qAsConst(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) -{ - m_mutex.lock(); - - if (m_surface) { - disconnect(m_surface, &QAbstractVideoSurface::supportedFormatsChanged, - this, &EVRCustomPresenter::supportedFormatsChanged); - } - - m_surface = surface; - - if (m_surface) { - connect(m_surface, &QAbstractVideoSurface::supportedFormatsChanged, - this, &EVRCustomPresenter::supportedFormatsChanged); - } - - m_mutex.unlock(); - - supportedFormatsChanged(); -} - -HRESULT EVRCustomPresenter::configureMixer(IMFTransform *mixer) -{ - // Set the zoom rectangle (ie, the source clipping rectangle). - return setMixerSourceRect(mixer, m_sourceRect); -} - -HRESULT EVRCustomPresenter::renegotiateMediaType() -{ - HRESULT hr = S_OK; - bool foundMediaType = false; - - IMFMediaType *mixerType = NULL; - IMFMediaType *optimalType = NULL; - - if (!m_mixer) - return MF_E_INVALIDREQUEST; - - // Loop through all of the mixer's proposed output types. - DWORD typeIndex = 0; - while (!foundMediaType && (hr != MF_E_NO_MORE_TYPES)) { - qt_evr_safe_release(&mixerType); - qt_evr_safe_release(&optimalType); - - // Step 1. Get the next media type supported by mixer. - hr = m_mixer->GetOutputAvailableType(0, typeIndex++, &mixerType); - if (FAILED(hr)) - break; - - // From now on, if anything in this loop fails, try the next type, - // until we succeed or the mixer runs out of types. - - // Step 2. Check if we support this media type. - if (SUCCEEDED(hr)) - hr = isMediaTypeSupported(mixerType); - - // Step 3. Adjust the mixer's type to match our requirements. - if (SUCCEEDED(hr)) - hr = createOptimalVideoType(mixerType, &optimalType); - - // Step 4. Check if the mixer will accept this media type. - if (SUCCEEDED(hr)) - hr = m_mixer->SetOutputType(0, optimalType, MFT_SET_TYPE_TEST_ONLY); - - // Step 5. Try to set the media type on ourselves. - if (SUCCEEDED(hr)) - hr = setMediaType(optimalType); - - // Step 6. Set output media type on mixer. - if (SUCCEEDED(hr)) { - hr = m_mixer->SetOutputType(0, optimalType, 0); - - // If something went wrong, clear the media type. - if (FAILED(hr)) - setMediaType(NULL); - } - - if (SUCCEEDED(hr)) - foundMediaType = true; - } - - qt_evr_safe_release(&mixerType); - qt_evr_safe_release(&optimalType); - - return hr; -} - -HRESULT EVRCustomPresenter::flush() -{ - m_prerolled = false; - - // The scheduler might have samples that are waiting for - // their presentation time. Tell the scheduler to flush. - - // This call blocks until the scheduler threads discards all scheduled samples. - m_scheduler.flush(); - - // Flush the frame-step queue. - for (auto sample : qAsConst(m_frameStep.samples)) - sample->Release(); - m_frameStep.samples.clear(); - - if (m_renderState == RenderStopped && m_surface && m_surface->isActive()) { - // Repaint with black. - presentSample(NULL); - } - - return S_OK; -} - -HRESULT EVRCustomPresenter::processInputNotify() -{ - HRESULT hr = S_OK; - - // Set the flag that says the mixer has a new sample. - m_sampleNotify = true; - - if (!m_mediaType) { - // We don't have a valid media type yet. - hr = MF_E_TRANSFORM_TYPE_NOT_SET; - } else { - // Try to process an output sample. - processOutputLoop(); - } - return hr; -} - -HRESULT EVRCustomPresenter::beginStreaming() -{ - HRESULT hr = S_OK; - - // Start the scheduler thread. - hr = m_scheduler.startScheduler(m_clock); - - return hr; -} - -HRESULT EVRCustomPresenter::endStreaming() -{ - HRESULT hr = S_OK; - - // Stop the scheduler thread. - hr = m_scheduler.stopScheduler(); - - return hr; -} - -HRESULT EVRCustomPresenter::checkEndOfStream() -{ - if (!m_endStreaming) { - // The EVR did not send the MFVP_MESSAGE_ENDOFSTREAM message. - return S_OK; - } - - if (m_sampleNotify) { - // The mixer still has input. - return S_OK; - } - - if (m_scheduler.areSamplesScheduled()) { - // Samples are still scheduled for rendering. - return S_OK; - } - - // Everything is complete. Now we can tell the EVR that we are done. - notifyEvent(EC_COMPLETE, (LONG_PTR)S_OK, 0); - m_endStreaming = false; - - stopSurface(); - return S_OK; -} - -HRESULT EVRCustomPresenter::prepareFrameStep(DWORD steps) -{ - HRESULT hr = S_OK; - - // Cache the step count. - m_frameStep.steps += steps; - - // Set the frame-step state. - m_frameStep.state = FrameStepWaitingStart; - - // If the clock is are already running, we can start frame-stepping now. - // Otherwise, we will start when the clock starts. - if (m_renderState == RenderStarted) - hr = startFrameStep(); - - return hr; -} - -HRESULT EVRCustomPresenter::startFrameStep() -{ - HRESULT hr = S_OK; - IMFSample *sample = NULL; - - if (m_frameStep.state == FrameStepWaitingStart) { - // We have a frame-step request, and are waiting for the clock to start. - // Set the state to "pending," which means we are waiting for samples. - m_frameStep.state = FrameStepPending; - - // If the frame-step queue already has samples, process them now. - while (!m_frameStep.samples.isEmpty() && (m_frameStep.state == FrameStepPending)) { - sample = m_frameStep.samples.takeFirst(); - - hr = deliverFrameStepSample(sample); - if (FAILED(hr)) - goto done; - - qt_evr_safe_release(&sample); - - // We break from this loop when: - // (a) the frame-step queue is empty, or - // (b) the frame-step operation is complete. - } - } else if (m_frameStep.state == FrameStepNone) { - // We are not frame stepping. Therefore, if the frame-step queue has samples, - // we need to process them normally. - while (!m_frameStep.samples.isEmpty()) { - sample = m_frameStep.samples.takeFirst(); - - hr = deliverSample(sample, false); - if (FAILED(hr)) - goto done; - - qt_evr_safe_release(&sample); - } - } - -done: - qt_evr_safe_release(&sample); - return hr; -} - -HRESULT EVRCustomPresenter::completeFrameStep(IMFSample *sample) -{ - HRESULT hr = S_OK; - MFTIME sampleTime = 0; - MFTIME systemTime = 0; - - // Update our state. - m_frameStep.state = FrameStepComplete; - m_frameStep.sampleNoRef = 0; - - // Notify the EVR that the frame-step is complete. - notifyEvent(EC_STEP_COMPLETE, FALSE, 0); // FALSE = completed (not cancelled) - - // If we are scrubbing (rate == 0), also send the "scrub time" event. - if (isScrubbing()) { - // Get the time stamp from the sample. - hr = sample->GetSampleTime(&sampleTime); - if (FAILED(hr)) { - // No time stamp. Use the current presentation time. - if (m_clock) - m_clock->GetCorrelatedTime(0, &sampleTime, &systemTime); - - hr = S_OK; // (Not an error condition.) - } - - notifyEvent(EC_SCRUB_TIME, DWORD(sampleTime), DWORD(((sampleTime) >> 32) & 0xffffffff)); - } - return hr; -} - -HRESULT EVRCustomPresenter::cancelFrameStep() -{ - FrameStepState oldState = m_frameStep.state; - - m_frameStep.state = FrameStepNone; - m_frameStep.steps = 0; - m_frameStep.sampleNoRef = 0; - // Don't clear the frame-step queue yet, because we might frame step again. - - if (oldState > FrameStepNone && oldState < FrameStepComplete) { - // We were in the middle of frame-stepping when it was cancelled. - // Notify the EVR. - notifyEvent(EC_STEP_COMPLETE, TRUE, 0); // TRUE = cancelled - } - return S_OK; -} - -HRESULT EVRCustomPresenter::createOptimalVideoType(IMFMediaType *proposedType, IMFMediaType **optimalType) -{ - HRESULT hr = S_OK; - - RECT rcOutput; - ZeroMemory(&rcOutput, sizeof(rcOutput)); - - MFVideoArea displayArea; - ZeroMemory(&displayArea, sizeof(displayArea)); - - IMFMediaType *mtOptimal = NULL; - - UINT64 size; - int width; - int height; - - // Clone the proposed type. - - hr = MFCreateMediaType(&mtOptimal); - if (FAILED(hr)) - goto done; - - hr = proposedType->CopyAllItems(mtOptimal); - if (FAILED(hr)) - goto done; - - // Modify the new type. - - hr = proposedType->GetUINT64(MF_MT_FRAME_SIZE, &size); - width = int(HI32(size)); - height = int(LO32(size)); - rcOutput.left = 0; - rcOutput.top = 0; - rcOutput.right = width; - rcOutput.bottom = height; - - // Set the geometric aperture, and disable pan/scan. - displayArea = qt_evr_makeMFArea(0, 0, rcOutput.right, rcOutput.bottom); - - hr = mtOptimal->SetUINT32(MF_MT_PAN_SCAN_ENABLED, FALSE); - if (FAILED(hr)) - goto done; - - hr = mtOptimal->SetBlob(MF_MT_GEOMETRIC_APERTURE, reinterpret_cast<UINT8*>(&displayArea), - sizeof(displayArea)); - if (FAILED(hr)) - goto done; - - // Set the pan/scan aperture and the minimum display aperture. We don't care - // about them per se, but the mixer will reject the type if these exceed the - // frame dimentions. - hr = mtOptimal->SetBlob(MF_MT_PAN_SCAN_APERTURE, reinterpret_cast<UINT8*>(&displayArea), - sizeof(displayArea)); - if (FAILED(hr)) - goto done; - - hr = mtOptimal->SetBlob(MF_MT_MINIMUM_DISPLAY_APERTURE, reinterpret_cast<UINT8*>(&displayArea), - sizeof(displayArea)); - if (FAILED(hr)) - goto done; - - // Return the pointer to the caller. - *optimalType = mtOptimal; - (*optimalType)->AddRef(); - -done: - qt_evr_safe_release(&mtOptimal); - return hr; - -} - -HRESULT EVRCustomPresenter::setMediaType(IMFMediaType *mediaType) -{ - // Note: mediaType can be NULL (to clear the type) - - // Clearing the media type is allowed in any state (including shutdown). - if (!mediaType) { - stopSurface(); - qt_evr_safe_release(&m_mediaType); - releaseResources(); - return S_OK; - } - - MFRatio fps = { 0, 0 }; - QList<IMFSample*> sampleQueue; - - // Cannot set the media type after shutdown. - HRESULT hr = checkShutdown(); - if (FAILED(hr)) - goto done; - - // Check if the new type is actually different. - // Note: This function safely handles NULL input parameters. - if (qt_evr_areMediaTypesEqual(m_mediaType, mediaType)) - goto done; // Nothing more to do. - - // We're really changing the type. First get rid of the old type. - qt_evr_safe_release(&m_mediaType); - releaseResources(); - - // Initialize the presenter engine with the new media type. - // The presenter engine allocates the samples. - - hr = m_presentEngine->createVideoSamples(mediaType, sampleQueue); - if (FAILED(hr)) - goto done; - - // Mark each sample with our token counter. If this batch of samples becomes - // invalid, we increment the counter, so that we know they should be discarded. - for (auto sample : qAsConst(sampleQueue)) { - hr = sample->SetUINT32(MFSamplePresenter_SampleCounter, m_tokenCounter); - if (FAILED(hr)) - goto done; - } - - // Add the samples to the sample pool. - hr = m_samplePool.initialize(sampleQueue); - if (FAILED(hr)) - goto done; - - // Set the frame rate on the scheduler. - if (SUCCEEDED(qt_evr_getFrameRate(mediaType, &fps)) && (fps.Numerator != 0) && (fps.Denominator != 0)) { - m_scheduler.setFrameRate(fps); - } else { - // NOTE: The mixer's proposed type might not have a frame rate, in which case - // we'll use an arbitrary default. (Although it's unlikely the video source - // does not have a frame rate.) - m_scheduler.setFrameRate(g_DefaultFrameRate); - } - - // Store the media type. - m_mediaType = mediaType; - m_mediaType->AddRef(); - - startSurface(); - -done: - if (FAILED(hr)) - releaseResources(); - return hr; -} - -HRESULT EVRCustomPresenter::isMediaTypeSupported(IMFMediaType *proposed) -{ - D3DFORMAT d3dFormat = D3DFMT_UNKNOWN; - BOOL compressed = FALSE; - MFVideoInterlaceMode interlaceMode = MFVideoInterlace_Unknown; - MFVideoArea videoCropArea; - UINT32 width = 0, height = 0; - - // Validate the format. - HRESULT hr = qt_evr_getFourCC(proposed, reinterpret_cast<DWORD*>(&d3dFormat)); - if (FAILED(hr)) - return hr; - - 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); - if (FAILED(hr)) - return hr; - - if (compressed) - return MF_E_INVALIDMEDIATYPE; - - // The D3DPresentEngine checks whether surfaces can be created using this format - hr = m_presentEngine->checkFormat(d3dFormat); - if (FAILED(hr)) - return hr; - - // Reject interlaced formats. - hr = proposed->GetUINT32(MF_MT_INTERLACE_MODE, reinterpret_cast<UINT32*>(&interlaceMode)); - if (FAILED(hr)) - return hr; - - if (interlaceMode != MFVideoInterlace_Progressive) - return MF_E_INVALIDMEDIATYPE; - - hr = MFGetAttributeSize(proposed, MF_MT_FRAME_SIZE, &width, &height); - if (FAILED(hr)) - return hr; - - // Validate the various apertures (cropping regions) against the frame size. - // Any of these apertures may be unspecified in the media type, in which case - // we ignore it. We just want to reject invalid apertures. - - if (SUCCEEDED(proposed->GetBlob(MF_MT_PAN_SCAN_APERTURE, - reinterpret_cast<UINT8*>(&videoCropArea), - sizeof(videoCropArea), nullptr))) { - hr = qt_evr_validateVideoArea(videoCropArea, width, height); - } - if (SUCCEEDED(proposed->GetBlob(MF_MT_GEOMETRIC_APERTURE, - reinterpret_cast<UINT8*>(&videoCropArea), - sizeof(videoCropArea), nullptr))) { - hr = qt_evr_validateVideoArea(videoCropArea, width, height); - } - if (SUCCEEDED(proposed->GetBlob(MF_MT_MINIMUM_DISPLAY_APERTURE, - reinterpret_cast<UINT8*>(&videoCropArea), - sizeof(videoCropArea), nullptr))) { - hr = qt_evr_validateVideoArea(videoCropArea, width, height); - } - return hr; -} - -void EVRCustomPresenter::processOutputLoop() -{ - HRESULT hr = S_OK; - - // Process as many samples as possible. - while (hr == S_OK) { - // If the mixer doesn't have a new input sample, break from the loop. - if (!m_sampleNotify) { - hr = MF_E_TRANSFORM_NEED_MORE_INPUT; - break; - } - - // Try to process a sample. - hr = processOutput(); - - // NOTE: ProcessOutput can return S_FALSE to indicate it did not - // process a sample. If so, break out of the loop. - } - - if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { - // The mixer has run out of input data. Check for end-of-stream. - checkEndOfStream(); - } -} - -HRESULT EVRCustomPresenter::processOutput() -{ - HRESULT hr = S_OK; - DWORD status = 0; - LONGLONG mixerStartTime = 0, mixerEndTime = 0; - MFTIME systemTime = 0; - BOOL repaint = m_repaint; // Temporarily store this state flag. - - MFT_OUTPUT_DATA_BUFFER dataBuffer; - ZeroMemory(&dataBuffer, sizeof(dataBuffer)); - - IMFSample *sample = NULL; - - // If the clock is not running, we present the first sample, - // and then don't present any more until the clock starts. - - if ((m_renderState != RenderStarted) && !m_repaint && m_prerolled) - return S_FALSE; - - // Make sure we have a pointer to the mixer. - if (!m_mixer) - return MF_E_INVALIDREQUEST; - - // Try to get a free sample from the video sample pool. - hr = m_samplePool.getSample(&sample); - if (hr == MF_E_SAMPLEALLOCATOR_EMPTY) // No free samples. Try again when a sample is released. - return S_FALSE; - if (FAILED(hr)) - return hr; - - // From now on, we have a valid video sample pointer, where the mixer will - // write the video data. - - if (m_repaint) { - // Repaint request. Ask the mixer for the most recent sample. - setDesiredSampleTime(sample, m_scheduler.lastSampleTime(), m_scheduler.frameDuration()); - - m_repaint = false; // OK to clear this flag now. - } else { - // Not a repaint request. Clear the desired sample time; the mixer will - // give us the next frame in the stream. - clearDesiredSampleTime(sample); - - if (m_clock) { - // Latency: Record the starting time for ProcessOutput. - m_clock->GetCorrelatedTime(0, &mixerStartTime, &systemTime); - } - } - - // Now we are ready to get an output sample from the mixer. - dataBuffer.dwStreamID = 0; - dataBuffer.pSample = sample; - dataBuffer.dwStatus = 0; - - hr = m_mixer->ProcessOutput(0, 1, &dataBuffer, &status); - - if (FAILED(hr)) { - // Return the sample to the pool. - HRESULT hr2 = m_samplePool.returnSample(sample); - if (FAILED(hr2)) { - hr = hr2; - goto done; - } - // Handle some known error codes from ProcessOutput. - if (hr == MF_E_TRANSFORM_TYPE_NOT_SET) { - // The mixer's format is not set. Negotiate a new format. - hr = renegotiateMediaType(); - } else if (hr == MF_E_TRANSFORM_STREAM_CHANGE) { - // There was a dynamic media type change. Clear our media type. - setMediaType(NULL); - } else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { - // The mixer needs more input. - // We have to wait for the mixer to get more input. - m_sampleNotify = false; - } - } else { - // We got an output sample from the mixer. - - if (m_clock && !repaint) { - // Latency: Record the ending time for the ProcessOutput operation, - // and notify the EVR of the latency. - - m_clock->GetCorrelatedTime(0, &mixerEndTime, &systemTime); - - LONGLONG latencyTime = mixerEndTime - mixerStartTime; - notifyEvent(EC_PROCESSING_LATENCY, reinterpret_cast<LONG_PTR>(&latencyTime), 0); - } - - // Set up notification for when the sample is released. - hr = trackSample(sample); - if (FAILED(hr)) - goto done; - - // Schedule the sample. - if ((m_frameStep.state == FrameStepNone) || repaint) { - hr = deliverSample(sample, repaint); - if (FAILED(hr)) - goto done; - } else { - // We are frame-stepping (and this is not a repaint request). - hr = deliverFrameStepSample(sample); - if (FAILED(hr)) - goto done; - } - - m_prerolled = true; // We have presented at least one sample now. - } - -done: - qt_evr_safe_release(&sample); - - // Important: Release any events returned from the ProcessOutput method. - qt_evr_safe_release(&dataBuffer.pEvents); - return hr; -} - -HRESULT EVRCustomPresenter::deliverSample(IMFSample *sample, bool repaint) -{ - // If we are not actively playing, OR we are scrubbing (rate = 0) OR this is a - // repaint request, then we need to present the sample immediately. Otherwise, - // schedule it normally. - - bool presentNow = ((m_renderState != RenderStarted) || isScrubbing() || repaint); - - HRESULT hr = m_scheduler.scheduleSample(sample, presentNow); - - if (FAILED(hr)) { - // Notify the EVR that we have failed during streaming. The EVR will notify the - // pipeline. - - notifyEvent(EC_ERRORABORT, hr, 0); - } - - return hr; -} - -HRESULT EVRCustomPresenter::deliverFrameStepSample(IMFSample *sample) -{ - HRESULT hr = S_OK; - IUnknown *unk = NULL; - - // For rate 0, discard any sample that ends earlier than the clock time. - if (isScrubbing() && m_clock && qt_evr_isSampleTimePassed(m_clock, sample)) { - // Discard this sample. - } else if (m_frameStep.state >= FrameStepScheduled) { - // A frame was already submitted. Put this sample on the frame-step queue, - // in case we are asked to step to the next frame. If frame-stepping is - // cancelled, this sample will be processed normally. - sample->AddRef(); - m_frameStep.samples.append(sample); - } else { - // We're ready to frame-step. - - // Decrement the number of steps. - if (m_frameStep.steps > 0) - m_frameStep.steps--; - - if (m_frameStep.steps > 0) { - // This is not the last step. Discard this sample. - } else if (m_frameStep.state == FrameStepWaitingStart) { - // This is the right frame, but the clock hasn't started yet. Put the - // sample on the frame-step queue. When the clock starts, the sample - // will be processed. - sample->AddRef(); - m_frameStep.samples.append(sample); - } else { - // This is the right frame *and* the clock has started. Deliver this sample. - hr = deliverSample(sample, false); - if (FAILED(hr)) - goto done; - - // Query for IUnknown so that we can identify the sample later. - // Per COM rules, an object always returns the same pointer when QI'ed for IUnknown. - hr = sample->QueryInterface(IID_PPV_ARGS(&unk)); - if (FAILED(hr)) - goto done; - - m_frameStep.sampleNoRef = reinterpret_cast<DWORD_PTR>(unk); // No add-ref. - - // NOTE: We do not AddRef the IUnknown pointer, because that would prevent the - // sample from invoking the OnSampleFree callback after the sample is presented. - // We use this IUnknown pointer purely to identify the sample later; we never - // attempt to dereference the pointer. - - m_frameStep.state = FrameStepScheduled; - } - } -done: - qt_evr_safe_release(&unk); - return hr; -} - -HRESULT EVRCustomPresenter::trackSample(IMFSample *sample) -{ - IMFTrackedSample *tracked = NULL; - - HRESULT hr = sample->QueryInterface(IID_PPV_ARGS(&tracked)); - - if (SUCCEEDED(hr)) - hr = tracked->SetAllocator(&m_sampleFreeCB, NULL); - - qt_evr_safe_release(&tracked); - return hr; -} - -void EVRCustomPresenter::releaseResources() -{ - // Increment the token counter to indicate that all existing video samples - // are "stale." As these samples get released, we'll dispose of them. - // - // Note: The token counter is required because the samples are shared - // between more than one thread, and they are returned to the presenter - // through an asynchronous callback (onSampleFree). Without the token, we - // might accidentally re-use a stale sample after the ReleaseResources - // method returns. - - m_tokenCounter++; - - flush(); - - m_samplePool.clear(); - - m_presentEngine->releaseResources(); -} - -HRESULT EVRCustomPresenter::onSampleFree(IMFAsyncResult *result) -{ - IUnknown *object = NULL; - IMFSample *sample = NULL; - IUnknown *unk = NULL; - UINT32 token; - - // Get the sample from the async result object. - HRESULT hr = result->GetObject(&object); - if (FAILED(hr)) - goto done; - - hr = object->QueryInterface(IID_PPV_ARGS(&sample)); - if (FAILED(hr)) - goto done; - - // If this sample was submitted for a frame-step, the frame step operation - // is complete. - - if (m_frameStep.state == FrameStepScheduled) { - // Query the sample for IUnknown and compare it to our cached value. - hr = sample->QueryInterface(IID_PPV_ARGS(&unk)); - if (FAILED(hr)) - goto done; - - if (m_frameStep.sampleNoRef == reinterpret_cast<DWORD_PTR>(unk)) { - // Notify the EVR. - hr = completeFrameStep(sample); - if (FAILED(hr)) - goto done; - } - - // Note: Although object is also an IUnknown pointer, it is not - // guaranteed to be the exact pointer value returned through - // QueryInterface. Therefore, the second QueryInterface call is - // required. - } - - m_mutex.lock(); - - token = MFGetAttributeUINT32(sample, MFSamplePresenter_SampleCounter, (UINT32)-1); - - if (token == m_tokenCounter) { - // Return the sample to the sample pool. - hr = m_samplePool.returnSample(sample); - if (SUCCEEDED(hr)) { - // A free sample is available. Process more data if possible. - processOutputLoop(); - } - } - - m_mutex.unlock(); - -done: - if (FAILED(hr)) - notifyEvent(EC_ERRORABORT, hr, 0); - qt_evr_safe_release(&object); - qt_evr_safe_release(&sample); - qt_evr_safe_release(&unk); - return hr; -} - -float EVRCustomPresenter::getMaxRate(bool thin) -{ - // Non-thinned: - // If we have a valid frame rate and a monitor refresh rate, the maximum - // playback rate is equal to the refresh rate. Otherwise, the maximum rate - // is unbounded (FLT_MAX). - - // Thinned: The maximum rate is unbounded. - - float maxRate = FLT_MAX; - MFRatio fps = { 0, 0 }; - UINT monitorRateHz = 0; - - if (!thin && m_mediaType) { - qt_evr_getFrameRate(m_mediaType, &fps); - monitorRateHz = m_presentEngine->refreshRate(); - - if (fps.Denominator && fps.Numerator && monitorRateHz) { - // Max Rate = Refresh Rate / Frame Rate - maxRate = (float)MulDiv(monitorRateHz, fps.Denominator, fps.Numerator); - } - } - - return maxRate; -} - -bool EVRCustomPresenter::event(QEvent *e) -{ - switch (int(e->type())) { - case StartSurface: - startSurface(); - return true; - case StopSurface: - stopSurface(); - return true; - case PresentSample: - presentSample(static_cast<PresentSampleEvent *>(e)->sample()); - return true; - default: - break; - } - 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_presentEngine->videoSurfaceFormat().isValid()) - return; - - QVideoFrame frame = m_presentEngine->makeVideoFrame(sample); - - // Since start/end times are related to a position when the clock is started, - // to have times from the beginning, need to adjust it by adding seeked position. - if (m_positionOffset) { - if (frame.startTime()) - frame.setStartTime(frame.startTime() + m_positionOffset); - if (frame.endTime()) - frame.setEndTime(frame.endTime() + m_positionOffset); - } - - 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); -} - -void EVRCustomPresenter::positionChanged(qint64 position) -{ - m_positionOffset = position * 1000; -} - -HRESULT setDesiredSampleTime(IMFSample *sample, const LONGLONG &sampleTime, const LONGLONG &duration) -{ - if (!sample) - return E_POINTER; - - HRESULT hr = S_OK; - IMFDesiredSample *desired = NULL; - - hr = sample->QueryInterface(IID_PPV_ARGS(&desired)); - if (SUCCEEDED(hr)) - desired->SetDesiredSampleTimeAndDuration(sampleTime, duration); - - qt_evr_safe_release(&desired); - return hr; -} - -HRESULT clearDesiredSampleTime(IMFSample *sample) -{ - if (!sample) - return E_POINTER; - - HRESULT hr = S_OK; - - IMFDesiredSample *desired = NULL; - IUnknown *unkSwapChain = NULL; - - // We store some custom attributes on the sample, so we need to cache them - // and reset them. - // - // This works around the fact that IMFDesiredSample::Clear() removes all of the - // attributes from the sample. - - UINT32 counter = MFGetAttributeUINT32(sample, MFSamplePresenter_SampleCounter, (UINT32)-1); - - hr = sample->QueryInterface(IID_PPV_ARGS(&desired)); - if (SUCCEEDED(hr)) { - desired->Clear(); - - hr = sample->SetUINT32(MFSamplePresenter_SampleCounter, counter); - if (FAILED(hr)) - goto done; - } - -done: - qt_evr_safe_release(&unkSwapChain); - qt_evr_safe_release(&desired); - return hr; -} - -HRESULT setMixerSourceRect(IMFTransform *mixer, const MFVideoNormalizedRect &sourceRect) -{ - if (!mixer) - return E_POINTER; - - IMFAttributes *attributes = NULL; - - HRESULT hr = mixer->GetAttributes(&attributes); - if (SUCCEEDED(hr)) { - hr = attributes->SetBlob(video_ZOOM_RECT, reinterpret_cast<const UINT8*>(&sourceRect), - sizeof(sourceRect)); - attributes->Release(); - } - return hr; -} - -static QVideoFrame::PixelFormat pixelFormatFromMediaType(IMFMediaType *type) -{ - GUID majorType; - if (FAILED(type->GetMajorType(&majorType))) - return QVideoFrame::Format_Invalid; - if (majorType != MFMediaType_Video) - return QVideoFrame::Format_Invalid; - - GUID subtype; - if (FAILED(type->GetGUID(MF_MT_SUBTYPE, &subtype))) - return QVideoFrame::Format_Invalid; - - if (subtype == MFVideoFormat_RGB32) - return QVideoFrame::Format_RGB32; - if (subtype == MFVideoFormat_ARGB32) - return QVideoFrame::Format_ARGB32; - if (subtype == MFVideoFormat_RGB24) - return QVideoFrame::Format_RGB24; - if (subtype == MFVideoFormat_RGB565) - return QVideoFrame::Format_RGB565; - if (subtype == MFVideoFormat_RGB555) - return QVideoFrame::Format_RGB555; - if (subtype == MFVideoFormat_AYUV) - return QVideoFrame::Format_AYUV444; - if (subtype == MFVideoFormat_I420) - return QVideoFrame::Format_YUV420P; - if (subtype == MFVideoFormat_UYVY) - return QVideoFrame::Format_UYVY; - if (subtype == MFVideoFormat_YV12) - return QVideoFrame::Format_YV12; - if (subtype == MFVideoFormat_NV12) - return QVideoFrame::Format_NV12; - - return QVideoFrame::Format_Invalid; -} - -QT_END_NAMESPACE diff --git a/src/plugins/common/evr/evrcustompresenter.h b/src/plugins/common/evr/evrcustompresenter.h deleted file mode 100644 index c1c21580e..000000000 --- a/src/plugins/common/evr/evrcustompresenter.h +++ /dev/null @@ -1,377 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 https://www.qt.io/terms-conditions. For further -** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef EVRCUSTOMPRESENTER_H -#define EVRCUSTOMPRESENTER_H - -#include <QObject> -#include <qmutex.h> -#include <qqueue.h> -#include <qevent.h> -#include <qvideosurfaceformat.h> - -#include "evrdefs.h" - -QT_BEGIN_NAMESPACE - -class EVRCustomPresenter; -class D3DPresentEngine; - -class QAbstractVideoSurface; - -template<class T> -class AsyncCallback : public IMFAsyncCallback -{ - Q_DISABLE_COPY(AsyncCallback) -public: - typedef HRESULT (T::*InvokeFn)(IMFAsyncResult *asyncResult); - - AsyncCallback(T *parent, InvokeFn fn) : m_parent(parent), m_invokeFn(fn) - { - } - - // IUnknown - STDMETHODIMP QueryInterface(REFIID iid, void** ppv) override - { - if (!ppv) - return E_POINTER; - - if (iid == __uuidof(IUnknown)) { - *ppv = static_cast<IUnknown*>(static_cast<IMFAsyncCallback*>(this)); - } else if (iid == __uuidof(IMFAsyncCallback)) { - *ppv = static_cast<IMFAsyncCallback*>(this); - } else { - *ppv = NULL; - return E_NOINTERFACE; - } - AddRef(); - return S_OK; - } - - STDMETHODIMP_(ULONG) AddRef() override { - // Delegate to parent class. - return m_parent->AddRef(); - } - STDMETHODIMP_(ULONG) Release() override { - // Delegate to parent class. - return m_parent->Release(); - } - - // IMFAsyncCallback methods - STDMETHODIMP GetParameters(DWORD*, DWORD*) override - { - // Implementation of this method is optional. - return E_NOTIMPL; - } - - STDMETHODIMP Invoke(IMFAsyncResult* asyncResult) override - { - return (m_parent->*m_invokeFn)(asyncResult); - } - - T *m_parent; - InvokeFn m_invokeFn; -}; - -class Scheduler -{ - Q_DISABLE_COPY(Scheduler) -public: - enum ScheduleEvent - { - Terminate = WM_USER, - Schedule = WM_USER + 1, - Flush = WM_USER + 2 - }; - - Scheduler(EVRCustomPresenter *presenter); - ~Scheduler(); - - void setFrameRate(const MFRatio &fps); - void setClockRate(float rate) { m_playbackRate = rate; } - - const LONGLONG &lastSampleTime() const { return m_lastSampleTime; } - const LONGLONG &frameDuration() const { return m_perFrameInterval; } - - HRESULT startScheduler(IMFClock *clock); - HRESULT stopScheduler(); - - HRESULT scheduleSample(IMFSample *sample, bool presentNow); - HRESULT processSamplesInQueue(LONG *nextSleep); - HRESULT processSample(IMFSample *sample, LONG *nextSleep); - HRESULT flush(); - - bool areSamplesScheduled(); - - // ThreadProc for the scheduler thread. - static DWORD WINAPI schedulerThreadProc(LPVOID parameter); - -private: - DWORD schedulerThreadProcPrivate(); - - EVRCustomPresenter *m_presenter; - - QQueue<IMFSample*> m_scheduledSamples; // Samples waiting to be presented. - - IMFClock *m_clock; // Presentation clock. Can be NULL. - - DWORD m_threadID; - HANDLE m_schedulerThread; - HANDLE m_threadReadyEvent; - HANDLE m_flushEvent; - - float m_playbackRate; - MFTIME m_perFrameInterval; // Duration of each frame. - LONGLONG m_perFrame_1_4th; // 1/4th of the frame duration. - MFTIME m_lastSampleTime; // Most recent sample time. - - QMutex m_mutex; -}; - -class SamplePool -{ - Q_DISABLE_COPY(SamplePool) -public: - SamplePool(); - ~SamplePool(); - - HRESULT initialize(QList<IMFSample*> &samples); - HRESULT clear(); - - HRESULT getSample(IMFSample **sample); - HRESULT returnSample(IMFSample *sample); - -private: - QMutex m_mutex; - QList<IMFSample*> m_videoSampleQueue; - bool m_initialized; -}; - -class EVRCustomPresenter - : public QObject - , public IMFVideoDeviceID - , public IMFVideoPresenter // Inherits IMFClockStateSink - , public IMFRateSupport - , public IMFGetService - , public IMFTopologyServiceLookupClient -{ - Q_DISABLE_COPY(EVRCustomPresenter) -public: - // Defines the state of the presenter. - enum RenderState - { - RenderStarted = 1, - RenderStopped, - RenderPaused, - RenderShutdown // Initial state. - }; - - // Defines the presenter's state with respect to frame-stepping. - enum FrameStepState - { - FrameStepNone, // Not frame stepping. - FrameStepWaitingStart, // Frame stepping, but the clock is not started. - FrameStepPending, // Clock is started. Waiting for samples. - FrameStepScheduled, // Submitted a sample for rendering. - FrameStepComplete // Sample was rendered. - }; - - enum PresenterEvents - { - StartSurface = QEvent::User, - StopSurface = QEvent::User + 1, - PresentSample = QEvent::User + 2 - }; - - EVRCustomPresenter(QAbstractVideoSurface *surface = 0); - ~EVRCustomPresenter() override; - - bool isValid() const; - - // IUnknown methods - STDMETHODIMP QueryInterface(REFIID riid, void ** ppv) override; - STDMETHODIMP_(ULONG) AddRef() override; - STDMETHODIMP_(ULONG) Release() override; - - // IMFGetService methods - STDMETHODIMP GetService(REFGUID guidService, REFIID riid, LPVOID *ppvObject) override; - - // IMFVideoPresenter methods - STDMETHODIMP ProcessMessage(MFVP_MESSAGE_TYPE message, ULONG_PTR param) override; - STDMETHODIMP GetCurrentMediaType(IMFVideoMediaType** mediaType) override; - - // IMFClockStateSink methods - STDMETHODIMP OnClockStart(MFTIME systemTime, LONGLONG clockStartOffset) override; - STDMETHODIMP OnClockStop(MFTIME systemTime) override; - STDMETHODIMP OnClockPause(MFTIME systemTime) override; - STDMETHODIMP OnClockRestart(MFTIME systemTime) override; - STDMETHODIMP OnClockSetRate(MFTIME systemTime, float rate) override; - - // IMFRateSupport methods - STDMETHODIMP GetSlowestRate(MFRATE_DIRECTION direction, BOOL thin, float *rate) override; - STDMETHODIMP GetFastestRate(MFRATE_DIRECTION direction, BOOL thin, float *rate) override; - STDMETHODIMP IsRateSupported(BOOL thin, float rate, float *nearestSupportedRate) override; - - // IMFVideoDeviceID methods - STDMETHODIMP GetDeviceID(IID* deviceID) override; - - // IMFTopologyServiceLookupClient methods - STDMETHODIMP InitServicePointers(IMFTopologyServiceLookup *lookup) override; - STDMETHODIMP ReleaseServicePointers() override; - - void supportedFormatsChanged(); - void setSurface(QAbstractVideoSurface *surface); - - void startSurface(); - void stopSurface(); - void presentSample(IMFSample *sample); - - bool event(QEvent *) override; - -public Q_SLOTS: - void positionChanged(qint64 position); - -private: - HRESULT checkShutdown() const - { - if (m_renderState == RenderShutdown) - return MF_E_SHUTDOWN; - else - return S_OK; - } - - // The "active" state is started or paused. - inline bool isActive() const - { - return ((m_renderState == RenderStarted) || (m_renderState == RenderPaused)); - } - - // Scrubbing occurs when the frame rate is 0. - inline bool isScrubbing() const { return m_playbackRate == 0.0f; } - - // Send an event to the EVR through its IMediaEventSink interface. - void notifyEvent(long eventCode, LONG_PTR param1, LONG_PTR param2) - { - if (m_mediaEventSink) - m_mediaEventSink->Notify(eventCode, param1, param2); - } - - float getMaxRate(bool thin); - - // Mixer operations - HRESULT configureMixer(IMFTransform *mixer); - - // Formats - HRESULT createOptimalVideoType(IMFMediaType* proposed, IMFMediaType **optimal); - HRESULT setMediaType(IMFMediaType *mediaType); - HRESULT isMediaTypeSupported(IMFMediaType *mediaType); - - // Message handlers - HRESULT flush(); - HRESULT renegotiateMediaType(); - HRESULT processInputNotify(); - HRESULT beginStreaming(); - HRESULT endStreaming(); - HRESULT checkEndOfStream(); - - // Managing samples - void processOutputLoop(); - HRESULT processOutput(); - HRESULT deliverSample(IMFSample *sample, bool repaint); - HRESULT trackSample(IMFSample *sample); - void releaseResources(); - - // Frame-stepping - HRESULT prepareFrameStep(DWORD steps); - HRESULT startFrameStep(); - HRESULT deliverFrameStepSample(IMFSample *sample); - HRESULT completeFrameStep(IMFSample *sample); - HRESULT cancelFrameStep(); - - // Callback when a video sample is released. - HRESULT onSampleFree(IMFAsyncResult *result); - AsyncCallback<EVRCustomPresenter> m_sampleFreeCB; - - // Holds information related to frame-stepping. - struct FrameStep - { - FrameStepState state = FrameStepNone; - QList<IMFSample*> samples; - DWORD steps = 0; - DWORD_PTR sampleNoRef = 0; - }; - - long m_refCount; - - RenderState m_renderState; - FrameStep m_frameStep; - - QRecursiveMutex m_mutex; - - // Samples and scheduling - Scheduler m_scheduler; // Manages scheduling of samples. - SamplePool m_samplePool; // Pool of allocated samples. - DWORD m_tokenCounter; // Counter. Incremented whenever we create new samples. - - // Rendering state - bool m_sampleNotify; // Did the mixer signal it has an input sample? - bool m_repaint; // Do we need to repaint the last sample? - bool m_prerolled; // Have we presented at least one sample? - bool m_endStreaming; // Did we reach the end of the stream (EOS)? - - MFVideoNormalizedRect m_sourceRect; - float m_playbackRate; - - 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. - IMediaEventSink *m_mediaEventSink; // The EVR's event-sink interface. - IMFMediaType *m_mediaType; // Output media type - - QAbstractVideoSurface *m_surface; - bool m_canRenderToSurface; - qint64 m_positionOffset; // Seek position in microseconds. -}; - -bool qt_evr_setCustomPresenter(IUnknown *evr, EVRCustomPresenter *presenter); - -QT_END_NAMESPACE - -#endif // EVRCUSTOMPRESENTER_H diff --git a/src/plugins/common/evr/evrd3dpresentengine.cpp b/src/plugins/common/evr/evrd3dpresentengine.cpp deleted file mode 100644 index 964504e48..000000000 --- a/src/plugins/common/evr/evrd3dpresentengine.cpp +++ /dev/null @@ -1,413 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 https://www.qt.io/terms-conditions. For further -** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "evrd3dpresentengine.h" - -#include "evrhelpers.h" - -#include <qabstractvideobuffer.h> -#include <QAbstractVideoSurface> -#include <qvideoframe.h> -#include <QDebug> -#include <qthread.h> -#include <QOffscreenSurface> - -static const int PRESENTER_BUFFER_COUNT = 3; - -QT_BEGIN_NAMESPACE - -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) - { - 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() override - { - if (m_surface) { - if (m_mapMode != NotMapped) - m_surface->UnlockRect(); - m_surface->Release(); - } - if (m_sample) - m_sample->Release(); - } - - QVariant handle() const override; - - MapMode mapMode() const override { return m_mapMode; } - uchar *map(MapMode, int*, int*) override; - void unmap() override; - -private: - mutable D3DPresentEngine *m_engine; - IMFSample *m_sample; - IDirect3DSurface9 *m_surface; - MapMode m_mapMode; - mutable unsigned int m_textureId = 0; -}; - -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 -{ - return m_textureId; -} - - -D3DPresentEngine::D3DPresentEngine() - : m_deviceResetToken(0) - , m_D3D9(0) - , m_device(0) - , m_deviceManager(0) - , m_useTextureRendering(false) -{ - ZeroMemory(&m_displayMode, sizeof(m_displayMode)); - - HRESULT hr = initializeD3D(); - - if (SUCCEEDED(hr)) { - hr = createD3DDevice(); - if (FAILED(hr)) - qWarning("Failed to create D3D device"); - } else { - qWarning("Failed to initialize D3D"); - } -} - -D3DPresentEngine::~D3DPresentEngine() -{ - releaseResources(); - - qt_evr_safe_release(&m_device); - qt_evr_safe_release(&m_deviceManager); - qt_evr_safe_release(&m_D3D9); -} - -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; - - 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; - - 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; -} - -bool D3DPresentEngine::isValid() const -{ - return m_device != NULL; -} - -void D3DPresentEngine::releaseResources() -{ - m_surfaceFormat = QVideoSurfaceFormat(); -} - -HRESULT D3DPresentEngine::getService(REFGUID, REFIID riid, void** ppv) -{ - HRESULT hr = S_OK; - - if (riid == __uuidof(IDirect3DDeviceManager9)) { - if (m_deviceManager == NULL) { - hr = MF_E_UNSUPPORTED_SERVICE; - } else { - *ppv = m_deviceManager; - m_deviceManager->AddRef(); - } - } else { - hr = MF_E_UNSUPPORTED_SERVICE; - } - - return hr; -} - -HRESULT D3DPresentEngine::checkFormat(D3DFORMAT format) -{ - if (!m_D3D9 || !m_device) - return E_FAIL; - - HRESULT hr = S_OK; - - D3DDISPLAYMODE mode; - D3DDEVICE_CREATION_PARAMETERS params; - - hr = m_device->GetCreationParameters(¶ms); - if (FAILED(hr)) - return hr; - - UINT uAdapter = params.AdapterOrdinal; - D3DDEVTYPE type = params.DeviceType; - - hr = m_D3D9->GetAdapterDisplayMode(uAdapter, &mode); - if (FAILED(hr)) - return hr; - - 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 -{ - return false; -} - -void D3DPresentEngine::setHint(Hint hint, bool enable) -{ - if (hint == RenderToTexture) - m_useTextureRendering = enable && supportsTextureRendering(); -} - -HRESULT D3DPresentEngine::createVideoSamples(IMFMediaType *format, QList<IMFSample*> &videoSampleQueue) -{ - if (!format) - return MF_E_UNEXPECTED; - - HRESULT hr = S_OK; - - IDirect3DSurface9 *surface = NULL; - IMFSample *videoSample = NULL; - - releaseResources(); - - UINT32 width = 0, height = 0; - hr = MFGetAttributeSize(format, MF_MT_FRAME_SIZE, &width, &height); - if (FAILED(hr)) - 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++) { - hr = m_device->CreateRenderTarget(width, height, - (D3DFORMAT)d3dFormat, - D3DMULTISAMPLE_NONE, - 0, - TRUE, - &surface, NULL); - if (FAILED(hr)) - goto done; - - hr = MFCreateVideoSampleFromSurface(surface, &videoSample); - if (FAILED(hr)) - goto done; - - videoSample->AddRef(); - videoSampleQueue.append(videoSample); - - qt_evr_safe_release(&videoSample); - qt_evr_safe_release(&surface); - } - -done: - if (SUCCEEDED(hr)) { - m_surfaceFormat = QVideoSurfaceFormat(QSize(width, height), - m_useTextureRendering ? QVideoFrame::Format_RGB32 - : qt_evr_pixelFormatFromD3DFormat(d3dFormat), - m_useTextureRendering ? QAbstractVideoBuffer::GLTextureHandle - : QAbstractVideoBuffer::NoHandle); - UINT32 horizontal = 1, vertical = 1; - hr = MFGetAttributeRatio(format, MF_MT_PIXEL_ASPECT_RATIO, &horizontal, &vertical); - if (SUCCEEDED(hr)) - m_surfaceFormat.setPixelAspectRatio(horizontal, vertical); - } else { - releaseResources(); - } - - qt_evr_safe_release(&videoSample); - qt_evr_safe_release(&surface); - return hr; -} - -QVideoFrame D3DPresentEngine::makeVideoFrame(IMFSample *sample) -{ - if (!sample) - return QVideoFrame(); - - QVideoFrame frame(new IMFSampleVideoBuffer(this, sample, m_surfaceFormat.handleType()), - m_surfaceFormat.frameSize(), - m_surfaceFormat.pixelFormat()); - - // WMF uses 100-nanosecond units, Qt uses microseconds - LONGLONG startTime = 0; - auto hr = sample->GetSampleTime(&startTime); - if (SUCCEEDED(hr)) { - frame.setStartTime(startTime * 0.1); - - LONGLONG duration = -1; - if (SUCCEEDED(sample->GetSampleDuration(&duration))) - frame.setEndTime((startTime + duration) * 0.1); - } - - return frame; -} - -QT_END_NAMESPACE diff --git a/src/plugins/common/evr/evrd3dpresentengine.h b/src/plugins/common/evr/evrd3dpresentengine.h deleted file mode 100644 index eb2def7b2..000000000 --- a/src/plugins/common/evr/evrd3dpresentengine.h +++ /dev/null @@ -1,152 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 https://www.qt.io/terms-conditions. For further -** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef EVRD3DPRESENTENGINE_H -#define EVRD3DPRESENTENGINE_H - -#include <QMutex> -#include <QVideoSurfaceFormat> - -#include <d3d9.h> - -struct IDirect3D9Ex; -struct IDirect3DDevice9Ex; -struct IDirect3DDeviceManager9; -struct IDirect3DSurface9; -struct IDirect3DTexture9; -struct IMFSample; -struct IMFMediaType; - -// Randomly generated GUIDs -static const GUID MFSamplePresenter_SampleCounter = -{ 0xb0bb83cc, 0xf10f, 0x4e2e, { 0xaa, 0x2b, 0x29, 0xea, 0x5e, 0x92, 0xef, 0x85 } }; - -QT_BEGIN_NAMESPACE - -class QAbstractVideoSurface; - -#ifdef MAYBE_ANGLE - -class OpenGLResources; - -class EGLWrapper -{ - Q_DISABLE_COPY(EGLWrapper) -public: - EGLWrapper(); - - __eglMustCastToProperFunctionPointerType getProcAddress(const char *procname); - EGLSurface createPbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list); - EGLBoolean destroySurface(EGLDisplay dpy, EGLSurface surface); - EGLBoolean bindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer); - EGLBoolean releaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer); - -private: - typedef __eglMustCastToProperFunctionPointerType (EGLAPIENTRYP EglGetProcAddress)(const char *procname); - typedef EGLSurface (EGLAPIENTRYP EglCreatePbufferSurface)(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list); - typedef EGLBoolean (EGLAPIENTRYP EglDestroySurface)(EGLDisplay dpy, EGLSurface surface); - typedef EGLBoolean (EGLAPIENTRYP EglBindTexImage)(EGLDisplay dpy, EGLSurface surface, EGLint buffer); - typedef EGLBoolean (EGLAPIENTRYP EglReleaseTexImage)(EGLDisplay dpy, EGLSurface surface, EGLint buffer); - - EglGetProcAddress m_eglGetProcAddress; - EglCreatePbufferSurface m_eglCreatePbufferSurface; - EglDestroySurface m_eglDestroySurface; - EglBindTexImage m_eglBindTexImage; - EglReleaseTexImage m_eglReleaseTexImage; -}; - -#endif // MAYBE_ANGLE - -class D3DPresentEngine -{ - Q_DISABLE_COPY(D3DPresentEngine) -public: - enum Hint - { - RenderToTexture - }; - - D3DPresentEngine(); - virtual ~D3DPresentEngine(); - - bool isValid() const; - void setHint(Hint hint, bool enable = true); - - HRESULT getService(REFGUID guidService, REFIID riid, void** ppv); - HRESULT checkFormat(D3DFORMAT format); - UINT refreshRate() const { return m_displayMode.RefreshRate; } - - bool supportsTextureRendering() const; - bool isTextureRenderingEnabled() const { return m_useTextureRendering; } - - HRESULT createVideoSamples(IMFMediaType *format, QList<IMFSample*>& videoSampleQueue); - QVideoSurfaceFormat videoSurfaceFormat() const { return m_surfaceFormat; } - QVideoFrame makeVideoFrame(IMFSample* sample); - - void releaseResources(); - -private: - HRESULT initializeD3D(); - HRESULT createD3DDevice(); - - - UINT m_deviceResetToken; - D3DDISPLAYMODE m_displayMode; - - IDirect3D9Ex *m_D3D9; - IDirect3DDevice9Ex *m_device; - IDirect3DDeviceManager9 *m_deviceManager; - - QVideoSurfaceFormat m_surfaceFormat; - - bool m_useTextureRendering; - -#ifdef MAYBE_ANGLE - unsigned int updateTexture(IDirect3DSurface9 *src); - - OpenGLResources *m_glResources; - IDirect3DTexture9 *m_texture; -#endif - - friend class IMFSampleVideoBuffer; -}; - -QT_END_NAMESPACE - -#endif // EVRD3DPRESENTENGINE_H diff --git a/src/plugins/common/evr/evrdefs.cpp b/src/plugins/common/evr/evrdefs.cpp deleted file mode 100644 index e143ada0b..000000000 --- a/src/plugins/common/evr/evrdefs.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 https://www.qt.io/terms-conditions. For further -** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "evrdefs.h" - -const CLSID clsid_EnhancedVideoRenderer = { 0xfa10746c, 0x9b63, 0x4b6c, {0xbc, 0x49, 0xfc, 0x30, 0xe, 0xa5, 0xf2, 0x56} }; -const GUID mr_VIDEO_RENDER_SERVICE = { 0x1092a86c, 0xab1a, 0x459a, {0xa3, 0x36, 0x83, 0x1f, 0xbc, 0x4d, 0x11, 0xff} }; -const GUID mr_VIDEO_MIXER_SERVICE = { 0x73cd2fc, 0x6cf4, 0x40b7, {0x88, 0x59, 0xe8, 0x95, 0x52, 0xc8, 0x41, 0xf8} }; -const GUID mr_BUFFER_SERVICE = { 0xa562248c, 0x9ac6, 0x4ffc, {0x9f, 0xba, 0x3a, 0xf8, 0xf8, 0xad, 0x1a, 0x4d} }; -const GUID video_ZOOM_RECT = { 0x7aaa1638, 0x1b7f, 0x4c93, {0xbd, 0x89, 0x5b, 0x9c, 0x9f, 0xb6, 0xfc, 0xf0} }; -const GUID iid_IDirect3DDevice9 = { 0xd0223b96, 0xbf7a, 0x43fd, {0x92, 0xbd, 0xa4, 0x3b, 0xd, 0x82, 0xb9, 0xeb} }; -const GUID iid_IDirect3DSurface9 = { 0xcfbaf3a, 0x9ff6, 0x429a, {0x99, 0xb3, 0xa2, 0x79, 0x6a, 0xf8, 0xb8, 0x9b} }; diff --git a/src/plugins/common/evr/evrdefs.h b/src/plugins/common/evr/evrdefs.h deleted file mode 100644 index 4f3dd832a..000000000 --- a/src/plugins/common/evr/evrdefs.h +++ /dev/null @@ -1,353 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 https://www.qt.io/terms-conditions. For further -** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef EVRDEFS_H -#define EVRDEFS_H - -#include <d3d9.h> -#include <evr9.h> -#include <evr.h> -#include <dxva2api.h> -#include <mfapi.h> -#include <mfidl.h> -#include <mferror.h> - -extern const CLSID clsid_EnhancedVideoRenderer; -extern const GUID mr_VIDEO_RENDER_SERVICE; -extern const GUID mr_VIDEO_MIXER_SERVICE; -extern const GUID mr_BUFFER_SERVICE; -extern const GUID video_ZOOM_RECT; -extern const GUID iid_IDirect3DDevice9; -extern const GUID iid_IDirect3DSurface9; - -// The following is required to compile with MinGW - -extern "C" { -HRESULT WINAPI MFCreateVideoSampleFromSurface(IUnknown *pUnkSurface, IMFSample **ppSample); -HRESULT WINAPI Direct3DCreate9Ex(UINT SDKVersion, IDirect3D9Ex**); -} - -#ifndef PRESENTATION_CURRENT_POSITION -#define PRESENTATION_CURRENT_POSITION 0x7fffffffffffffff -#endif - -#ifndef MF_E_SHUTDOWN -#define MF_E_SHUTDOWN ((HRESULT)0xC00D3E85L) -#endif - -#ifndef MF_E_SAMPLEALLOCATOR_EMPTY -#define MF_E_SAMPLEALLOCATOR_EMPTY ((HRESULT)0xC00D4A3EL) -#endif - -#ifndef MF_E_TRANSFORM_STREAM_CHANGE -#define MF_E_TRANSFORM_STREAM_CHANGE ((HRESULT)0xC00D6D61L) -#endif - -#ifndef MF_E_TRANSFORM_NEED_MORE_INPUT -#define MF_E_TRANSFORM_NEED_MORE_INPUT ((HRESULT)0xC00D6D72L) -#endif - -#if defined(__GNUC__) && !defined(_MFVideoNormalizedRect_) -#define _MFVideoNormalizedRect_ -typedef struct MFVideoNormalizedRect { - float left; - float top; - float right; - float bottom; -} MFVideoNormalizedRect; -#endif - -#include <initguid.h> - -#ifndef __IMFGetService_INTERFACE_DEFINED__ -#define __IMFGetService_INTERFACE_DEFINED__ -DEFINE_GUID(IID_IMFGetService, 0xfa993888, 0x4383, 0x415a, 0xa9,0x30, 0xdd,0x47,0x2a,0x8c,0xf6,0xf7); -MIDL_INTERFACE("fa993888-4383-415a-a930-dd472a8cf6f7") -IMFGetService : public IUnknown -{ - virtual HRESULT STDMETHODCALLTYPE GetService(REFGUID, REFIID, LPVOID *) = 0; -}; -#ifdef __CRT_UUID_DECL -__CRT_UUID_DECL(IMFGetService, 0xfa993888, 0x4383, 0x415a, 0xa9,0x30, 0xdd,0x47,0x2a,0x8c,0xf6,0xf7) -#endif -#endif // __IMFGetService_INTERFACE_DEFINED__ - -#ifndef __IMFVideoDisplayControl_INTERFACE_DEFINED__ -#define __IMFVideoDisplayControl_INTERFACE_DEFINED__ -typedef enum MFVideoAspectRatioMode -{ - MFVideoARMode_None = 0, - MFVideoARMode_PreservePicture = 0x1, - MFVideoARMode_PreservePixel = 0x2, - MFVideoARMode_NonLinearStretch = 0x4, - MFVideoARMode_Mask = 0x7 -} MFVideoAspectRatioMode; - -DEFINE_GUID(IID_IMFVideoDisplayControl, 0xa490b1e4, 0xab84, 0x4d31, 0xa1,0xb2, 0x18,0x1e,0x03,0xb1,0x07,0x7a); -MIDL_INTERFACE("a490b1e4-ab84-4d31-a1b2-181e03b1077a") -IMFVideoDisplayControl : public IUnknown -{ - virtual HRESULT STDMETHODCALLTYPE GetNativeVideoSize(SIZE *, SIZE *) = 0; - virtual HRESULT STDMETHODCALLTYPE GetIdealVideoSize(SIZE *, SIZE *) = 0; - virtual HRESULT STDMETHODCALLTYPE SetVideoPosition(const MFVideoNormalizedRect *, const LPRECT) = 0; - virtual HRESULT STDMETHODCALLTYPE GetVideoPosition(MFVideoNormalizedRect *, LPRECT) = 0; - virtual HRESULT STDMETHODCALLTYPE SetAspectRatioMode(DWORD) = 0; - virtual HRESULT STDMETHODCALLTYPE GetAspectRatioMode(DWORD *) = 0; - virtual HRESULT STDMETHODCALLTYPE SetVideoWindow(HWND) = 0; - virtual HRESULT STDMETHODCALLTYPE GetVideoWindow(HWND *) = 0; - virtual HRESULT STDMETHODCALLTYPE RepaintVideo(void) = 0; - virtual HRESULT STDMETHODCALLTYPE GetCurrentImage(BITMAPINFOHEADER *, BYTE **, DWORD *, LONGLONG *) = 0; - virtual HRESULT STDMETHODCALLTYPE SetBorderColor(COLORREF) = 0; - virtual HRESULT STDMETHODCALLTYPE GetBorderColor(COLORREF *) = 0; - virtual HRESULT STDMETHODCALLTYPE SetRenderingPrefs(DWORD) = 0; - virtual HRESULT STDMETHODCALLTYPE GetRenderingPrefs(DWORD *) = 0; - virtual HRESULT STDMETHODCALLTYPE SetFullscreen(BOOL) = 0; - virtual HRESULT STDMETHODCALLTYPE GetFullscreen(BOOL *) = 0; -}; -#ifdef __CRT_UUID_DECL -__CRT_UUID_DECL(IMFVideoDisplayControl, 0xa490b1e4, 0xab84, 0x4d31, 0xa1,0xb2, 0x18,0x1e,0x03,0xb1,0x07,0x7a) -#endif -#endif // __IMFVideoDisplayControl_INTERFACE_DEFINED__ - -#ifndef __IMFVideoProcessor_INTERFACE_DEFINED__ -#define __IMFVideoProcessor_INTERFACE_DEFINED__ -DEFINE_GUID(IID_IMFVideoProcessor, 0x6AB0000C, 0xFECE, 0x4d1f, 0xA2,0xAC, 0xA9,0x57,0x35,0x30,0x65,0x6E); -MIDL_INTERFACE("6AB0000C-FECE-4d1f-A2AC-A9573530656E") -IMFVideoProcessor : public IUnknown -{ - virtual HRESULT STDMETHODCALLTYPE GetAvailableVideoProcessorModes(UINT *, GUID **) = 0; - virtual HRESULT STDMETHODCALLTYPE GetVideoProcessorCaps(LPGUID, DXVA2_VideoProcessorCaps *) = 0; - virtual HRESULT STDMETHODCALLTYPE GetVideoProcessorMode(LPGUID) = 0; - virtual HRESULT STDMETHODCALLTYPE SetVideoProcessorMode(LPGUID) = 0; - virtual HRESULT STDMETHODCALLTYPE GetProcAmpRange(DWORD, DXVA2_ValueRange *) = 0; - virtual HRESULT STDMETHODCALLTYPE GetProcAmpValues(DWORD, DXVA2_ProcAmpValues *) = 0; - virtual HRESULT STDMETHODCALLTYPE SetProcAmpValues(DWORD, DXVA2_ProcAmpValues *) = 0; - virtual HRESULT STDMETHODCALLTYPE GetFilteringRange(DWORD, DXVA2_ValueRange *) = 0; - virtual HRESULT STDMETHODCALLTYPE GetFilteringValue(DWORD, DXVA2_Fixed32 *) = 0; - virtual HRESULT STDMETHODCALLTYPE SetFilteringValue(DWORD, DXVA2_Fixed32 *) = 0; - virtual HRESULT STDMETHODCALLTYPE GetBackgroundColor(COLORREF *) = 0; - virtual HRESULT STDMETHODCALLTYPE SetBackgroundColor(COLORREF) = 0; -}; -#ifdef __CRT_UUID_DECL -__CRT_UUID_DECL(IMFVideoProcessor, 0x6AB0000C, 0xFECE, 0x4d1f, 0xA2,0xAC, 0xA9,0x57,0x35,0x30,0x65,0x6E) -#endif -#endif // __IMFVideoProcessor_INTERFACE_DEFINED__ - -#ifndef __IMFVideoDeviceID_INTERFACE_DEFINED__ -#define __IMFVideoDeviceID_INTERFACE_DEFINED__ -DEFINE_GUID(IID_IMFVideoDeviceID, 0xA38D9567, 0x5A9C, 0x4f3c, 0xB2,0x93, 0x8E,0xB4,0x15,0xB2,0x79,0xBA); -MIDL_INTERFACE("A38D9567-5A9C-4f3c-B293-8EB415B279BA") -IMFVideoDeviceID : public IUnknown -{ -public: - virtual HRESULT STDMETHODCALLTYPE GetDeviceID(IID *pDeviceID) = 0; -}; -#ifdef __CRT_UUID_DECL -__CRT_UUID_DECL(IMFVideoDeviceID, 0xA38D9567, 0x5A9C, 0x4f3c, 0xB2,0x93, 0x8E,0xB4,0x15,0xB2,0x79,0xBA) -#endif -#endif // __IMFVideoDeviceID_INTERFACE_DEFINED__ - -#ifndef __IMFClockStateSink_INTERFACE_DEFINED__ -#define __IMFClockStateSink_INTERFACE_DEFINED__ -DEFINE_GUID(IID_IMFClockStateSink, 0xF6696E82, 0x74F7, 0x4f3d, 0xA1,0x78, 0x8A,0x5E,0x09,0xC3,0x65,0x9F); -MIDL_INTERFACE("F6696E82-74F7-4f3d-A178-8A5E09C3659F") -IMFClockStateSink : public IUnknown -{ -public: - virtual HRESULT STDMETHODCALLTYPE OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset) = 0; - virtual HRESULT STDMETHODCALLTYPE OnClockStop(MFTIME hnsSystemTime) = 0; - virtual HRESULT STDMETHODCALLTYPE OnClockPause(MFTIME hnsSystemTime) = 0; - virtual HRESULT STDMETHODCALLTYPE OnClockRestart(MFTIME hnsSystemTime) = 0; - virtual HRESULT STDMETHODCALLTYPE OnClockSetRate(MFTIME hnsSystemTime, float flRate) = 0; -}; -#ifdef __CRT_UUID_DECL -__CRT_UUID_DECL(IMFClockStateSink, 0xF6696E82, 0x74F7, 0x4f3d, 0xA1,0x78, 0x8A,0x5E,0x09,0xC3,0x65,0x9F) -#endif -#endif // __IMFClockStateSink_INTERFACE_DEFINED__ - -#ifndef __IMFVideoPresenter_INTERFACE_DEFINED__ -#define __IMFVideoPresenter_INTERFACE_DEFINED__ -typedef enum MFVP_MESSAGE_TYPE -{ - MFVP_MESSAGE_FLUSH = 0, - MFVP_MESSAGE_INVALIDATEMEDIATYPE = 0x1, - MFVP_MESSAGE_PROCESSINPUTNOTIFY = 0x2, - MFVP_MESSAGE_BEGINSTREAMING = 0x3, - MFVP_MESSAGE_ENDSTREAMING = 0x4, - MFVP_MESSAGE_ENDOFSTREAM = 0x5, - MFVP_MESSAGE_STEP = 0x6, - MFVP_MESSAGE_CANCELSTEP = 0x7 -} MFVP_MESSAGE_TYPE; - -DEFINE_GUID(IID_IMFVideoPresenter, 0x29AFF080, 0x182A, 0x4a5d, 0xAF,0x3B, 0x44,0x8F,0x3A,0x63,0x46,0xCB); -MIDL_INTERFACE("29AFF080-182A-4a5d-AF3B-448F3A6346CB") -IMFVideoPresenter : public IMFClockStateSink -{ -public: - virtual HRESULT STDMETHODCALLTYPE ProcessMessage(MFVP_MESSAGE_TYPE eMessage, ULONG_PTR ulParam) = 0; - virtual HRESULT STDMETHODCALLTYPE GetCurrentMediaType(IMFVideoMediaType **ppMediaType) = 0; -}; -#ifdef __CRT_UUID_DECL -__CRT_UUID_DECL(IMFVideoPresenter, 0x29AFF080, 0x182A, 0x4a5d, 0xAF,0x3B, 0x44,0x8F,0x3A,0x63,0x46,0xCB) -#endif -#endif // __IMFVideoPresenter_INTERFACE_DEFINED__ - -#ifndef __IMFRateSupport_INTERFACE_DEFINED__ -#define __IMFRateSupport_INTERFACE_DEFINED__ -DEFINE_GUID(IID_IMFRateSupport, 0x0a9ccdbc, 0xd797, 0x4563, 0x96,0x67, 0x94,0xec,0x5d,0x79,0x29,0x2d); -MIDL_INTERFACE("0a9ccdbc-d797-4563-9667-94ec5d79292d") -IMFRateSupport : public IUnknown -{ -public: - virtual HRESULT STDMETHODCALLTYPE GetSlowestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float *pflRate) = 0; - virtual HRESULT STDMETHODCALLTYPE GetFastestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float *pflRate) = 0; - virtual HRESULT STDMETHODCALLTYPE IsRateSupported(BOOL fThin, float flRate, float *pflNearestSupportedRate) = 0; -}; -#ifdef __CRT_UUID_DECL -__CRT_UUID_DECL(IMFRateSupport, 0x0a9ccdbc, 0xd797, 0x4563, 0x96,0x67, 0x94,0xec,0x5d,0x79,0x29,0x2d) -#endif -#endif // __IMFRateSupport_INTERFACE_DEFINED__ - -#ifndef __IMFTopologyServiceLookup_INTERFACE_DEFINED__ -#define __IMFTopologyServiceLookup_INTERFACE_DEFINED__ -typedef enum _MF_SERVICE_LOOKUP_TYPE -{ - MF_SERVICE_LOOKUP_UPSTREAM = 0, - MF_SERVICE_LOOKUP_UPSTREAM_DIRECT = (MF_SERVICE_LOOKUP_UPSTREAM + 1), - MF_SERVICE_LOOKUP_DOWNSTREAM = (MF_SERVICE_LOOKUP_UPSTREAM_DIRECT + 1), - MF_SERVICE_LOOKUP_DOWNSTREAM_DIRECT = (MF_SERVICE_LOOKUP_DOWNSTREAM + 1), - MF_SERVICE_LOOKUP_ALL = (MF_SERVICE_LOOKUP_DOWNSTREAM_DIRECT + 1), - MF_SERVICE_LOOKUP_GLOBAL = (MF_SERVICE_LOOKUP_ALL + 1) -} MF_SERVICE_LOOKUP_TYPE; - -DEFINE_GUID(IID_IMFTopologyServiceLookup, 0xfa993889, 0x4383, 0x415a, 0xa9,0x30, 0xdd,0x47,0x2a,0x8c,0xf6,0xf7); -MIDL_INTERFACE("fa993889-4383-415a-a930-dd472a8cf6f7") -IMFTopologyServiceLookup : public IUnknown -{ -public: - virtual HRESULT STDMETHODCALLTYPE LookupService(MF_SERVICE_LOOKUP_TYPE Type, - DWORD dwIndex, - REFGUID guidService, - REFIID riid, - LPVOID *ppvObjects, - DWORD *pnObjects) = 0; -}; -#ifdef __CRT_UUID_DECL -__CRT_UUID_DECL(IMFTopologyServiceLookup, 0xfa993889, 0x4383, 0x415a, 0xa9,0x30, 0xdd,0x47,0x2a,0x8c,0xf6,0xf7) -#endif -#endif // __IMFTopologyServiceLookup_INTERFACE_DEFINED__ - -#ifndef __IMFTopologyServiceLookupClient_INTERFACE_DEFINED__ -#define __IMFTopologyServiceLookupClient_INTERFACE_DEFINED__ -DEFINE_GUID(IID_IMFTopologyServiceLookupClient, 0xfa99388a, 0x4383, 0x415a, 0xa9,0x30, 0xdd,0x47,0x2a,0x8c,0xf6,0xf7); -MIDL_INTERFACE("fa99388a-4383-415a-a930-dd472a8cf6f7") -IMFTopologyServiceLookupClient : public IUnknown -{ -public: - virtual HRESULT STDMETHODCALLTYPE InitServicePointers(IMFTopologyServiceLookup *pLookup) = 0; - virtual HRESULT STDMETHODCALLTYPE ReleaseServicePointers(void) = 0; -}; -#ifdef __CRT_UUID_DECL -__CRT_UUID_DECL(IMFTopologyServiceLookupClient, 0xfa99388a, 0x4383, 0x415a, 0xa9,0x30, 0xdd,0x47,0x2a,0x8c,0xf6,0xf7) -#endif -#endif // __IMFTopologyServiceLookupClient_INTERFACE_DEFINED__ - -#ifndef __IMediaEventSink_INTERFACE_DEFINED__ -#define __IMediaEventSink_INTERFACE_DEFINED__ -DEFINE_GUID(IID_IMediaEventSink, 0x56a868a2, 0x0ad4, 0x11ce, 0xb0,0x3a, 0x00,0x20,0xaf,0x0b,0xa7,0x70); -MIDL_INTERFACE("56a868a2-0ad4-11ce-b03a-0020af0ba770") -IMediaEventSink : public IUnknown -{ -public: - virtual HRESULT STDMETHODCALLTYPE Notify(long EventCode, LONG_PTR EventParam1, LONG_PTR EventParam2) = 0; -}; -#ifdef __CRT_UUID_DECL -__CRT_UUID_DECL(IMediaEventSink, 0x56a868a2, 0x0ad4, 0x11ce, 0xb0,0x3a, 0x00,0x20,0xaf,0x0b,0xa7,0x70) -#endif -#endif // __IMediaEventSink_INTERFACE_DEFINED__ - -#ifndef __IMFVideoRenderer_INTERFACE_DEFINED__ -#define __IMFVideoRenderer_INTERFACE_DEFINED__ -DEFINE_GUID(IID_IMFVideoRenderer, 0xDFDFD197, 0xA9CA, 0x43d8, 0xB3,0x41, 0x6A,0xF3,0x50,0x37,0x92,0xCD); -MIDL_INTERFACE("DFDFD197-A9CA-43d8-B341-6AF3503792CD") -IMFVideoRenderer : public IUnknown -{ -public: - virtual HRESULT STDMETHODCALLTYPE InitializeRenderer(IMFTransform *pVideoMixer, - IMFVideoPresenter *pVideoPresenter) = 0; -}; -#ifdef __CRT_UUID_DECL -__CRT_UUID_DECL(IMFVideoRenderer, 0xDFDFD197, 0xA9CA, 0x43d8, 0xB3,0x41, 0x6A,0xF3,0x50,0x37,0x92,0xCD) -#endif -#endif // __IMFVideoRenderer_INTERFACE_DEFINED__ - -#ifndef __IMFTrackedSample_INTERFACE_DEFINED__ -#define __IMFTrackedSample_INTERFACE_DEFINED__ -DEFINE_GUID(IID_IMFTrackedSample, 0x245BF8E9, 0x0755, 0x40f7, 0x88,0xA5, 0xAE,0x0F,0x18,0xD5,0x5E,0x17); -MIDL_INTERFACE("245BF8E9-0755-40f7-88A5-AE0F18D55E17") -IMFTrackedSample : public IUnknown -{ -public: - virtual HRESULT STDMETHODCALLTYPE SetAllocator(IMFAsyncCallback *pSampleAllocator, IUnknown *pUnkState) = 0; -}; -#ifdef __CRT_UUID_DECL -__CRT_UUID_DECL(IMFTrackedSample, 0x245BF8E9, 0x0755, 0x40f7, 0x88,0xA5, 0xAE,0x0F,0x18,0xD5,0x5E,0x17) -#endif -#endif // __IMFTrackedSample_INTERFACE_DEFINED__ - -#ifndef __IMFDesiredSample_INTERFACE_DEFINED__ -#define __IMFDesiredSample_INTERFACE_DEFINED__ -DEFINE_GUID(IID_IMFDesiredSample, 0x56C294D0, 0x753E, 0x4260, 0x8D,0x61, 0xA3,0xD8,0x82,0x0B,0x1D,0x54); -MIDL_INTERFACE("56C294D0-753E-4260-8D61-A3D8820B1D54") -IMFDesiredSample : public IUnknown -{ -public: - virtual HRESULT STDMETHODCALLTYPE GetDesiredSampleTimeAndDuration(LONGLONG *phnsSampleTime, - LONGLONG *phnsSampleDuration) = 0; - virtual void STDMETHODCALLTYPE SetDesiredSampleTimeAndDuration(LONGLONG hnsSampleTime, - LONGLONG hnsSampleDuration) = 0; - virtual void STDMETHODCALLTYPE Clear( void) = 0; -}; -#ifdef __CRT_UUID_DECL -__CRT_UUID_DECL(IMFDesiredSample, 0x56C294D0, 0x753E, 0x4260, 0x8D,0x61, 0xA3,0xD8,0x82,0x0B,0x1D,0x54) -#endif -#endif - -#endif // EVRDEFS_H - diff --git a/src/plugins/common/evr/evrhelpers.cpp b/src/plugins/common/evr/evrhelpers.cpp deleted file mode 100644 index a315f1a73..000000000 --- a/src/plugins/common/evr/evrhelpers.cpp +++ /dev/null @@ -1,186 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 https://www.qt.io/terms-conditions. For further -** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#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 - -QT_BEGIN_NAMESPACE - -HRESULT qt_evr_getFourCC(IMFMediaType *type, DWORD *fourCC) -{ - if (!fourCC) - return E_POINTER; - - HRESULT hr = S_OK; - GUID guidSubType = GUID_NULL; - - if (SUCCEEDED(hr)) - hr = type->GetGUID(MF_MT_SUBTYPE, &guidSubType); - - if (SUCCEEDED(hr)) - *fourCC = guidSubType.Data1; - - return hr; -} - -bool qt_evr_areMediaTypesEqual(IMFMediaType *type1, IMFMediaType *type2) -{ - if (!type1 && !type2) - return true; - if (!type1 || !type2) - return false; - - DWORD dwFlags = 0; - HRESULT hr = type1->IsEqual(type2, &dwFlags); - - return (hr == S_OK); -} - -HRESULT qt_evr_validateVideoArea(const MFVideoArea& area, UINT32 width, UINT32 height) -{ - float fOffsetX = qt_evr_MFOffsetToFloat(area.OffsetX); - float fOffsetY = qt_evr_MFOffsetToFloat(area.OffsetY); - - if ( ((LONG)fOffsetX + area.Area.cx > (LONG)width) || - ((LONG)fOffsetY + area.Area.cy > (LONG)height) ) { - return MF_E_INVALIDMEDIATYPE; - } - return S_OK; -} - -bool qt_evr_isSampleTimePassed(IMFClock *clock, IMFSample *sample) -{ - if (!sample || !clock) - return false; - - HRESULT hr = S_OK; - MFTIME hnsTimeNow = 0; - MFTIME hnsSystemTime = 0; - MFTIME hnsSampleStart = 0; - MFTIME hnsSampleDuration = 0; - - hr = clock->GetCorrelatedTime(0, &hnsTimeNow, &hnsSystemTime); - - if (SUCCEEDED(hr)) - hr = sample->GetSampleTime(&hnsSampleStart); - - if (SUCCEEDED(hr)) - hr = sample->GetSampleDuration(&hnsSampleDuration); - - if (SUCCEEDED(hr)) { - if (hnsSampleStart + hnsSampleDuration < hnsTimeNow) - return true; - } - - return false; -} - -QVideoFrame::PixelFormat qt_evr_pixelFormatFromD3DFormat(DWORD 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; - } -} - -QT_END_NAMESPACE diff --git a/src/plugins/common/evr/evrhelpers.h b/src/plugins/common/evr/evrhelpers.h deleted file mode 100644 index b5bdf5ead..000000000 --- a/src/plugins/common/evr/evrhelpers.h +++ /dev/null @@ -1,101 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 https://www.qt.io/terms-conditions. For further -** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef EVRHELPERS_H -#define EVRHELPERS_H - -#include "evrdefs.h" -#include <qvideoframe.h> - -QT_BEGIN_NAMESPACE - -template<class T> -static inline void qt_evr_safe_release(T **unk) -{ - if (*unk) { - (*unk)->Release(); - *unk = NULL; - } -} - -HRESULT qt_evr_getFourCC(IMFMediaType *type, DWORD *fourCC); - -bool qt_evr_areMediaTypesEqual(IMFMediaType *type1, IMFMediaType *type2); - -HRESULT qt_evr_validateVideoArea(const MFVideoArea& area, UINT32 width, UINT32 height); - -bool qt_evr_isSampleTimePassed(IMFClock *clock, IMFSample *sample); - -inline float qt_evr_MFOffsetToFloat(const MFOffset& offset) -{ - return offset.value + (float(offset.fract) / 65536); -} - -inline MFOffset qt_evr_makeMFOffset(float v) -{ - MFOffset offset; - offset.value = short(v); - offset.fract = WORD(65536 * (v-offset.value)); - return offset; -} - -inline MFVideoArea qt_evr_makeMFArea(float x, float y, DWORD width, DWORD height) -{ - MFVideoArea area; - area.OffsetX = qt_evr_makeMFOffset(x); - area.OffsetY = qt_evr_makeMFOffset(y); - area.Area.cx = width; - area.Area.cy = height; - return area; -} - -inline HRESULT qt_evr_getFrameRate(IMFMediaType *pType, MFRatio *pRatio) -{ - return MFGetAttributeRatio(pType, MF_MT_FRAME_RATE, - reinterpret_cast<UINT32*>(&pRatio->Numerator), - reinterpret_cast<UINT32*>(&pRatio->Denominator)); -} - -QVideoFrame::PixelFormat qt_evr_pixelFormatFromD3DFormat(DWORD format); -D3DFORMAT qt_evr_D3DFormatFromPixelFormat(QVideoFrame::PixelFormat format); - -QT_END_NAMESPACE - -#endif // EVRHELPERS_H - diff --git a/src/plugins/common/evr/evrvideowindowcontrol.cpp b/src/plugins/common/evr/evrvideowindowcontrol.cpp deleted file mode 100644 index 95f63c2e7..000000000 --- a/src/plugins/common/evr/evrvideowindowcontrol.cpp +++ /dev/null @@ -1,362 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 https://www.qt.io/terms-conditions. For further -** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "evrvideowindowcontrol.h" - -#ifndef QT_NO_WIDGETS -#include <qwidget.h> -#endif - -EvrVideoWindowControl::EvrVideoWindowControl(QObject *parent) - : QVideoWindowControl(parent) - , m_windowId(0) - , m_windowColor(RGB(0, 0, 0)) - , m_dirtyValues(0) - , m_aspectRatioMode(Qt::KeepAspectRatio) - , m_brightness(0) - , m_contrast(0) - , m_hue(0) - , m_saturation(0) - , m_fullScreen(false) - , m_displayControl(0) - , m_processor(0) -{ -} - -EvrVideoWindowControl::~EvrVideoWindowControl() -{ - clear(); -} - -bool EvrVideoWindowControl::setEvr(IUnknown *evr) -{ - clear(); - - if (!evr) - return true; - - IMFGetService *service = NULL; - - if (SUCCEEDED(evr->QueryInterface(IID_PPV_ARGS(&service))) - && SUCCEEDED(service->GetService(mr_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&m_displayControl)))) { - - service->GetService(mr_VIDEO_MIXER_SERVICE, IID_PPV_ARGS(&m_processor)); - - setWinId(m_windowId); - setDisplayRect(m_displayRect); - setAspectRatioMode(m_aspectRatioMode); - m_dirtyValues = DXVA2_ProcAmp_Brightness | DXVA2_ProcAmp_Contrast | DXVA2_ProcAmp_Hue | DXVA2_ProcAmp_Saturation; - applyImageControls(); - } - - if (service) - service->Release(); - - return m_displayControl != NULL; -} - -void EvrVideoWindowControl::clear() -{ - if (m_displayControl) - m_displayControl->Release(); - m_displayControl = NULL; - - if (m_processor) - m_processor->Release(); - m_processor = NULL; -} - -WId EvrVideoWindowControl::winId() const -{ - return m_windowId; -} - -void EvrVideoWindowControl::setWinId(WId id) -{ - m_windowId = id; - -#ifndef QT_NO_WIDGETS - if (QWidget *widget = QWidget::find(m_windowId)) { - const QColor color = widget->palette().color(QPalette::Window); - - m_windowColor = RGB(color.red(), color.green(), color.blue()); - } -#endif - - if (m_displayControl) - m_displayControl->SetVideoWindow(HWND(m_windowId)); -} - -QRect EvrVideoWindowControl::displayRect() const -{ - return m_displayRect; -} - -void EvrVideoWindowControl::setDisplayRect(const QRect &rect) -{ - m_displayRect = rect; - - if (m_displayControl) { - RECT displayRect = { rect.left(), rect.top(), rect.right() + 1, rect.bottom() + 1 }; - QSize sourceSize = nativeSize(); - - RECT sourceRect = { 0, 0, sourceSize.width(), sourceSize.height() }; - - if (m_aspectRatioMode == Qt::KeepAspectRatioByExpanding) { - QSize clippedSize = rect.size(); - clippedSize.scale(sourceRect.right, sourceRect.bottom, Qt::KeepAspectRatio); - - sourceRect.left = (sourceRect.right - clippedSize.width()) / 2; - sourceRect.top = (sourceRect.bottom - clippedSize.height()) / 2; - sourceRect.right = sourceRect.left + clippedSize.width(); - sourceRect.bottom = sourceRect.top + clippedSize.height(); - } - - if (sourceSize.width() > 0 && sourceSize.height() > 0) { - MFVideoNormalizedRect sourceNormRect; - sourceNormRect.left = float(sourceRect.left) / float(sourceRect.right); - sourceNormRect.top = float(sourceRect.top) / float(sourceRect.bottom); - sourceNormRect.right = float(sourceRect.right) / float(sourceRect.right); - sourceNormRect.bottom = float(sourceRect.bottom) / float(sourceRect.bottom); - m_displayControl->SetVideoPosition(&sourceNormRect, &displayRect); - } else { - m_displayControl->SetVideoPosition(NULL, &displayRect); - } - - // To refresh content immediately. - repaint(); - } -} - -bool EvrVideoWindowControl::isFullScreen() const -{ - return m_fullScreen; -} - -void EvrVideoWindowControl::setFullScreen(bool fullScreen) -{ - if (m_fullScreen == fullScreen) - return; - emit fullScreenChanged(m_fullScreen = fullScreen); -} - -void EvrVideoWindowControl::repaint() -{ - QSize size = nativeSize(); - if (size.width() > 0 && size.height() > 0 - && m_displayControl - && SUCCEEDED(m_displayControl->RepaintVideo())) { - return; - } - - PAINTSTRUCT paint; - if (HDC dc = ::BeginPaint(HWND(m_windowId), &paint)) { - HPEN pen = ::CreatePen(PS_SOLID, 1, m_windowColor); - HBRUSH brush = ::CreateSolidBrush(m_windowColor); - ::SelectObject(dc, pen); - ::SelectObject(dc, brush); - - ::Rectangle( - dc, - m_displayRect.left(), - m_displayRect.top(), - m_displayRect.right() + 1, - m_displayRect.bottom() + 1); - - ::DeleteObject(pen); - ::DeleteObject(brush); - ::EndPaint(HWND(m_windowId), &paint); - } -} - -QSize EvrVideoWindowControl::nativeSize() const -{ - QSize size; - if (m_displayControl) { - SIZE sourceSize; - if (SUCCEEDED(m_displayControl->GetNativeVideoSize(&sourceSize, 0))) - size = QSize(sourceSize.cx, sourceSize.cy); - } - return size; -} - -Qt::AspectRatioMode EvrVideoWindowControl::aspectRatioMode() const -{ - return m_aspectRatioMode; -} - -void EvrVideoWindowControl::setAspectRatioMode(Qt::AspectRatioMode mode) -{ - m_aspectRatioMode = mode; - - if (m_displayControl) { - switch (mode) { - case Qt::IgnoreAspectRatio: - //comment from MSDN: Do not maintain the aspect ratio of the video. Stretch the video to fit the output rectangle. - m_displayControl->SetAspectRatioMode(MFVideoARMode_None); - break; - case Qt::KeepAspectRatio: - //comment from MSDN: Preserve the aspect ratio of the video by letterboxing or within the output rectangle. - m_displayControl->SetAspectRatioMode(MFVideoARMode_PreservePicture); - break; - case Qt::KeepAspectRatioByExpanding: - //for this mode, more adjustment will be done in setDisplayRect - m_displayControl->SetAspectRatioMode(MFVideoARMode_PreservePicture); - break; - default: - break; - } - setDisplayRect(m_displayRect); - } -} - -int EvrVideoWindowControl::brightness() const -{ - return m_brightness; -} - -void EvrVideoWindowControl::setBrightness(int brightness) -{ - if (m_brightness == brightness) - return; - - m_brightness = brightness; - - m_dirtyValues |= DXVA2_ProcAmp_Brightness; - - applyImageControls(); - - emit brightnessChanged(brightness); -} - -int EvrVideoWindowControl::contrast() const -{ - return m_contrast; -} - -void EvrVideoWindowControl::setContrast(int contrast) -{ - if (m_contrast == contrast) - return; - - m_contrast = contrast; - - m_dirtyValues |= DXVA2_ProcAmp_Contrast; - - applyImageControls(); - - emit contrastChanged(contrast); -} - -int EvrVideoWindowControl::hue() const -{ - return m_hue; -} - -void EvrVideoWindowControl::setHue(int hue) -{ - if (m_hue == hue) - return; - - m_hue = hue; - - m_dirtyValues |= DXVA2_ProcAmp_Hue; - - applyImageControls(); - - emit hueChanged(hue); -} - -int EvrVideoWindowControl::saturation() const -{ - return m_saturation; -} - -void EvrVideoWindowControl::setSaturation(int saturation) -{ - if (m_saturation == saturation) - return; - - m_saturation = saturation; - - m_dirtyValues |= DXVA2_ProcAmp_Saturation; - - applyImageControls(); - - emit saturationChanged(saturation); -} - -void EvrVideoWindowControl::applyImageControls() -{ - if (m_processor) { - DXVA2_ProcAmpValues values; - if (m_dirtyValues & DXVA2_ProcAmp_Brightness) { - values.Brightness = scaleProcAmpValue(DXVA2_ProcAmp_Brightness, m_brightness); - } - if (m_dirtyValues & DXVA2_ProcAmp_Contrast) { - values.Contrast = scaleProcAmpValue(DXVA2_ProcAmp_Contrast, m_contrast); - } - if (m_dirtyValues & DXVA2_ProcAmp_Hue) { - values.Hue = scaleProcAmpValue(DXVA2_ProcAmp_Hue, m_hue); - } - if (m_dirtyValues & DXVA2_ProcAmp_Saturation) { - values.Saturation = scaleProcAmpValue(DXVA2_ProcAmp_Saturation, m_saturation); - } - - if (SUCCEEDED(m_processor->SetProcAmpValues(m_dirtyValues, &values))) { - m_dirtyValues = 0; - } - } -} - -DXVA2_Fixed32 EvrVideoWindowControl::scaleProcAmpValue(DWORD prop, int value) const -{ - float scaledValue = 0.0; - - DXVA2_ValueRange range; - if (SUCCEEDED(m_processor->GetProcAmpRange(prop, &range))) { - scaledValue = DXVA2FixedToFloat(range.DefaultValue); - if (value > 0) - scaledValue += float(value) * (DXVA2FixedToFloat(range.MaxValue) - DXVA2FixedToFloat(range.DefaultValue)) / 100; - else if (value < 0) - scaledValue -= float(value) * (DXVA2FixedToFloat(range.MinValue) - DXVA2FixedToFloat(range.DefaultValue)) / 100; - } - - return DXVA2FloatToFixed(scaledValue); -} diff --git a/src/plugins/common/evr/evrvideowindowcontrol.h b/src/plugins/common/evr/evrvideowindowcontrol.h deleted file mode 100644 index ce3b7746f..000000000 --- a/src/plugins/common/evr/evrvideowindowcontrol.h +++ /dev/null @@ -1,109 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Mobility Components. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 https://www.qt.io/terms-conditions. For further -** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef EVRVIDEOWINDOWCONTROL_H -#define EVRVIDEOWINDOWCONTROL_H - -#include "qvideowindowcontrol.h" - -#include "evrdefs.h" - -QT_BEGIN_NAMESPACE - -class EvrVideoWindowControl : public QVideoWindowControl -{ - Q_OBJECT -public: - EvrVideoWindowControl(QObject *parent = 0); - ~EvrVideoWindowControl() override; - - bool setEvr(IUnknown *evr); - - WId winId() const override; - void setWinId(WId id) override; - - QRect displayRect() const override; - void setDisplayRect(const QRect &rect) override; - - bool isFullScreen() const override; - void setFullScreen(bool fullScreen) override; - - void repaint() override; - - QSize nativeSize() const override; - - Qt::AspectRatioMode aspectRatioMode() const override; - void setAspectRatioMode(Qt::AspectRatioMode mode) override; - - int brightness() const override; - void setBrightness(int brightness) override; - - int contrast() const override; - void setContrast(int contrast) override; - - int hue() const override; - void setHue(int hue) override; - - int saturation() const override; - void setSaturation(int saturation) override; - - void applyImageControls(); - -private: - void clear(); - DXVA2_Fixed32 scaleProcAmpValue(DWORD prop, int value) const; - - WId m_windowId; - COLORREF m_windowColor; - DWORD m_dirtyValues; - Qt::AspectRatioMode m_aspectRatioMode; - QRect m_displayRect; - int m_brightness; - int m_contrast; - int m_hue; - int m_saturation; - bool m_fullScreen; - - IMFVideoDisplayControl *m_displayControl; - IMFVideoProcessor *m_processor; -}; - -QT_END_NAMESPACE - -#endif |