diff --git a/SpoutCamDX.vcxproj b/SpoutCamDX.vcxproj index 759b5c5..5b3c6b2 100644 --- a/SpoutCamDX.vcxproj +++ b/SpoutCamDX.vcxproj @@ -28,23 +28,23 @@ DynamicLibrary - MultiByte + Unicode v141 DynamicLibrary - MultiByte + Unicode v141 DynamicLibrary v141 - MultiByte + Unicode DynamicLibrary v141 - MultiByte + Unicode @@ -114,9 +114,6 @@ copy /y $(TargetPath) release\win32\SpoutCam32.ax - - PerMonitorHighDPIAware - @@ -144,11 +141,10 @@ copy /y $(TargetPath) release\win32\SpoutCam32.ax + + - - PerMonitorHighDPIAware - @@ -193,9 +189,6 @@ copy /y $(TargetPath) release\x64\SpoutCam64.ax - - PerMonitorHighDPIAware - diff --git a/SpoutDX/winproj2017/SpoutDX.vcxproj b/SpoutDX/winproj2017/SpoutDX.vcxproj index b70aca5..2c25244 100644 --- a/SpoutDX/winproj2017/SpoutDX.vcxproj +++ b/SpoutDX/winproj2017/SpoutDX.vcxproj @@ -50,27 +50,27 @@ StaticLibrary true - MultiByte + Unicode v141 StaticLibrary true - MultiByte + Unicode v141 StaticLibrary false true - MultiByte + Unicode v141 StaticLibrary false true - MultiByte + Unicode v141 diff --git a/baseclasses/winproj2017/BaseClasses.vcxproj b/baseclasses/winproj2017/BaseClasses.vcxproj index 3a67e78..bf413f6 100644 --- a/baseclasses/winproj2017/BaseClasses.vcxproj +++ b/baseclasses/winproj2017/BaseClasses.vcxproj @@ -43,6 +43,7 @@ StaticLibrary v141 + Unicode diff --git a/release/win32/SpoutCam32.ax b/release/win32/SpoutCam32.ax index 1cd1718..2109a5f 100644 Binary files a/release/win32/SpoutCam32.ax and b/release/win32/SpoutCam32.ax differ diff --git a/release/x64/SpoutCam64.ax b/release/x64/SpoutCam64.ax index dda10dd..bcc7932 100644 Binary files a/release/x64/SpoutCam64.ax and b/release/x64/SpoutCam64.ax differ diff --git a/source/cam.cpp b/source/cam.cpp index e159f99..b91f1ed 100644 --- a/source/cam.cpp +++ b/source/cam.cpp @@ -263,6 +263,12 @@ Returned to timing by RED5 Conditional receive if DirectX initialization failed Version 2.022 + 16.10.20 FillBuffer correct cast for TimeGetTime calculations + Use TimeBeginPeriod for maximum precision of TimeGetTime and Sleep + DirectX device not required - in SpoutDX class. + Do not go to static on first DirectX initialize. + 17.10.20 Change to Unicode for WCHAR folder name support + Verson 2.023 */ @@ -293,7 +299,7 @@ CUnknown * WINAPI CVCam::CreateInstance(LPUNKNOWN lpunk, HRESULT *phr) // debug console window // OpenSpoutConsole(); // Empty console // EnableSpoutLog(); // Show error logs - // printf("SpoutCamDX ~~ Vers 2.021\n"); + // printf("SpoutCamDX ~~ Vers 2.023\n"); // For clear options dialog for scaled display SetProcessDPIAware(); @@ -512,7 +518,6 @@ HRESULT CVCamStream::put_Settings(DWORD dwFps, DWORD dwResolution, DWORD dwMirro CVCamStream::CVCamStream(HRESULT *phr, CVCam *pParent, LPCWSTR pPinName) : CSourceStream(NAME(SPOUTCAMNAME), phr, pParent, pPinName), m_pParent(pParent) //VS: replaced SpoutCamName with makro SPOUTCAMNAME, NAME() expects LPCTSTR { - g_pd3dDevice = nullptr; bDXinitialized = false; // DirectX bMemoryMode = false; // Default mode is texture, true means memoryshare bInvert = true; // Not currently used @@ -521,6 +526,10 @@ CVCamStream::CVCamStream(HRESULT *phr, CVCam *pParent, LPCWSTR pPinName) : g_Height = 480; g_SenderName[0] = 0; g_ActiveSender[0] = 0; + + // Maximum precision of timeGetTime used in FillBuffer + timeGetDevCaps(&g_caps, sizeof(g_caps)); + timeBeginPeriod(g_caps.wPeriodMin); // // Retrieve fps and resolution from registry "SpoutCamConfig" @@ -717,6 +726,10 @@ CVCamStream::~CVCamStream() if (bDXinitialized) receiver.CleanupDX11(); + + // End timer precision + timeEndPeriod(g_caps.wPeriodMin); + } HRESULT CVCamStream::QueryInterface(REFIID riid, void **ppv) @@ -753,7 +766,7 @@ HRESULT CVCamStream::FillBuffer(IMediaSample *pms) HRESULT hr = S_OK; BYTE *pData = nullptr; - VIDEOINFOHEADER *pvi = (VIDEOINFOHEADER *) m_mt.Format(); + VIDEOINFOHEADER *pvi = (VIDEOINFOHEADER *)m_mt.Format(); // If graph is inactive stop cueing samples if(!m_pParent->IsActive()) { @@ -763,66 +776,69 @@ HRESULT CVCamStream::FillBuffer(IMediaSample *pms) // Memory share mode not supported by DirectX if (bMemoryMode) return FALSE; - - /* + + // + // Timing - modified from Red5 method // - // Simple timing modifed from original Vcam - // https://github.com/johnmaccormick/MultiCam/blob/master/vcam/Filters.cpp - // Causes hesitations in some software - REFERENCE_TIME rtNow; - REFERENCE_TIME avgFrameTime = ((VIDEOINFOHEADER*)m_mt.pbFormat)->AvgTimePerFrame; - rtNow = m_rtLastTime; - m_rtLastTime += avgFrameTime; - pms->SetTime(&rtNow, &m_rtLastTime); - pms->SetSyncPoint(TRUE); - */ - // Timing from Red 5 - // Seems stable for more applications + // Set the timestamps that will govern playback frame rate. + // The current time is the sample's start. + REFERENCE_TIME rtNow = m_rtLastTime; + REFERENCE_TIME avgFrameTime = g_FrameTime; // Desired average frame time is set by the user - //create some working info - REFERENCE_TIME rtNow, rtDelta, rtDelta2 = 0;//delta for dropped, delta 2 for sleep. - REFERENCE_TIME avgFrameTime = ((VIDEOINFOHEADER*)m_mt.pbFormat)->AvgTimePerFrame; + // Create some working info + REFERENCE_TIME rtDelta, rtDelta2 = 0LL; // delta for dropped, delta 2 for sleep. - //What TIme is iT REALLY??? + // + // What time is it REALLY ??? + // m_pParent->GetSyncSource(&m_pClock); - - m_pClock->GetTime(&refSync1); - if (m_pClock) + if (m_pClock) { + m_pClock->GetTime(&refSync1); m_pClock->Release(); - if (NumFrames <= 1) - {//initiate values - refStart = refSync1;//FirstFrame No Drop. - refSync2 = 0; + } + else { + // Some programs do not implement the DirectShow clock and can crash if assumed + // so we can use TimeGetTime instead. Only millisecond precision, but so is Sleep. + refSync1 = (REFERENCE_TIME)timeGetTime() * 10000LL; // Cast before the multiply to avoid overflow + } + if (NumFrames <= 1) { + // initiate values + refStart = refSync1; // FirstFrame No Drop + refSync2 = 0; } rtNow = m_rtLastTime; m_rtLastTime = avgFrameTime + m_rtLastTime; - //IAMDropppedFrame. We only have avgFrameTime to generate image. - // Find generated stream time and compare to real elapsed time + // IAMDropppedFrame. We only have avgFrameTime to generate image. + // Find generated stream time and compare to real elapsed time. rtDelta = ((refSync1 - refStart) - (((NumFrames)*avgFrameTime) - avgFrameTime)); - - if (rtDelta - refSync2 < 0) - {//we are early + if (rtDelta - refSync2 < 0) { + // we are early rtDelta2 = rtDelta - refSync2; - if (abs(rtDelta2 / 10000) >= 1) - Sleep(abs(rtDelta2 / 10000)); + DWORD dwSleep = (DWORD)abs(rtDelta2 / 10000LL); + if (dwSleep >= 1) + Sleep(dwSleep); } - else if (rtDelta / avgFrameTime > NumDroppedFrames) - { //new dropped frame + else if (rtDelta / avgFrameTime > NumDroppedFrames) { + // new dropped frame NumDroppedFrames = rtDelta / avgFrameTime; // Figure new RT for sleeping refSync2 = NumDroppedFrames * avgFrameTime; - //Our time stamping needs adjustment. - //Find total real stream time from start time + // Our time stamping needs adjustment. + // Find total real stream time from start time. rtNow = refSync1 - refStart; m_rtLastTime = rtNow + avgFrameTime; pms->SetDiscontinuity(true); } - pms->SetTime(&rtNow, &m_rtLastTime); - pms->SetSyncPoint(TRUE); + + // The SetTime method sets the stream times when this sample should begin and finish. + hr = pms->SetTime(&rtNow, &m_rtLastTime); + // Set true on every sample for uncompressed frames + hr = pms->SetSyncPoint(true); + // ============== END OF INITIAL TIMING ============ // Check access to the sample's data buffer pms->GetPointer(&pData); @@ -838,7 +854,6 @@ HRESULT CVCamStream::FillBuffer(IMediaSample *pms) return NOERROR; } - // Sizes should be OK, but check again unsigned int size = (unsigned int)pms->GetSize(); // TODO : check imagesize = width*height*3; @@ -859,32 +874,31 @@ HRESULT CVCamStream::FillBuffer(IMediaSample *pms) if (!receiver.OpenDirectX11()) { return NOERROR; } - g_pd3dDevice = receiver.GetDevice(); bDXinitialized = true; } // endif !bDXinitialized - else { - // Get bgr pixels from the sender bgra shared texture - // ReceiveImage handles sender detection, connection and copy of pixels - if (receiver.ReceiveImage(pData, g_Width, g_Height, true, bInvert)) { - // rgb(not rgba) = true, invert = true - // If IsUpdated() returns true, the sender has changed - if (receiver.IsUpdated()) { - if (strcmp(g_SenderName, receiver.GetSenderName()) != 0) { - // Only test for change of sender name. - // The pixel buffer (pData) remains the same size and - // ReceiveImage uses resampling for a different texture size - strcpy_s(g_SenderName, 256, receiver.GetSenderName()); - // Set the sender name to the registry for SpoutCamSettings - WritePathToRegistry(HKEY_CURRENT_USER, "Software\\Leading Edge\\SpoutCam", "sendername", g_SenderName); - } + + // DirectX is initialized OK + // Get bgr pixels from the sender bgra shared texture + // ReceiveImage handles sender detection, connection and copy of pixels + if (receiver.ReceiveImage(pData, g_Width, g_Height, true, bInvert)) { + // rgb(not rgba) = true, invert = true + // If IsUpdated() returns true, the sender has changed + if (receiver.IsUpdated()) { + if (strcmp(g_SenderName, receiver.GetSenderName()) != 0) { + // Only test for change of sender name. + // The pixel buffer (pData) remains the same size and + // ReceiveImage uses resampling for a different texture size + strcpy_s(g_SenderName, 256, receiver.GetSenderName()); + // Set the sender name to the registry for SpoutCamSettings + WritePathToRegistry(HKEY_CURRENT_USER, "Software\\Leading Edge\\SpoutCam", "sendername", g_SenderName); } - bInitialized = true; - NumFrames++; - return NOERROR; - } - else { - ReleaseCamReceiver(); } + bInitialized = true; + NumFrames++; + return NOERROR; + } + else { + ReleaseCamReceiver(); } ShowStatic : @@ -989,7 +1003,6 @@ HRESULT CVCamStream::GetMediaType(int iPosition, CMediaType *pmt) const GUID SubTypeGUID = GetBitmapSubtype(&pvi->bmiHeader); pmt->SetSubtype(&SubTypeGUID); pmt->SetVariableSize(); // LJ - to be checked - pmt->SetSampleSize(pvi->bmiHeader.biSizeImage); return NOERROR; diff --git a/source/cam.h b/source/cam.h index ab62785..08b3cda 100644 --- a/source/cam.h +++ b/source/cam.h @@ -31,6 +31,11 @@ #include "..\SpoutDX\source\SpoutDX.h" #include +// LJ DEBUG +#include +#include +using namespace std::chrono_literals; + //<==================== VS-START ====================> #include "dshowutil.h" @@ -210,7 +215,6 @@ class CVCamStream : public CSourceStream, public IAMStreamConfig, public IKsProp char g_SenderName[256]; char g_ActiveSender[256]; // The name of any Spout sender being received - ID3D11Device* g_pd3dDevice; // DirectX 11.0 device pointer bool bMemoryMode; // true = memory, false = texture bool bInvert; bool bInitialized; @@ -222,6 +226,7 @@ class CVCamStream : public CSourceStream, public IAMStreamConfig, public IKsProp DWORD dwFps; // Fps from SpoutCamConfig DWORD dwResolution; // Resolution from SpoutCamConfig int g_FrameTime; // Frame time to use based on fps selection + TIMECAPS g_caps; // Timer capability for Sleep precision private: diff --git a/source/camprops.cpp b/source/camprops.cpp index 8205847..f3f2d48 100644 --- a/source/camprops.cpp +++ b/source/camprops.cpp @@ -112,23 +112,23 @@ HRESULT CSpoutCamProperties::OnActivate() hwndCtl = GetDlgItem(this->m_Dlg, IDC_FPS); - char fps_values[6][3] = + WCHAR fps_values[6][3] = { - "10", - "15", - "25", - "30", // default - "50", - "60" + L"10", + L"15", + L"25", + L"30", // default + L"50", + L"60" }; - char fps[3]; + WCHAR fps[3]; int k = 0; memset(&fps, 0, sizeof(fps)); for (k = 0; k <= 5; k += 1) { - strcpy_s(fps, sizeof(fps) / sizeof(char), (char*)fps_values[k]); + wcscpy_s(fps, sizeof(fps) / sizeof(WCHAR), fps_values[k]); ComboBox_AddString(hwndCtl, fps); } @@ -147,26 +147,26 @@ HRESULT CSpoutCamProperties::OnActivate() hwndCtl = GetDlgItem(this->m_Dlg, IDC_RESOLUTION); - char res_values[11][14] = + WCHAR res_values[11][14] = { - "Active Sender", - "320 x 240", - "640 x 360", - "640 x 480", // default if no sender - "800 x 600", - "1024 x 720", - "1024 x 768", - "1280 x 720", - "1280 x 960", - "1280 x 1024", - "1920 x 1080" + L"Active Sender", + L"320 x 240", + L"640 x 360", + L"640 x 480", // default if no sender + L"800 x 600", + L"1024 x 720", + L"1024 x 768", + L"1280 x 720", + L"1280 x 960", + L"1280 x 1024", + L"1920 x 1080" }; - char res[14]; + WCHAR res[14]; memset(&res, 0, sizeof(res)); for (k = 0; k <= 10; k += 1) { - strcpy_s(res, sizeof(res) / sizeof(char), (char*)res_values[k]); + wcscpy_s(res, sizeof(res) / sizeof(WCHAR), res_values[k]); ComboBox_AddString(hwndCtl, res); } @@ -208,7 +208,7 @@ HRESULT CSpoutCamProperties::OnActivate() // Show SpoutCam version hwndCtl = GetDlgItem(this->m_Dlg, IDC_VERS); - Static_SetText(hwndCtl, "Version: " _VER_VERSION_STRING); + Static_SetText(hwndCtl, L"Version: " _VER_VERSION_STRING); m_bIsInitialized = TRUE; @@ -225,9 +225,9 @@ HRESULT CSpoutCamProperties::OnApplyChanges() { TRACE("OnApplyChanges"); - HWND hwndCtl; DWORD dwFps, dwResolution, dwMirror, dwSwap, dwFlip; + // ================================= // Get old fps and resolution for user warning DWORD dwOldFps, dwOldResolution; ReadDwordFromRegistry(HKEY_CURRENT_USER, "Software\\Leading Edge\\SpoutCam", "fps", &dwOldFps); @@ -238,16 +238,18 @@ HRESULT CSpoutCamProperties::OnApplyChanges() if (MessageBoxA(NULL, "For change of resolution or fps, you\nhave to stop and re-start SpoutCam\nDo you want to change ? ", "Warning", MB_YESNO | MB_TOPMOST | MB_ICONQUESTION) == IDNO) { if (dwOldFps != dwFps) ComboBox_SetCurSel(GetDlgItem(this->m_Dlg, IDC_FPS), dwOldFps); - if(dwOldResolution != dwResolution) + if (dwOldResolution != dwResolution) ComboBox_SetCurSel(GetDlgItem(this->m_Dlg, IDC_RESOLUTION), dwOldResolution); return -1; } } + // ================================= + WriteDwordToRegistry(HKEY_CURRENT_USER, "Software\\Leading Edge\\SpoutCam", "fps", dwFps); WriteDwordToRegistry(HKEY_CURRENT_USER, "Software\\Leading Edge\\SpoutCam", "resolution", dwResolution); - hwndCtl = GetDlgItem(this->m_Dlg, IDC_MIRROR); + HWND hwndCtl = GetDlgItem(this->m_Dlg, IDC_MIRROR); dwMirror = Button_GetCheck(hwndCtl); WriteDwordToRegistry(HKEY_CURRENT_USER, "Software\\Leading Edge\\SpoutCam", "mirror", dwMirror); @@ -258,7 +260,7 @@ HRESULT CSpoutCamProperties::OnApplyChanges() hwndCtl = GetDlgItem(this->m_Dlg, IDC_FLIP); dwFlip = Button_GetCheck(hwndCtl); WriteDwordToRegistry(HKEY_CURRENT_USER, "Software\\Leading Edge\\SpoutCam", "flip", dwFlip); - + if (m_pCamSettings) m_pCamSettings->put_Settings(dwFps, dwResolution, dwMirror, dwSwap, dwFlip); diff --git a/source/camprops.h b/source/camprops.h index 34e9d72..951dca8 100644 --- a/source/camprops.h +++ b/source/camprops.h @@ -13,13 +13,12 @@ class CSpoutCamProperties : public CBasePropertyPage HRESULT OnConnect(IUnknown *pUnknown); HRESULT OnDisconnect(); HRESULT OnActivate(); - // HRESULT OnDeactivate(); + //HRESULT OnDeactivate(); HRESULT OnApplyChanges(); CSpoutCamProperties(LPUNKNOWN lpunk, HRESULT *phr); BOOL m_bIsInitialized; // Used to ignore startup messages ICamSettings *m_pCamSettings; // The custom interface on the filter - }; diff --git a/source/dll.cpp b/source/dll.cpp index c045162..84c8638 100644 --- a/source/dll.cpp +++ b/source/dll.cpp @@ -140,21 +140,23 @@ HRESULT RegisterFilter( STDAPI RegisterFilters( BOOL bRegister ) { + ASSERT(g_hInst != 0); + HRESULT hr = NOERROR; WCHAR achFileName[MAX_PATH]; - char achTemp[MAX_PATH]; - ASSERT(g_hInst != 0); - - if( 0 == GetModuleFileNameA(g_hInst, achTemp, sizeof(achTemp))) - return AmHresultFromWin32(GetLastError()); + + //<==================== VS-START ====================> + if (0 == GetModuleFileNameW(g_hInst, achFileName, sizeof(achFileName))) + { + return AmHresultFromWin32(GetLastError()); + } + //<==================== VS-END ====================> - MultiByteToWideChar(CP_ACP, 0L, achTemp, lstrlenA(achTemp) + 1, - achFileName, NUMELMS(achFileName)); - hr = CoInitialize(0); if(bRegister) { hr = AMovieSetupRegisterServer(CLSID_SpoutCam, SpoutCamName, achFileName, L"Both", L"InprocServer32"); + hr = AMovieSetupRegisterServer(CLSID_SpoutCamPropertyPage, L"Settings", achFileName, L"Both", L"InprocServer32"); //VS } if( SUCCEEDED(hr) ) @@ -184,8 +186,11 @@ STDAPI RegisterFilters( BOOL bRegister ) fm->Release(); } - if( SUCCEEDED(hr) && !bRegister ) - hr = AMovieSetupUnregisterServer( CLSID_SpoutCam ); + if (SUCCEEDED(hr) && !bRegister) + { + hr = AMovieSetupUnregisterServer(CLSID_SpoutCam); + hr = AMovieSetupUnregisterServer(CLSID_SpoutCamPropertyPage); //VS + } CoFreeUnusedLibraries(); CoUninitialize(); @@ -196,20 +201,12 @@ STDAPI RegisterFilters( BOOL bRegister ) // see http://msdn.microsoft.com/en-us/library/windows/desktop/dd376682%28v=vs.85%29.aspx STDAPI DllRegisterServer() { - //<==================== VS-START ====================> - HRESULT hr = RegisterFilters(TRUE); - if (SUCCEEDED(hr)) hr = AMovieDllRegisterServer2(TRUE); - return hr; - //<==================== VS-END ======================> + return RegisterFilters(TRUE); } STDAPI DllUnregisterServer() { - //<==================== VS-START ====================> - HRESULT hr = RegisterFilters(FALSE); - if (SUCCEEDED(hr)) hr = AMovieDllRegisterServer2(FALSE); - return hr; - //<==================== VS-END ======================> + return RegisterFilters(FALSE); } //<==================== VS-START ====================> diff --git a/source/version.h b/source/version.h index 9ff6e3b..fb2043c 100644 --- a/source/version.h +++ b/source/version.h @@ -9,7 +9,7 @@ #define _VER_MAJORVERSION_STRING "2" #define _VER_MINORVERSION 1 -#define _VER_MINORVERSION_STRING "022" +#define _VER_MINORVERSION_STRING "023" #define _VER_BUGFIXVERSION 0 #define _VER_BUGFIXVERSION_STRING "0"