8#include <private/qwindowsmultimediautils_p.h>
9#include <private/qplatformvideosink_p.h>
10#include <private/qwindowsmfdefs_p.h>
14#include <QtCore/qmutex.h>
15#include <QtCore/qvarlengtharray.h>
16#include <QtCore/qrect.h>
31const static MFRatio g_DefaultFrameRate = { 30, 1 };
47 if (!evr || !presenter)
53 if (SUCCEEDED(evr->QueryInterface(IID_PPV_ARGS(&
renderer)))) {
69 ComPtr<IMFSample>
sample()
const {
return m_sample; }
72 const ComPtr<IMFSample> m_sample;
76 : m_presenter(presenter)
78 , m_playbackRate(1.0f)
85 m_scheduledSamples.
clear();
90 UINT64 AvgTimePerFrame = 0;
93 MFFrameRateToAverageTimePerFrame(fps.Numerator, fps.Denominator, &AvgTimePerFrame);
96 m_perFrame_1_4th = AvgTimePerFrame / 4;
101 if (m_schedulerThread)
115 m_threadReadyEvent =
EventHandle{ CreateEvent(NULL, FALSE, FALSE, NULL) };
116 if (!m_threadReadyEvent) {
117 hr = HRESULT_FROM_WIN32(GetLastError());
122 m_flushEvent =
EventHandle{ CreateEvent(NULL, FALSE, FALSE, NULL) };
124 hr = HRESULT_FROM_WIN32(GetLastError());
130 if (!m_schedulerThread) {
131 hr = HRESULT_FROM_WIN32(GetLastError());
136 hObjects[0] = m_threadReadyEvent.
get();
137 hObjects[1] = m_schedulerThread.
get();
138 dwWait = WaitForMultipleObjects(2, hObjects, FALSE, INFINITE);
139 if (WAIT_OBJECT_0 != dwWait) {
141 m_schedulerThread = {};
151 m_threadReadyEvent = {};
158 if (!m_schedulerThread)
162 PostThreadMessage(m_threadID,
Terminate, 0, 0);
165 WaitForSingleObject(m_schedulerThread.
get(), INFINITE);
168 m_schedulerThread = {};
173 m_scheduledSamples.
clear();
184 if (m_schedulerThread) {
186 PostThreadMessage(m_threadID,
Flush, 0 , 0);
190 HANDLE objects[] = { m_flushEvent.
get(), m_schedulerThread.
get() };
201 return m_scheduledSamples.
count() > 0;
206 if (!m_schedulerThread)
207 return MF_E_NOT_INITIALIZED;
210 DWORD dwExitCode = 0;
212 GetExitCodeThread(m_schedulerThread.
get(), &dwExitCode);
213 if (dwExitCode != STILL_ACTIVE)
216 if (presentNow || !m_clock) {
220 qCDebug(qLcEvrCustomPresenter) <<
"Discard the sample, it came too late";
226 m_scheduledSamples.
enqueue(sample);
230 PostThreadMessage(m_threadID,
Schedule, 0, 0);
241 QQueue<ComPtr<IMFSample>> scheduledSamples;
244 m_scheduledSamples.
swap(scheduledSamples);
248 while (!scheduledSamples.isEmpty()) {
249 ComPtr<IMFSample> sample = scheduledSamples.dequeue();
254 if (isSampleReadyToPresent(sample.Get(), &wait)) {
261 scheduledSamples.prepend(sample);
267 scheduledSamples.append(std::move(m_scheduledSamples));
268 m_scheduledSamples.
swap(scheduledSamples);
281bool Scheduler::isSampleReadyToPresent(IMFSample *sample, LONG *pNextSleep)
const
287 MFTIME hnsPresentationTime = 0;
288 MFTIME hnsTimeNow = 0;
289 MFTIME hnsSystemTime = 0;
293 HRESULT hr = sample->GetSampleTime(&hnsPresentationTime);
298 hr = m_clock->GetCorrelatedTime(0, &hnsTimeNow, &hnsSystemTime);
302 MFTIME hnsDelta = hnsPresentationTime - hnsTimeNow;
303 if (m_playbackRate < 0) {
306 hnsDelta = - hnsDelta;
309 if (hnsDelta < - m_perFrame_1_4th) {
312 }
else if (hnsDelta > (3 * m_perFrame_1_4th)) {
314 *pNextSleep =
MFTimeToMsec(hnsDelta - (3 * m_perFrame_1_4th));
318 if (m_playbackRate != 0)
319 *pNextSleep = (LONG)(*pNextSleep /
qFabs(m_playbackRate));
320 return *pNextSleep == 0;
332 return scheduler->schedulerThreadProcPrivate();
335DWORD Scheduler::schedulerThreadProcPrivate()
339 LONG wait = INFINITE;
340 bool exitThread =
false;
344 PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
347 SetEvent(m_threadReadyEvent.
get());
349 while (!exitThread) {
351 DWORD
result = MsgWaitForMultipleObjects(0, NULL, FALSE, wait, QS_POSTMESSAGE);
353 if (
result == WAIT_TIMEOUT) {
360 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
361 bool processSamples =
true;
363 switch (msg.message) {
370 m_scheduledSamples.
clear();
373 SetEvent(m_flushEvent.
get());
377 if (processSamples) {
381 processSamples = (wait != (LONG)INFINITE);
389 return (SUCCEEDED(hr) ? 0 : 1);
394 : m_initialized(
false)
408 if (!m_initialized) {
409 qCWarning(qLcEvrCustomPresenter) <<
"SamplePool is not initialized yet";
413 if (m_videoSampleQueue.
isEmpty()) {
414 qCDebug(qLcEvrCustomPresenter) <<
"SamplePool is empty";
432 if (!m_initialized) {
433 qCWarning(qLcEvrCustomPresenter) <<
"SamplePool is not initialized yet";
437 m_videoSampleQueue.
append(sample);
445 return MF_E_INVALIDREQUEST;
450 m_initialized =
true;
459 m_videoSampleQueue.
clear();
460 m_initialized =
false;
470 , m_renderState(RenderShutdown)
473 , m_sampleNotify(
false)
475 , m_endStreaming(
false)
476 , m_playbackRate(1.0f)
480 , m_canRenderToSurface(
false)
481 , m_positionOffset(0)
484 m_sourceRect.top = 0;
485 m_sourceRect.left = 0;
486 m_sourceRect.bottom = 1;
487 m_sourceRect.right = 1;
496 m_samplePool.
clear();
498 delete m_presentEngine;
505 if (
riid == IID_IMFGetService) {
506 *ppvObject =
static_cast<IMFGetService*
>(
this);
507 }
else if (
riid == IID_IMFTopologyServiceLookupClient) {
508 *ppvObject =
static_cast<IMFTopologyServiceLookupClient*
>(
this);
509 }
else if (
riid == IID_IMFVideoDeviceID) {
510 *ppvObject =
static_cast<IMFVideoDeviceID*
>(
this);
511 }
else if (
riid == IID_IMFVideoPresenter) {
512 *ppvObject =
static_cast<IMFVideoPresenter*
>(
this);
513 }
else if (
riid == IID_IMFRateSupport) {
514 *ppvObject =
static_cast<IMFRateSupport*
>(
this);
515 }
else if (
riid == IID_IUnknown) {
516 *ppvObject =
static_cast<IUnknown*
>(
static_cast<IMFGetService*
>(
this));
517 }
else if (
riid == IID_IMFClockStateSink) {
518 *ppvObject =
static_cast<IMFClockStateSink*
>(
this);
521 return E_NOINTERFACE;
527ULONG EVRCustomPresenter::AddRef()
529 return InterlockedIncrement(&m_refCount);
532ULONG EVRCustomPresenter::Release()
534 ULONG uCount = InterlockedDecrement(&m_refCount);
548 if (guidService != MR_VIDEO_RENDER_SERVICE)
549 return MF_E_UNSUPPORTED_SERVICE;
565 *deviceID = IID_IDirect3DDevice9;
576 DWORD objectCount = 0;
578 const std::lock_guard<QRecursiveMutex> locker(m_mutex);
582 return MF_E_INVALIDREQUEST;
586 m_mediaEventSink.Reset();
591 lookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0,
592 MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&m_clock),
599 hr = lookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0,
600 MR_VIDEO_MIXER_SERVICE, IID_PPV_ARGS(&m_mixer),
608 hr = configureMixer(m_mixer.Get());
615 hr = lookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0,
616 MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&m_mediaEventSink),
644 m_mediaEventSink.Reset();
651 return m_presentEngine->
isValid() && m_canRenderToSurface;
658 const std::lock_guard<QRecursiveMutex> locker(m_mutex);
660 hr = checkShutdown();
666 case MFVP_MESSAGE_FLUSH:
671 case MFVP_MESSAGE_INVALIDATEMEDIATYPE:
672 hr = renegotiateMediaType();
676 case MFVP_MESSAGE_PROCESSINPUTNOTIFY:
677 hr = processInputNotify();
681 case MFVP_MESSAGE_BEGINSTREAMING:
682 hr = beginStreaming();
686 case MFVP_MESSAGE_ENDSTREAMING:
691 case MFVP_MESSAGE_ENDOFSTREAM:
693 m_endStreaming =
true;
695 hr = checkEndOfStream();
699 case MFVP_MESSAGE_STEP:
700 hr = prepareFrameStep(DWORD(
param));
704 case MFVP_MESSAGE_CANCELSTEP:
705 hr = cancelFrameStep();
725 const std::lock_guard<QRecursiveMutex> locker(m_mutex);
727 hr = checkShutdown();
732 return MF_E_NOT_INITIALIZED;
734 return m_mediaType->QueryInterface(IID_PPV_ARGS(mediaType));
739 const std::lock_guard<QRecursiveMutex> locker(m_mutex);
761 hr = startFrameStep();
774 const std::lock_guard<QRecursiveMutex> locker(m_mutex);
786 hr = startFrameStep();
798 const std::lock_guard<QRecursiveMutex> locker(m_mutex);
818 const std::lock_guard<QRecursiveMutex> locker(m_mutex);
835 const std::lock_guard<QRecursiveMutex> locker(m_mutex);
843 if ((m_playbackRate == 0.0f) && (
rate != 0.0f)) {
845 m_frameStep.samples.
clear();
848 m_playbackRate =
rate;
861 const std::lock_guard<QRecursiveMutex> locker(m_mutex);
878 const std::lock_guard<QRecursiveMutex> locker(m_mutex);
880 float maxRate = 0.0f;
887 maxRate = getMaxRate(thin);
900 const std::lock_guard<QRecursiveMutex> locker(m_mutex);
902 float maxRate = 0.0f;
903 float nearestRate =
rate;
911 maxRate = getMaxRate(thin);
915 hr = MF_E_UNSUPPORTED_RATE;
918 nearestRate = maxRate;
921 nearestRate = -nearestRate;
926 if (nearestSupportedRate)
927 *nearestSupportedRate = nearestRate;
934 const std::lock_guard<QRecursiveMutex> locker(m_mutex);
936 m_canRenderToSurface =
false;
944 m_canRenderToSurface =
true;
966 m_cropRect = cropRect;
970HRESULT EVRCustomPresenter::configureMixer(IMFTransform *mixer)
976HRESULT EVRCustomPresenter::renegotiateMediaType()
979 bool foundMediaType =
false;
981 IMFMediaType *mixerType = NULL;
982 IMFMediaType *optimalType = NULL;
985 return MF_E_INVALIDREQUEST;
989 while (!foundMediaType && (hr != MF_E_NO_MORE_TYPES)) {
994 hr = m_mixer->GetOutputAvailableType(0, typeIndex++, &mixerType);
1003 hr = isMediaTypeSupported(mixerType);
1007 hr = createOptimalVideoType(mixerType, &optimalType);
1011 hr = m_mixer->SetOutputType(0, optimalType, MFT_SET_TYPE_TEST_ONLY);
1015 hr = setMediaType(optimalType);
1018 if (SUCCEEDED(hr)) {
1019 hr = m_mixer->SetOutputType(0, optimalType, 0);
1027 foundMediaType =
true;
1036HRESULT EVRCustomPresenter::flush()
1038 m_prerolled =
false;
1044 m_scheduler.
flush();
1047 m_frameStep.samples.
clear();
1057HRESULT EVRCustomPresenter::processInputNotify()
1062 m_sampleNotify =
true;
1066 hr = MF_E_TRANSFORM_TYPE_NOT_SET;
1069 processOutputLoop();
1074HRESULT EVRCustomPresenter::beginStreaming()
1084HRESULT EVRCustomPresenter::endStreaming()
1094HRESULT EVRCustomPresenter::checkEndOfStream()
1096 if (!m_endStreaming) {
1101 if (m_sampleNotify) {
1112 notifyEvent(EC_COMPLETE, (LONG_PTR)S_OK, 0);
1113 m_endStreaming =
false;
1119HRESULT EVRCustomPresenter::prepareFrameStep(DWORD steps)
1124 m_frameStep.steps += steps;
1132 hr = startFrameStep();
1137HRESULT EVRCustomPresenter::startFrameStep()
1146 const ComPtr<IMFSample> sample = m_frameStep.samples.
takeFirst();
1148 const HRESULT hr = deliverFrameStepSample(sample.Get());
1159 while (!m_frameStep.samples.
isEmpty()) {
1160 const ComPtr<IMFSample> sample = m_frameStep.samples.
takeFirst();
1162 const HRESULT hr = deliverSample(sample.Get());
1171HRESULT EVRCustomPresenter::completeFrameStep(
const ComPtr<IMFSample> &sample)
1174 MFTIME sampleTime = 0;
1175 MFTIME systemTime = 0;
1179 m_frameStep.sampleNoRef = 0;
1182 notifyEvent(EC_STEP_COMPLETE, FALSE, 0);
1185 if (isScrubbing()) {
1187 hr = sample->GetSampleTime(&sampleTime);
1191 m_clock->GetCorrelatedTime(0, &sampleTime, &systemTime);
1196 notifyEvent(EC_SCRUB_TIME, DWORD(sampleTime), DWORD(((sampleTime) >> 32) & 0xffffffff));
1201HRESULT EVRCustomPresenter::cancelFrameStep()
1206 m_frameStep.steps = 0;
1207 m_frameStep.sampleNoRef = 0;
1213 notifyEvent(EC_STEP_COMPLETE, TRUE, 0);
1218HRESULT EVRCustomPresenter::createOptimalVideoType(IMFMediaType *proposedType, IMFMediaType **optimalType)
1223 ZeroMemory(&rcOutput,
sizeof(rcOutput));
1225 MFVideoArea displayArea;
1226 ZeroMemory(&displayArea,
sizeof(displayArea));
1228 IMFMediaType *mtOptimal = NULL;
1236 hr = MFCreateMediaType(&mtOptimal);
1240 hr = proposedType->CopyAllItems(mtOptimal);
1246 hr = proposedType->GetUINT64(MF_MT_FRAME_SIZE, &
size);
1251 rcOutput.left = m_cropRect.
x();
1252 rcOutput.top = m_cropRect.
y();
1253 rcOutput.right = m_cropRect.
x() + m_cropRect.
width();
1254 rcOutput.bottom = m_cropRect.
y() + m_cropRect.
height();
1256 m_sourceRect.left = float(m_cropRect.
x()) /
width;
1257 m_sourceRect.top = float(m_cropRect.
y()) /
height;
1258 m_sourceRect.right = float(m_cropRect.
x() + m_cropRect.
width()) /
width;
1259 m_sourceRect.bottom = float(m_cropRect.
y() + m_cropRect.
height()) /
height;
1262 configureMixer(m_mixer.Get());
1266 rcOutput.right =
width;
1267 rcOutput.bottom =
height;
1272 rcOutput.bottom - rcOutput.top);
1274 hr = mtOptimal->SetUINT32(MF_MT_PAN_SCAN_ENABLED, FALSE);
1278 hr = mtOptimal->SetBlob(MF_MT_GEOMETRIC_APERTURE,
reinterpret_cast<UINT8*
>(&displayArea),
1279 sizeof(displayArea));
1286 hr = mtOptimal->SetBlob(MF_MT_PAN_SCAN_APERTURE,
reinterpret_cast<UINT8*
>(&displayArea),
1287 sizeof(displayArea));
1291 hr = mtOptimal->SetBlob(MF_MT_MINIMUM_DISPLAY_APERTURE,
reinterpret_cast<UINT8*
>(&displayArea),
1292 sizeof(displayArea));
1297 *optimalType = mtOptimal;
1298 (*optimalType)->AddRef();
1306HRESULT EVRCustomPresenter::setMediaType(IMFMediaType *mediaType)
1313 m_mediaType.Reset();
1318 MFRatio fps = { 0, 0 };
1319 QList<ComPtr<IMFSample>> sampleQueue;
1332 m_mediaType.Reset();
1344 for (
auto sample :
std::as_const(sampleQueue)) {
1351 hr = m_samplePool.
initialize(std::move(sampleQueue));
1356 if (SUCCEEDED(
qt_evr_getFrameRate(mediaType, &fps)) && (fps.Numerator != 0) && (fps.Denominator != 0)) {
1366 m_mediaType = mediaType;
1367 m_mediaType->AddRef();
1377HRESULT EVRCustomPresenter::isMediaTypeSupported(IMFMediaType *proposed)
1379 D3DFORMAT d3dFormat = D3DFMT_UNKNOWN;
1381 MFVideoInterlaceMode interlaceMode = MFVideoInterlace_Unknown;
1382 MFVideoArea videoCropArea;
1392 return MF_E_INVALIDMEDIATYPE;
1395 hr = proposed->IsCompressedFormat(&
compressed);
1400 return MF_E_INVALIDMEDIATYPE;
1408 hr = proposed->GetUINT32(MF_MT_INTERLACE_MODE,
reinterpret_cast<UINT32*
>(&interlaceMode));
1412 if (interlaceMode != MFVideoInterlace_Progressive)
1413 return MF_E_INVALIDMEDIATYPE;
1415 hr = MFGetAttributeSize(proposed, MF_MT_FRAME_SIZE, &
width, &
height);
1423 if (SUCCEEDED(proposed->GetBlob(MF_MT_PAN_SCAN_APERTURE,
1424 reinterpret_cast<UINT8*
>(&videoCropArea),
1425 sizeof(videoCropArea),
nullptr))) {
1428 if (SUCCEEDED(proposed->GetBlob(MF_MT_GEOMETRIC_APERTURE,
1429 reinterpret_cast<UINT8*
>(&videoCropArea),
1430 sizeof(videoCropArea),
nullptr))) {
1433 if (SUCCEEDED(proposed->GetBlob(MF_MT_MINIMUM_DISPLAY_APERTURE,
1434 reinterpret_cast<UINT8*
>(&videoCropArea),
1435 sizeof(videoCropArea),
nullptr))) {
1441void EVRCustomPresenter::processOutputLoop()
1446 while (hr == S_OK) {
1448 if (!m_sampleNotify) {
1449 hr = MF_E_TRANSFORM_NEED_MORE_INPUT;
1454 hr = processOutput();
1460 if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
1466HRESULT EVRCustomPresenter::processOutput()
1475 return MF_E_INVALIDREQUEST;
1478 ComPtr<IMFSample> sample = m_samplePool.
takeSample();
1485 LONGLONG mixerStartTime = 0, mixerEndTime = 0;
1486 MFTIME systemTime = 0;
1490 m_clock->GetCorrelatedTime(0, &mixerStartTime, &systemTime);
1495 MFT_OUTPUT_DATA_BUFFER dataBuffer = {};
1496 dataBuffer.pSample = sample.Get();
1497 HRESULT hr = m_mixer->ProcessOutput(0, 1, &dataBuffer, &status);
1506 if (hr == MF_E_TRANSFORM_TYPE_NOT_SET) {
1508 hr = renegotiateMediaType();
1509 }
else if (hr == MF_E_TRANSFORM_STREAM_CHANGE) {
1512 }
else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
1515 m_sampleNotify =
false;
1526 m_clock->GetCorrelatedTime(0, &mixerEndTime, &systemTime);
1528 LONGLONG latencyTime = mixerEndTime - mixerStartTime;
1529 notifyEvent(EC_PROCESSING_LATENCY,
reinterpret_cast<LONG_PTR
>(&latencyTime), 0);
1533 hr = trackSample(sample);
1539 hr = deliverSample(sample);
1541 hr = deliverFrameStepSample(sample);
1550HRESULT EVRCustomPresenter::deliverSample(
const ComPtr<IMFSample> &sample)
1556 bool presentNow = ((m_renderState !=
RenderStarted) || isScrubbing());
1564 notifyEvent(EC_ERRORABORT, hr, 0);
1570HRESULT EVRCustomPresenter::deliverFrameStepSample(
const ComPtr<IMFSample> &sample)
1573 IUnknown *unk = NULL;
1582 m_frameStep.samples.
append(sample);
1587 if (m_frameStep.steps > 0)
1588 m_frameStep.steps--;
1590 if (m_frameStep.steps > 0) {
1596 m_frameStep.samples.
append(sample);
1599 hr = deliverSample(sample);
1605 hr = sample->QueryInterface(IID_PPV_ARGS(&unk));
1609 m_frameStep.sampleNoRef =
reinterpret_cast<DWORD_PTR>(unk);
1624HRESULT EVRCustomPresenter::trackSample(
const ComPtr<IMFSample> &sample)
1626 IMFTrackedSample *tracked = NULL;
1628 HRESULT hr = sample->QueryInterface(IID_PPV_ARGS(&tracked));
1631 hr = tracked->SetAllocator(&m_sampleFreeCB, NULL);
1637void EVRCustomPresenter::releaseResources()
1652 m_samplePool.
clear();
1657HRESULT EVRCustomPresenter::onSampleFree(IMFAsyncResult *
result)
1659 IUnknown *
object = NULL;
1660 IMFSample *sample = NULL;
1661 IUnknown *unk = NULL;
1669 hr =
object->QueryInterface(IID_PPV_ARGS(&sample));
1678 hr = sample->QueryInterface(IID_PPV_ARGS(&unk));
1682 if (m_frameStep.sampleNoRef ==
reinterpret_cast<DWORD_PTR>(unk)) {
1684 hr = completeFrameStep(sample);
1699 if (
token == m_tokenCounter) {
1703 processOutputLoop();
1710 notifyEvent(EC_ERRORABORT, hr, 0);
1717float EVRCustomPresenter::getMaxRate(
bool thin)
1726 float maxRate = FLT_MAX;
1727 MFRatio fps = { 0, 0 };
1728 UINT monitorRateHz = 0;
1730 if (!thin && m_mediaType) {
1734 if (fps.Denominator && fps.Numerator && monitorRateHz) {
1736 maxRate = (float)MulDiv(monitorRateHz, fps.Denominator, fps.Numerator);
1745 switch (
int(e->
type())) {
1791 if (m_positionOffset) {
1792 if (
frame.startTime())
1793 frame.setStartTime(
frame.startTime() + m_positionOffset);
1794 if (
frame.endTime())
1795 frame.setEndTime(
frame.endTime() + m_positionOffset);
1798 ComPtr<IMFMediaType> inputStreamType;
1799 if (SUCCEEDED(m_mixer->GetInputCurrentType(0, inputStreamType.GetAddressOf()))) {
1800 auto rotation =
static_cast<MFVideoRotationFormat
>(MFGetAttributeUINT32(inputStreamType.Get(), MF_MT_VIDEO_ROTATION, 0));
1815 m_positionOffset =
position * 1000;
1823 IMFAttributes *attributes = NULL;
1825 HRESULT hr = mixer->GetAttributes(&attributes);
1826 if (SUCCEEDED(hr)) {
1827 hr = attributes->SetBlob(VIDEO_ZOOM_RECT,
reinterpret_cast<const UINT8*
>(&sourceRect),
1828 sizeof(sourceRect));
1829 attributes->Release();
1837 if (FAILED(
type->GetMajorType(&majorType)))
1839 if (majorType != MFMediaType_Video)
1843 if (FAILED(
type->GetGUID(MF_MT_SUBTYPE, &subtype)))
void setSink(QVideoSink *sink)
HRESULT createVideoSamples(IMFMediaType *format, QList< ComPtr< IMFSample > > &videoSampleQueue, QSize frameSize)
QVideoFrameFormat videoSurfaceFormat() const
HRESULT getService(REFGUID guidService, REFIID riid, void **ppv)
HRESULT checkFormat(D3DFORMAT format)
QVideoFrame makeVideoFrame(const ComPtr< IMFSample > &sample)
void positionChanged(qint64 position)
STDMETHODIMP GetDeviceID(IID *deviceID) override
STDMETHODIMP GetSlowestRate(MFRATE_DIRECTION direction, BOOL thin, float *rate) override
STDMETHODIMP OnClockStop(MFTIME systemTime) override
STDMETHODIMP ReleaseServicePointers() override
STDMETHODIMP QueryInterface(REFIID riid, void **ppv) override
STDMETHODIMP OnClockRestart(MFTIME systemTime) override
STDMETHODIMP InitServicePointers(IMFTopologyServiceLookup *lookup) override
STDMETHODIMP GetService(REFGUID guidService, REFIID riid, LPVOID *ppvObject) override
void supportedFormatsChanged()
void setCropRect(QRect cropRect)
STDMETHODIMP IsRateSupported(BOOL thin, float rate, float *nearestSupportedRate) override
STDMETHODIMP OnClockSetRate(MFTIME systemTime, float rate) override
STDMETHODIMP GetCurrentMediaType(IMFVideoMediaType **mediaType) override
void setSink(QVideoSink *sink)
bool event(QEvent *) override
This virtual function receives events to an object and should return true if the event e was recogniz...
STDMETHODIMP GetFastestRate(MFRATE_DIRECTION direction, BOOL thin, float *rate) override
void presentSample(const ComPtr< IMFSample > &sample)
STDMETHODIMP OnClockStart(MFTIME systemTime, LONGLONG clockStartOffset) override
STDMETHODIMP OnClockPause(MFTIME systemTime) override
STDMETHODIMP ProcessMessage(MFVP_MESSAGE_TYPE message, ULONG_PTR param) override
~EVRCustomPresenter() override
EVRCustomPresenter(QVideoSink *sink=0)
ComPtr< IMFSample > sample() const
PresentSampleEvent(const ComPtr< IMFSample > &sample)
static void postEvent(QObject *receiver, QEvent *event, int priority=Qt::NormalEventPriority)
Type
This enum type defines the valid event types in Qt.
Type type() const
Returns the event type.
bool isEmpty() const noexcept
qsizetype count() const noexcept
void append(parameter_type t)
void unlock() noexcept
Unlocks the mutex.
void lock() noexcept
Locks the mutex.
virtual bool event(QEvent *event)
This virtual function receives events to an object and should return true if the event e was recogniz...
QThread * thread() const
Returns the thread in which the object lives.
void deleteLater()
\threadsafe
void enqueue(const T &t)
Adds value t to the tail of the queue.
void swap(QQueue< T > &other) noexcept
\inmodule QtCore\reentrant
constexpr int height() const noexcept
Returns the height of the rectangle.
constexpr bool isValid() const noexcept
Returns true if the rectangle is valid, otherwise returns false.
constexpr int x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
constexpr QSize size() const noexcept
Returns the size of the rectangle.
constexpr int width() const noexcept
Returns the width of the rectangle.
constexpr int y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
static QThread * currentThread()
Type get() const noexcept
The QVideoFrame class represents a frame of video data.
The QVideoSink class represents a generic sink for video data.
QPlatformVideoSink * platformVideoSink() const
ComPtr< IMFSample > takeSample()
void returnSample(const ComPtr< IMFSample > &sample)
HRESULT initialize(QList< ComPtr< IMFSample > > &&samples)
Scheduler(EVRCustomPresenter *presenter)
HRESULT startScheduler(ComPtr< IMFClock > clock)
void setFrameRate(const MFRatio &fps)
void setClockRate(float rate)
HRESULT processSamplesInQueue(LONG *nextSleep)
bool areSamplesScheduled()
HRESULT scheduleSample(const ComPtr< IMFSample > &sample, bool presentNow)
static DWORD WINAPI schedulerThreadProc(LPVOID parameter)
static LONG MFTimeToMsec(const LONGLONG &time)
static QVideoFrameFormat::PixelFormat pixelFormatFromMediaType(IMFMediaType *type)
static HRESULT setMixerSourceRect(IMFTransform *mixer, const MFVideoNormalizedRect &nrcSource)
static const DWORD SCHEDULER_TIMEOUT
bool qt_evr_setCustomPresenter(IUnknown *evr, EVRCustomPresenter *presenter)
static const MFTIME ONE_SECOND
static const LONG ONE_MSEC
static QT_END_NAMESPACE const GUID MFSamplePresenter_SampleCounter
D3DFORMAT qt_evr_D3DFormatFromPixelFormat(QVideoFrameFormat::PixelFormat format)
bool qt_evr_areMediaTypesEqual(IMFMediaType *type1, IMFMediaType *type2)
QT_BEGIN_NAMESPACE HRESULT qt_evr_getFourCC(IMFMediaType *type, DWORD *fourCC)
bool qt_evr_isSampleTimePassed(IMFClock *clock, IMFSample *sample)
HRESULT qt_evr_validateVideoArea(const MFVideoArea &area, UINT32 width, UINT32 height)
HRESULT qt_evr_getFrameRate(IMFMediaType *pType, MFRatio *pRatio)
MFVideoArea qt_evr_makeMFArea(float x, float y, DWORD width, DWORD height)
static QT_BEGIN_NAMESPACE void qt_evr_safe_release(T **unk)
Combined button and popup list for selecting options.
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
GLint GLsizei GLsizei height
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint GLsizei const GLchar * message
GLenum const GLint * param
GLint GLsizei GLsizei GLenum format
GLsizei GLenum GLboolean sink
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
IUIViewSettingsInterop __RPC__in REFIID riid
#define QMM_PRESENTATION_CURRENT_POSITION
QSvgRenderer * renderer
[0]