Przeglądaj źródła

1、实现CFormView来显示UB530视频采集;

scbc.sat2 5 lat temu
rodzic
commit
ba180c02ad

+ 42 - 11
SATHelper/SATHelper/MainFrm.cpp

@@ -67,6 +67,8 @@ CMainFrame::CMainFrame() noexcept :m_trayIcon(IDR_MAINFRAME)
 	{
 		m_pViewIDE[i] = NULL;
 	}
+
+	m_pUB530View = m_pDeviceView = NULL;
 }
 
 CMainFrame::~CMainFrame()
@@ -269,37 +271,56 @@ int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
 
 #if 0 // 第一个视图;
 	CCreateContext context;
-	CChildFrame* pChildFrame = new CChildFrame();
+	m_pUB530View = new CChildFrame();
 	context.m_pLastView = NULL;
 	context.m_pCurrentFrame = this;
 	context.m_pCurrentDoc = m_pDoc;
 	context.m_pNewViewClass = RUNTIME_CLASS(CSATHelperView);
 	context.m_pNewDocTemplate = m_pDoc->GetDocTemplate();
-	if (pChildFrame->LoadFrame(1100, WS_MAXIMIZE | WS_OVERLAPPEDWINDOW /*WS_CHILDWINDOW*/, this, &context))
+	if (m_pUB530View->LoadFrame(1100, WS_MAXIMIZE | WS_OVERLAPPEDWINDOW /*WS_CHILDWINDOW*/, this, &context))
 	{
-		pChildFrame->ShowWindow(SW_SHOWMAXIMIZED);
-		pChildFrame->InitialUpdateFrame(context.m_pCurrentDoc, TRUE);
-		pChildFrame->MDIActivate();
+		//m_pUB530View->ShowWindow(SW_SHOWMAXIMIZED);
+		m_pUB530View->InitialUpdateFrame(context.m_pCurrentDoc, TRUE);
+		//m_pUB530View->MDIActivate();
 	}
 #endif
 
 #if 1 // 第一个视图;
 	CCreateContext context;
-	CChildFrame* pChildFrame = new CChildFrame();
+	m_pUB530View = new CChildFrame();
 	context.m_pLastView = NULL;
 	context.m_pCurrentFrame = this;
 	context.m_pCurrentDoc = m_pDoc;
-	context.m_pNewViewClass = RUNTIME_CLASS(CDeviceView);
+	context.m_pNewViewClass = RUNTIME_CLASS(CUB530View);
 	context.m_pNewDocTemplate = m_pDoc->GetDocTemplate();
+	if (m_pUB530View->LoadFrame(DLG_UB530VIEW, WS_MAXIMIZE | WS_OVERLAPPEDWINDOW /*WS_CHILDWINDOW*/, this, &context))
+	{
+		//m_pUB530View->ShowWindow(SW_SHOWMAXIMIZED);
+		m_pUB530View->InitialUpdateFrame(context.m_pCurrentDoc, TRUE);
+		//m_pUB530View->MDIActivate();
+	}
+#endif
+
+#if 2 // 第二个视图;
+	CCreateContext context2;
+	m_pDeviceView = new CChildFrame();
+	context2.m_pLastView = NULL;
+	context2.m_pCurrentFrame = this;
+	context2.m_pCurrentDoc = m_pDoc;
+	context2.m_pNewViewClass = RUNTIME_CLASS(CDeviceView);
+	context2.m_pNewDocTemplate = m_pDoc->GetDocTemplate();
 	// 说明:DLG_DEVICEMANAGER对话框的Style属性必须设置成Child才能LoadFrame成功;
-	if (pChildFrame->LoadFrame(DLG_DEVICEMANAGER, WS_MAXIMIZE | WS_CHILDWINDOW, this, &context))
+	if (m_pDeviceView->LoadFrame(DLG_DEVICEMANAGER, WS_MAXIMIZE | WS_CHILDWINDOW, this, &context2))
 	{
-		pChildFrame->ShowWindow(SW_SHOWMAXIMIZED);
-		pChildFrame->InitialUpdateFrame(NULL, TRUE);
-		pChildFrame->MDIActivate();
+		//m_pDeviceView->ShowWindow(SW_SHOWMAXIMIZED);
+		m_pDeviceView->InitialUpdateFrame(NULL, TRUE);
+		//m_pDeviceView->MDIActivate();
 	}
 #endif
 
+	m_pUB530View->MDIActivate();
+	m_pUB530View->ShowWindow(SW_SHOWMAXIMIZED);
+
 	return 0;
 }
 
@@ -695,6 +716,11 @@ LRESULT CMainFrame::OnRibbonChanged(WPARAM wParam, LPARAM lParam)
 	if (nCategory == 1)
 	{
 		AfxMessageBox(_T("视频Ribbon"));
+		if (m_pUB530View)
+		{
+			m_pUB530View->MDIActivate();
+			m_pUB530View->ShowWindow(SW_SHOWMAXIMIZED);
+		}
 	}
 	else if (nCategory == 2)
 	{
@@ -702,6 +728,11 @@ LRESULT CMainFrame::OnRibbonChanged(WPARAM wParam, LPARAM lParam)
 		CView *pView = ((CFrameWnd*)(AfxGetApp()->m_pMainWnd))->GetActiveFrame()->GetActiveView();
 		//pView->ShowWindow(SW_HIDE);
 		//CDeviceView view;
+		if (m_pDeviceView)
+		{
+			m_pDeviceView->MDIActivate();
+			m_pDeviceView->ShowWindow(SW_SHOWMAXIMIZED);
+		}
 	}
 
 	return LRESULT();

+ 3 - 0
SATHelper/SATHelper/MainFrm.h

@@ -23,6 +23,7 @@
 #include "SATHelperView.h"
 #include "ChildFrm.h"
 #include "DeviceView.h"
+#include "UB530View.h"
 //////////////////////////////////////////////////////////////////////////
 #include "TrayIcon.h"
 #define USE_TRAYICON 1
@@ -46,6 +47,8 @@ public:
 	CSATHelperDoc* m_pDoc;
 	CFormView* m_pActiveView;
 	CChildFrame* m_pViewIDE[10];
+	CChildFrame* m_pUB530View;
+	CChildFrame* m_pDeviceView;
 
 // 操作
 public:

+ 1 - 0
SATHelper/SATHelper/MemoryClient.cpp

@@ -5,6 +5,7 @@
 #include "Global.h"
 #include "MainFrm.h"
 
+CFormView* CMemoryClient::m_pView2 = NULL;
 CSATHelperView* CMemoryClient::m_pView = NULL;
 HANDLE CMemoryClient::m_hRecordFile = NULL;
 HANDLE CMemoryClient::m_hThreadAudio = NULL;

+ 1 - 0
SATHelper/SATHelper/MemoryClient.h

@@ -22,6 +22,7 @@ private:
 	static HANDLE m_hThreadAudio;
 public:
 	static CSATHelperView* m_pView;
+	static CFormView* m_pView2;
 	static HANDLE m_hRecordFile;
 	BOOL StartThread();
 	void EndOfThread();

+ 3 - 2
SATHelper/SATHelper/Resource.h

@@ -112,8 +112,9 @@
 #define IDR_RIBBON                      307
 #define IDB_CHECKED                     310
 #define IDB_UNCHECKED                   311
-#define IDD_DIALOG1                     312
 #define DLG_DEVICEMANAGER               312
+#define DLG_UB530                       314
+#define DLG_UB530VIEW                   314
 #define ID_WRITE_PASTEASHYPERLINK       32770
 #define ID_TRAYMENU_RECONNECT           32771
 #define ID_TRAYMENU_EXIT                32772
@@ -139,7 +140,7 @@
 // 
 #ifdef APSTUDIO_INVOKED
 #ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE        314
+#define _APS_NEXT_RESOURCE_VALUE        316
 #define _APS_NEXT_COMMAND_VALUE         32775
 #define _APS_NEXT_CONTROL_VALUE         1000
 #define _APS_NEXT_SYMED_VALUE           310

+ 2 - 2
SATHelper/SATHelper/SATHelper.cpp

@@ -80,7 +80,7 @@ CSATHelperApp theApp;
 CIOCPModel g_iocp;
 HANDLE g_hMutex = NULL;	// 全局互斥量;
 ULONG_PTR CSATHelperApp::m_gdiplusToken = 0;
-
+CMainFrame* g_pMainFrame = NULL;
 // CMainFrame* g_pMainFrame = NULL;
 
 BOOL CSATHelperApp::InitInstance()
@@ -202,7 +202,7 @@ BOOL CSATHelperApp::InitInstance()
 		delete pMainFrame;
 		return FALSE;
 	}
-	m_pMainWnd = pMainFrame;
+	m_pMainWnd = g_pMainFrame = pMainFrame;
 
 
 	// 分析标准 shell 命令、DDE、打开文件操作的命令行

+ 19 - 0
SATHelper/SATHelper/SATHelper.rc

@@ -449,6 +449,12 @@ BEGIN
     PUSHBUTTON      "取消",IDCANCEL,255,156,50,14
 END
 
+DLG_UB530VIEW DIALOGEX 0, 0, 310, 176
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_BORDER
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+END
+
 
 /////////////////////////////////////////////////////////////////////////////
 //
@@ -512,6 +518,14 @@ BEGIN
         TOPMARGIN, 7
         BOTTOMMARGIN, 170
     END
+
+    DLG_UB530VIEW, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 303
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 169
+    END
 END
 #endif    // APSTUDIO_INVOKED
 
@@ -534,6 +548,11 @@ BEGIN
     0
 END
 
+DLG_UB530VIEW AFX_DIALOG_LAYOUT
+BEGIN
+    0
+END
+
 
 /////////////////////////////////////////////////////////////////////////////
 //

+ 2 - 0
SATHelper/SATHelper/SATHelper.vcxproj

@@ -233,6 +233,7 @@
     <ClInclude Include="targetver.h" />
     <ClInclude Include="tinyxml2.h" />
     <ClInclude Include="TrayIcon.h" />
+    <ClInclude Include="UB530View.h" />
     <ClInclude Include="ViewTree.h" />
   </ItemGroup>
   <ItemGroup>
@@ -279,6 +280,7 @@
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
     </ClCompile>
     <ClCompile Include="TrayIcon.cpp" />
+    <ClCompile Include="UB530View.cpp" />
     <ClCompile Include="ViewTree.cpp" />
   </ItemGroup>
   <ItemGroup>

+ 50 - 35
SATHelper/SATHelper/SATHelper.vcxproj.filters

@@ -28,6 +28,15 @@
     <Filter Include="UI">
       <UniqueIdentifier>{71b6c470-1206-4d26-a155-8475a6ffec8a}</UniqueIdentifier>
     </Filter>
+    <Filter Include="tinyxml">
+      <UniqueIdentifier>{e0676784-5cf9-4107-9f3c-f3653d4d18e0}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="内存通信">
+      <UniqueIdentifier>{40141f1d-97c3-4250-b0f8-212872fba529}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="串口">
+      <UniqueIdentifier>{ed995c5b-408e-413c-93ea-67ed56e847fc}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="SATHelper.h">
@@ -54,9 +63,6 @@
     <ClInclude Include="Resource.h">
       <Filter>头文件</Filter>
     </ClInclude>
-    <ClInclude Include="ViewTree.h">
-      <Filter>头文件</Filter>
-    </ClInclude>
     <ClInclude Include="stdafx.h">
       <Filter>头文件</Filter>
     </ClInclude>
@@ -114,27 +120,9 @@
     <ClInclude Include="Global.h">
       <Filter>头文件</Filter>
     </ClInclude>
-    <ClInclude Include="MemoryClient.h">
-      <Filter>头文件</Filter>
-    </ClInclude>
-    <ClInclude Include="MemoryComm.h">
-      <Filter>头文件</Filter>
-    </ClInclude>
-    <ClInclude Include="MemoryDef.h">
-      <Filter>头文件</Filter>
-    </ClInclude>
     <ClInclude Include="QCAP.H">
       <Filter>头文件</Filter>
     </ClInclude>
-    <ClInclude Include="stdint.h">
-      <Filter>头文件</Filter>
-    </ClInclude>
-    <ClInclude Include="SynSerial.h">
-      <Filter>头文件</Filter>
-    </ClInclude>
-    <ClInclude Include="tinyxml2.h">
-      <Filter>头文件</Filter>
-    </ClInclude>
     <ClInclude Include="TrayIcon.h">
       <Filter>头文件</Filter>
     </ClInclude>
@@ -150,6 +138,30 @@
     <ClInclude Include="DeviceView.h">
       <Filter>头文件</Filter>
     </ClInclude>
+    <ClInclude Include="tinyxml2.h">
+      <Filter>tinyxml</Filter>
+    </ClInclude>
+    <ClInclude Include="stdint.h">
+      <Filter>tinyxml</Filter>
+    </ClInclude>
+    <ClInclude Include="MemoryComm.h">
+      <Filter>内存通信</Filter>
+    </ClInclude>
+    <ClInclude Include="MemoryClient.h">
+      <Filter>内存通信</Filter>
+    </ClInclude>
+    <ClInclude Include="MemoryDef.h">
+      <Filter>内存通信</Filter>
+    </ClInclude>
+    <ClInclude Include="SynSerial.h">
+      <Filter>串口</Filter>
+    </ClInclude>
+    <ClInclude Include="ViewTree.h">
+      <Filter>DockPane</Filter>
+    </ClInclude>
+    <ClInclude Include="UB530View.h">
+      <Filter>头文件</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="SATHelper.cpp">
@@ -167,9 +179,6 @@
     <ClCompile Include="SATHelperView.cpp">
       <Filter>源文件</Filter>
     </ClCompile>
-    <ClCompile Include="ViewTree.cpp">
-      <Filter>源文件</Filter>
-    </ClCompile>
     <ClCompile Include="stdafx.cpp">
       <Filter>源文件</Filter>
     </ClCompile>
@@ -227,28 +236,34 @@
     <ClCompile Include="Global.cpp">
       <Filter>源文件</Filter>
     </ClCompile>
-    <ClCompile Include="MemoryClient.cpp">
+    <ClCompile Include="TrayIcon.cpp">
       <Filter>源文件</Filter>
     </ClCompile>
-    <ClCompile Include="MemoryComm.cpp">
-      <Filter>源文件</Filter>
+    <ClCompile Include="IOCPModel.cpp">
+      <Filter>iocp</Filter>
     </ClCompile>
-    <ClCompile Include="SynSerial.cpp">
+    <ClCompile Include="IRControlWnd.cpp">
+      <Filter>DockPane</Filter>
+    </ClCompile>
+    <ClCompile Include="DeviceView.cpp">
       <Filter>源文件</Filter>
     </ClCompile>
     <ClCompile Include="tinyxml2.cpp">
-      <Filter>源文件</Filter>
+      <Filter>tinyxml</Filter>
     </ClCompile>
-    <ClCompile Include="TrayIcon.cpp">
-      <Filter>源文件</Filter>
+    <ClCompile Include="MemoryClient.cpp">
+      <Filter>内存通信</Filter>
     </ClCompile>
-    <ClCompile Include="IOCPModel.cpp">
-      <Filter>iocp</Filter>
+    <ClCompile Include="MemoryComm.cpp">
+      <Filter>内存通信</Filter>
     </ClCompile>
-    <ClCompile Include="IRControlWnd.cpp">
+    <ClCompile Include="SynSerial.cpp">
+      <Filter>串口</Filter>
+    </ClCompile>
+    <ClCompile Include="ViewTree.cpp">
       <Filter>DockPane</Filter>
     </ClCompile>
-    <ClCompile Include="DeviceView.cpp">
+    <ClCompile Include="UB530View.cpp">
       <Filter>源文件</Filter>
     </ClCompile>
   </ItemGroup>

+ 2 - 2
SATHelper/SATHelper/SATHelperView.cpp

@@ -30,7 +30,7 @@
 
 
 CMemoryClient g_ub530;
-static CMainFrame* g_pMainFrame = NULL;
+extern CMainFrame* g_pMainFrame;
 
 
 VOID Dbg(CHAR* pszStr, ...)
@@ -987,7 +987,7 @@ int CSATHelperView::OnCreate(LPCREATESTRUCT lpCreateStruct)
 	g_ub530.InitMemery();
 	g_ub530.StartThread();
 
-	g_pMainFrame = (CMainFrame*)this->GetParent();
+	//g_pMainFrame = (CMainFrame*)this->GetParent();
 
 	// TODO:  在此添加您专用的创建代码
 	// 创建视频流,并关联指定显示窗口;

+ 1133 - 0
SATHelper/SATHelper/UB530View.cpp

@@ -0,0 +1,1133 @@
+// UB530View.cpp: 实现文件
+//
+
+#include "stdafx.h"
+#include "SATHelper.h"
+#include "UB530View.h"
+#include "MainFrm.h"
+
+extern CMemoryClient g_ub530;
+extern CMainFrame* g_pMainFrame;
+
+VOID Dbg2(CHAR* pszStr, ...)
+{
+	char szData[MAX_PATH] = "[SC] ";
+	va_list args;
+	va_start(args, pszStr);
+	_vsnprintf_s(szData + 5, MAX_PATH - 5, MAX_PATH - 6, pszStr, args);
+	va_end(args);
+	strcat_s(szData, "\n");
+	OutputDebugStringA(szData);
+}
+
+//  FORMAT CHANGED CALLBACK FUNCTION
+//
+QRETURN on_process_format_changed2(PVOID pDevice, ULONG nVideoInput, ULONG nAudioInput, ULONG nVideoWidth, ULONG nVideoHeight, BOOL bVideoIsInterleaved, double dVideoFrameRate, ULONG nAudioChannels, ULONG nAudioBitsPerSample, ULONG nAudioSampleFrequency, PVOID pUserData)
+{
+	//Dbg("format changed Detected  \n");
+	CUB530View* pView = (CUB530View*)pUserData;
+	if (pView == NULL) { return QCAP_RT_OK; }
+	if (pView->GetSafeHwnd() == NULL) { return QCAP_RT_OK; }
+
+	pView->m_nVideoWidth = nVideoWidth;
+	pView->m_nVideoHeight = nVideoHeight;
+	pView->m_bVideoIsInterleaved = bVideoIsInterleaved;
+	pView->m_dVideoFrameRate = dVideoFrameRate;
+	pView->m_nAudioChannels = nAudioChannels;
+	pView->m_nAudioBitsPerSample = nAudioBitsPerSample;
+	pView->m_nAudioSampleFrequency = nAudioSampleFrequency;
+	// OUTPUT FORMAT CHANGED MESSAGE
+	//
+	CHAR strVideoInput[MAX_PATH] = { 0 };
+	CHAR strAudioInput[MAX_PATH] = { 0 };
+	CHAR strFrameType[MAX_PATH] = { 0 };
+	UINT nVH = 0;
+
+	if (nVideoInput == 0) { sprintf_s(strVideoInput, "COMPOSITE"); }
+	if (nVideoInput == 1) { sprintf_s(strVideoInput, "SVIDEO"); }
+	if (nVideoInput == 2) { sprintf_s(strVideoInput, "HDMI"); }
+	if (nVideoInput == 3) { sprintf_s(strVideoInput, "DVI_D"); }
+	if (nVideoInput == 4) { sprintf_s(strVideoInput, "COMPONENTS (YCBCR)"); }
+	if (nVideoInput == 5) { sprintf_s(strVideoInput, "DVI_A (RGB / VGA)"); }
+	if (nVideoInput == 6) { sprintf_s(strVideoInput, "SDI"); }
+	if (nVideoInput == 7) { sprintf_s(strVideoInput, "AUTO"); }
+	if (nAudioInput == 0) { sprintf_s(strAudioInput, "EMBEDDED_AUDIO"); }
+	if (nAudioInput == 1) { sprintf_s(strAudioInput, "LINE_IN"); }
+
+	if (bVideoIsInterleaved == TRUE) { nVH = nVideoHeight / 2; }
+	else { nVH = nVideoHeight; }
+
+	if (bVideoIsInterleaved == TRUE) { sprintf_s(strFrameType, " I "); }
+	else { sprintf_s(strFrameType, " P "); }
+
+	pView->m_strFormatChangedOutput.Format(
+		_T("INFO : %d x %d%s @%2.3f FPS , %d CH x %d BITS x %d HZ ,  VIDEO INPUT : %s ,  AUDIO INPUT : %s"),
+		nVideoWidth,
+		nVH,
+		strFrameType,
+		dVideoFrameRate,
+		nAudioChannels,
+		nAudioBitsPerSample,
+		nAudioSampleFrequency,
+		strVideoInput,
+		strAudioInput
+	);
+	Global::WriteTextLog(_T("采集卡格式变更:%d x %d%s @%2.3f FPS , %d CH x %d BITS x %d HZ ,  视频输入源 : %s ,  音频输入源 : %s"),
+		nVideoWidth,
+		nVH,
+		strFrameType,
+		dVideoFrameRate,
+		nAudioChannels,
+		nAudioBitsPerSample,
+		nAudioSampleFrequency,
+		strVideoInput,
+		strAudioInput);
+
+	::SendMessage(g_pMainFrame->m_hWnd, MSG_STATUS_BAR, (WPARAM)&pView->m_strFormatChangedOutput, ID_STATUSBAR_PANE1);
+
+	// NO SOURCE
+	//
+	if (nVideoWidth == 0 &&
+		nVideoHeight == 0 &&
+		dVideoFrameRate == 0.0 &&
+		nAudioChannels == 0 &&
+		nAudioBitsPerSample == 0 &&
+		nAudioSampleFrequency == 0)
+	{
+		pView->m_bNoSignal = TRUE;
+	}
+	else
+	{
+		pView->m_bNoSignal = FALSE;
+	}
+
+	pView->SetTimer(0x00000000, 1, NULL);
+
+	return QCAP_RT_OK;
+}
+
+// NO SIGNAL DETEACTED CALLBACK FUNCTION
+//
+QRETURN on_process_no_signal_detected2(PVOID pDevice, ULONG nVideoInput, ULONG nAudioInput, PVOID pUserData)
+{
+	AFX_MANAGE_STATE(AfxGetStaticModuleState());
+	CUB530View* pView = (CUB530View*)pUserData;
+
+	//Dbg("No Signal Detected  \n");
+	if (pView == NULL) { return QCAP_RT_OK; }
+	if (pView->GetSafeHwnd() == NULL) { return QCAP_RT_OK; }
+
+	//pView->SetRibbonStatusBarText("当前采集卡无信号。", ID_STATUSBAR_PANE1);
+	Global::WriteTextLog(_T("当前采集卡无信号"));
+	::SendMessage(g_pMainFrame->m_hWnd, MSG_STATUS_BAR, (WPARAM)&CString("当前采集卡无信号"), ID_STATUSBAR_PANE1);
+
+	pView->m_bNoSignal = TRUE;
+	pView->SetTimer(0x00000000, 1, NULL);
+
+	return QCAP_RT_OK;
+}
+
+// SIGNAL REMOVED CALLBACK FUNCTION
+//
+QRETURN on_process_signal_removed2(PVOID pDevice, ULONG nVideoInput, ULONG nAudioInput, PVOID pUserData)
+{
+	AFX_MANAGE_STATE(AfxGetStaticModuleState());
+	CUB530View* pView = (CUB530View*)pUserData;
+	if (pView == NULL) { return QCAP_RT_OK; }
+	if (pView->GetSafeHwnd() == NULL) { return QCAP_RT_OK; }
+
+	//pView->SetRibbonStatusBarText("当前采集卡信号被移除。", ID_STATUSBAR_PANE1);
+	Global::WriteTextLog(_T("当前采集卡信号被移除"));
+	::SendMessage(g_pMainFrame->m_hWnd, MSG_STATUS_BAR, (WPARAM)&CString("当前采集卡信号被移除"), ID_STATUSBAR_PANE1);
+
+	pView->m_bNoSignal = TRUE;
+	pView->SetTimer(0x00000000, 1, NULL);
+
+	return QCAP_RT_OK;
+}
+
+// PREVIEW VIDEO CALLBACK FUNCTION
+//
+QRETURN on_process_preview_video_buffer2(PVOID pDevice, double dSampleTime, BYTE* pFrameBuffer, ULONG nFrameBufferLen, PVOID pUserData)
+{
+	CUB530View* pView = (CUB530View*)pUserData;
+	if (pView)
+	{
+		// 尝试加锁;
+		if (!pView->m_mut_cpature.try_lock())
+		{
+#ifdef DEBUG
+			OutputDebugStringA("!pView->m_mut_cpature.try_lock()\n");
+#endif
+			return QCAP_RT_OK;
+		}
+
+		// 是否触发截图;
+		if (pView->m_bCaptureImage)
+		{
+			// 加锁;
+			std::lock_guard<std::mutex> lk(pView->m_mut_thread);
+			// 复制数据;
+			pView->m_dwBufferLen = nFrameBufferLen;
+			pView->m_pBuffer = new BYTE[nFrameBufferLen];
+			memcpy(pView->m_pBuffer, pFrameBuffer, nFrameBufferLen);
+			// 通知线程保存图片;
+			pView->m_thread_cond.notify_one();
+			// 恢复截图标记,防止重复截图;
+			pView->m_bCaptureImage = FALSE;
+#ifdef DEBUG
+			OutputDebugStringA("preview_video_buffer:pView->m_bCaptureImage\n");
+#endif
+		}
+
+		// 解锁;
+		pView->m_mut_cpature.unlock();
+	}
+
+	return QCAP_RT_OK;
+}
+
+// PREVIEW AUDIO CALLBACK FUNCTION
+//
+QRETURN on_process_preview_audio_buffer2(PVOID pDevice, double dSampleTime, BYTE* pFrameBuffer, ULONG nFrameBufferLen, PVOID pUserData)
+{
+	return QCAP_RT_OK;
+}
+
+// VIDEO HARDARE ENCODER CALLBACK FUNCTION
+//
+QRETURN on_process_hardware_encoder_video_buffer2(PVOID pDevice, UINT iRecNum, double dSampleTime, BYTE* pFrameBuffer, ULONG nFrameBufferLen, BOOL bIsKeyFrame, PVOID pUserData)
+{
+	return QCAP_RT_OK;
+}
+
+QRETURN on_process_snapshot_done2(PVOID pDevice, CHAR* pszFilePathName, PVOID pUserData)
+{
+	return QCAP_RT_OK;
+}
+
+QRETURN on_process_snapshot_stream2(PVOID pDevice, CHAR* pszFilePathName, BYTE* pStreamBuffer, ULONG nStreamBufferLen, PVOID pUserData)
+{
+	// 注意:在调用本回调函数前,已经保存了图片!
+	CUB530View* pView = (CUB530View*)pUserData;
+	if (pView->m_bHoriontal || pView->m_bVertically)
+		Global::SaveImgByRotate(pszFilePathName, pStreamBuffer, nStreamBufferLen, pView->m_bHoriontal, pView->m_bVertically);
+
+	return QCAP_RT_OK;
+}
+// CUB530View
+
+IMPLEMENT_DYNCREATE(CUB530View, CFormView)
+
+CUB530View::CUB530View(): CFormView(DLG_UB530VIEW)
+{
+	m_hVideoDevice = NULL;
+	m_bIsRecord = FALSE;
+	m_bNoSignal = FALSE;
+	m_bVertically = FALSE;
+	m_bHoriontal = FALSE;
+	m_bAppQuit = FALSE;
+	m_pBuffer = NULL;
+	m_bCaptureImage = FALSE;
+	m_dwBufferLen = 0;
+	m_bIsMp4 = TRUE;
+	m_bSupportGPU = FALSE;
+}
+
+CUB530View::~CUB530View()
+{
+	g_ub530.EndOfThread();
+	m_bAppQuit = TRUE;
+	HwUninitialize();
+}
+
+void CUB530View::DoDataExchange(CDataExchange* pDX)
+{
+	CFormView::DoDataExchange(pDX);
+}
+
+BEGIN_MESSAGE_MAP(CUB530View, CFormView)
+	///////////////////////////////////
+	ON_WM_TIMER()
+	ON_COMMAND(ID_CUT_BMP, &CUB530View::OnCutBmp)
+	ON_COMMAND(ID_CUT_JPG, &CUB530View::OnCutJpg)
+	ON_COMMAND(ID_START_RECORD, &CUB530View::OnStartRecord)
+	ON_COMMAND(ID_STOP_RECORD, &CUB530View::OnStopRecord)
+	ON_COMMAND(ID_CHECK_VERTICALLY, &CUB530View::OnCheckVertically)
+	ON_COMMAND(ID_CHECK_HORIONTAL, &CUB530View::OnCheckHoriontal)
+	ON_UPDATE_COMMAND_UI(ID_CHECK_VERTICALLY, &CUB530View::OnUpdateCheckVertically)
+	ON_UPDATE_COMMAND_UI(ID_CHECK_HORIONTAL, &CUB530View::OnUpdateCheckHoriontal)
+	ON_COMMAND(ID_TRAYMENU_RECONNECT, &CUB530View::OnTraymenuReconnect)
+	ON_COMMAND(ID_CHECK_SUPORT_GPU, &CUB530View::OnCheckSuportGpu)
+	ON_COMMAND(ID_CHECK_FORMAT_MP4, &CUB530View::OnCheckFormatMp4)
+	ON_COMMAND(ID_CHECK_FORMAT_AVI, &CUB530View::OnCheckFormatAvi)
+	ON_UPDATE_COMMAND_UI(ID_CHECK_SUPORT_GPU, &CUB530View::OnUpdateCheckSuportGpu)
+	ON_UPDATE_COMMAND_UI(ID_CHECK_FORMAT_MP4, &CUB530View::OnUpdateCheckFormatMp4)
+	ON_UPDATE_COMMAND_UI(ID_CHECK_FORMAT_AVI, &CUB530View::OnUpdateCheckFormatAvi)
+	ON_UPDATE_COMMAND_UI(ID_START_RECORD, &CUB530View::OnUpdateStartRecord)
+	ON_UPDATE_COMMAND_UI(ID_STOP_RECORD, &CUB530View::OnUpdateStopRecord)
+END_MESSAGE_MAP()
+
+
+// CUB530View 诊断
+
+#ifdef _DEBUG
+void CUB530View::AssertValid() const
+{
+	CFormView::AssertValid();
+}
+
+#ifndef _WIN32_WCE
+void CUB530View::Dump(CDumpContext& dc) const
+{
+	CFormView::Dump(dc);
+}
+#endif
+#endif //_DEBUG
+
+
+// CUB530View 消息处理程序
+
+
+void CUB530View::OnInitialUpdate()
+{
+	CFormView::OnInitialUpdate();
+
+	// TODO: 在此添加专用代码和/或调用基类
+	CMemoryClient::m_pView2 = this;
+	g_ub530.InitMemery();
+	g_ub530.StartThread();
+
+	//g_pMainFrame = (CMainFrame*)this->GetParent();
+
+	// TODO:  在此添加您专用的创建代码
+	// 创建视频流,并关联指定显示窗口;
+	HwInitialize();
+
+	// 创建截图线程;
+	std::thread t(CaptureImageThread, this);
+	t.detach();
+
+}
+
+
+void CUB530View::OnDraw(CDC* pDC)
+{
+	// TODO: 在此添加专用代码和/或调用基类
+	// TO FILL IN THE TEXT 
+	//
+	if (m_hVideoDevice == 0 || m_bNoSignal) {
+
+		CFont font;
+		ULONG nFontSize = 300;
+		font.CreatePointFont(nFontSize, TEXT("Arial"), NULL);
+		HFONT hOldFont = (HFONT)pDC->SelectObject(&font);
+		pDC->SetBkMode(TRANSPARENT);
+		pDC->SetTextColor(RGB(255, 255, 255));
+
+		CRect rect_client;
+		GetClientRect(&rect_client);
+
+		CString string = _T("");
+		if (m_hVideoDevice == 0)
+		{
+			CBrush brush_fill_rect(RGB(0, 0, 0));
+			pDC->FillRect(&rect_client, &brush_fill_rect);
+			string = TEXT("No Device");
+			//g_pMainFrame->SetRibbonStatusBarText("当前采集卡设备被移除。", ID_STATUSBAR_PANE1);
+		}
+		else if (m_bNoSignal)
+		{
+			CBrush brush_fill_rect(RGB(0, 0, 255));
+			pDC->FillRect(&rect_client, &brush_fill_rect);
+			string = TEXT("No Source");
+			//g_pMainFrame->SetRibbonStatusBarText("当前采集卡信号被移除。", ID_STATUSBAR_PANE1);
+		}
+		pDC->DrawText(string, &rect_client, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
+
+		pDC->SelectObject(&hOldFont);
+		font.DeleteObject();
+	}
+}
+
+
+BOOL CUB530View::HwInitialize()
+{
+	if (m_hVideoDevice != NULL)
+		return TRUE;
+
+	// CALLBACK FUNCTION       
+	PF_FORMAT_CHANGED_CALLBACK pFormatChangedCB = { 0 };
+	PF_VIDEO_PREVIEW_CALLBACK  pPreviewVideoCB = { 0 };
+	PF_AUDIO_PREVIEW_CALLBACK pPreviewAudioCB = { 0 };
+	PF_VIDEO_HARDWARE_ENCODER_CALLBACK pHardwareEncoderVideoCB = { 0 };
+	PF_NO_SIGNAL_DETECTED_CALLBACK pNoSignalDetectedCB = { 0 };
+	PF_SIGNAL_REMOVED_CALLBACK pSignalRemovedCB = { 0 };
+	PF_SNAPSHOT_DONE_CALLBACK pSnapShotDoneCB = { 0 };
+	PF_SNAPSHOT_STREAM_CALLBACK pSnapShotStreamCB = { 0 };
+	// CREATE CAPTURE DEVICE
+	//
+	if (m_hVideoDevice == NULL)
+		QCAP_CREATE("CY3014 USB", 0, m_hWnd, &m_hVideoDevice, 1);
+
+	if (m_hVideoDevice == NULL) {
+		return FALSE;
+	}
+
+	// REGISTER FORMAT CHANGED CALLBACK FUNCTION
+	pFormatChangedCB = on_process_format_changed2;
+	QCAP_REGISTER_FORMAT_CHANGED_CALLBACK(m_hVideoDevice, pFormatChangedCB, this);
+
+	// REGISTER PREVIEW VIDEO CALLBACK FUNCTION
+	pPreviewVideoCB = on_process_preview_video_buffer2;
+	QCAP_REGISTER_VIDEO_PREVIEW_CALLBACK(m_hVideoDevice, pPreviewVideoCB, this);
+
+	// REGISTER PREVIEW AUDIO CALLBACK FUNCTION
+	//pPreviewAudioCB = on_process_preview_audio_buffer;
+	//QCAP_REGISTER_AUDIO_PREVIEW_CALLBACK(m_hVideoDevice, pPreviewAudioCB, this);
+
+	// REGISTER HARDWARE ENCODER VIDEO CALLBACK FUNCTION
+	//pHardwareEncoderVideoCB = on_process_hardware_encoder_video_buffer;
+	//QCAP_REGISTER_VIDEO_HARDWARE_ENCODER_CALLBACK(m_hVideoDevice, 0, pHardwareEncoderVideoCB, this);
+
+	// REGISTER NO SIGNAL DETECTED CALLBACK FUNCTION
+	pNoSignalDetectedCB = on_process_no_signal_detected2;
+	QCAP_REGISTER_NO_SIGNAL_DETECTED_CALLBACK(m_hVideoDevice, pNoSignalDetectedCB, this);
+
+	// REGISTER SIGNAL REMOVED CALLBACK FUNCTION
+	pSignalRemovedCB = on_process_signal_removed2;
+	QCAP_REGISTER_SIGNAL_REMOVED_CALLBACK(m_hVideoDevice, pSignalRemovedCB, this);
+
+#if 1
+	// 
+	pSnapShotDoneCB = on_process_snapshot_done2;
+	QCAP_REGISTER_SNAPSHOT_DONE_CALLBACK(m_hVideoDevice, pSnapShotDoneCB, this);
+
+	// 
+	pSnapShotStreamCB = on_process_snapshot_stream2;
+	QCAP_REGISTER_SNAPSHOT_STREAM_CALLBACK(m_hVideoDevice, pSnapShotStreamCB, this);
+#endif
+
+	QCAP_SET_VIDEO_DEINTERLACE_TYPE(m_hVideoDevice, QCAP_SOFTWARE_DEINTERLACE_TYPE_BLENDING);
+
+	QCAP_SET_VIDEO_DEINTERLACE(m_hVideoDevice, 0);
+	QCAP_SET_AUDIO_VOLUME(m_hVideoDevice, 100);
+	QCAP_SET_VIDEO_HARDWARE_ENCODER_PROPERTY(m_hVideoDevice, 0, QCAP_ENCODER_FORMAT_H264, QCAP_RECORD_MODE_CBR, 8000, 12 * 1024 * 1024, 30, 0, 0, QCAP_DOWNSCALE_MODE_OFF, 0, 0);
+
+	QCAP_SET_VIDEO_INPUT(m_hVideoDevice, QCAP_INPUT_TYPE_AUTO);
+	QCAP_RUN(m_hVideoDevice);
+
+	// 刷新区域;
+	Invalidate();
+
+	// UPDATE USER INTERFACE RESOURCE
+	if (m_hVideoDevice == 0) {
+		/*m_oSetupDialog.m_btnVideoInput.EnableWindow(FALSE);
+		m_oSetupDialog.m_btnVideoQuality.EnableWindow(FALSE);
+		m_oSetupDialog.m_btnAudioInput.EnableWindow(FALSE);
+		m_oSetupDialog.m_btnSnapshot_bmp.EnableWindow(FALSE);
+		m_oSetupDialog.m_btnSnapshot_jpg.EnableWindow(FALSE);
+		m_oSetupDialog.m_btnRecordStart_1_1.EnableWindow(FALSE);
+		m_oSetupDialog.m_btnRecordStop_1_1.EnableWindow(FALSE);
+		m_oSetupDialog.m_btnRecordStart_1_2.EnableWindow(FALSE);
+		m_oSetupDialog.m_btnRecordStop_1_2.EnableWindow(FALSE);
+		m_oSetupDialog.m_btnRecordStart_1_3.EnableWindow(FALSE);
+		m_oSetupDialog.m_btnRecordStop_1_3.EnableWindow(FALSE);
+		m_oSetupDialog.m_checkGPU_1_1.EnableWindow(FALSE);
+		m_oSetupDialog.m_checkGPU_1_1.SetCheck(0);
+		m_oSetupDialog.m_checkGPU_1_2.EnableWindow(FALSE);
+		m_oSetupDialog.m_checkGPU_1_2.SetCheck(0);
+		m_oSetupDialog.m_checkGPU_1_3.EnableWindow(FALSE);
+		m_oSetupDialog.m_checkGPU_1_3.SetCheck(0);
+		m_oSetupDialog.m_checkAutoDeinterlace.EnableWindow(FALSE);
+		m_oSetupDialog.m_checkAutoDeinterlace.SetCheck(0);*/
+	}
+	else {
+		/*m_oSetupDialog.m_btnSnapshot_bmp.EnableWindow(TRUE);
+		m_oSetupDialog.m_btnSnapshot_jpg.EnableWindow(TRUE);
+		m_oSetupDialog.m_btnRecordStart_1_1.EnableWindow(TRUE);
+		m_oSetupDialog.m_btnRecordStop_1_1.EnableWindow(FALSE);
+		m_oSetupDialog.m_btnRecordStart_1_2.EnableWindow(TRUE);
+		m_oSetupDialog.m_btnRecordStop_1_2.EnableWindow(FALSE);
+		m_oSetupDialog.m_btnRecordStart_1_3.EnableWindow(TRUE);
+		m_oSetupDialog.m_btnRecordStop_1_3.EnableWindow(FALSE);
+		m_oSetupDialog.m_checkGPU_1_1.EnableWindow(FALSE);
+		m_oSetupDialog.m_checkGPU_1_1.SetCheck(0);
+		m_oSetupDialog.m_checkGPU_1_2.EnableWindow(TRUE);
+		m_oSetupDialog.m_checkGPU_1_2.SetCheck(0);
+		m_oSetupDialog.m_checkGPU_1_3.EnableWindow(TRUE);
+		m_oSetupDialog.m_checkGPU_1_3.SetCheck(0);
+		m_oSetupDialog.m_checkAutoDeinterlace.EnableWindow(TRUE);
+		m_oSetupDialog.m_checkAutoDeinterlace.SetCheck(0);*/
+	}
+
+	return TRUE;
+}
+
+BOOL CUB530View::HwUninitialize()
+{
+	if (m_hVideoDevice != 0) {
+		QCAP_STOP(m_hVideoDevice);
+		QCAP_DESTROY(m_hVideoDevice);
+		m_hVideoDevice = NULL;
+	}
+
+	return TRUE;
+}
+
+void CUB530View::CaptureSingleImage(LPTSTR lpszFileName, BOOL bIsJPG)
+{
+	if (m_hVideoDevice != NULL)
+	{
+		if (bIsJPG)
+		{
+			QCAP_SNAPSHOT_JPG(m_hVideoDevice, lpszFileName, 100, FALSE, 5000); //参数4:是否异步;
+		}
+		else
+		{
+			QCAP_SNAPSHOT_BMP(m_hVideoDevice, lpszFileName, FALSE, 5000);
+		}
+#ifdef _DEBUG
+		Global::WriteTextLog("完成:CaptureSingleImage");
+#endif
+	}
+}
+
+std::string CUB530View::CaptureSingleImageAutoName(LPCTSTR lpszDir, BOOL bIsJPG)
+{
+	if (m_hVideoDevice != NULL)
+	{
+		TCHAR szPath[MAX_PATH] = { 0 };
+		// 毫秒级;
+		time_point<system_clock, ::chrono::milliseconds> tp = time_point_cast<std::chrono::milliseconds>(system_clock::now());
+		auto tt = std::chrono::system_clock::to_time_t(tp);
+		std::tm now = { 0 };
+		localtime_s(&now, &tt); // 时间戳转成本地时间;
+		int msc = tp.time_since_epoch().count() % 1000;
+		if (bIsJPG)
+		{
+			_stprintf_s(szPath, _T("%s%04d%02d%02d%02d%02d%02d%03d.jpg"),
+				lpszDir ? lpszDir : Global::g_szCurModuleDir,
+				now.tm_year + 1990,
+				now.tm_mon + 1,
+				now.tm_mday,
+				now.tm_hour,
+				now.tm_min,
+				now.tm_sec,
+				msc);
+			QCAP_SNAPSHOT_JPG(m_hVideoDevice, szPath, 100, FALSE, 5000);
+		}
+		else
+		{
+			_stprintf_s(szPath, _T("%s%04d%02d%02d%02d%02d%02d%03d.bmp"),
+				lpszDir ? lpszDir : Global::g_szCurModuleDir,
+				now.tm_year + 1990,
+				now.tm_mon + 1,
+				now.tm_mday,
+				now.tm_hour,
+				now.tm_min,
+				now.tm_sec,
+				msc);
+			QCAP_SNAPSHOT_BMP(m_hVideoDevice, szPath, FALSE, 5000);
+		}
+#ifdef _DEBUG
+		Global::WriteTextLog("完成:CaptureSingleImageAutoName");
+#endif
+		return std::string(szPath);
+	}
+
+	return std::string();
+}
+
+void CUB530View::CaptureMultiImage(LPCTSTR lpszDir, LPCTSTR lpszPrefix, BOOL bIsJPG, int nDurationTime)
+{
+	std::thread t([&](CUB530View* p, LPCTSTR lpszDir, LPCTSTR lpszPrefix, BOOL bIsJPG, int nDurationTime) {
+		// 连续截图;
+		TCHAR szDir[MAX_PATH] = { 0 };
+		TCHAR szPath[MAX_PATH] = { 0 };
+
+		_stprintf_s(szDir, lpszPrefix ? _T("%s%s-") : _T("%s%s"),
+			lpszDir ? lpszDir : Global::g_szCurModuleDir,
+			lpszPrefix ? lpszPrefix : _T(""));
+
+		auto start = system_clock::now();
+		while (true)
+		{
+			// C++11获取当前时间;
+			time_point<system_clock, ::chrono::milliseconds> tp = time_point_cast<std::chrono::milliseconds>(system_clock::now());
+			if (bIsJPG)
+			{
+				_stprintf_s(szPath, _T("%s%lld.jpg"), szDir, tp.time_since_epoch().count());
+				QCAP_SNAPSHOT_JPG(m_hVideoDevice, szPath, 100, TRUE);
+				// 等待磁盘完成写入;
+				//Sleep(20);
+			}
+			else
+			{
+				_stprintf_s(szPath, _T("%s%lld.bmp"), szDir, tp.time_since_epoch().count());
+				QCAP_SNAPSHOT_BMP(m_hVideoDevice, szPath, TRUE);
+				// 等待磁盘完成写入;
+				//Sleep(530);
+			}
+
+			auto duration = duration_cast<milliseconds>(system_clock::now() - start);
+			if (duration.count() >= nDurationTime)
+				break;
+		}
+		}, this, lpszDir, lpszPrefix, bIsJPG, nDurationTime);
+	t.detach();
+}
+
+
+void CUB530View::CaptureSingleImageEx(LPTSTR lpszFileName, BOOL bIsJPG)
+{
+	{
+		// 加锁;
+		std::lock_guard<std::mutex> lk(m_mut_cpature);
+		// 标记截图;
+		m_bCaptureImage = TRUE;
+		// 初始化数据;
+		ZeroMemory(&m_CaptureInfo, sizeof(CaptureInfo));
+		m_CaptureInfo.bIsJPG = bIsJPG;
+		m_CaptureInfo.bSingle = TRUE;
+		m_CaptureInfo.IsAutoName = FALSE;
+		m_CaptureInfo.nCaputerCount = 0;
+		m_CaptureInfo.nKeepTime = 0;
+		memset(m_CaptureInfo.szPrefix, 0, 64);
+		//_stprintf_s(m_CaptureInfo.szSaveDir, _T("%s"), lpszFileName);
+		_stprintf_s(m_CaptureInfo.szSaveDir, _T("%s"), lpszFileName);
+		//m_strCaptureName = lpszFileName;
+	}
+
+	// 等待截图完成;
+	{
+		// 加锁;
+		std::unique_lock<std::mutex> lk(m_mut_cpature);
+		m_capture_cond.wait(lk, [&]() {return !m_pBuffer; });
+		// 解锁;
+		lk.unlock();
+	}
+}
+
+std::string CUB530View::CaptureSingleImageAutoNameEx(LPCTSTR lpszDir, BOOL bIsJPG)
+{
+	{
+		// 加锁;
+		std::lock_guard<std::mutex> lk(m_mut_cpature);
+		// 标记截图;
+		m_bCaptureImage = TRUE;
+		// 初始化数据;
+		ZeroMemory(&m_CaptureInfo, sizeof(CaptureInfo));
+		m_CaptureInfo.bIsJPG = bIsJPG;
+		m_CaptureInfo.bSingle = TRUE;
+		m_CaptureInfo.IsAutoName = FALSE;
+		m_CaptureInfo.nCaputerCount = 0;
+		m_CaptureInfo.nKeepTime = 0;
+		memset(m_CaptureInfo.szPrefix, 0, 64);
+		memset(m_CaptureInfo.szSaveDir, 0, MAX_PATH);
+
+		// 毫秒级;
+		time_point<system_clock, ::chrono::milliseconds> tp = time_point_cast<std::chrono::milliseconds>(system_clock::now());
+		auto tt = std::chrono::system_clock::to_time_t(tp);
+		std::tm now = { 0 };
+		localtime_s(&now, &tt); // 时间戳转成本地时间;
+		int msc = tp.time_since_epoch().count() % 1000;
+		if (bIsJPG)
+		{
+			_stprintf_s(m_CaptureInfo.szSaveDir, _T("%s%04d%02d%02d%02d%02d%02d%03d.jpg"),
+				lpszDir ? lpszDir : Global::g_szCurModuleDir,
+				now.tm_year + 1990,
+				now.tm_mon + 1,
+				now.tm_mday,
+				now.tm_hour,
+				now.tm_min,
+				now.tm_sec,
+				msc);
+		}
+		else
+		{
+			_stprintf_s(m_CaptureInfo.szSaveDir, _T("%s%04d%02d%02d%02d%02d%02d%03d.bmp"),
+				lpszDir ? lpszDir : Global::g_szCurModuleDir,
+				now.tm_year + 1990,
+				now.tm_mon + 1,
+				now.tm_mday,
+				now.tm_hour,
+				now.tm_min,
+				now.tm_sec,
+				msc);
+		}
+
+#ifdef DEBUG
+		OutputDebugStringA(m_CaptureInfo.szSaveDir);
+		OutputDebugStringA("\tCVideoCaptureView::CaptureSingleImageAutoNameEx\n");
+#endif // DEBUG
+	}
+
+	// 等待截图完成;
+	{
+		// 加锁;
+		std::unique_lock<std::mutex> lk(m_mut_cpature);
+		m_capture_cond.wait(lk, [&]() {return !m_pBuffer; });
+		// 解锁;
+		lk.unlock();
+	}
+
+	return std::string(m_CaptureInfo.szSaveDir);
+}
+
+void CUB530View::CaptureMultiImageEx(LPCTSTR lpszDir, LPCTSTR lpszPrefix, BOOL bIsJPG, int nDurationTime)
+{
+	std::thread t([&](CUB530View* p, LPCTSTR lpszDir, LPCTSTR lpszPrefix, BOOL bIsJPG, int nDurationTime) {
+		// 连续截图;
+		TCHAR szDir[MAX_PATH] = { 0 };
+		_stprintf_s(szDir, lpszPrefix ? _T("%s%s-") : _T("%s%s"),
+			lpszDir ? lpszDir : Global::g_szCurModuleDir,
+			lpszPrefix ? lpszPrefix : _T(""));
+
+		auto start = system_clock::now();
+		while (true)
+		{
+			// C++11获取当前时间;
+			time_point<system_clock, ::chrono::milliseconds> tp = time_point_cast<std::chrono::milliseconds>(system_clock::now());
+
+			{
+				// 加锁;
+				std::lock_guard<std::mutex> lk(m_mut_cpature);
+				// 标记截图;
+				m_bCaptureImage = TRUE;
+				// 初始化数据;
+				ZeroMemory(&m_CaptureInfo, sizeof(CaptureInfo));
+				m_CaptureInfo.bIsJPG = bIsJPG;
+				m_CaptureInfo.bSingle = FALSE;
+				m_CaptureInfo.IsAutoName = TRUE;
+				m_CaptureInfo.nCaputerCount = 0;
+				m_CaptureInfo.nKeepTime = nDurationTime;
+				_stprintf_s(m_CaptureInfo.szPrefix, _T("%s"), lpszPrefix);
+				if (bIsJPG)
+				{
+					_stprintf_s(m_CaptureInfo.szSaveDir, _T("%s%lld.jpg"), szDir, tp.time_since_epoch().count());
+				}
+				else
+				{
+					_stprintf_s(m_CaptureInfo.szSaveDir, _T("%s%lld.bmp"), szDir, tp.time_since_epoch().count());
+				}
+			}
+
+			// 等待截图完成;
+			{
+				// 加锁;
+				std::unique_lock<std::mutex> lk(m_mut_cpature);
+				m_capture_cond.wait(lk, [&]() {return !m_pBuffer; });
+				// 解锁;
+				lk.unlock();
+			}
+
+			auto duration = duration_cast<milliseconds>(system_clock::now() - start);
+			if (duration.count() >= nDurationTime)
+				break;
+		}
+		}, this, lpszDir, lpszPrefix, bIsJPG, nDurationTime);
+	t.detach();
+}
+
+BOOL CUB530View::SaveImageByCaptureInfo(const CaptureInfo& capInfo)
+{
+	if (m_pBuffer == NULL)
+	{
+		return FALSE;
+	}
+
+	BOOL bRet = FALSE;
+	// 保存截图;
+	HGLOBAL hMemery = GlobalAlloc(GMEM_MOVEABLE, m_nVideoWidth * m_nVideoHeight * 4);
+	if (hMemery != NULL)
+	{
+		BYTE* pDstFrameBuffer = NULL;
+		pDstFrameBuffer = (BYTE*)GlobalLock(hMemery);
+		if (pDstFrameBuffer != NULL)
+		{
+			QRESULT QRet = QCAP_COLORSPACE_YUY2_TO_ABGR32(m_pBuffer,
+				m_nVideoWidth,
+				m_nVideoHeight,
+				0,
+				pDstFrameBuffer,
+				m_nVideoWidth,
+				m_nVideoHeight,
+				0);
+
+			Status stat = GenericError;
+			Bitmap* pImg = ::new Bitmap(
+				m_nVideoWidth,
+				m_nVideoHeight,
+				m_nVideoWidth * 4,
+				PixelFormat32bppRGB,
+				pDstFrameBuffer);
+
+			if (m_bHoriontal && !m_bVertically)
+				pImg->RotateFlip(RotateNoneFlipX);// 水平翻转;
+			else if (m_bHoriontal && m_bVertically)
+				pImg->RotateFlip(Rotate180FlipNone);// 270度;
+			else if (!m_bHoriontal && m_bVertically)
+				pImg->RotateFlip(Rotate180FlipX);// 垂直翻转;
+
+			CLSID encoderClsid = { 0 };
+			CString strFileName = m_CaptureInfo.szSaveDir;
+			// 需要判断路径是否存在,不存在创建目录;
+			int nIndex = strFileName.ReverseFind(_T('\\'));
+			if (nIndex != -1)
+			{
+				if (!PathFileExists(strFileName.Left(nIndex)))
+				{
+					// 如果文件夹不存在,创建;
+					SHCreateDirectoryEx(NULL, strFileName.Left(nIndex), NULL);
+				}
+			}
+
+			BSTR newfile = strFileName.AllocSysString();
+			if (!capInfo.bIsJPG)
+			{
+				Global::GetEncoderClsid(L"image/bmp", &encoderClsid);
+				stat = pImg->Save(newfile, &encoderClsid, NULL);
+			}
+			else
+			{
+				Global::GetEncoderClsid(L"image/jpeg", &encoderClsid);
+				EncoderParameters encoderParameters;
+				encoderParameters.Count = 1;
+				encoderParameters.Parameter[0].Guid = EncoderQuality;
+				encoderParameters.Parameter[0].Type = EncoderParameterValueTypeLong;
+				encoderParameters.Parameter[0].NumberOfValues = 1;
+				// Save the image as a JPEG with quality level 100.
+				ULONG uQuality = 100;
+				encoderParameters.Parameter[0].Value = &uQuality;
+				stat = pImg->Save(newfile, &encoderClsid, &encoderParameters);
+			}
+
+			if (pImg)
+				::delete pImg;
+			pImg = NULL;
+			SysFreeString(newfile);
+
+			bRet = (stat == 0 ? TRUE : FALSE);
+#ifdef DEBUG
+			if (bRet)
+			{
+				OutputDebugStringA(strFileName);
+				OutputDebugStringA("\tSave Image::Ok\n");
+			}
+#endif
+		}
+#ifdef DEBUG
+		else
+		{
+			OutputDebugStringA("pDstFrameBuffer == NULL\n");
+		}
+#endif
+
+		GlobalUnlock(hMemery);
+	}
+#ifdef DEBUG
+	else
+	{
+		DWORD dwError = GetLastError();
+		CString strError = _T("");
+		strError.Format(_T("hMemery == NULL分配内存出错:%ld\n"), dwError);
+		OutputDebugStringA(strError);
+	}
+#endif
+
+	if (m_pBuffer)
+		delete[]m_pBuffer;
+	m_pBuffer = NULL;
+
+	// 必须调用GlobalFree释放;
+	GlobalFree(hMemery);
+
+	return bRet;
+}
+
+void CUB530View::CaptureImageThread(CUB530View* pView)
+{
+	CString strFileName = _T("");
+	while (!pView->m_bAppQuit)
+	{
+		std::unique_lock<std::mutex> lk(pView->m_mut_thread);   // 这里使用unique_lock是为了后面方便解锁
+#if 1	// 避免线程虚假唤醒;
+		pView->m_thread_cond.wait(lk, [&]() {return pView->m_pBuffer; });
+#else
+		while (!pView->m_pBuffer)
+			pView->m_data_cond.wait(lk);
+#endif
+		// 保存截图;
+		pView->SaveImageByCaptureInfo(pView->m_CaptureInfo);
+		// 通知截图完成;
+		pView->m_capture_cond.notify_one();
+
+		// 解锁;
+		lk.unlock();
+
+		// sleep 10ms;
+		//this_thread::sleep_for(chrono::milliseconds(10));
+	}
+}
+
+void CUB530View::StartRecord(DWORD dwDuration, LPCTSTR lpSavePath)
+{
+	QRESULT QRet = QCAP_RS_SUCCESSFUL;
+	if (!m_bIsMp4) // 音频格式;
+	{
+		QRet = QCAP_SET_AUDIO_RECORD_PROPERTY(m_hVideoDevice, 0, QCAP_ENCODER_TYPE_SOFTWARE, QCAP_ENCODER_FORMAT_PCM);
+		//_tcscat_s(szPath, _T(".avi"));
+	}
+	else
+	{
+		QRet = QCAP_SET_AUDIO_RECORD_PROPERTY(m_hVideoDevice, 0, QCAP_ENCODER_TYPE_SOFTWARE, QCAP_ENCODER_FORMAT_AAC);
+		//_tcscat_s(szPath, _T(".mp4"));
+	}
+
+	// 设置视频属性;
+	QRet = QCAP_SET_VIDEO_RECORD_PROPERTY(
+		m_hVideoDevice,
+		0,
+		m_bSupportGPU ? QCAP_ENCODER_TYPE_INTEL_MEDIA_SDK : QCAP_ENCODER_TYPE_SOFTWARE,
+		QCAP_ENCODER_FORMAT_H264,
+		QCAP_RECORD_MODE_CBR,
+		8000,
+		16 * 1024 * 1024, // 16最高质量;
+		30, // 每秒多少帧
+		0,
+		0,
+		QCAP_DOWNSCALE_MODE_OFF);
+
+	// 开始录屏;
+	QRet = QCAP_START_RECORD(m_hVideoDevice, 0, const_cast<CHAR*>(lpSavePath), QCAP_RECORD_FLAG_FULL, 0.0, 0.0, 0.0, 0, NULL);
+
+	m_bIsRecord = TRUE;
+}
+
+void CUB530View::StopRecord()
+{
+	QCAP_STOP_RECORD(m_hVideoDevice, 0);
+	m_bIsRecord = FALSE;
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+void CUB530View::SetRibbonStatusBarText(CString strText, int uId)
+{
+	if (g_pMainFrame)
+	{
+		g_pMainFrame->SetRibbonStatusBarText(strText, uId);
+	}
+}
+
+
+void CUB530View::OnTimer(UINT_PTR nIDEvent)
+{
+	// TODO: 在此添加消息处理程序代码和/或调用默认值
+	if (nIDEvent == 0)
+	{
+		KillTimer(0);
+
+		if (m_bNoSignal)
+		{
+			if (m_bIsRecord)
+			{
+				QCAP_STOP_RECORD(m_hVideoDevice, 0);
+				m_bIsRecord = FALSE;
+			}
+		}
+		else
+		{
+
+		}
+	}
+
+	CView::OnTimer(nIDEvent);
+}
+
+
+void CUB530View::OnCutBmp()
+{
+	// TODO: 在此添加命令处理程序代码
+	CaptureSingleImageAutoName(NULL, FALSE);
+}
+
+
+void CUB530View::OnCutJpg()
+{
+	// TODO: 在此添加命令处理程序代码
+	CaptureSingleImageAutoName(NULL, TRUE);
+}
+
+
+void CUB530View::OnStartRecord()
+{
+	// TODO: 在此添加命令处理程序代码
+	TCHAR szPath[MAX_PATH] = { 0 };
+	// 毫秒级;
+	time_point<system_clock, ::chrono::milliseconds> tp = time_point_cast<std::chrono::milliseconds>(system_clock::now());
+	auto tt = std::chrono::system_clock::to_time_t(tp);
+	std::tm now = { 0 };
+	localtime_s(&now, &tt); // 时间戳转成本地时间;
+	int msc = tp.time_since_epoch().count() % 1000;
+
+	_stprintf_s(szPath, _T("%s%04d%02d%02d%02d%02d%02d%03d"),
+		Global::g_szCurModuleDir,
+		now.tm_year + 1990,
+		now.tm_mon + 1,
+		now.tm_mday,
+		now.tm_hour,
+		now.tm_min,
+		now.tm_sec,
+		msc);
+
+	QRESULT QRet = QCAP_RS_SUCCESSFUL;
+	if (!m_bIsMp4) // 音频格式;
+	{
+		QRet = QCAP_SET_AUDIO_RECORD_PROPERTY(m_hVideoDevice, 0, QCAP_ENCODER_TYPE_SOFTWARE, QCAP_ENCODER_FORMAT_PCM);
+		_tcscat_s(szPath, _T(".avi"));
+	}
+	else
+	{
+		QRet = QCAP_SET_AUDIO_RECORD_PROPERTY(m_hVideoDevice, 0, QCAP_ENCODER_TYPE_SOFTWARE, QCAP_ENCODER_FORMAT_AAC);
+		_tcscat_s(szPath, _T(".mp4"));
+	}
+
+	// 设置视频属性;
+	QRet = QCAP_SET_VIDEO_RECORD_PROPERTY(
+		m_hVideoDevice,
+		0,
+		m_bSupportGPU ? QCAP_ENCODER_TYPE_INTEL_MEDIA_SDK : QCAP_ENCODER_TYPE_SOFTWARE,
+		QCAP_ENCODER_FORMAT_H264,
+		QCAP_RECORD_MODE_CBR,
+		8000,
+		16 * 1024 * 1024, // 16最高质量;
+		30, // 每秒多少帧
+		0,
+		0,
+		QCAP_DOWNSCALE_MODE_OFF);
+
+
+	// 开始录屏;
+	QRet = QCAP_START_RECORD(m_hVideoDevice, 0, szPath, QCAP_RECORD_FLAG_FULL, 0.0, 0.0, 0.0, 0, NULL);
+
+	m_bIsRecord = TRUE;
+}
+
+
+void CUB530View::OnStopRecord()
+{
+	// TODO: 在此添加命令处理程序代码
+	QCAP_STOP_RECORD(m_hVideoDevice, 0);
+	m_bIsRecord = FALSE;
+}
+
+
+void CUB530View::OnCheckVertically()
+{
+	// TODO: 在此添加命令处理程序代码
+	CMainFrame* pMain = (CMainFrame*)AfxGetMainWnd();
+	CMFCRibbonButton* pCheckbox = pMain->GetRibbonButton(ID_CHECK_VERTICALLY);
+	m_bVertically = !pCheckbox->IsChecked();
+	if (m_hVideoDevice)
+	{
+		QCAP_SET_VIDEO_MIRROR(m_hVideoDevice, m_bHoriontal, m_bVertically);
+	}
+}
+
+
+void CUB530View::OnCheckHoriontal()
+{
+	// TODO: 在此添加命令处理程序代码
+	CMainFrame* pMain = (CMainFrame*)AfxGetMainWnd();
+	CMFCRibbonButton* pCheckbox = pMain->GetRibbonButton(ID_CHECK_HORIONTAL);
+	m_bHoriontal = !pCheckbox->IsChecked();
+	if (m_hVideoDevice)
+	{
+		QCAP_SET_VIDEO_MIRROR(m_hVideoDevice, m_bHoriontal, m_bVertically);
+	}
+}
+
+
+void CUB530View::OnUpdateCheckVertically(CCmdUI* pCmdUI)
+{
+	// TODO: 在此添加命令更新用户界面处理程序代码
+	pCmdUI->SetCheck(m_bVertically);
+}
+
+
+void CUB530View::OnUpdateCheckHoriontal(CCmdUI* pCmdUI)
+{
+	// TODO: 在此添加命令更新用户界面处理程序代码
+	pCmdUI->SetCheck(m_bHoriontal);
+}
+
+
+void CUB530View::OnTraymenuReconnect()
+{
+	// TODO: 在此添加命令处理程序代码
+	HwUninitialize();// 断开;
+	Invalidate();
+	HwInitialize();// 重连;
+}
+
+
+void CUB530View::OnCheckSuportGpu()
+{
+	// TODO: 在此添加命令处理程序代码
+	CMainFrame* pMain = (CMainFrame*)AfxGetMainWnd();
+	CMFCRibbonButton* pCheckbox = pMain->GetRibbonButton(ID_CHECK_SUPORT_GPU);
+	m_bSupportGPU = !pCheckbox->IsChecked();
+}
+
+
+void CUB530View::OnCheckFormatMp4()
+{
+	CMainFrame* pMain = (CMainFrame*)AfxGetMainWnd();
+	CMFCRibbonButton* pCheckbox = pMain->GetRibbonButton(ID_CHECK_FORMAT_MP4);
+	m_bIsMp4 = !pCheckbox->IsChecked();
+}
+
+
+void CUB530View::OnCheckFormatAvi()
+{
+	CMainFrame* pMain = (CMainFrame*)AfxGetMainWnd();
+	CMFCRibbonButton* pCheckbox = pMain->GetRibbonButton(ID_CHECK_FORMAT_AVI);
+	m_bIsMp4 = pCheckbox->IsChecked();
+}
+
+
+void CUB530View::OnUpdateCheckSuportGpu(CCmdUI* pCmdUI)
+{
+	// TODO: 在此添加命令更新用户界面处理程序代码
+	pCmdUI->SetCheck(m_bSupportGPU);
+}
+
+
+void CUB530View::OnUpdateCheckFormatMp4(CCmdUI* pCmdUI)
+{
+	// TODO: 在此添加命令更新用户界面处理程序代码
+	pCmdUI->SetCheck(m_bIsMp4);
+}
+
+
+void CUB530View::OnUpdateCheckFormatAvi(CCmdUI* pCmdUI)
+{
+	// TODO: 在此添加命令更新用户界面处理程序代码
+	pCmdUI->SetCheck(!m_bIsMp4);
+}
+
+
+void CUB530View::OnUpdateStartRecord(CCmdUI* pCmdUI)
+{
+	// TODO: 在此添加命令更新用户界面处理程序代码
+	pCmdUI->Enable(!m_bIsRecord);
+}
+
+
+void CUB530View::OnUpdateStopRecord(CCmdUI* pCmdUI)
+{
+	// TODO: 在此添加命令更新用户界面处理程序代码
+	pCmdUI->Enable(m_bIsRecord);
+}

+ 158 - 0
SATHelper/SATHelper/UB530View.h

@@ -0,0 +1,158 @@
+#pragma once
+
+
+#include "MemoryClient.h"
+// CUB530View 窗体视图
+
+class CUB530View : public CFormView
+{
+	DECLARE_DYNCREATE(CUB530View)
+
+protected:
+	CUB530View();           // 动态创建所使用的受保护的构造函数
+	virtual ~CUB530View();
+
+public:
+#ifdef AFX_DESIGN_TIME
+	enum { IDD = DLG_UB530VIEW };
+#endif
+#ifdef _DEBUG
+	virtual void AssertValid() const;
+#ifndef _WIN32_WCE
+	virtual void Dump(CDumpContext& dc) const;
+#endif
+#endif
+
+protected:
+	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
+
+	DECLARE_MESSAGE_MAP()
+public:
+	virtual void OnInitialUpdate();
+	virtual void OnDraw(CDC* /*pDC*/);
+
+
+	//////////////////////////////////////////////////////////////////////////////////////////
+public:
+	// 设备句柄;
+	PVOID 				m_hVideoDevice;
+	// 是否有信号;
+	BOOL				m_bNoSignal;
+	// 是否在录频;
+	BOOL				m_bIsRecord;
+	// 录频格式;
+	BOOL				m_bIsMp4; // FALSE= AVI
+	//////////////////////////////////////////////////////////////////////////
+	// VIDEO PROPERTIES
+	// 是否支持GPU;
+	BOOL				m_bSupportGPU;
+	// 视频流宽度;
+	ULONG				m_nVideoWidth;
+	// 视频流高度;
+	ULONG				m_nVideoHeight;
+
+	BOOL				m_bVideoIsInterleaved;
+
+	double				m_dVideoFrameRate;
+
+	BOOL				m_bVideoDeinterlaceEnable;
+	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// AUDIO PROPERTIES
+
+	ULONG				m_nAudioChannels;
+
+	ULONG				m_nAudioBitsPerSample;
+
+	ULONG				m_nAudioSampleFrequency;
+
+	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// QUALITY PROPERTIES
+
+	ULONG				m_nSharpness;
+
+	ULONG				m_nSaturation;
+
+	ULONG				m_nHue;
+
+	ULONG				m_nConstrast;
+
+	ULONG				m_nBrightness;
+
+	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// RECORD & FILE PROPERTIES
+
+	// 截图路径;
+	CString				m_strSnapshotPath;
+	//
+	CString				m_strFormatChangedOutput;
+	// 垂直镜像;
+	BOOL				m_bVertically;
+	// 水平镜像;
+	BOOL				m_bHoriontal;
+
+	// 程序退出;
+	BOOL				m_bAppQuit;
+
+public:
+	// 初始化设备;
+	BOOL HwInitialize();
+	// 释放设备;
+	BOOL HwUninitialize();
+
+	// 单次截图;
+	void CaptureSingleImage(LPTSTR lpszFileName, BOOL bIsJPG = TRUE);
+	// 单次截图并自动命名;
+	std::string CaptureSingleImageAutoName(LPCTSTR lpszDir, BOOL bIsJPG = TRUE);
+	// 连续截图;//默认持续1000ms;
+	void CaptureMultiImage(LPCTSTR lpszDir, LPCTSTR lpszPrefix, BOOL bIsJPG, int nDurationTime = 1000);
+
+	//////////////////////////////////////////////////////////////////////////
+	// ->预览截图;
+	CaptureInfo m_CaptureInfo;
+	BOOL m_bCaptureImage;
+	std::mutex m_mut_cpature;
+	std::condition_variable m_capture_cond;
+	// 单次截图;
+	void CaptureSingleImageEx(LPTSTR lpszFileName, BOOL bIsJPG = TRUE);
+	// 单次截图并自动命名;
+	std::string CaptureSingleImageAutoNameEx(LPCTSTR lpszDir, BOOL bIsJPG = TRUE);
+	// 连续截图;//默认持续1000ms;
+	void CaptureMultiImageEx(LPCTSTR lpszDir, LPCTSTR lpszPrefix, BOOL bIsJPG, int nDurationTime = 1000);
+	// 截图;
+	BOOL SaveImageByCaptureInfo(const CaptureInfo& capInfo);
+
+	// 截图线程;
+	BYTE* m_pBuffer;
+	DWORD m_dwBufferLen;
+
+	std::mutex m_mut_thread;
+	std::condition_variable m_thread_cond; //使用std::condition_variable等待数据
+	static void CaptureImageThread(CUB530View* pView);
+
+	// 录屏;
+	void StartRecord(DWORD dwDuration, LPCTSTR lpSavePath);
+	void StopRecord();
+
+	public:
+
+public:
+	void SetRibbonStatusBarText(CString strText, int uId);
+	friend class CMemoryClient;
+	afx_msg void OnTimer(UINT_PTR nIDEvent);
+	afx_msg void OnCutBmp();
+	afx_msg void OnCutJpg();
+	afx_msg void OnStartRecord();
+	afx_msg void OnStopRecord();
+	afx_msg void OnCheckVertically();
+	afx_msg void OnCheckHoriontal();
+	afx_msg void OnUpdateCheckVertically(CCmdUI* pCmdUI);
+	afx_msg void OnUpdateCheckHoriontal(CCmdUI* pCmdUI);
+	afx_msg void OnTraymenuReconnect();
+	afx_msg void OnCheckSuportGpu();
+	afx_msg void OnCheckFormatMp4();
+	afx_msg void OnCheckFormatAvi();
+	afx_msg void OnUpdateCheckSuportGpu(CCmdUI* pCmdUI);
+	afx_msg void OnUpdateCheckFormatMp4(CCmdUI* pCmdUI);
+	afx_msg void OnUpdateCheckFormatAvi(CCmdUI* pCmdUI);
+	afx_msg void OnUpdateStartRecord(CCmdUI* pCmdUI);
+	afx_msg void OnUpdateStopRecord(CCmdUI* pCmdUI);
+};
+
+

+ 1 - 0
SATHelper/SATHelper/stdafx.h

@@ -60,5 +60,6 @@ using namespace chrono;
 #include <afxext.h>
 #include <afxcontrolbars.h>
 #include <afxext.h>
+#include <afxext.h>
 
 #endif //PCH_H