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"