WMF: enabled HW-accelerated video decoding for the QML video item.
It also applies to QGraphicsVideoItem when used on a GL viewport. We now have a new video sink that is based on Microsoft's EVR sink, we just replace the default Presenter with our own. Frames are rendered into D3D surfaces using DXVA, then copied into a shared D3D/EGL surface and finally bound to a GL texture to be used by the video surface. The shared D3D/EGL surface is a feature provided by ANGLE and therefore Qt must be compiled with ANGLE for this new video sink to be compiled and used. Change-Id: I0b7b9968eed5488f9ef1a2dcca5213bd0af232ab Reviewed-by: Yoann Lopes <yoann.lopes@digia.com>
This commit is contained in:
committed by
The Qt Project
parent
02add40392
commit
101c78983a
2052
src/plugins/wmf/evrcustompresenter.cpp
Normal file
2052
src/plugins/wmf/evrcustompresenter.cpp
Normal file
File diff suppressed because it is too large
Load Diff
333
src/plugins/wmf/evrcustompresenter.h
Normal file
333
src/plugins/wmf/evrcustompresenter.h
Normal file
@@ -0,0 +1,333 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** 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 Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef EVRCUSTOMPRESENTER_H
|
||||
#define EVRCUSTOMPRESENTER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <qmutex.h>
|
||||
#include <qqueue.h>
|
||||
#include <evr.h>
|
||||
#include "mfactivate.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class D3DPresentEngine;
|
||||
class QAbstractVideoSurface;
|
||||
|
||||
class Scheduler
|
||||
{
|
||||
public:
|
||||
enum ScheduleEvent
|
||||
{
|
||||
Terminate = WM_USER,
|
||||
Schedule = WM_USER + 1,
|
||||
Flush = WM_USER + 2
|
||||
};
|
||||
|
||||
Scheduler();
|
||||
~Scheduler();
|
||||
|
||||
void setCallback(QObject *cb) {
|
||||
m_CB = cb;
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
// ThreadProc for the scheduler thread.
|
||||
static DWORD WINAPI schedulerThreadProc(LPVOID parameter);
|
||||
|
||||
private:
|
||||
DWORD schedulerThreadProcPrivate();
|
||||
|
||||
QQueue<IMFSample*> m_scheduledSamples; // Samples waiting to be presented.
|
||||
|
||||
IMFClock *m_clock; // Presentation clock. Can be NULL.
|
||||
QObject *m_CB; // Weak reference; do not delete.
|
||||
|
||||
DWORD m_threadID;
|
||||
HANDLE m_schedulerThread;
|
||||
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
|
||||
{
|
||||
public:
|
||||
SamplePool();
|
||||
~SamplePool();
|
||||
|
||||
HRESULT initialize(QList<IMFSample*> &samples);
|
||||
HRESULT clear();
|
||||
|
||||
HRESULT getSample(IMFSample **sample);
|
||||
HRESULT returnSample(IMFSample *sample);
|
||||
BOOL areSamplesPending();
|
||||
|
||||
private:
|
||||
QMutex m_mutex;
|
||||
QList<IMFSample*> m_videoSampleQueue;
|
||||
bool m_initialized;
|
||||
DWORD m_pending;
|
||||
};
|
||||
|
||||
class EVRCustomPresenter
|
||||
: public QObject
|
||||
, public IMFVideoDeviceID
|
||||
, public IMFVideoPresenter // Inherits IMFClockStateSink
|
||||
, public IMFRateSupport
|
||||
, public IMFGetService
|
||||
, public IMFTopologyServiceLookupClient
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
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.
|
||||
};
|
||||
|
||||
EVRCustomPresenter();
|
||||
~EVRCustomPresenter();
|
||||
|
||||
// IUnknown methods
|
||||
STDMETHODIMP QueryInterface(REFIID riid, void ** ppv);
|
||||
STDMETHODIMP_(ULONG) AddRef();
|
||||
STDMETHODIMP_(ULONG) Release();
|
||||
|
||||
// IMFGetService methods
|
||||
STDMETHODIMP GetService(REFGUID guidService, REFIID riid, LPVOID *ppvObject);
|
||||
|
||||
// IMFVideoPresenter methods
|
||||
STDMETHODIMP ProcessMessage(MFVP_MESSAGE_TYPE message, ULONG_PTR param);
|
||||
STDMETHODIMP GetCurrentMediaType(IMFVideoMediaType** mediaType);
|
||||
|
||||
// IMFClockStateSink methods
|
||||
STDMETHODIMP OnClockStart(MFTIME systemTime, LONGLONG clockStartOffset);
|
||||
STDMETHODIMP OnClockStop(MFTIME systemTime);
|
||||
STDMETHODIMP OnClockPause(MFTIME systemTime);
|
||||
STDMETHODIMP OnClockRestart(MFTIME systemTime);
|
||||
STDMETHODIMP OnClockSetRate(MFTIME systemTime, float rate);
|
||||
|
||||
// IMFRateSupport methods
|
||||
STDMETHODIMP GetSlowestRate(MFRATE_DIRECTION direction, BOOL thin, float *rate);
|
||||
STDMETHODIMP GetFastestRate(MFRATE_DIRECTION direction, BOOL thin, float *rate);
|
||||
STDMETHODIMP IsRateSupported(BOOL thin, float rate, float *nearestSupportedRate);
|
||||
|
||||
// IMFVideoDeviceID methods
|
||||
STDMETHODIMP GetDeviceID(IID* deviceID);
|
||||
|
||||
// IMFTopologyServiceLookupClient methods
|
||||
STDMETHODIMP InitServicePointers(IMFTopologyServiceLookup *lookup);
|
||||
STDMETHODIMP ReleaseServicePointers();
|
||||
|
||||
void supportedFormatsChanged();
|
||||
void setSurface(QAbstractVideoSurface *surface);
|
||||
|
||||
private Q_SLOTS:
|
||||
void startSurface();
|
||||
void stopSurface();
|
||||
|
||||
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
|
||||
{
|
||||
FrameStep()
|
||||
: state(FrameStepNone)
|
||||
, steps(0)
|
||||
, sampleNoRef(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
FrameStepState state;
|
||||
QList<IMFSample*> samples;
|
||||
DWORD steps;
|
||||
DWORD_PTR sampleNoRef;
|
||||
};
|
||||
|
||||
long m_refCount;
|
||||
|
||||
RenderState m_renderState;
|
||||
FrameStep m_frameStep;
|
||||
|
||||
QMutex 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_D3DPresentEngine; // 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;
|
||||
QList<DWORD> m_supportedGLFormats;
|
||||
};
|
||||
|
||||
class EVRCustomPresenterActivate : public MFAbstractActivate
|
||||
{
|
||||
public:
|
||||
EVRCustomPresenterActivate();
|
||||
~EVRCustomPresenterActivate()
|
||||
{ }
|
||||
|
||||
STDMETHODIMP ActivateObject(REFIID riid, void **ppv);
|
||||
STDMETHODIMP ShutdownObject();
|
||||
STDMETHODIMP DetachObject();
|
||||
|
||||
void setSurface(QAbstractVideoSurface *surface);
|
||||
void supportedFormatsChanged();
|
||||
|
||||
private:
|
||||
EVRCustomPresenter *m_presenter;
|
||||
QAbstractVideoSurface *m_surface;
|
||||
QMutex m_mutex;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // EVRCUSTOMPRESENTER_H
|
||||
580
src/plugins/wmf/evrd3dpresentengine.cpp
Normal file
580
src/plugins/wmf/evrd3dpresentengine.cpp
Normal file
@@ -0,0 +1,580 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** 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 Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "evrd3dpresentengine.h"
|
||||
|
||||
#include "mfglobal.h"
|
||||
|
||||
#include <qtgui/qguiapplication.h>
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
#include <qtgui/qopenglcontext.h>
|
||||
#include <qabstractvideobuffer.h>
|
||||
#include <QAbstractVideoSurface>
|
||||
#include <qvideoframe.h>
|
||||
#include <QDebug>
|
||||
#include <qopenglcontext.h>
|
||||
#include <qwindow.h>
|
||||
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
#include <GLES2/gl2.h>
|
||||
#include <d3d9.h>
|
||||
#include <dxva2api.h>
|
||||
#include <WinUser.h>
|
||||
#include <evr.h>
|
||||
|
||||
QT_USE_NAMESPACE
|
||||
|
||||
static const DWORD PRESENTER_BUFFER_COUNT = 3;
|
||||
|
||||
class TextureVideoBuffer : public QAbstractVideoBuffer
|
||||
{
|
||||
public:
|
||||
TextureVideoBuffer(GLuint textureId)
|
||||
: QAbstractVideoBuffer(GLTextureHandle)
|
||||
, m_textureId(textureId)
|
||||
{}
|
||||
|
||||
~TextureVideoBuffer() {}
|
||||
|
||||
MapMode mapMode() const { return NotMapped; }
|
||||
uchar *map(MapMode, int*, int*) { return 0; }
|
||||
void unmap() {}
|
||||
|
||||
QVariant handle() const
|
||||
{
|
||||
return QVariant::fromValue<unsigned int>(m_textureId);
|
||||
}
|
||||
|
||||
private:
|
||||
GLuint m_textureId;
|
||||
};
|
||||
|
||||
|
||||
D3DPresentEngine::D3DPresentEngine()
|
||||
: QObject()
|
||||
, m_mutex(QMutex::Recursive)
|
||||
, m_deviceResetToken(0)
|
||||
, m_D3D9(0)
|
||||
, m_device(0)
|
||||
, m_deviceManager(0)
|
||||
, m_surface(0)
|
||||
, m_glContext(0)
|
||||
, m_offscreenSurface(0)
|
||||
, m_eglDisplay(0)
|
||||
, m_eglConfig(0)
|
||||
, m_eglSurface(0)
|
||||
, m_glTexture(0)
|
||||
, m_texture(0)
|
||||
{
|
||||
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()
|
||||
{
|
||||
qt_wmf_safeRelease(&m_texture);
|
||||
qt_wmf_safeRelease(&m_device);
|
||||
qt_wmf_safeRelease(&m_deviceManager);
|
||||
qt_wmf_safeRelease(&m_D3D9);
|
||||
|
||||
if (m_eglSurface) {
|
||||
eglReleaseTexImage(m_eglDisplay, m_eglSurface, EGL_BACK_BUFFER);
|
||||
eglDestroySurface(m_eglDisplay, m_eglSurface);
|
||||
m_eglSurface = NULL;
|
||||
}
|
||||
if (m_glTexture)
|
||||
glDeleteTextures(1, &m_glTexture);
|
||||
|
||||
delete m_glContext;
|
||||
delete m_offscreenSurface;
|
||||
}
|
||||
|
||||
void D3DPresentEngine::start()
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
if (!m_surfaceFormat.isValid())
|
||||
return;
|
||||
|
||||
if (!m_texture)
|
||||
createOffscreenTexture();
|
||||
|
||||
if (m_surface && !m_surface->isActive())
|
||||
m_surface->start(m_surfaceFormat);
|
||||
}
|
||||
|
||||
void D3DPresentEngine::stop()
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
if (m_surface && m_surface->isActive())
|
||||
m_surface->stop();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
UINT uAdapter = D3DADAPTER_DEFAULT;
|
||||
D3DDEVTYPE type = D3DDEVTYPE_HAL;
|
||||
|
||||
D3DDISPLAYMODE mode;
|
||||
D3DDEVICE_CREATION_PARAMETERS params;
|
||||
|
||||
// Our shared D3D/EGL surface only supports RGB32,
|
||||
// reject all other formats
|
||||
if (format != D3DFMT_X8R8G8B8)
|
||||
return MF_E_INVALIDMEDIATYPE;
|
||||
|
||||
if (m_device) {
|
||||
hr = m_device->GetCreationParameters(¶ms);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
uAdapter = params.AdapterOrdinal;
|
||||
type = params.DeviceType;
|
||||
}
|
||||
|
||||
hr = m_D3D9->GetAdapterDisplayMode(uAdapter, &mode);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
return m_D3D9->CheckDeviceType(uAdapter, type, mode.Format, format, TRUE);
|
||||
}
|
||||
|
||||
HRESULT D3DPresentEngine::createVideoSamples(IMFMediaType *format, QList<IMFSample*> &videoSampleQueue)
|
||||
{
|
||||
if (!format)
|
||||
return MF_E_UNEXPECTED;
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
D3DPRESENT_PARAMETERS pp;
|
||||
|
||||
IDirect3DSwapChain9 *swapChain = NULL;
|
||||
IMFSample *videoSample = NULL;
|
||||
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
releaseResources();
|
||||
|
||||
// Get the swap chain parameters from the media type.
|
||||
hr = getSwapChainPresentParameters(format, &pp);
|
||||
if (FAILED(hr))
|
||||
goto done;
|
||||
|
||||
// Create the video samples.
|
||||
for (int i = 0; i < PRESENTER_BUFFER_COUNT; i++) {
|
||||
// Create a new swap chain.
|
||||
hr = m_device->CreateAdditionalSwapChain(&pp, &swapChain);
|
||||
if (FAILED(hr))
|
||||
goto done;
|
||||
|
||||
// Create the video sample from the swap chain.
|
||||
hr = createD3DSample(swapChain, &videoSample);
|
||||
if (FAILED(hr))
|
||||
goto done;
|
||||
|
||||
// Add it to the list.
|
||||
videoSample->AddRef();
|
||||
videoSampleQueue.append(videoSample);
|
||||
|
||||
// Set the swap chain pointer as a custom attribute on the sample. This keeps
|
||||
// a reference count on the swap chain, so that the swap chain is kept alive
|
||||
// for the duration of the sample's lifetime.
|
||||
hr = videoSample->SetUnknown(MFSamplePresenter_SampleSwapChain, swapChain);
|
||||
if (FAILED(hr))
|
||||
goto done;
|
||||
|
||||
qt_wmf_safeRelease(&videoSample);
|
||||
qt_wmf_safeRelease(&swapChain);
|
||||
}
|
||||
|
||||
done:
|
||||
if (FAILED(hr))
|
||||
releaseResources();
|
||||
|
||||
qt_wmf_safeRelease(&swapChain);
|
||||
qt_wmf_safeRelease(&videoSample);
|
||||
return hr;
|
||||
}
|
||||
|
||||
void D3DPresentEngine::releaseResources()
|
||||
{
|
||||
}
|
||||
|
||||
void D3DPresentEngine::presentSample(void *opaque, qint64)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
IMFSample *sample = reinterpret_cast<IMFSample*>(opaque);
|
||||
IMFMediaBuffer* buffer = NULL;
|
||||
IDirect3DSurface9* surface = NULL;
|
||||
|
||||
if (sample) {
|
||||
// Get the buffer from the sample.
|
||||
hr = sample->GetBufferByIndex(0, &buffer);
|
||||
if (FAILED(hr))
|
||||
goto done;
|
||||
|
||||
// Get the surface from the buffer.
|
||||
hr = MFGetService(buffer, MR_BUFFER_SERVICE, IID_PPV_ARGS(&surface));
|
||||
if (FAILED(hr))
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (surface && updateTexture(surface)) {
|
||||
m_surface->present(QVideoFrame(new TextureVideoBuffer(m_glTexture),
|
||||
m_surfaceFormat.frameSize(),
|
||||
m_surfaceFormat.pixelFormat()));
|
||||
}
|
||||
|
||||
done:
|
||||
qt_wmf_safeRelease(&surface);
|
||||
qt_wmf_safeRelease(&buffer);
|
||||
qt_wmf_safeRelease(&sample);
|
||||
}
|
||||
|
||||
void D3DPresentEngine::setSurface(QAbstractVideoSurface *surface)
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
m_surface = surface;
|
||||
}
|
||||
|
||||
void D3DPresentEngine::setSurfaceFormat(const QVideoSurfaceFormat &format)
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
m_surfaceFormat = format;
|
||||
}
|
||||
|
||||
void D3DPresentEngine::createOffscreenTexture()
|
||||
{
|
||||
// First, check if we have a context on this thread
|
||||
QOpenGLContext *currentContext = QOpenGLContext::currentContext();
|
||||
|
||||
if (!currentContext) {
|
||||
//Create OpenGL context and set share context from surface
|
||||
QOpenGLContext *shareContext = qobject_cast<QOpenGLContext*>(m_surface->property("GLContext").value<QObject*>());
|
||||
if (!shareContext)
|
||||
return;
|
||||
|
||||
m_offscreenSurface = new QWindow;
|
||||
m_offscreenSurface->setSurfaceType(QWindow::OpenGLSurface);
|
||||
//Needs geometry to be a valid surface, but size is not important
|
||||
m_offscreenSurface->setGeometry(-1, -1, 1, 1);
|
||||
m_offscreenSurface->create();
|
||||
|
||||
m_glContext = new QOpenGLContext;
|
||||
m_glContext->setFormat(m_offscreenSurface->requestedFormat());
|
||||
m_glContext->setShareContext(shareContext);
|
||||
|
||||
if (!m_glContext->create()) {
|
||||
delete m_glContext;
|
||||
delete m_offscreenSurface;
|
||||
m_glContext = 0;
|
||||
m_offscreenSurface = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
currentContext = m_glContext;
|
||||
}
|
||||
|
||||
if (m_glContext)
|
||||
m_glContext->makeCurrent(m_offscreenSurface);
|
||||
|
||||
QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
|
||||
m_eglDisplay = static_cast<EGLDisplay*>(
|
||||
nativeInterface->nativeResourceForContext("eglDisplay", currentContext));
|
||||
m_eglConfig = static_cast<EGLDisplay*>(
|
||||
nativeInterface->nativeResourceForContext("eglConfig", currentContext));
|
||||
|
||||
glGenTextures(1, &m_glTexture);
|
||||
|
||||
|
||||
int w = m_surfaceFormat.frameWidth();
|
||||
int h = m_surfaceFormat.frameHeight();
|
||||
|
||||
EGLint attribs[] = {
|
||||
EGL_WIDTH, w,
|
||||
EGL_HEIGHT, h,
|
||||
EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGB,
|
||||
EGL_TEXTURE_TARGET, EGL_TEXTURE_2D,
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
EGLSurface pbuffer = eglCreatePbufferSurface(m_eglDisplay, m_eglConfig, attribs);
|
||||
|
||||
HANDLE share_handle = 0;
|
||||
PFNEGLQUERYSURFACEPOINTERANGLEPROC eglQuerySurfacePointerANGLE =
|
||||
reinterpret_cast<PFNEGLQUERYSURFACEPOINTERANGLEPROC>(eglGetProcAddress("eglQuerySurfacePointerANGLE"));
|
||||
eglQuerySurfacePointerANGLE(
|
||||
m_eglDisplay,
|
||||
pbuffer,
|
||||
EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, &share_handle);
|
||||
|
||||
|
||||
m_device->CreateTexture(w, h, 1,
|
||||
D3DUSAGE_RENDERTARGET,
|
||||
D3DFMT_X8R8G8B8,
|
||||
D3DPOOL_DEFAULT,
|
||||
&m_texture,
|
||||
&share_handle);
|
||||
|
||||
m_eglSurface = pbuffer;
|
||||
|
||||
if (m_glContext)
|
||||
m_glContext->doneCurrent();
|
||||
}
|
||||
|
||||
bool D3DPresentEngine::updateTexture(IDirect3DSurface9 *src)
|
||||
{
|
||||
if (!m_texture)
|
||||
return false;
|
||||
|
||||
if (m_glContext)
|
||||
m_glContext->makeCurrent(m_offscreenSurface);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, m_glTexture);
|
||||
|
||||
IDirect3DSurface9 *dest = NULL;
|
||||
|
||||
// Copy the sample surface to the shared D3D/EGL surface
|
||||
HRESULT hr = m_texture->GetSurfaceLevel(0, &dest);
|
||||
if (FAILED(hr))
|
||||
goto done;
|
||||
|
||||
hr = m_device->StretchRect(src, NULL, dest, NULL, D3DTEXF_NONE);
|
||||
if (FAILED(hr))
|
||||
qWarning("Failed to copy D3D surface");
|
||||
|
||||
if (hr == S_OK)
|
||||
eglBindTexImage(m_eglDisplay, m_eglSurface, EGL_BACK_BUFFER);
|
||||
|
||||
done:
|
||||
qt_wmf_safeRelease(&dest);
|
||||
|
||||
if (m_glContext)
|
||||
m_glContext->doneCurrent();
|
||||
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
HRESULT D3DPresentEngine::initializeD3D()
|
||||
{
|
||||
HRESULT hr = Direct3DCreate9Ex(D3D_SDK_VERSION, &m_D3D9);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
hr = DXVA2CreateDirect3DDeviceManager9(&m_deviceResetToken, &m_deviceManager);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT D3DPresentEngine::createD3DDevice()
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
HWND hwnd = NULL;
|
||||
UINT uAdapterID = D3DADAPTER_DEFAULT;
|
||||
DWORD vp = 0;
|
||||
|
||||
D3DCAPS9 ddCaps;
|
||||
ZeroMemory(&ddCaps, sizeof(ddCaps));
|
||||
|
||||
IDirect3DDevice9Ex* device = NULL;
|
||||
|
||||
// Hold the lock because we might be discarding an existing device.
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
if (!m_D3D9 || !m_deviceManager)
|
||||
return MF_E_NOT_INITIALIZED;
|
||||
|
||||
hwnd = ::GetShellWindow();
|
||||
|
||||
// Note: The presenter creates additional swap chains to present the
|
||||
// video frames. Therefore, it does not use the device's implicit
|
||||
// swap chain, so the size of the back buffer here is 1 x 1.
|
||||
|
||||
D3DPRESENT_PARAMETERS pp;
|
||||
ZeroMemory(&pp, sizeof(pp));
|
||||
|
||||
pp.BackBufferWidth = 1;
|
||||
pp.BackBufferHeight = 1;
|
||||
pp.BackBufferFormat = D3DFMT_UNKNOWN;
|
||||
pp.BackBufferCount = 1;
|
||||
pp.Windowed = TRUE;
|
||||
pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
||||
pp.BackBufferFormat = D3DFMT_UNKNOWN;
|
||||
pp.hDeviceWindow = hwnd;
|
||||
pp.Flags = D3DPRESENTFLAG_VIDEO;
|
||||
pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
|
||||
|
||||
hr = m_D3D9->GetDeviceCaps(uAdapterID, D3DDEVTYPE_HAL, &ddCaps);
|
||||
if (FAILED(hr))
|
||||
goto done;
|
||||
|
||||
if (ddCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
|
||||
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
|
||||
else
|
||||
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
|
||||
|
||||
hr = m_D3D9->CreateDeviceEx(
|
||||
uAdapterID,
|
||||
D3DDEVTYPE_HAL,
|
||||
pp.hDeviceWindow,
|
||||
vp | D3DCREATE_NOWINDOWCHANGES | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE,
|
||||
&pp,
|
||||
NULL,
|
||||
&device
|
||||
);
|
||||
if (FAILED(hr))
|
||||
goto done;
|
||||
|
||||
hr = m_D3D9->GetAdapterDisplayMode(uAdapterID, &m_displayMode);
|
||||
if (FAILED(hr))
|
||||
goto done;
|
||||
|
||||
hr = m_deviceManager->ResetDevice(device, m_deviceResetToken);
|
||||
if (FAILED(hr))
|
||||
goto done;
|
||||
|
||||
qt_wmf_safeRelease(&m_device);
|
||||
|
||||
m_device = device;
|
||||
m_device->AddRef();
|
||||
|
||||
done:
|
||||
qt_wmf_safeRelease(&device);
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT D3DPresentEngine::createD3DSample(IDirect3DSwapChain9 *swapChain, IMFSample **videoSample)
|
||||
{
|
||||
D3DCOLOR clrBlack = D3DCOLOR_ARGB(0xFF, 0x00, 0x00, 0x00);
|
||||
|
||||
IDirect3DSurface9* surface = NULL;
|
||||
IMFSample* sample = NULL;
|
||||
|
||||
// Get the back buffer surface.
|
||||
HRESULT hr = swapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &surface);
|
||||
if (FAILED(hr))
|
||||
goto done;
|
||||
|
||||
// Fill it with black.
|
||||
hr = m_device->ColorFill(surface, NULL, clrBlack);
|
||||
if (FAILED(hr))
|
||||
goto done;
|
||||
|
||||
hr = MFCreateVideoSampleFromSurface(surface, &sample);
|
||||
if (FAILED(hr))
|
||||
goto done;
|
||||
|
||||
*videoSample = sample;
|
||||
(*videoSample)->AddRef();
|
||||
|
||||
done:
|
||||
qt_wmf_safeRelease(&surface);
|
||||
qt_wmf_safeRelease(&sample);
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT D3DPresentEngine::getSwapChainPresentParameters(IMFMediaType *type, D3DPRESENT_PARAMETERS* pp)
|
||||
{
|
||||
ZeroMemory(pp, sizeof(D3DPRESENT_PARAMETERS));
|
||||
|
||||
// Get some information about the video format.
|
||||
|
||||
UINT32 width = 0, height = 0;
|
||||
|
||||
HRESULT hr = MFGetAttributeSize(type, MF_MT_FRAME_SIZE, &width, &height);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
DWORD d3dFormat = 0;
|
||||
|
||||
hr = qt_wmf_getFourCC(type, &d3dFormat);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
ZeroMemory(pp, sizeof(D3DPRESENT_PARAMETERS));
|
||||
pp->BackBufferWidth = width;
|
||||
pp->BackBufferHeight = height;
|
||||
pp->Windowed = TRUE;
|
||||
pp->SwapEffect = D3DSWAPEFFECT_DISCARD;
|
||||
pp->BackBufferFormat = (D3DFORMAT)d3dFormat;
|
||||
pp->hDeviceWindow = ::GetShellWindow();
|
||||
pp->Flags = D3DPRESENTFLAG_VIDEO;
|
||||
pp->PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
|
||||
|
||||
D3DDEVICE_CREATION_PARAMETERS params;
|
||||
hr = m_device->GetCreationParameters(¶ms);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
if (params.DeviceType != D3DDEVTYPE_HAL)
|
||||
pp->Flags |= D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
130
src/plugins/wmf/evrd3dpresentengine.h
Normal file
130
src/plugins/wmf/evrd3dpresentengine.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** 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 Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef EVRD3DPRESENTENGINE_H
|
||||
#define EVRD3DPRESENTENGINE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <EGL/egl.h>
|
||||
#include <QMutex>
|
||||
#include <d3d9types.h>
|
||||
#include <QVideoSurfaceFormat>
|
||||
|
||||
struct IDirect3D9Ex;
|
||||
struct IDirect3DDevice9;
|
||||
struct IDirect3DDevice9Ex;
|
||||
struct IDirect3DDeviceManager9;
|
||||
struct IDirect3DSurface9;
|
||||
struct IDirect3DTexture9;
|
||||
struct IMFSample;
|
||||
struct IMFMediaType;
|
||||
struct IDirect3DSwapChain9;
|
||||
|
||||
// Randomly generated GUIDs
|
||||
static const GUID MFSamplePresenter_SampleCounter =
|
||||
{ 0xb0bb83cc, 0xf10f, 0x4e2e, { 0xaa, 0x2b, 0x29, 0xea, 0x5e, 0x92, 0xef, 0x85 } };
|
||||
|
||||
static const GUID MFSamplePresenter_SampleSwapChain =
|
||||
{ 0xad885bd1, 0x7def, 0x414a, { 0xb5, 0xb0, 0xd3, 0xd2, 0x63, 0xd6, 0xe9, 0x6d } };
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QAbstractVideoSurface;
|
||||
class QOpenGLContext;
|
||||
|
||||
class D3DPresentEngine : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
D3DPresentEngine();
|
||||
virtual ~D3DPresentEngine();
|
||||
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
HRESULT getService(REFGUID guidService, REFIID riid, void** ppv);
|
||||
HRESULT checkFormat(D3DFORMAT format);
|
||||
|
||||
HRESULT createVideoSamples(IMFMediaType *format, QList<IMFSample*>& videoSampleQueue);
|
||||
void releaseResources();
|
||||
|
||||
UINT refreshRate() const { return m_displayMode.RefreshRate; }
|
||||
|
||||
void setSurface(QAbstractVideoSurface *surface);
|
||||
void setSurfaceFormat(const QVideoSurfaceFormat &format);
|
||||
|
||||
void createOffscreenTexture();
|
||||
bool updateTexture(IDirect3DSurface9 *src);
|
||||
|
||||
public Q_SLOTS:
|
||||
void presentSample(void* sample, qint64 llTarget);
|
||||
|
||||
private:
|
||||
HRESULT initializeD3D();
|
||||
HRESULT getSwapChainPresentParameters(IMFMediaType *type, D3DPRESENT_PARAMETERS *pp);
|
||||
HRESULT createD3DDevice();
|
||||
HRESULT createD3DSample(IDirect3DSwapChain9 *swapChain, IMFSample **videoSample);
|
||||
|
||||
QMutex m_mutex;
|
||||
|
||||
UINT m_deviceResetToken;
|
||||
D3DDISPLAYMODE m_displayMode;
|
||||
|
||||
IDirect3D9Ex *m_D3D9;
|
||||
IDirect3DDevice9Ex *m_device;
|
||||
IDirect3DDeviceManager9 *m_deviceManager;
|
||||
|
||||
QVideoSurfaceFormat m_surfaceFormat;
|
||||
QAbstractVideoSurface *m_surface;
|
||||
|
||||
QOpenGLContext *m_glContext;
|
||||
QWindow *m_offscreenSurface;
|
||||
|
||||
EGLDisplay *m_eglDisplay;
|
||||
EGLConfig *m_eglConfig;
|
||||
EGLSurface m_eglSurface;
|
||||
unsigned int m_glTexture;
|
||||
IDirect3DTexture9 *m_texture;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // EVRD3DPRESENTENGINE_H
|
||||
89
src/plugins/wmf/mfactivate.cpp
Normal file
89
src/plugins/wmf/mfactivate.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** 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 Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "mfactivate.h"
|
||||
|
||||
#include <mfapi.h>
|
||||
|
||||
MFAbstractActivate::MFAbstractActivate()
|
||||
: m_attributes(0)
|
||||
, m_cRef(1)
|
||||
{
|
||||
MFCreateAttributes(&m_attributes, 0);
|
||||
}
|
||||
|
||||
MFAbstractActivate::~MFAbstractActivate()
|
||||
{
|
||||
if (m_attributes)
|
||||
m_attributes->Release();
|
||||
}
|
||||
|
||||
|
||||
HRESULT MFAbstractActivate::QueryInterface(REFIID riid, LPVOID *ppvObject)
|
||||
{
|
||||
if (!ppvObject)
|
||||
return E_POINTER;
|
||||
if (riid == IID_IMFActivate) {
|
||||
*ppvObject = static_cast<IMFActivate*>(this);
|
||||
} else if (riid == IID_IMFAttributes) {
|
||||
*ppvObject = static_cast<IMFAttributes*>(this);
|
||||
} else if (riid == IID_IUnknown) {
|
||||
*ppvObject = static_cast<IUnknown*>(static_cast<IMFActivate*>(this));
|
||||
} else {
|
||||
*ppvObject = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
ULONG MFAbstractActivate::AddRef(void)
|
||||
{
|
||||
return InterlockedIncrement(&m_cRef);
|
||||
}
|
||||
|
||||
ULONG MFAbstractActivate::Release(void)
|
||||
{
|
||||
ULONG cRef = InterlockedDecrement(&m_cRef);
|
||||
if (cRef == 0)
|
||||
delete this;
|
||||
return m_cRef;
|
||||
}
|
||||
216
src/plugins/wmf/mfactivate.h
Normal file
216
src/plugins/wmf/mfactivate.h
Normal file
@@ -0,0 +1,216 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** 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 Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef MFACTIVATE_H
|
||||
#define MFACTIVATE_H
|
||||
|
||||
#include "mfglobal.h"
|
||||
|
||||
#include <mfidl.h>
|
||||
|
||||
class MFAbstractActivate : public IMFActivate
|
||||
{
|
||||
public:
|
||||
explicit MFAbstractActivate();
|
||||
virtual ~MFAbstractActivate();
|
||||
|
||||
//from IUnknown
|
||||
STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObject);
|
||||
STDMETHODIMP_(ULONG) AddRef(void);
|
||||
STDMETHODIMP_(ULONG) Release(void);
|
||||
|
||||
//from IMFAttributes
|
||||
STDMETHODIMP GetItem(REFGUID guidKey, PROPVARIANT *pValue)
|
||||
{
|
||||
return m_attributes->GetItem(guidKey, pValue);
|
||||
}
|
||||
|
||||
STDMETHODIMP GetItemType(REFGUID guidKey, MF_ATTRIBUTE_TYPE *pType)
|
||||
{
|
||||
return m_attributes->GetItemType(guidKey, pType);
|
||||
}
|
||||
|
||||
STDMETHODIMP CompareItem(REFGUID guidKey, REFPROPVARIANT Value, BOOL *pbResult)
|
||||
{
|
||||
return m_attributes->CompareItem(guidKey, Value, pbResult);
|
||||
}
|
||||
|
||||
STDMETHODIMP Compare(IMFAttributes *pTheirs, MF_ATTRIBUTES_MATCH_TYPE MatchType, BOOL *pbResult)
|
||||
{
|
||||
return m_attributes->Compare(pTheirs, MatchType, pbResult);
|
||||
}
|
||||
|
||||
STDMETHODIMP GetUINT32(REFGUID guidKey, UINT32 *punValue)
|
||||
{
|
||||
return m_attributes->GetUINT32(guidKey, punValue);
|
||||
}
|
||||
|
||||
STDMETHODIMP GetUINT64(REFGUID guidKey, UINT64 *punValue)
|
||||
{
|
||||
return m_attributes->GetUINT64(guidKey, punValue);
|
||||
}
|
||||
|
||||
STDMETHODIMP GetDouble(REFGUID guidKey, double *pfValue)
|
||||
{
|
||||
return m_attributes->GetDouble(guidKey, pfValue);
|
||||
}
|
||||
|
||||
STDMETHODIMP GetGUID(REFGUID guidKey, GUID *pguidValue)
|
||||
{
|
||||
return m_attributes->GetGUID(guidKey, pguidValue);
|
||||
}
|
||||
|
||||
STDMETHODIMP GetStringLength(REFGUID guidKey, UINT32 *pcchLength)
|
||||
{
|
||||
return m_attributes->GetStringLength(guidKey, pcchLength);
|
||||
}
|
||||
|
||||
STDMETHODIMP GetString(REFGUID guidKey, LPWSTR pwszValue, UINT32 cchBufSize, UINT32 *pcchLength)
|
||||
{
|
||||
return m_attributes->GetString(guidKey, pwszValue, cchBufSize, pcchLength);
|
||||
}
|
||||
|
||||
STDMETHODIMP GetAllocatedString(REFGUID guidKey, LPWSTR *ppwszValue, UINT32 *pcchLength)
|
||||
{
|
||||
return m_attributes->GetAllocatedString(guidKey, ppwszValue, pcchLength);
|
||||
}
|
||||
|
||||
STDMETHODIMP GetBlobSize(REFGUID guidKey, UINT32 *pcbBlobSize)
|
||||
{
|
||||
return m_attributes->GetBlobSize(guidKey, pcbBlobSize);
|
||||
}
|
||||
|
||||
STDMETHODIMP GetBlob(REFGUID guidKey, UINT8 *pBuf, UINT32 cbBufSize, UINT32 *pcbBlobSize)
|
||||
{
|
||||
return m_attributes->GetBlob(guidKey, pBuf, cbBufSize, pcbBlobSize);
|
||||
}
|
||||
|
||||
STDMETHODIMP GetAllocatedBlob(REFGUID guidKey, UINT8 **ppBuf, UINT32 *pcbSize)
|
||||
{
|
||||
return m_attributes->GetAllocatedBlob(guidKey, ppBuf, pcbSize);
|
||||
}
|
||||
|
||||
STDMETHODIMP GetUnknown(REFGUID guidKey, REFIID riid, LPVOID *ppv)
|
||||
{
|
||||
return m_attributes->GetUnknown(guidKey, riid, ppv);
|
||||
}
|
||||
|
||||
STDMETHODIMP SetItem(REFGUID guidKey, REFPROPVARIANT Value)
|
||||
{
|
||||
return m_attributes->SetItem(guidKey, Value);
|
||||
}
|
||||
|
||||
STDMETHODIMP DeleteItem(REFGUID guidKey)
|
||||
{
|
||||
return m_attributes->DeleteItem(guidKey);
|
||||
}
|
||||
|
||||
STDMETHODIMP DeleteAllItems()
|
||||
{
|
||||
return m_attributes->DeleteAllItems();
|
||||
}
|
||||
|
||||
STDMETHODIMP SetUINT32(REFGUID guidKey, UINT32 unValue)
|
||||
{
|
||||
return m_attributes->SetUINT32(guidKey, unValue);
|
||||
}
|
||||
|
||||
STDMETHODIMP SetUINT64(REFGUID guidKey, UINT64 unValue)
|
||||
{
|
||||
return m_attributes->SetUINT64(guidKey, unValue);
|
||||
}
|
||||
|
||||
STDMETHODIMP SetDouble(REFGUID guidKey, double fValue)
|
||||
{
|
||||
return m_attributes->SetDouble(guidKey, fValue);
|
||||
}
|
||||
|
||||
STDMETHODIMP SetGUID(REFGUID guidKey, REFGUID guidValue)
|
||||
{
|
||||
return m_attributes->SetGUID(guidKey, guidValue);
|
||||
}
|
||||
|
||||
STDMETHODIMP SetString(REFGUID guidKey, LPCWSTR wszValue)
|
||||
{
|
||||
return m_attributes->SetString(guidKey, wszValue);
|
||||
}
|
||||
|
||||
STDMETHODIMP SetBlob(REFGUID guidKey, const UINT8 *pBuf, UINT32 cbBufSize)
|
||||
{
|
||||
return m_attributes->SetBlob(guidKey, pBuf, cbBufSize);
|
||||
}
|
||||
|
||||
STDMETHODIMP SetUnknown(REFGUID guidKey, IUnknown *pUnknown)
|
||||
{
|
||||
return m_attributes->SetUnknown(guidKey, pUnknown);
|
||||
}
|
||||
|
||||
STDMETHODIMP LockStore()
|
||||
{
|
||||
return m_attributes->LockStore();
|
||||
}
|
||||
|
||||
STDMETHODIMP UnlockStore()
|
||||
{
|
||||
return m_attributes->UnlockStore();
|
||||
}
|
||||
|
||||
STDMETHODIMP GetCount(UINT32 *pcItems)
|
||||
{
|
||||
return m_attributes->GetCount(pcItems);
|
||||
}
|
||||
|
||||
STDMETHODIMP GetItemByIndex(UINT32 unIndex, GUID *pguidKey, PROPVARIANT *pValue)
|
||||
{
|
||||
return m_attributes->GetItemByIndex(unIndex, pguidKey, pValue);
|
||||
}
|
||||
|
||||
STDMETHODIMP CopyAllItems(IMFAttributes *pDest)
|
||||
{
|
||||
return m_attributes->CopyAllItems(pDest);
|
||||
}
|
||||
|
||||
private:
|
||||
IMFAttributes *m_attributes;
|
||||
ULONG m_cRef;
|
||||
};
|
||||
|
||||
#endif // MFACTIVATE_H
|
||||
124
src/plugins/wmf/mfglobal.cpp
Normal file
124
src/plugins/wmf/mfglobal.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** 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 Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "mfglobal.h"
|
||||
|
||||
HRESULT qt_wmf_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;
|
||||
}
|
||||
|
||||
MFRatio qt_wmf_getPixelAspectRatio(IMFMediaType *type)
|
||||
{
|
||||
MFRatio ratio = { 0, 0 };
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
hr = MFGetAttributeRatio(type, MF_MT_PIXEL_ASPECT_RATIO, (UINT32*)&ratio.Numerator, (UINT32*)&ratio.Denominator);
|
||||
if (FAILED(hr)) {
|
||||
ratio.Numerator = 1;
|
||||
ratio.Denominator = 1;
|
||||
}
|
||||
return ratio;
|
||||
}
|
||||
|
||||
bool qt_wmf_areMediaTypesEqual(IMFMediaType *type1, IMFMediaType *type2)
|
||||
{
|
||||
if (!type1 && !type2)
|
||||
return true;
|
||||
else if (!type1 || !type2)
|
||||
return false;
|
||||
|
||||
DWORD dwFlags = 0;
|
||||
HRESULT hr = type1->IsEqual(type2, &dwFlags);
|
||||
|
||||
return (hr == S_OK);
|
||||
}
|
||||
|
||||
HRESULT qt_wmf_validateVideoArea(const MFVideoArea& area, UINT32 width, UINT32 height)
|
||||
{
|
||||
float fOffsetX = qt_wmf_MFOffsetToFloat(area.OffsetX);
|
||||
float fOffsetY = qt_wmf_MFOffsetToFloat(area.OffsetY);
|
||||
|
||||
if ( ((LONG)fOffsetX + area.Area.cx > (LONG)width) ||
|
||||
((LONG)fOffsetY + area.Area.cy > (LONG)height) )
|
||||
return MF_E_INVALIDMEDIATYPE;
|
||||
else
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
bool qt_wmf_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;
|
||||
}
|
||||
157
src/plugins/wmf/mfglobal.h
Normal file
157
src/plugins/wmf/mfglobal.h
Normal file
@@ -0,0 +1,157 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** 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 Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef MFGLOBAL_H
|
||||
#define MFGLOBAL_H
|
||||
|
||||
#include <mfapi.h>
|
||||
#include <mfidl.h>
|
||||
#include <Mferror.h>
|
||||
|
||||
|
||||
template<class T>
|
||||
class AsyncCallback : public IMFAsyncCallback
|
||||
{
|
||||
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)
|
||||
{
|
||||
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() {
|
||||
// Delegate to parent class.
|
||||
return m_parent->AddRef();
|
||||
}
|
||||
STDMETHODIMP_(ULONG) Release() {
|
||||
// Delegate to parent class.
|
||||
return m_parent->Release();
|
||||
}
|
||||
|
||||
|
||||
// IMFAsyncCallback methods
|
||||
STDMETHODIMP GetParameters(DWORD*, DWORD*)
|
||||
{
|
||||
// Implementation of this method is optional.
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
STDMETHODIMP Invoke(IMFAsyncResult* asyncResult)
|
||||
{
|
||||
return (m_parent->*m_invokeFn)(asyncResult);
|
||||
}
|
||||
|
||||
T *m_parent;
|
||||
InvokeFn m_invokeFn;
|
||||
};
|
||||
|
||||
template <class T> void qt_wmf_safeRelease(T **ppT)
|
||||
{
|
||||
if (*ppT) {
|
||||
(*ppT)->Release();
|
||||
*ppT = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void qt_wmf_copyComPointer(T* &dest, T *src)
|
||||
{
|
||||
if (dest)
|
||||
dest->Release();
|
||||
dest = src;
|
||||
if (dest)
|
||||
dest->AddRef();
|
||||
}
|
||||
|
||||
HRESULT qt_wmf_getFourCC(IMFMediaType *type, DWORD *fourCC);
|
||||
MFRatio qt_wmf_getPixelAspectRatio(IMFMediaType *type);
|
||||
bool qt_wmf_areMediaTypesEqual(IMFMediaType *type1, IMFMediaType *type2);
|
||||
HRESULT qt_wmf_validateVideoArea(const MFVideoArea& area, UINT32 width, UINT32 height);
|
||||
bool qt_wmf_isSampleTimePassed(IMFClock *clock, IMFSample *sample);
|
||||
|
||||
inline float qt_wmf_MFOffsetToFloat(const MFOffset& offset)
|
||||
{
|
||||
return offset.value + (float(offset.fract) / 65536);
|
||||
}
|
||||
|
||||
inline MFOffset qt_wmf_makeMFOffset(float v)
|
||||
{
|
||||
MFOffset offset;
|
||||
offset.value = short(v);
|
||||
offset.fract = WORD(65536 * (v-offset.value));
|
||||
return offset;
|
||||
}
|
||||
|
||||
inline MFVideoArea qt_wmf_makeMFArea(float x, float y, DWORD width, DWORD height)
|
||||
{
|
||||
MFVideoArea area;
|
||||
area.OffsetX = qt_wmf_makeMFOffset(x);
|
||||
area.OffsetY = qt_wmf_makeMFOffset(y);
|
||||
area.Area.cx = width;
|
||||
area.Area.cy = height;
|
||||
return area;
|
||||
}
|
||||
|
||||
inline HRESULT qt_wmf_getFrameRate(IMFMediaType *pType, MFRatio *pRatio)
|
||||
{
|
||||
return MFGetAttributeRatio(pType, MF_MT_FRAME_RATE, (UINT32*)&pRatio->Numerator, (UINT32*)&pRatio->Denominator);
|
||||
}
|
||||
|
||||
|
||||
#endif // MFGLOBAL_H
|
||||
@@ -40,7 +40,10 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include "mfvideorenderercontrol.h"
|
||||
#include <mferror.h>
|
||||
#include "mfglobal.h"
|
||||
#ifdef QT_OPENGL_ES_2_ANGLE
|
||||
#include "evrcustompresenter.h"
|
||||
#endif
|
||||
#include <qabstractvideosurface.h>
|
||||
#include <qvideosurfaceformat.h>
|
||||
#include <qtcore/qtimer.h>
|
||||
@@ -114,67 +117,6 @@ namespace
|
||||
MapMode m_mapMode;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class AsyncCallback : public IMFAsyncCallback
|
||||
{
|
||||
public:
|
||||
typedef HRESULT (T::*InvokeFn)(IMFAsyncResult *pAsyncResult);
|
||||
|
||||
AsyncCallback(T *pParent, InvokeFn fn) : m_pParent(pParent), m_pInvokeFn(fn)
|
||||
{
|
||||
}
|
||||
|
||||
// IUnknown
|
||||
STDMETHODIMP QueryInterface(REFIID iid, void** ppv)
|
||||
{
|
||||
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()
|
||||
{
|
||||
// Delegate to parent class.
|
||||
return m_pParent->AddRef();
|
||||
}
|
||||
STDMETHODIMP_(ULONG) Release()
|
||||
{
|
||||
// Delegate to parent class.
|
||||
return m_pParent->Release();
|
||||
}
|
||||
|
||||
// IMFAsyncCallback methods
|
||||
STDMETHODIMP GetParameters(DWORD*, DWORD*)
|
||||
{
|
||||
// Implementation of this method is optional.
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
STDMETHODIMP Invoke(IMFAsyncResult* pAsyncResult)
|
||||
{
|
||||
return (m_pParent->*m_pInvokeFn)(pAsyncResult);
|
||||
}
|
||||
|
||||
T *m_pParent;
|
||||
InvokeFn m_pInvokeFn;
|
||||
};
|
||||
|
||||
|
||||
// Custom interface for handling IMFStreamSink::PlaceMarker calls asynchronously.
|
||||
MIDL_INTERFACE("a3ff32de-1031-438a-8b47-82f8acda59b7")
|
||||
IMarker : public IUnknown
|
||||
@@ -2134,6 +2076,9 @@ MFVideoRendererControl::MFVideoRendererControl(QObject *parent)
|
||||
, m_surface(0)
|
||||
, m_currentActivate(0)
|
||||
, m_callback(0)
|
||||
#ifdef QT_OPENGL_ES_2_ANGLE
|
||||
, m_presenterActivate(0)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
@@ -2147,6 +2092,14 @@ void MFVideoRendererControl::clear()
|
||||
if (m_surface)
|
||||
m_surface->stop();
|
||||
|
||||
#ifdef QT_OPENGL_ES_2_ANGLE
|
||||
if (m_presenterActivate) {
|
||||
m_presenterActivate->ShutdownObject();
|
||||
m_presenterActivate->Release();
|
||||
m_presenterActivate = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_currentActivate) {
|
||||
m_currentActivate->ShutdownObject();
|
||||
m_currentActivate->Release();
|
||||
@@ -2174,12 +2127,22 @@ void MFVideoRendererControl::setSurface(QAbstractVideoSurface *surface)
|
||||
connect(m_surface, SIGNAL(supportedFormatsChanged()), this, SLOT(supportedFormatsChanged()));
|
||||
}
|
||||
|
||||
#ifdef QT_OPENGL_ES_2_ANGLE
|
||||
if (m_presenterActivate)
|
||||
m_presenterActivate->setSurface(m_surface);
|
||||
else
|
||||
#endif
|
||||
if (m_currentActivate)
|
||||
static_cast<VideoRendererActivate*>(m_currentActivate)->setSurface(m_surface);
|
||||
}
|
||||
|
||||
void MFVideoRendererControl::customEvent(QEvent *event)
|
||||
{
|
||||
#ifdef QT_OPENGL_ES_2_ANGLE
|
||||
if (m_presenterActivate)
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (!m_currentActivate)
|
||||
return;
|
||||
|
||||
@@ -2203,23 +2166,48 @@ void MFVideoRendererControl::customEvent(QEvent *event)
|
||||
|
||||
void MFVideoRendererControl::supportedFormatsChanged()
|
||||
{
|
||||
#ifdef QT_OPENGL_ES_2_ANGLE
|
||||
if (m_presenterActivate)
|
||||
m_presenterActivate->supportedFormatsChanged();
|
||||
else
|
||||
#endif
|
||||
if (m_currentActivate)
|
||||
static_cast<VideoRendererActivate*>(m_currentActivate)->supportedFormatsChanged();
|
||||
}
|
||||
|
||||
void MFVideoRendererControl::present()
|
||||
{
|
||||
#ifdef QT_OPENGL_ES_2_ANGLE
|
||||
if (m_presenterActivate)
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (m_currentActivate)
|
||||
static_cast<VideoRendererActivate*>(m_currentActivate)->present();
|
||||
}
|
||||
|
||||
IMFActivate* MFVideoRendererControl::createActivate()
|
||||
{
|
||||
Q_ASSERT(m_surface);
|
||||
|
||||
clear();
|
||||
|
||||
#ifdef QT_OPENGL_ES_2_ANGLE
|
||||
// We can use the EVR with our custom presenter only if the surface supports OpenGL
|
||||
// texture handles
|
||||
if (!m_surface->supportedPixelFormats(QAbstractVideoBuffer::GLTextureHandle).isEmpty()) {
|
||||
// Create the EVR media sink, but replace the presenter with our own
|
||||
if (SUCCEEDED(MFCreateVideoRendererActivate(::GetShellWindow(), &m_currentActivate))) {
|
||||
m_presenterActivate = new EVRCustomPresenterActivate;
|
||||
m_currentActivate->SetUnknown(MF_ACTIVATE_CUSTOM_VIDEO_PRESENTER_ACTIVATE, m_presenterActivate);
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_currentActivate)
|
||||
#endif
|
||||
m_currentActivate = new VideoRendererActivate(this);
|
||||
if (m_surface)
|
||||
setSurface(m_surface);
|
||||
|
||||
setSurface(m_surface);
|
||||
|
||||
return m_currentActivate;
|
||||
}
|
||||
|
||||
@@ -46,6 +46,14 @@
|
||||
#include <mfapi.h>
|
||||
#include <mfidl.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
#ifdef QT_OPENGL_ES_2_ANGLE
|
||||
class EVRCustomPresenterActivate;
|
||||
#endif
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
QT_USE_NAMESPACE
|
||||
|
||||
class MFVideoRendererControl : public QVideoRendererControl
|
||||
@@ -74,6 +82,10 @@ private:
|
||||
QAbstractVideoSurface *m_surface;
|
||||
IMFActivate *m_currentActivate;
|
||||
IMFSampleGrabberSinkCallback *m_callback;
|
||||
|
||||
#ifdef QT_OPENGL_ES_2_ANGLE
|
||||
EVRCustomPresenterActivate *m_presenterActivate;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -16,14 +16,32 @@ HEADERS += \
|
||||
mfstream.h \
|
||||
sourceresolver.h \
|
||||
samplegrabber.h \
|
||||
mftvideo.h
|
||||
mftvideo.h \
|
||||
mfglobal.h \
|
||||
mfactivate.h
|
||||
|
||||
SOURCES += \
|
||||
wmfserviceplugin.cpp \
|
||||
mfstream.cpp \
|
||||
sourceresolver.cpp \
|
||||
samplegrabber.cpp \
|
||||
mftvideo.cpp
|
||||
mftvideo.cpp \
|
||||
mfactivate.cpp \
|
||||
mfglobal.cpp
|
||||
|
||||
contains(QT_CONFIG, angle) {
|
||||
LIBS += -ld3d9 -ldxva2 -lwinmm -levr
|
||||
QT += gui-private
|
||||
|
||||
HEADERS += \
|
||||
evrcustompresenter.h \
|
||||
evrd3dpresentengine.h
|
||||
|
||||
SOURCES += \
|
||||
evrcustompresenter.cpp \
|
||||
evrd3dpresentengine.cpp
|
||||
}
|
||||
|
||||
|
||||
include (player/player.pri)
|
||||
include (decoder/decoder.pri)
|
||||
|
||||
Reference in New Issue
Block a user