Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mpc-hc/mpc-hc.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/filters/renderer/VideoRenderers/EVRAllocatorPresenter.cpp')
-rw-r--r--src/filters/renderer/VideoRenderers/EVRAllocatorPresenter.cpp677
1 files changed, 350 insertions, 327 deletions
diff --git a/src/filters/renderer/VideoRenderers/EVRAllocatorPresenter.cpp b/src/filters/renderer/VideoRenderers/EVRAllocatorPresenter.cpp
index 4e0ce31ea..add9ec42c 100644
--- a/src/filters/renderer/VideoRenderers/EVRAllocatorPresenter.cpp
+++ b/src/filters/renderer/VideoRenderers/EVRAllocatorPresenter.cpp
@@ -1,5 +1,5 @@
/*
- * (C) 2006-2014 see Authors.txt
+ * (C) 2006-2017 see Authors.txt
*
* This file is part of MPC-HC.
*
@@ -40,6 +40,8 @@ enum EVR_STATS_MSG {
MSG_MIXEROUT
};
+// Guid to tag IMFSample with a group id
+static const GUID GUID_GROUP_ID = { 0x309e32cc, 0x9b23, 0x4c6c, { 0x86, 0x63, 0xcd, 0xd9, 0xad, 0x49, 0x7f, 0x8a } };
// Guid to tag IMFSample with DirectX surface index
static const GUID GUID_SURFACE_INDEX = { 0x30c8e9f6, 0x415, 0x4b81, { 0xa3, 0x15, 0x1, 0xa, 0xc6, 0xa9, 0xda, 0x19 } };
@@ -67,51 +69,48 @@ using namespace DSObjects;
CEVRAllocatorPresenter::CEVRAllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, CString& _Error)
: CDX9AllocatorPresenter(hWnd, bFullscreen, hr, true, _Error)
- , m_hDXVA2Lib(nullptr)
- , m_hEVRLib(nullptr)
- , m_hAVRTLib(nullptr)
- , m_nResetToken(0)
- , m_hThread(nullptr)
- , m_hGetMixerThread(nullptr)
- , m_hVSyncThread(nullptr)
- , m_hEvtFlush(nullptr)
- , m_hEvtQuit(nullptr)
- , m_bEvtQuit(0)
- , m_bEvtFlush(0)
, m_ModeratedTime(0)
, m_ModeratedTimeLast(-1)
, m_ModeratedClockLast(-1)
, m_ModeratedTimer(0)
, m_LastClockState(MFCLOCK_STATE_INVALID)
- , m_nRenderState(Shutdown)
+ , m_pOuterEVR(nullptr)
+ , m_dwVideoAspectRatioMode(MFVideoARMode_PreservePicture)
+ , m_dwVideoRenderPrefs((MFVideoRenderPrefs)0)
+ , m_BorderColor(RGB(0, 0, 0))
+ , m_hEvtQuit(nullptr)
+ , m_bEvtQuit(0)
+ , m_hEvtFlush(nullptr)
+ , m_bEvtFlush(0)
, m_fUseInternalTimer(false)
, m_LastSetOutputRange(-1)
, m_bPendingRenegotiate(false)
, m_bPendingMediaFinished(false)
- , m_bWaitingSample(false)
- , m_pCurrentDisplaydSample(nullptr)
- , m_nStepCount(0)
- , m_dwVideoAspectRatioMode(MFVideoARMode_PreservePicture)
- , m_dwVideoRenderPrefs((MFVideoRenderPrefs)0)
- , m_BorderColor(RGB(0, 0, 0))
- , m_bSignaledStarvation(false)
- , m_StarvationClock(0)
- , m_pOuterEVR(nullptr)
+ , m_hThread(nullptr)
+ , m_hGetMixerThread(nullptr)
+ , m_hVSyncThread(nullptr)
+ , m_nRenderState(Shutdown)
+ , m_nCurrentGroupId(0)
+ , m_bLastSampleOffsetValid(false)
, m_LastScheduledSampleTime(-1)
+ , m_LastScheduledSampleTimeFP(-1)
, m_LastScheduledUncorrectedSampleTime(-1)
, m_MaxSampleDuration(0)
, m_LastSampleOffset(0)
, m_LastPredictedSync(0)
, m_VSyncOffsetHistoryPos(0)
- , m_bLastSampleOffsetValid(false)
- , m_LastScheduledSampleTimeFP(-1)
- , pfDXVA2CreateDirect3DDeviceManager9(nullptr)
- , pfMFCreateDXSurfaceBuffer(nullptr)
- , pfMFCreateVideoSampleFromSurface(nullptr)
- , pfMFCreateVideoMediaType(nullptr)
- , pfAvSetMmThreadCharacteristicsW(nullptr)
- , pfAvSetMmThreadPriority(nullptr)
- , pfAvRevertMmThreadCharacteristics(nullptr)
+ , m_nResetToken(0)
+ , m_nStepCount(0)
+ , m_bSignaledStarvation(false)
+ , m_StarvationClock(0)
+ , m_SampleFreeCallback(this, &CEVRAllocatorPresenter::OnSampleFree)
+ , fnDXVA2CreateDirect3DDeviceManager9(_T("dxva2.dll"), "DXVA2CreateDirect3DDeviceManager9")
+ , fnMFCreateDXSurfaceBuffer(_T("evr.dll"), "MFCreateDXSurfaceBuffer")
+ , fnMFCreateVideoSampleFromSurface(_T("evr.dll"), "MFCreateVideoSampleFromSurface")
+ , fnMFCreateMediaType(_T("mfplat.dll"), "MFCreateMediaType")
+ , fnAvSetMmThreadCharacteristicsW(_T("avrt.dll"), "AvSetMmThreadCharacteristicsW")
+ , fnAvSetMmThreadPriority(_T("avrt.dll"), "AvSetMmThreadPriority")
+ , fnAvRevertMmThreadCharacteristics(_T("avrt.dll"), "AvRevertMmThreadCharacteristics")
{
const CRenderersSettings& r = GetRenderersSettings();
@@ -123,62 +122,25 @@ CEVRAllocatorPresenter::CEVRAllocatorPresenter(HWND hWnd, bool bFullscreen, HRES
return;
}
- // Load EVR specific DLLs
- m_hDXVA2Lib = LoadLibrary(L"dxva2.dll");
- if (m_hDXVA2Lib) {
- pfDXVA2CreateDirect3DDeviceManager9 = (PTR_DXVA2CreateDirect3DDeviceManager9) GetProcAddress(m_hDXVA2Lib, "DXVA2CreateDirect3DDeviceManager9");
- }
-
- // Load EVR functions
- m_hEVRLib = LoadLibrary(L"evr.dll");
- if (m_hEVRLib) {
- pfMFCreateDXSurfaceBuffer = (PTR_MFCreateDXSurfaceBuffer) GetProcAddress(m_hEVRLib, "MFCreateDXSurfaceBuffer");
- pfMFCreateVideoSampleFromSurface = (PTR_MFCreateVideoSampleFromSurface) GetProcAddress(m_hEVRLib, "MFCreateVideoSampleFromSurface");
- pfMFCreateVideoMediaType = (PTR_MFCreateVideoMediaType) GetProcAddress(m_hEVRLib, "MFCreateVideoMediaType");
- }
-
- if (!pfDXVA2CreateDirect3DDeviceManager9 || !pfMFCreateDXSurfaceBuffer || !pfMFCreateVideoSampleFromSurface || !pfMFCreateVideoMediaType) {
- if (!pfDXVA2CreateDirect3DDeviceManager9) {
+ if (!fnDXVA2CreateDirect3DDeviceManager9 || !fnMFCreateDXSurfaceBuffer || !fnMFCreateVideoSampleFromSurface || !fnMFCreateMediaType) {
+ if (!fnDXVA2CreateDirect3DDeviceManager9) {
_Error += L"Could not find DXVA2CreateDirect3DDeviceManager9 (dxva2.dll)\n";
}
- if (!pfMFCreateDXSurfaceBuffer) {
+ if (!fnMFCreateDXSurfaceBuffer) {
_Error += L"Could not find MFCreateDXSurfaceBuffer (evr.dll)\n";
}
- if (!pfMFCreateVideoSampleFromSurface) {
+ if (!fnMFCreateVideoSampleFromSurface) {
_Error += L"Could not find MFCreateVideoSampleFromSurface (evr.dll)\n";
}
- if (!pfMFCreateVideoMediaType) {
- _Error += L"Could not find MFCreateVideoMediaType (evr.dll)\n";
+ if (!fnMFCreateMediaType) {
+ _Error += L"Could not find MFCreateMediaType (mfplat.dll)\n";
}
hr = E_FAIL;
return;
}
- // Load mfplat fuctions
-#if 0
- m_hMFPlatLib = LoadLibrary(L"mfplat.dll");
- if (m_hMFPlatLib) {
- (FARPROC&)pMFCreateMediaType = GetProcAddress(m_hMFPlatLib, "MFCreateMediaType");
- (FARPROC&)pMFInitMediaTypeFromAMMediaType = GetProcAddress(m_hMFPlatLib, "MFInitMediaTypeFromAMMediaType");
- (FARPROC&)pMFInitAMMediaTypeFromMFMediaType = GetProcAddress(m_hMFPlatLib, "MFInitAMMediaTypeFromMFMediaType");
- }
-
- if (!pMFCreateMediaType || !pMFInitMediaTypeFromAMMediaType || !pMFInitAMMediaTypeFromMFMediaType) {
- hr = E_FAIL;
- return;
- }
-#endif
-
- // Load Vista+ specific DLLs
- m_hAVRTLib = LoadLibrary(L"avrt.dll");
- if (m_hAVRTLib) {
- pfAvSetMmThreadCharacteristicsW = (PTR_AvSetMmThreadCharacteristicsW) GetProcAddress(m_hAVRTLib, "AvSetMmThreadCharacteristicsW");
- pfAvSetMmThreadPriority = (PTR_AvSetMmThreadPriority) GetProcAddress(m_hAVRTLib, "AvSetMmThreadPriority");
- pfAvRevertMmThreadCharacteristics = (PTR_AvRevertMmThreadCharacteristics) GetProcAddress(m_hAVRTLib, "AvRevertMmThreadCharacteristics");
- }
-
// Init DXVA manager
- hr = pfDXVA2CreateDirect3DDeviceManager9(&m_nResetToken, &m_pD3DManager);
+ hr = fnDXVA2CreateDirect3DDeviceManager9(&m_nResetToken, &m_pD3DManager);
if (SUCCEEDED(hr) && m_pD3DManager) {
hr = m_pD3DManager->ResetDevice(m_pD3DDev, m_nResetToken);
if (FAILED(hr)) {
@@ -189,7 +151,7 @@ CEVRAllocatorPresenter::CEVRAllocatorPresenter(HWND hWnd, bool bFullscreen, HRES
HANDLE hDevice;
if (SUCCEEDED(m_pD3DManager->OpenDeviceHandle(&hDevice)) &&
SUCCEEDED(m_pD3DManager->GetVideoService(hDevice, IID_PPV_ARGS(&pDecoderService)))) {
- TRACE_EVR("EVR: DXVA2 : device handle = 0x%08x", hDevice);
+ TRACE_EVR("EVR: DXVA2 : device handle = 0x%08x\n", hDevice);
HookDirectXVideoDecoderService(pDecoderService);
m_pD3DManager->CloseDeviceHandle(hDevice);
@@ -212,16 +174,6 @@ CEVRAllocatorPresenter::~CEVRAllocatorPresenter()
m_pMediaType = nullptr;
m_pClock = nullptr;
m_pD3DManager = nullptr;
-
- if (m_hDXVA2Lib) {
- FreeLibrary(m_hDXVA2Lib);
- }
- if (m_hEVRLib) {
- FreeLibrary(m_hEVRLib);
- }
- if (m_hAVRTLib) {
- FreeLibrary(m_hAVRTLib);
- }
}
void CEVRAllocatorPresenter::ResetStats()
@@ -360,6 +312,22 @@ STDMETHODIMP_(bool) CEVRAllocatorPresenter::Paint(bool bAll)
return __super::Paint(bAll);
}
+STDMETHODIMP_(bool) CEVRAllocatorPresenter::Paint(IMFSample* pMFSample)
+{
+ CAutoLock lock(&m_RenderLock);
+
+ m_pCurrentlyDisplayedSample = pMFSample;
+ pMFSample->GetUINT32(GUID_SURFACE_INDEX, (UINT32*)&m_nCurSurface);
+
+ auto sampleHasCurrentGroupId = [this](IMFSample * pSample) {
+ UINT32 nGroupId;
+ return (SUCCEEDED(pSample->GetUINT32(GUID_GROUP_ID, &nGroupId)) && nGroupId == m_nCurrentGroupId);
+ };
+ ASSERT(sampleHasCurrentGroupId(pMFSample));
+
+ return Paint(true);
+}
+
STDMETHODIMP CEVRAllocatorPresenter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
{
HRESULT hr;
@@ -399,6 +367,9 @@ STDMETHODIMP CEVRAllocatorPresenter::NonDelegatingQueryInterface(REFIID riid, vo
// IMFClockStateSink
STDMETHODIMP CEVRAllocatorPresenter::OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset)
{
+ HRESULT hr;
+ CHECK_HR(CheckShutdown());
+
m_nRenderState = Started;
TRACE_EVR("EVR: OnClockStart hnsSystemTime = %I64d, llClockStartOffset = %I64d\n", hnsSystemTime, llClockStartOffset);
@@ -410,6 +381,9 @@ STDMETHODIMP CEVRAllocatorPresenter::OnClockStart(MFTIME hnsSystemTime, LONGLONG
STDMETHODIMP CEVRAllocatorPresenter::OnClockStop(MFTIME hnsSystemTime)
{
+ HRESULT hr;
+ CHECK_HR(CheckShutdown());
+
TRACE_EVR("EVR: OnClockStop hnsSystemTime = %I64d\n", hnsSystemTime);
m_nRenderState = Stopped;
@@ -420,6 +394,9 @@ STDMETHODIMP CEVRAllocatorPresenter::OnClockStop(MFTIME hnsSystemTime)
STDMETHODIMP CEVRAllocatorPresenter::OnClockPause(MFTIME hnsSystemTime)
{
+ HRESULT hr;
+ CHECK_HR(CheckShutdown());
+
TRACE_EVR("EVR: OnClockPause hnsSystemTime = %I64d\n", hnsSystemTime);
if (!m_bSignaledStarvation) {
m_nRenderState = Paused;
@@ -431,6 +408,9 @@ STDMETHODIMP CEVRAllocatorPresenter::OnClockPause(MFTIME hnsSystemTime)
STDMETHODIMP CEVRAllocatorPresenter::OnClockRestart(MFTIME hnsSystemTime)
{
+ HRESULT hr;
+ CHECK_HR(CheckShutdown());
+
m_nRenderState = Started;
m_ModeratedTimeLast = -1;
@@ -608,6 +588,7 @@ void CEVRAllocatorPresenter::CompleteFrameStep(bool bCancel)
STDMETHODIMP CEVRAllocatorPresenter::ProcessMessage(MFVP_MESSAGE_TYPE eMessage, ULONG_PTR ulParam)
{
HRESULT hr = S_OK;
+ CHECK_HR(CheckShutdown());
switch (eMessage) {
case MFVP_MESSAGE_BEGINSTREAMING: // The EVR switched from stopped to paused. The presenter should allocate resources
@@ -713,95 +694,77 @@ HRESULT CEVRAllocatorPresenter::IsMediaTypeSupported(IMFMediaType* pMixerType)
return hr;
}
-HRESULT CEVRAllocatorPresenter::CreateProposedOutputType(IMFMediaType* pMixerType, IMFMediaType** ppType)
+HRESULT CEVRAllocatorPresenter::CreateOptimalOutputType(IMFMediaType* pMixerProposedType, IMFMediaType* pMixerInputType, IMFMediaType** ppType)
{
HRESULT hr;
- AM_MEDIA_TYPE* pAMMedia = nullptr;
- LARGE_INTEGER i64Size;
- MFVIDEOFORMAT* VideoFormat;
+ IMFMediaType* pOptimalMediaType;
- CHECK_HR(pMixerType->GetRepresentation(FORMAT_MFVideoFormat, (void**)&pAMMedia));
+ CHECK_HR(fnMFCreateMediaType(&pOptimalMediaType));
+ CHECK_HR(pMixerProposedType->CopyAllItems(pOptimalMediaType));
- VideoFormat = (MFVIDEOFORMAT*)pAMMedia->pbFormat;
+ const GUID colorAttributes[] = {
+ MF_MT_VIDEO_LIGHTING,
+ MF_MT_VIDEO_PRIMARIES,
+ MF_MT_TRANSFER_FUNCTION,
+ MF_MT_YUV_MATRIX,
+ MF_MT_VIDEO_CHROMA_SITING
+ };
- IMFVideoMediaType* pMediaType;
- hr = pfMFCreateVideoMediaType(VideoFormat, &pMediaType);
+ auto copyAttribute = [](IMFAttributes * pFrom, IMFAttributes * pTo, REFGUID guidKey) {
+ PROPVARIANT val;
+ HRESULT hr = pFrom->GetItem(guidKey, &val);
-#if 0
- // This code doesn't work, use same method as VMR9 instead
- if (VideoFormat->videoInfo.FramesPerSecond.Numerator != 0) {
- switch (VideoFormat->videoInfo.InterlaceMode) {
- case MFVideoInterlace_Progressive:
- case MFVideoInterlace_MixedInterlaceOrProgressive:
- default: {
- m_rtTimePerFrame = (10000000I64 * VideoFormat->videoInfo.FramesPerSecond.Denominator) / VideoFormat->videoInfo.FramesPerSecond.Numerator;
- m_bInterlaced = false;
- }
- break;
- case MFVideoInterlace_FieldSingleUpper:
- case MFVideoInterlace_FieldSingleLower:
- case MFVideoInterlace_FieldInterleavedUpperFirst:
- case MFVideoInterlace_FieldInterleavedLowerFirst: {
- m_rtTimePerFrame = (20000000I64 * VideoFormat->videoInfo.FramesPerSecond.Denominator) / VideoFormat->videoInfo.FramesPerSecond.Numerator;
- m_bInterlaced = true;
- }
- break;
+ if (SUCCEEDED(hr)) {
+ hr = pTo->SetItem(guidKey, val);
+ PropVariantClear(&val);
+ } else if (hr == MF_E_ATTRIBUTENOTFOUND) {
+ hr = pTo->DeleteItem(guidKey);
}
- }
-#endif
+ return hr;
+ };
- CSize videoSize;
- videoSize.cx = VideoFormat->videoInfo.dwWidth;
- videoSize.cy = VideoFormat->videoInfo.dwHeight;
-
- if (SUCCEEDED(hr)) {
- i64Size.HighPart = videoSize.cx;
- i64Size.LowPart = videoSize.cy;
- pMediaType->SetUINT64(MF_MT_FRAME_SIZE, i64Size.QuadPart);
-
- pMediaType->SetUINT32(MF_MT_PAN_SCAN_ENABLED, 0);
-
- const CRenderersSettings& r = GetRenderersSettings();
-
-#if 1
- if (r.m_AdvRendSets.iEVROutputRange == 1) {
- pMediaType->SetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, MFNominalRange_16_235);
- } else {
- pMediaType->SetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, MFNominalRange_0_255);
+ for (REFGUID guidKey : colorAttributes) {
+ if (FAILED(hr = copyAttribute(pMixerInputType, pOptimalMediaType, guidKey))) {
+ TRACE_EVR(_T("Copying color attribute %s failed: 0x%08x\n"), CComBSTR(guidKey), hr);
}
+ }
- // m_pMediaType->SetUINT32 (MF_MT_TRANSFER_FUNCTION, MFVideoTransFunc_10);
-#else
-
- pMediaType->SetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, MFNominalRange_0_255);
- if (r.iEVROutputRange == 1) {
- pMediaType->SetUINT32(MF_MT_YUV_MATRIX, MFVideoTransferMatrix_BT601);
- } else {
- pMediaType->SetUINT32(MF_MT_YUV_MATRIX, MFVideoTransferMatrix_BT709);
- }
-#endif
+ pOptimalMediaType->SetUINT32(MF_MT_PAN_SCAN_ENABLED, 0);
+ const CRenderersSettings& r = GetRenderersSettings();
+ UINT32 nominalRange;
+ if (SUCCEEDED(pMixerInputType->GetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, &nominalRange))
+ && nominalRange == MFNominalRange_0_255) {
+ // EVR mixer always assume 16-235 input. To ensure that luminance range won't be expanded we requests 16-235 also on output.
+ // Request 16-235 to ensure untouched luminance range on output. It is the only way to pass 0-255 without changes.
+ nominalRange = MFNominalRange_16_235;
+ m_LastSetOutputRange = -1; // -1 to prevent renegotiations because of different value than this in settings.
+ } else {
+ nominalRange = (r.m_AdvRendSets.iEVROutputRange == 1) ? MFNominalRange_16_235 : MFNominalRange_0_255;
m_LastSetOutputRange = r.m_AdvRendSets.iEVROutputRange;
+ }
+ pOptimalMediaType->SetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, nominalRange);
- i64Size.HighPart = VideoFormat->videoInfo.PixelAspectRatio.Numerator;
- i64Size.LowPart = VideoFormat->videoInfo.PixelAspectRatio.Denominator;
- pMediaType->SetUINT64(MF_MT_PIXEL_ASPECT_RATIO, i64Size.QuadPart);
+ ULARGE_INTEGER ui64Size;
+ pOptimalMediaType->GetUINT64(MF_MT_FRAME_SIZE, &ui64Size.QuadPart);
- MFVideoArea Area = MakeArea(0, 0, videoSize.cx, videoSize.cy);
- pMediaType->SetBlob(MF_MT_GEOMETRIC_APERTURE, (UINT8*)&Area, sizeof(MFVideoArea));
+ CSize videoSize((LONG)ui64Size.HighPart, (LONG)ui64Size.LowPart);
+ MFVideoArea Area = MakeArea(0, 0, videoSize.cx, videoSize.cy);
+ pOptimalMediaType->SetBlob(MF_MT_GEOMETRIC_APERTURE, (UINT8*)&Area, sizeof(MFVideoArea));
- }
+ ULARGE_INTEGER ui64AspectRatio;
+ pOptimalMediaType->GetUINT64(MF_MT_PIXEL_ASPECT_RATIO, &ui64AspectRatio.QuadPart);
- UINT64 dwARx = UINT64(VideoFormat->videoInfo.PixelAspectRatio.Numerator) * videoSize.cx;
- UINT64 dwARy = UINT64(VideoFormat->videoInfo.PixelAspectRatio.Denominator) * videoSize.cy;
- UINT64 gcd = GCD(dwARx, dwARy);
+ UINT64 ui64ARx = UINT64(ui64AspectRatio.HighPart) * ui64Size.HighPart;
+ UINT64 ui64ARy = UINT64(ui64AspectRatio.LowPart) * ui64Size.LowPart;
+ UINT64 gcd = GCD(ui64ARx, ui64ARy);
if (gcd > 1) {
- dwARx /= gcd;
- dwARy /= gcd;
+ ui64ARx /= gcd;
+ ui64ARy /= gcd;
}
- CSize aspectRatio((LONG)dwARx, (LONG)dwARy);
+ CSize aspectRatio((LONG)ui64ARx, (LONG)ui64ARy);
if (videoSize != m_nativeVideoSize || aspectRatio != m_aspectRatio) {
SetVideoSize(videoSize, aspectRatio);
@@ -811,19 +774,35 @@ HRESULT CEVRAllocatorPresenter::CreateProposedOutputType(IMFMediaType* pMixerTyp
}
}
- pMixerType->FreeRepresentation(FORMAT_MFVideoFormat, (void*)pAMMedia);
- pMediaType->QueryInterface(IID_PPV_ARGS(ppType));
+ *ppType = pOptimalMediaType;
+ (*ppType)->AddRef();
return hr;
}
HRESULT CEVRAllocatorPresenter::SetMediaType(IMFMediaType* pType)
{
- HRESULT hr;
+ HRESULT hr = S_OK;
AM_MEDIA_TYPE* pAMMedia = nullptr;
CString strTemp, strTemp1;
- CheckPointer(pType, E_POINTER);
+ CHECK_HR(CheckShutdown());
+
+ if (!pType) {
+ // Release
+ RemoveAllSamples();
+ DeleteSurfaces();
+ CAutoLock lock(&m_MediaTypeLock);
+ m_pMediaType = nullptr;
+ return hr;
+ }
+
+ DWORD dwFlags = 0;
+ if (m_pMediaType && m_pMediaType->IsEqual(pType, &dwFlags) == S_OK) {
+ // Nothing to do
+ return hr;
+ }
+
CHECK_HR(pType->GetRepresentation(FORMAT_VideoInfo2, (void**)&pAMMedia));
hr = InitializeDevice(pType);
@@ -1000,6 +979,7 @@ HRESULT CEVRAllocatorPresenter::RenegotiateMediaType()
HRESULT hr = S_OK;
CComPtr<IMFMediaType> pMixerType;
+ CComPtr<IMFMediaType> pMixerInputType;
CComPtr<IMFMediaType> pType;
if (!m_pMixer) {
@@ -1009,13 +989,13 @@ HRESULT CEVRAllocatorPresenter::RenegotiateMediaType()
CInterfaceArray<IMFMediaType> ValidMixerTypes;
// Get the mixer's input type
- hr = m_pMixer->GetInputCurrentType(0, &pType);
+ hr = m_pMixer->GetInputCurrentType(0, &pMixerInputType);
if (SUCCEEDED(hr)) {
AM_MEDIA_TYPE* pMT;
- hr = pType->GetRepresentation(FORMAT_VideoInfo2, (void**)&pMT);
+ hr = pMixerInputType->GetRepresentation(FORMAT_VideoInfo2, (void**)&pMT);
if (SUCCEEDED(hr)) {
m_inputMediaType = *pMT;
- pType->FreeRepresentation(FORMAT_VideoInfo2, pMT);
+ pMixerInputType->FreeRepresentation(FORMAT_VideoInfo2, pMT);
}
}
@@ -1037,7 +1017,7 @@ HRESULT CEVRAllocatorPresenter::RenegotiateMediaType()
}
if (SUCCEEDED(hr)) {
- hr = CreateProposedOutputType(pMixerType, &pType);
+ hr = CreateOptimalOutputType(pMixerType, pMixerInputType, &pType);
}
// Step 4. Check if the mixer will accept this media type.
@@ -1108,7 +1088,7 @@ HRESULT CEVRAllocatorPresenter::RenegotiateMediaType()
bool CEVRAllocatorPresenter::GetImageFromMixer()
{
- MFT_OUTPUT_DATA_BUFFER Buffer;
+ MFT_OUTPUT_DATA_BUFFER dataBuffer;
HRESULT hr = S_OK;
DWORD dwStatus;
REFERENCE_TIME nsSampleTime;
@@ -1119,26 +1099,34 @@ bool CEVRAllocatorPresenter::GetImageFromMixer()
bool bDoneSomething = false;
+ auto sampleHasCurrentGroupId = [this](IMFSample * pSample) {
+ UINT32 nGroupId;
+ return (SUCCEEDED(pSample->GetUINT32(GUID_GROUP_ID, &nGroupId)) && nGroupId == m_nCurrentGroupId);
+ };
+
while (SUCCEEDED(hr)) {
CComPtr<IMFSample> pSample;
if (FAILED(GetFreeSample(&pSample))) {
- m_bWaitingSample = true;
break;
}
- ZeroMemory(&Buffer, sizeof(Buffer));
- Buffer.pSample = pSample;
+ ZeroMemory(&dataBuffer, sizeof(dataBuffer));
+ dataBuffer.pSample = pSample;
pSample->GetUINT32(GUID_SURFACE_INDEX, &dwSurface);
+ ASSERT(sampleHasCurrentGroupId(pSample));
{
llClockBefore = GetRenderersData()->GetPerfCounter();
- hr = m_pMixer->ProcessOutput(0, 1, &Buffer, &dwStatus);
+ hr = m_pMixer->ProcessOutput(0, 1, &dataBuffer, &dwStatus);
llClockAfter = GetRenderersData()->GetPerfCounter();
}
if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
- MoveToFreeList(pSample, false);
+ AddToFreeList(pSample, false);
+ pSample = nullptr; // The sample should not be used after being queued
+ // Important: Release any events returned from the ProcessOutput method.
+ SAFE_RELEASE(dataBuffer.pEvents);
break;
}
@@ -1169,8 +1157,17 @@ bool CEVRAllocatorPresenter::GetImageFromMixer()
TRACE_EVR("EVR: Get from Mixer : %u (%I64d) (%I64d)\n", dwSurface, nsSampleTime, m_rtTimePerFrame ? nsSampleTime / m_rtTimePerFrame : 0);
- MoveToScheduledList(pSample, false);
- bDoneSomething = true;
+ if (SUCCEEDED(TrackSample(pSample))) {
+ AddToScheduledList(pSample, false);
+ pSample = nullptr; // The sample should not be used after being queued
+ bDoneSomething = true;
+ } else {
+ ASSERT(FALSE);
+ }
+
+ // Important: Release any events returned from the ProcessOutput method.
+ SAFE_RELEASE(dataBuffer.pEvents);
+
if (m_rtTimePerFrame == 0) {
break;
}
@@ -1199,27 +1196,33 @@ STDMETHODIMP CEVRAllocatorPresenter::GetCurrentMediaType(__deref_out IMFVideoMe
// IMFTopologyServiceLookupClient
STDMETHODIMP CEVRAllocatorPresenter::InitServicePointers(/* [in] */ __in IMFTopologyServiceLookup* pLookup)
{
+ HRESULT hr = S_OK;
DWORD dwObjects = 1;
+ CAutoLock cThreadsLock(&m_ThreadsLock);
+
TRACE_EVR("EVR: CEVRAllocatorPresenter::InitServicePointers\n");
- pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_MIXER_SERVICE,
- IID_PPV_ARGS(&m_pMixer), &dwObjects);
+ CHECK_HR(pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_MIXER_SERVICE,
+ IID_PPV_ARGS(&m_pMixer), &dwObjects));
- pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE,
- IID_PPV_ARGS(&m_pSink), &dwObjects);
+ CHECK_HR(pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE,
+ IID_PPV_ARGS(&m_pSink), &dwObjects));
pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE,
IID_PPV_ARGS(&m_pClock), &dwObjects);
StartWorkerThreads();
- return S_OK;
+ return hr;
}
STDMETHODIMP CEVRAllocatorPresenter::ReleaseServicePointers()
{
TRACE_EVR("EVR: CEVRAllocatorPresenter::ReleaseServicePointers\n");
+ CAutoLock cThreadsLock(&m_ThreadsLock);
+
StopWorkerThreads();
+
m_pMixer = nullptr;
m_pSink = nullptr;
m_pClock = nullptr;
@@ -1236,8 +1239,8 @@ STDMETHODIMP CEVRAllocatorPresenter::GetDeviceID(/* [out] */ __out IID* pDevice
// IMFGetService
STDMETHODIMP CEVRAllocatorPresenter::GetService(/* [in] */ __RPC__in REFGUID guidService,
- /* [in] */ __RPC__in REFIID riid,
- /* [iid_is][out] */ __RPC__deref_out_opt LPVOID* ppvObject)
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */ __RPC__deref_out_opt LPVOID* ppvObject)
{
if (guidService == MR_VIDEO_RENDER_SERVICE) {
return NonDelegatingQueryInterface(riid, ppvObject);
@@ -1529,11 +1532,14 @@ STDMETHODIMP CEVRAllocatorPresenter::InitializeDevice(IMFMediaType* pMediaType)
if (SUCCEEDED(hr)) {
for (int i = 0; i < m_nNbDXSurface; i++) {
CComPtr<IMFSample> pMFSample;
- hr = pfMFCreateVideoSampleFromSurface(m_pVideoSurface[i], &pMFSample);
+ hr = fnMFCreateVideoSampleFromSurface(m_pVideoSurface[i], &pMFSample);
if (SUCCEEDED(hr)) {
+ pMFSample->SetUINT32(GUID_GROUP_ID, m_nCurrentGroupId);
pMFSample->SetUINT32(GUID_SURFACE_INDEX, i);
+ CAutoLock sampleQueueLock(&m_SampleQueueLock);
m_FreeSamples.AddTail(pMFSample);
+ pMFSample = nullptr; // The sample should not be used after being queued
}
ASSERT(SUCCEEDED(hr));
}
@@ -1558,14 +1564,6 @@ DWORD WINAPI CEVRAllocatorPresenter::PresentThread(LPVOID lpParam)
return 0;
}
-void CEVRAllocatorPresenter::CheckWaitingSampleFromMixer()
-{
- if (m_bWaitingSample) {
- m_bWaitingSample = false;
- //GetImageFromMixer(); // Do this in processing thread instead
- }
-}
-
bool ExtractInterlaced(const AM_MEDIA_TYPE* pmt)
{
if (pmt->formattype == FORMAT_VideoInfo) {
@@ -1846,7 +1844,9 @@ LONGLONG CEVRAllocatorPresenter::GetClockTime(LONGLONG PerformanceCounter)
void CEVRAllocatorPresenter::OnVBlankFinished(bool bAll, LONGLONG PerformanceCounter)
{
- if (!m_pCurrentDisplaydSample || !m_OrderedPaint || !bAll) {
+ // This function is meant to be called only from the rendering function
+ // so with the ownership on m_RenderLock.
+ if (!m_pCurrentlyDisplayedSample || !m_OrderedPaint || !bAll) {
return;
}
@@ -1865,14 +1865,14 @@ void CEVRAllocatorPresenter::OnVBlankFinished(bool bAll, LONGLONG PerformanceCou
llClockTime = m_StarvationClock;
}
- if (SUCCEEDED(m_pCurrentDisplaydSample->GetSampleDuration(&SampleDuration))) {
+ if (SUCCEEDED(m_pCurrentlyDisplayedSample->GetSampleDuration(&SampleDuration))) {
// Some filters return invalid values, ignore them
if (SampleDuration > MIN_FRAME_TIME) {
TimePerFrame = SampleDuration;
}
}
- if (FAILED(m_pCurrentDisplaydSample->GetSampleTime(&nsSampleTime))) {
+ if (FAILED(m_pCurrentlyDisplayedSample->GetSampleTime(&nsSampleTime))) {
nsSampleTime = llClockTime;
}
@@ -1904,12 +1904,13 @@ void CEVRAllocatorPresenter::OnVBlankFinished(bool bAll, LONGLONG PerformanceCou
m_fSyncOffsetAvr = MeanOffset;
m_bSyncStatsAvailable = true;
m_fSyncOffsetStdDev = StdDev;
-
}
}
STDMETHODIMP_(bool) CEVRAllocatorPresenter::ResetDevice()
{
+ CAutoLock cThreadsLock(&m_ThreadsLock);
+
StopWorkerThreads();
CAutoLock lock(this);
@@ -1922,11 +1923,14 @@ STDMETHODIMP_(bool) CEVRAllocatorPresenter::ResetDevice()
for (int i = 0; i < m_nNbDXSurface; i++) {
CComPtr<IMFSample> pMFSample;
- HRESULT hr = pfMFCreateVideoSampleFromSurface(m_pVideoSurface[i], &pMFSample);
+ HRESULT hr = fnMFCreateVideoSampleFromSurface(m_pVideoSurface[i], &pMFSample);
if (SUCCEEDED(hr)) {
+ pMFSample->SetUINT32(GUID_GROUP_ID, m_nCurrentGroupId);
pMFSample->SetUINT32(GUID_SURFACE_INDEX, i);
+ CAutoLock sampleQueueLock(&m_SampleQueueLock);
m_FreeSamples.AddTail(pMFSample);
+ pMFSample = nullptr; // The sample should not be used after being queued
}
ASSERT(SUCCEEDED(hr));
}
@@ -1986,17 +1990,28 @@ void CEVRAllocatorPresenter::RenderThread()
// Tell Multimedia Class Scheduler we are a playback thread (increase priority)
HANDLE hAvrt = 0;
- if (pfAvSetMmThreadCharacteristicsW) {
+ if (fnAvSetMmThreadCharacteristicsW) {
DWORD dwTaskIndex = 0;
- hAvrt = pfAvSetMmThreadCharacteristicsW(L"Playback", &dwTaskIndex);
- if (pfAvSetMmThreadPriority) {
- pfAvSetMmThreadPriority(hAvrt, AVRT_PRIORITY_HIGH /*AVRT_PRIORITY_CRITICAL*/);
+ hAvrt = fnAvSetMmThreadCharacteristicsW(L"Playback", &dwTaskIndex);
+ if (fnAvSetMmThreadPriority) {
+ fnAvSetMmThreadPriority(hAvrt, AVRT_PRIORITY_HIGH /*AVRT_PRIORITY_CRITICAL*/);
}
}
timeGetDevCaps(&tc, sizeof(TIMECAPS));
DWORD dwResolution = std::min(std::max(tc.wPeriodMin, 0u), tc.wPeriodMax);
- DWORD dwUser = timeBeginPeriod(dwResolution);
+ VERIFY(timeBeginPeriod(dwResolution) == 0);
+
+ auto checkPendingMediaFinished = [this]() {
+ if (m_bPendingMediaFinished) {
+ CAutoLock lock(&m_SampleQueueLock);
+ if (m_ScheduledSamples.IsEmpty()) {
+ m_bPendingMediaFinished = false;
+ m_pSink->Notify(EC_COMPLETE, 0, 0);
+ }
+ }
+ };
+
const CRenderersSettings& r = GetRenderersSettings();
int NextSleepTime = 1;
@@ -2051,29 +2066,28 @@ void CEVRAllocatorPresenter::RenderThread()
//if (WaitForMultipleObjects (_countof(hEvtsBuff), hEvtsBuff, FALSE, INFINITE) == WAIT_OBJECT_0+2)
{
CComPtr<IMFSample> pMFSample;
- LONGLONG llPerf = GetRenderersData()->GetPerfCounter();
- UNREFERENCED_PARAMETER(llPerf);
+ //LONGLONG llPerf2 = GetRenderersData()->GetPerfCounter();
+ //UNREFERENCED_PARAMETER(llPerf2);
int nSamplesLeft = 0;
if (SUCCEEDED(GetScheduledSample(&pMFSample, nSamplesLeft))) {
- //pMFSample->GetUINT32 (GUID_SURFACE_INDEX, (UINT32*)&m_nCurSurface);
- m_pCurrentDisplaydSample = pMFSample;
+ //UINT32 nSurface;
+ //pMFSample->GetUINT32(GUID_SURFACE_INDEX, (UINT32*)&nSurface);
bool bValidSampleTime = true;
- HRESULT hGetSampleTime = pMFSample->GetSampleTime(&nsSampleTime);
- if (hGetSampleTime != S_OK || nsSampleTime == 0) {
+ HRESULT hrGetSampleTime = pMFSample->GetSampleTime(&nsSampleTime);
+ if (hrGetSampleTime != S_OK || nsSampleTime == 0) {
bValidSampleTime = false;
}
// We assume that all samples have the same duration
LONGLONG SampleDuration = 0;
bool bValidSampleDuration = true;
- HRESULT hGetSampleDuration = pMFSample->GetSampleDuration(&SampleDuration);
-
+ HRESULT hrGetSampleDuration = pMFSample->GetSampleDuration(&SampleDuration);
// Some filters return invalid values, ignore them
- if (hGetSampleTime != S_OK || SampleDuration <= MIN_FRAME_TIME) {
+ if (hrGetSampleDuration != S_OK || SampleDuration <= MIN_FRAME_TIME) {
bValidSampleDuration = false;
}
- //TRACE_EVR ("EVR: RenderThread ==>> Presenting surface %d (%I64d)\n", m_nCurSurface, nsSampleTime);
+ //TRACE_EVR("EVR: RenderThread ==>> Presenting surface %d (%I64d)\n", nSurface, nsSampleTime);
bool bStepForward = false;
@@ -2085,14 +2099,13 @@ void CEVRAllocatorPresenter::RenderThread()
m_nStepCount = 0;
/*
} else if (m_nStepCount > 0) {
- pMFSample->GetUINT32(GUID_SURFACE_INDEX, (UINT32 *)&m_nCurSurface);
++m_OrderedPaint;
if (!g_bExternalSubtitleTime) {
__super::SetTime (g_tSegmentStart + nsSampleTime);
}
- Paint(true);
+ Paint(pMFSample);
m_nDroppedUpdate = 0;
- CompleteFrameStep (false);
+ CompleteFrameStep(false);
bStepForward = true;
*/
} else if (m_nRenderState == Started) {
@@ -2108,18 +2121,13 @@ void CEVRAllocatorPresenter::RenderThread()
if (!bValidSampleTime) {
// Just play as fast as possible
bStepForward = true;
- pMFSample->GetUINT32(GUID_SURFACE_INDEX, (UINT32*)&m_nCurSurface);
++m_OrderedPaint;
if (!g_bExternalSubtitleTime) {
__super::SetTime(g_tSegmentStart + nsSampleTime);
}
- Paint(true);
+ Paint(pMFSample);
} else {
LONGLONG TimePerFrame = (LONGLONG)(GetFrameTime() * 10000000.0);
- LONGLONG DrawTime = m_PaintTime * 9 / 10 - 20000; // 2 ms offset (= m_PaintTime * 0.9 - 20000)
- //if (!r.bVMR9VSync)
- DrawTime = 0;
-
LONGLONG SyncOffset = 0;
LONGLONG VSyncTime = 0;
LONGLONG TimeToNextVSync = -1;
@@ -2227,7 +2235,6 @@ void CEVRAllocatorPresenter::RenderThread()
TRACE_EVR("EVR: Normalframe\n");
m_nDroppedUpdate = 0;
bStepForward = true;
- pMFSample->GetUINT32(GUID_SURFACE_INDEX, (UINT32*)&m_nCurSurface);
m_LastFrameDuration = nsSampleTime - m_LastSampleTime;
m_LastSampleTime = nsSampleTime;
m_LastPredictedSync = VSyncOffset0;
@@ -2241,7 +2248,7 @@ void CEVRAllocatorPresenter::RenderThread()
if (!g_bExternalSubtitleTime) {
__super::SetTime(g_tSegmentStart + nsSampleTime);
}
- Paint(true);
+ Paint(pMFSample);
NextSleepTime = 0;
m_pcFramesDrawn++;
@@ -2308,18 +2315,17 @@ void CEVRAllocatorPresenter::RenderThread()
if (!g_bExternalSubtitleTime) {
__super::SetTime(g_tSegmentStart + nsSampleTime);
}
- Paint(false);
+ Paint(pMFSample);
}
NextSleepTime = int(SampleDuration / 10000 - 2);
}
- m_pCurrentDisplaydSample = nullptr;
if (bStepForward) {
- MoveToFreeList(pMFSample, true);
- CheckWaitingSampleFromMixer();
m_MaxSampleDuration = std::max(SampleDuration, m_MaxSampleDuration);
+ checkPendingMediaFinished();
} else {
- MoveToScheduledList(pMFSample, true);
+ AddToScheduledList(pMFSample, true);
+ pMFSample = nullptr; // The sample should not be used after being queued
}
bForcePaint = false;
@@ -2328,8 +2334,9 @@ void CEVRAllocatorPresenter::RenderThread()
m_pSink->Notify(EC_STARVATION, 0, 0);
m_bSignaledStarvation = true;
}
+ } else {
+ checkPendingMediaFinished();
}
- //GetImageFromMixer();
}
//else
//{
@@ -2341,8 +2348,8 @@ void CEVRAllocatorPresenter::RenderThread()
}
timeEndPeriod(dwResolution);
- if (pfAvRevertMmThreadCharacteristics) {
- pfAvRevertMmThreadCharacteristics(hAvrt);
+ if (fnAvRevertMmThreadCharacteristics) {
+ fnAvRevertMmThreadCharacteristics(hAvrt);
}
}
@@ -2418,86 +2425,87 @@ void CEVRAllocatorPresenter::VSyncThread()
WaitForVBlankRange(ScanlineEnd, 5, true, true, false, bTakenLock);
LONGLONG TimeEnd = rd->GetPerfCounter();
- double nSeconds = double(TimeEnd - TimeStart) / 10000000.0;
- LONGLONG DiffMiddle = TimeMiddle - TimeStart;
- LONGLONG DiffEnd = TimeEnd - TimeMiddle;
- double DiffDiff;
- if (DiffEnd > DiffMiddle) {
- DiffDiff = double(DiffEnd) / double(DiffMiddle);
- } else {
- DiffDiff = double(DiffMiddle) / double(DiffEnd);
- }
- if (nSeconds > 0.003 && DiffDiff < 1.3) {
- double ScanLineSeconds;
- double nScanLines;
- if (ScanLineMiddle > ScanlineEnd) {
- ScanLineSeconds = double(TimeMiddle - TimeStart) / 10000000.0;
- nScanLines = ScanLineMiddle - ScanlineStart;
- } else {
- ScanLineSeconds = double(TimeEnd - TimeMiddle) / 10000000.0;
- nScanLines = ScanlineEnd - ScanLineMiddle;
- }
-
- double ScanLineTime = ScanLineSeconds / nScanLines;
-
- int iPos = m_DetectedRefreshRatePos % 100;
- m_ldDetectedScanlineRateList[iPos] = ScanLineTime;
- if (m_DetectedScanlineTime && ScanlineStart != ScanlineEnd) {
- int Diff = ScanlineEnd - ScanlineStart;
- nSeconds -= double(Diff) * m_DetectedScanlineTime;
- }
- m_ldDetectedRefreshRateList[iPos] = nSeconds;
- double Average = 0;
- double AverageScanline = 0;
- int nPos = std::min(iPos + 1, 100);
- for (int i = 0; i < nPos; ++i) {
- Average += m_ldDetectedRefreshRateList[i];
- AverageScanline += m_ldDetectedScanlineRateList[i];
- }
-
- if (nPos) {
- Average /= double(nPos);
- AverageScanline /= double(nPos);
- } else {
- Average = 0;
- AverageScanline = 0;
- }
+ double nSeconds = (TimeEnd - TimeStart) / 10000000.0;
+ LONGLONG llDiffMiddle = TimeMiddle - TimeStart;
+ ASSERT(llDiffMiddle > 0);
+
+ if (nSeconds > 0.003 && llDiffMiddle > 0) {
+ double dDiffMiddle = double(llDiffMiddle);
+ double dDiffEnd = double(TimeEnd - TimeMiddle);
+
+ double dDiffDiff = dDiffEnd / dDiffMiddle;
+ if (dDiffDiff < 1.3 && dDiffDiff > (1 / 1.3)) {
+ double ScanLineSeconds;
+ double nScanLines;
+ if (ScanLineMiddle > ScanlineEnd) {
+ ScanLineSeconds = dDiffMiddle / 10000000.0;
+ nScanLines = ScanLineMiddle - ScanlineStart;
+ } else {
+ ScanLineSeconds = dDiffEnd / 10000000.0;
+ nScanLines = ScanlineEnd - ScanLineMiddle;
+ }
- double ThisValue = Average;
+ double ScanLineTime = ScanLineSeconds / nScanLines;
- if (Average > 0.0 && AverageScanline > 0.0) {
- CAutoLock Lock(&m_refreshRateLock);
- ++m_DetectedRefreshRatePos;
- if (m_DetectedRefreshTime == 0 || m_DetectedRefreshTime / ThisValue > 1.01 || m_DetectedRefreshTime / ThisValue < 0.99) {
- m_DetectedRefreshTime = ThisValue;
- m_DetectedRefreshTimePrim = 0;
- }
- if (_isnan(m_DetectedRefreshTime)) {
- m_DetectedRefreshTime = 0.0;
+ int iPos = m_DetectedRefreshRatePos % 100;
+ m_ldDetectedScanlineRateList[iPos] = ScanLineTime;
+ if (m_DetectedScanlineTime && ScanlineStart != ScanlineEnd) {
+ int Diff = ScanlineEnd - ScanlineStart;
+ nSeconds -= double(Diff) * m_DetectedScanlineTime;
}
- if (_isnan(m_DetectedRefreshTimePrim)) {
- m_DetectedRefreshTimePrim = 0.0;
+ m_ldDetectedRefreshRateList[iPos] = nSeconds;
+ double Average = 0;
+ double AverageScanline = 0;
+ int nPos = std::min(iPos + 1, 100);
+ for (int i = 0; i < nPos; ++i) {
+ Average += m_ldDetectedRefreshRateList[i];
+ AverageScanline += m_ldDetectedScanlineRateList[i];
}
- ModerateFloat(m_DetectedRefreshTime, ThisValue, m_DetectedRefreshTimePrim, 1.5);
- if (m_DetectedRefreshTime > 0.0) {
- m_DetectedRefreshRate = 1.0 / m_DetectedRefreshTime;
+ if (nPos) {
+ Average /= double(nPos);
+ AverageScanline /= double(nPos);
} else {
- m_DetectedRefreshRate = 0.0;
+ Average = 0;
+ AverageScanline = 0;
}
- if (m_DetectedScanlineTime == 0 || m_DetectedScanlineTime / AverageScanline > 1.01 || m_DetectedScanlineTime / AverageScanline < 0.99) {
- m_DetectedScanlineTime = AverageScanline;
- m_DetectedScanlineTimePrim = 0;
- }
- ModerateFloat(m_DetectedScanlineTime, AverageScanline, m_DetectedScanlineTimePrim, 1.5);
- if (m_DetectedScanlineTime > 0.0) {
- m_DetectedScanlinesPerFrame = m_DetectedRefreshTime / m_DetectedScanlineTime;
- } else {
- m_DetectedScanlinesPerFrame = 0;
+ double ThisValue = Average;
+
+ if (Average > 0.0 && AverageScanline > 0.0) {
+ CAutoLock Lock(&m_refreshRateLock);
+ ++m_DetectedRefreshRatePos;
+ if (m_DetectedRefreshTime == 0 || m_DetectedRefreshTime / ThisValue > 1.01 || m_DetectedRefreshTime / ThisValue < 0.99) {
+ m_DetectedRefreshTime = ThisValue;
+ m_DetectedRefreshTimePrim = 0;
+ }
+ if (_isnan(m_DetectedRefreshTime)) {
+ m_DetectedRefreshTime = 0.0;
+ }
+ if (_isnan(m_DetectedRefreshTimePrim)) {
+ m_DetectedRefreshTimePrim = 0.0;
+ }
+
+ ModerateFloat(m_DetectedRefreshTime, ThisValue, m_DetectedRefreshTimePrim, 1.5);
+ if (m_DetectedRefreshTime > 0.0) {
+ m_DetectedRefreshRate = 1.0 / m_DetectedRefreshTime;
+ } else {
+ m_DetectedRefreshRate = 0.0;
+ }
+
+ if (m_DetectedScanlineTime == 0 || m_DetectedScanlineTime / AverageScanline > 1.01 || m_DetectedScanlineTime / AverageScanline < 0.99) {
+ m_DetectedScanlineTime = AverageScanline;
+ m_DetectedScanlineTimePrim = 0;
+ }
+ ModerateFloat(m_DetectedScanlineTime, AverageScanline, m_DetectedScanlineTimePrim, 1.5);
+ if (m_DetectedScanlineTime > 0.0) {
+ m_DetectedScanlinesPerFrame = m_DetectedRefreshTime / m_DetectedScanlineTime;
+ } else {
+ m_DetectedScanlinesPerFrame = 0;
+ }
}
+ //TRACE(_T("Refresh: %f\n"), RefreshRate);
}
- //TRACE(_T("Refresh: %f\n"), RefreshRate);
}
}
} else {
@@ -2534,7 +2542,8 @@ void CEVRAllocatorPresenter::OnResetDevice()
void CEVRAllocatorPresenter::RemoveAllSamples()
{
- CAutoLock AutoLock(&m_ImageProcessingLock);
+ CAutoLock imageProcesssingLock(&m_ImageProcessingLock);
+ CAutoLock sampleQueueLock(&m_SampleQueueLock);
FlushSamples();
m_ScheduledSamples.RemoveAll();
@@ -2542,6 +2551,8 @@ void CEVRAllocatorPresenter::RemoveAllSamples()
m_LastScheduledSampleTime = -1;
m_LastScheduledUncorrectedSampleTime = -1;
m_nUsedBuffer = 0;
+ // Increment the group id to make sure old samples will really be deleted
+ m_nCurrentGroupId++;
}
HRESULT CEVRAllocatorPresenter::GetFreeSample(IMFSample** ppSample)
@@ -2549,8 +2560,8 @@ HRESULT CEVRAllocatorPresenter::GetFreeSample(IMFSample** ppSample)
CAutoLock lock(&m_SampleQueueLock);
HRESULT hr = S_OK;
- if (m_FreeSamples.GetCount() > 1) { // <= Cannot use first free buffer (can be currently displayed)
- InterlockedIncrement(&m_nUsedBuffer);
+ if (!m_FreeSamples.IsEmpty()) {
+ m_nUsedBuffer++;
*ppSample = m_FreeSamples.RemoveHead().Detach();
} else {
hr = MF_E_SAMPLEALLOCATOR_EMPTY;
@@ -2559,15 +2570,15 @@ HRESULT CEVRAllocatorPresenter::GetFreeSample(IMFSample** ppSample)
return hr;
}
-HRESULT CEVRAllocatorPresenter::GetScheduledSample(IMFSample** ppSample, int& _Count)
+HRESULT CEVRAllocatorPresenter::GetScheduledSample(IMFSample** ppSample, int& count)
{
CAutoLock lock(&m_SampleQueueLock);
HRESULT hr = S_OK;
- _Count = (int)m_ScheduledSamples.GetCount();
- if (_Count > 0) {
+ count = (int)m_ScheduledSamples.GetCount();
+ if (count > 0) {
*ppSample = m_ScheduledSamples.RemoveHead().Detach();
- --_Count;
+ --count;
} else {
hr = MF_E_SAMPLEALLOCATOR_EMPTY;
}
@@ -2575,14 +2586,11 @@ HRESULT CEVRAllocatorPresenter::GetScheduledSample(IMFSample** ppSample, int& _C
return hr;
}
-void CEVRAllocatorPresenter::MoveToFreeList(IMFSample* pSample, bool bTail)
+void CEVRAllocatorPresenter::AddToFreeList(IMFSample* pSample, bool bTail)
{
CAutoLock lock(&m_SampleQueueLock);
- InterlockedDecrement(&m_nUsedBuffer);
- if (m_bPendingMediaFinished && m_nUsedBuffer == 0) {
- m_bPendingMediaFinished = false;
- m_pSink->Notify(EC_COMPLETE, 0, 0);
- }
+
+ m_nUsedBuffer--;
if (bTail) {
m_FreeSamples.AddTail(pSample);
} else {
@@ -2590,11 +2598,11 @@ void CEVRAllocatorPresenter::MoveToFreeList(IMFSample* pSample, bool bTail)
}
}
-void CEVRAllocatorPresenter::MoveToScheduledList(IMFSample* pSample, bool _bSorted)
+void CEVRAllocatorPresenter::AddToScheduledList(IMFSample* pSample, bool bSorted)
{
+ CAutoLock lock(&m_SampleQueueLock);
- if (_bSorted) {
- CAutoLock lock(&m_SampleQueueLock);
+ if (bSorted) {
// Insert sorted
/*POSITION Iterator = m_ScheduledSamples.GetHeadPosition();
@@ -2616,9 +2624,6 @@ void CEVRAllocatorPresenter::MoveToScheduledList(IMFSample* pSample, bool _bSort
m_ScheduledSamples.AddHead(pSample);
} else {
-
- CAutoLock lock(&m_SampleQueueLock);
-
const CRenderersSettings& r = GetRenderersSettings();
double ForceFPS = 0.0;
//double ForceFPS = 59.94;
@@ -2650,7 +2655,7 @@ void CEVRAllocatorPresenter::MoveToScheduledList(IMFSample* pSample, bool _bSort
}
if (Diff < m_rtTimePerFrame * 8 && m_rtTimePerFrame && Diff2 < m_rtTimePerFrame * 8) { // Detect seeking
int iPos = (m_DetectedFrameTimePos++) % 60;
- LONGLONG Diff = Time - PrevTime;
+ Diff = Time - PrevTime;
if (PrevTime == -1) {
Diff = 0;
}
@@ -2818,7 +2823,6 @@ void CEVRAllocatorPresenter::MoveToScheduledList(IMFSample* pSample, bool _bSort
m_LastScheduledSampleTime = Time;
m_ScheduledSamples.AddTail(pSample);
-
}
}
@@ -2826,21 +2830,40 @@ void CEVRAllocatorPresenter::FlushSamples()
{
CAutoLock lock(this);
CAutoLock lock2(&m_SampleQueueLock);
+ CAutoLock lock3(&m_RenderLock);
+
+ m_pCurrentlyDisplayedSample = nullptr;
+ m_ScheduledSamples.RemoveAll();
- FlushSamplesInternal();
+ m_LastSampleOffset = 0;
+ m_bLastSampleOffsetValid = false;
+ m_bSignaledStarvation = false;
m_LastScheduledSampleTime = -1;
}
-void CEVRAllocatorPresenter::FlushSamplesInternal()
+HRESULT CEVRAllocatorPresenter::TrackSample(IMFSample* pSample)
{
- while (!m_ScheduledSamples.IsEmpty()) {
- CComPtr<IMFSample> pMFSample;
-
- pMFSample = m_ScheduledSamples.RemoveHead();
- MoveToFreeList(pMFSample, true);
+ HRESULT hr = E_FAIL;
+ if (CComQIPtr<IMFTrackedSample> pTracked = pSample) {
+ hr = pTracked->SetAllocator(&m_SampleFreeCallback, nullptr);
}
+ return hr;
+}
- m_LastSampleOffset = 0;
- m_bLastSampleOffsetValid = false;
- m_bSignaledStarvation = false;
+HRESULT CEVRAllocatorPresenter::OnSampleFree(IMFAsyncResult* pResult)
+{
+ CComPtr<IUnknown> pObject;
+ HRESULT hr = pResult->GetObject(&pObject);
+ if (SUCCEEDED(hr)) {
+ if (CComQIPtr<IMFSample> pSample = pObject) {
+ // Ignore the sample if it is from an old group
+ UINT32 nGroupId;
+ CAutoLock sampleQueueLock(&m_SampleQueueLock);
+ if (SUCCEEDED(pSample->GetUINT32(GUID_GROUP_ID, &nGroupId)) && nGroupId == m_nCurrentGroupId) {
+ AddToFreeList(pSample, true);
+ pSample = nullptr; // The sample should not be used after being queued
+ }
+ }
+ }
+ return hr;
}