DocScannerCap.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  1. #ifndef _TWINKLE_DOC_VIDEOCAP_H__
  2. #define _TWINKLE_DOC_VIDEOCAP_H__
  3. #pragma once
  4. #include "SpBase.h"
  5. #include <opencv2/opencv.hpp>
  6. #include <string>
  7. #include <vector>
  8. #include <deque>
  9. #include "Dshow.h"
  10. #include "atlconv.h"
  11. #include "Dbt.h"
  12. #include "fileutil.h"
  13. #include "PortableScannerFSM.h"
  14. #pragma comment(lib,"Strmiids.lib")
  15. #pragma comment(lib,"Quartz.lib")
  16. #define TEST_FUNCTION
  17. #define DEFAULT_MAT_WINDOW_NAME TEXT("DOC-SCANNER_AREA_WINDOWS")
  18. using namespace cv;
  19. using namespace std;
  20. #define SAFE_RELEASE_IDEV(hd) \
  21. do { \
  22. if(hd != NULL) { \
  23. hd->Release(); \
  24. hd = NULL; \
  25. } \
  26. } while (false)
  27. typedef struct _CAMERA_INFOR_ITEM
  28. {
  29. char szDevName[MAX_PATH];
  30. char szCLSID[MAX_PATH];
  31. char szDevPath[MAX_PATH];
  32. LONG uWaveInID;
  33. void Cleanup() {
  34. uWaveInID = 0;
  35. memset(szDevName, 0, sizeof(szDevName));
  36. memset(szCLSID, 0, sizeof(szCLSID));
  37. memset(szDevPath, 0, sizeof(szDevPath));
  38. }
  39. void Copy(struct _CAMERA_INFOR_ITEM* prhs) {
  40. if(prhs != NULL) {
  41. uWaveInID = prhs->uWaveInID;
  42. strcpy(szDevPath, prhs->szDevPath);
  43. strcpy(szDevName, prhs->szDevName);
  44. strcpy(szCLSID, prhs->szCLSID);
  45. }
  46. }
  47. void Display() {
  48. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("[%ld]%s(%s)",uWaveInID, szDevName, szDevPath);
  49. DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("CLSID:%s", szCLSID);
  50. }
  51. } CAMERA_INFOR_ITEM, *PCAMERA_INFOR_ITEM;
  52. static int WrapW2A(VARIANT& varirant, char* szDst, const size_t maxLen) {
  53. int count = 0;
  54. WCHAR tmp[256];
  55. tmp[0] = 0;
  56. memset(szDst, '\0', sizeof(char)*maxLen);
  57. HRESULT hr = StringCchCopyW(tmp, 256, varirant.bstrVal);
  58. if(hr == S_OK) {
  59. count = WideCharToMultiByte(CP_ACP, 0, tmp, -1, szDst, maxLen, 0, NULL);
  60. } else {
  61. while (varirant.bstrVal[count] != 0x00 && count < maxLen) {
  62. szDst[count] = (char)varirant.bstrVal[count];
  63. count++;
  64. }
  65. }
  66. return count;
  67. /*
  68. USES_CONVERSION;
  69. lptstrValue = W2T(Value.bstrVal);
  70. */
  71. }
  72. typedef vector<PCAMERA_INFOR_ITEM> CAMERA_BUCKET;
  73. typedef CAMERA_BUCKET::const_iterator CAMERA_BUCKET_CITER;
  74. typedef CAMERA_BUCKET::iterator CAMERA_BUCKET_ITER;
  75. static void DestoryCamereBuckets(CAMERA_BUCKET& vtCameras)
  76. {
  77. if(!vtCameras.empty()) {
  78. for(CAMERA_BUCKET_ITER it=vtCameras.begin(); it!=vtCameras.end(); ++it) {
  79. if(*it) {
  80. delete (*it);
  81. (*it) = NULL;
  82. }
  83. }
  84. vtCameras.clear();
  85. }
  86. }
  87. // return the origin old count of video devices.
  88. int UpdateCameraInfors(CAMERA_BUCKET& vtCameraList);
  89. int GetCameraInfors(CAMERA_BUCKET& vtCameraList);
  90. int GetCameraCount();
  91. //returned value:
  92. // -2:inner error; -1:not founed; 0:idle; 1:busy
  93. int IsDeviceBusy(const char* lpcszDeviceName);
  94. void DisplayCameraInfos(const CAMERA_BUCKET& vtCameraList);
  95. // condition: lhs contains rhs or rhs contains lhs, use size() to judge which is more wider
  96. // return the diff elements
  97. int ExclusiveCameraBuckes(const CAMERA_BUCKET& lhs, const CAMERA_BUCKET& rhs, CAMERA_BUCKET& diff);
  98. #define EVTCODE_SCAN 0x0001
  99. #define EVTSTATUS_LOOSE 0x00
  100. #define EVTSTATUS_QUEUING 0x01
  101. #define EVTSTATUS_DEALING 0x02
  102. #define EVTSTATUS_DONE_MASK 0x10
  103. #define EVTSTATUS_DONE_SUCC 0x11
  104. #define EVTSTATUS_DONE_FAIL 0x12
  105. #define EVTSTATUS_ERROR_MASK 0x80
  106. #define EVTSTATUS_NOT_FOUND 0x81
  107. #define EVTSTATUS_TIMEOUT 0x82
  108. #define EVTPRIO_DEFAULT 0x00
  109. enum { GRAY=0, COLORFUL, MAX_COLORMODE };
  110. enum { ROI_DEFAULT=0, ROI_A4, ROI_IDCER, ROI_CUSTOM, MAX_RIOMODE };
  111. #define DR_X 0
  112. #define DR_Y 0
  113. #define DR_W 960
  114. #define DR_H 540
  115. class CDocScannerCap;
  116. typedef void (CDocScannerCap::*pFnEventFinished)
  117. (USHORT evtCode, UCHAR result, UINT checksum);
  118. extern pFnEventFinished OnEvtFinished;
  119. struct RequestEvent {
  120. RequestEvent():_cap(NULL){}
  121. UINT evtUniqueID; //Additional
  122. USHORT evtCode;
  123. UCHAR evtStatus;
  124. UCHAR evtPriority;
  125. void SetCapHandle(CDocScannerCap* cap) {
  126. _cap = cap;
  127. }
  128. void OnAnswer() {
  129. if(_cap && (evtStatus & EVTSTATUS_DONE_MASK)) {
  130. (_cap->*OnEvtFinished)(evtCode, evtStatus, evtUniqueID);
  131. }
  132. }
  133. enum { ReqLen, ReqVal, AnsLen, AnsVal } valType;
  134. union {
  135. DWORD dwDataLen;
  136. struct {
  137. WORD wHigh;
  138. WORD wLow;
  139. } dataVal;
  140. };
  141. CHAR* evtData;
  142. private:
  143. CDocScannerCap* _cap;
  144. };
  145. typedef RequestEvent *RequestEventPtr;
  146. static RequestEventPtr CreateRequestEvent(
  147. USHORT code,
  148. UCHAR status = EVTSTATUS_LOOSE,
  149. UCHAR priority = EVTPRIO_DEFAULT
  150. )
  151. {
  152. RequestEvent* evt = new RequestEvent();
  153. if(evt) {
  154. evt->evtCode = code;
  155. evt->evtStatus = status;
  156. evt->evtPriority = priority;
  157. evt->valType = RequestEvent::ReqLen;
  158. evt->dwDataLen = 0;
  159. evt->evtData = NULL;
  160. }
  161. return evt;
  162. }
  163. static void DestroyRequestEvent(RequestEventPtr *reqEvt)
  164. {
  165. if(reqEvt == NULL || (*reqEvt) == NULL) {
  166. return;
  167. }
  168. //TODO: Need Resouce Lock?
  169. RequestEventPtr pReqEvt = *reqEvt;
  170. if((pReqEvt->valType == RequestEvent::ReqLen || pReqEvt->valType == RequestEvent::ReqLen)
  171. && pReqEvt->dwDataLen > 0) {
  172. assert(pReqEvt->evtData != NULL);
  173. free(pReqEvt->evtData);
  174. pReqEvt->evtData = NULL;
  175. pReqEvt->dwDataLen = 0;
  176. }
  177. delete pReqEvt;
  178. reqEvt = NULL;
  179. return;
  180. }
  181. typedef std::deque<RequestEventPtr> EVENT_QUEUE;
  182. typedef EVENT_QUEUE::const_iterator EVENT_QUEUE_CITER;
  183. typedef EVENT_QUEUE::iterator EVENT_QUEUE_ITER;
  184. class CDocScannerCap
  185. {
  186. public:
  187. CDocScannerCap(CPortableScannerFSM* pFSM = NULL);
  188. ~CDocScannerCap(void);
  189. void Test();
  190. int GetCurScanID() const {
  191. return m_videoID;
  192. }
  193. cv::String GetCurDevName() {
  194. return devName;
  195. }
  196. int GetSpecificedCamInfor(const int camID, PCAMERA_INFOR_ITEM info);
  197. int GetCurCamInfo(PCAMERA_INFOR_ITEM info) {
  198. if(m_videoID >= 0) {
  199. return GetSpecificedCamInfor(m_videoID, info);
  200. }
  201. return m_videoID;
  202. }
  203. bool Open(unsigned int idx);
  204. bool OpenCamera(LPCTSTR lpcszDev);
  205. bool StartPreview();
  206. bool TerminatePreview();
  207. bool ScanImage(const char* lpcszFilePath);
  208. bool CloseCamera();
  209. bool ResetCamera();
  210. //Query status;
  211. bool IsAttached() const {
  212. return _isVal();
  213. }
  214. bool IsPreview() const {
  215. return m_fPreviewing;
  216. }
  217. bool IsWinHide() {
  218. return (!!m_bHide);
  219. }
  220. void DestroyPreviewWindow() {
  221. if(m_fPreviewing) {
  222. TerminatePreview();
  223. }else {
  224. _destroyWindow();
  225. }
  226. }
  227. //Attribute
  228. void SetColor(uchar attr) {
  229. if(attr >=0 && attr < MAX_COLORMODE) {
  230. m_colorMode = attr;
  231. }
  232. }
  233. uchar GetColorMode() const {
  234. return m_colorMode;
  235. }
  236. void SetWinPosition(int x, int y, int width, int height) {
  237. if(x >= 0 && y >= 0 && width >= 0 && height >= 0) {
  238. int nFullWidth = GetSystemMetrics(SM_CXSCREEN);
  239. int nFullHeight = GetSystemMetrics(SM_CYSCREEN);
  240. m_winSize.x = x;
  241. m_winSize.y = y;
  242. m_winSize.width = width;
  243. m_winSize.height = height;
  244. _resizeWindow();
  245. }
  246. }
  247. //Set region of capture.
  248. void SetROC(uchar region) {
  249. if(ROI_DEFAULT <= region && region < MAX_RIOMODE) {
  250. m_roiMode = region;
  251. if(m_roiMode == ROI_IDCER) {
  252. m_roiRate = 0.4f;
  253. } else {
  254. m_roiRate = 1.0f;
  255. }
  256. }
  257. }
  258. void SetROCValue(float value) {
  259. if(value >= 0.0f && value <= 1.0f) {
  260. m_roiRate = value;
  261. m_roiMode = ROI_CUSTOM;
  262. }
  263. }
  264. uchar GetROC() const {
  265. return m_roiMode;
  266. }
  267. void SetWinShown(bool bShown = true) {
  268. if(m_defWnd) {
  269. int nCmdShow = bShown ? SW_SHOW : SW_HIDE;
  270. ::ShowWindow(m_defWnd, nCmdShow);
  271. m_bHide = !bShown;
  272. }
  273. }
  274. void MouseClick( int event, int x, int y, int flags);
  275. void EvtFinishedHandle(USHORT evtCode, UCHAR result, UINT checksum);
  276. void SetHSPSType(bool bTrue = true) {
  277. m_bHSPSType = bTrue;
  278. }
  279. void SetResoultionRatio(int width, int height, int nframes = -1);
  280. DWORD GetError() const {
  281. return m_dwErrCode;
  282. }
  283. int ImageWriteUntil(LPCTSTR srcFilePath, const cv::Mat& src);
  284. int Resize(LPCTSTR srcFilePath, DWORD dwSrcFileSize, int compressRate);
  285. static DWORD GetFileSize(LPCTSTR srcFilePath);
  286. private:
  287. static UINT WINAPI WndPreviewDlgProc(PVOID param);
  288. bool InitHwndForNotify();
  289. bool RegisterVideoNotify();
  290. bool UnRegisterVideoNotify();
  291. bool IsColorAbnormal(IplImage* src);
  292. bool IsFrameFuzzy(IplImage* src);
  293. void _cleanup(bool toReleaseVC = true) {
  294. if(m_fPreviewing) {
  295. TerminatePreview();
  296. if(!toReleaseVC)
  297. Sleep(1000); /* 减少 m_cvCap 析构时调用 release 卡死的几率 */
  298. }
  299. _destroyWindow();
  300. if(m_cvCap.isOpened()) {
  301. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("cvCap release...");
  302. m_cvCap.release();
  303. m_videoID = -1;
  304. winName.clear();
  305. devName.clear();
  306. }
  307. //_resetWinSize();
  308. m_dwErrCode = ERROR_NOT_READY;
  309. DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("cvCap release done");
  310. return;
  311. }
  312. void _setProperty();
  313. void _setMouseCallback();
  314. size_t _combineFileName(char* szFnBuf, size_t sizeLen);
  315. int _getCamIDByDevName(LPCTSTR lpcszDevName);
  316. size_t _setDevName(LPCTSTR lpszName) {
  317. if(lpszName == NULL) {
  318. devName = "";
  319. } else {
  320. if(!devName.empty()) {
  321. devName.clear();
  322. }
  323. devName = lpszName;
  324. }
  325. return devName.size();
  326. }
  327. int MatResize(const cv::Mat& src, cv::Mat& dest, int quantity = 95);
  328. private:
  329. int m_videoID;
  330. cv::VideoCapture m_cvCap;
  331. Mat m_cmFrame;
  332. HWND m_defWnd;
  333. DWORD m_dwErrCode;
  334. HRESULT m_hrCoInited;
  335. //Windows
  336. bool _initWindow(bool fShown = false);
  337. //It would be invoked when received TerminatePreview requirement.
  338. void _destroyWindow();
  339. HANDLE m_hPreviewPro;
  340. cv::String winName;
  341. cv::String devName;
  342. //status
  343. bool _isVal() const{
  344. return !!m_cvCap.isOpened();
  345. }
  346. //event queue
  347. EVENT_QUEUE m_requestList;
  348. bool HasRequest() {
  349. if(m_requestList.empty()) {
  350. return false;
  351. }
  352. return true;
  353. }
  354. UINT GetUniqueID() const {
  355. UINT id = m_requestList.size();
  356. assert(id < UINT_MAX);
  357. return id;
  358. }
  359. RequestEventPtr CreateRequestEvent(
  360. USHORT code,
  361. UCHAR status = EVTSTATUS_LOOSE,
  362. UCHAR priority = EVTPRIO_DEFAULT
  363. )
  364. {
  365. RequestEventPtr evt = ::CreateRequestEvent(code, status, priority);
  366. if(evt) {
  367. evt->evtUniqueID = GetUniqueID();
  368. evt->SetCapHandle(this);
  369. }
  370. return evt;
  371. }
  372. RequestEventPtr GetRequest(bool fServerSide = true, USHORT matchedCode = (USHORT)0) {
  373. assert(!fServerSide || !matchedCode);
  374. RequestEventPtr ptr = NULL;
  375. if(!m_requestList.empty()) {
  376. for(EVENT_QUEUE_ITER iter=m_requestList.begin();
  377. iter!=m_requestList.end(); ++iter) {
  378. assert((*iter));
  379. RequestEventPtr item = *iter;
  380. if(fServerSide && item->evtStatus == EVTSTATUS_QUEUING) {
  381. //TODO:
  382. item->evtStatus = EVTSTATUS_DEALING;
  383. ptr = item;
  384. break;
  385. }
  386. if(!fServerSide && ((item->evtStatus & EVTSTATUS_DONE_MASK) == EVTSTATUS_DONE_MASK)) {
  387. if(!matchedCode || (matchedCode == item->evtCode)) {
  388. ptr = item;
  389. break;
  390. }
  391. }
  392. }
  393. }
  394. return ptr;
  395. }
  396. int WaitForResponse(USHORT aimCode, DWORD dwMillSecond = INFINITE) {
  397. int nRet = EVTSTATUS_NOT_FOUND;
  398. RequestEventPtr item = NULL;
  399. const DWORD dwStart = GetTickCount();
  400. if(dwMillSecond == INFINITE) {
  401. //TODO:
  402. return nRet;
  403. }
  404. else {
  405. nRet = EVTSTATUS_TIMEOUT;
  406. while (getTickCount() >= dwStart + dwMillSecond)
  407. {
  408. item = GetRequest(false, aimCode);
  409. if(item) {
  410. nRet = item->evtStatus;
  411. break;
  412. }
  413. }
  414. }
  415. if(item) {
  416. //Destroy ??
  417. TakeOutFromRequestQueue(item);
  418. }
  419. return nRet;
  420. }
  421. bool TakeOutFromRequestQueue(RequestEventPtr pEvtReq) {
  422. int offset = -1;
  423. if(!m_requestList.empty()) {
  424. int tmp = 0;
  425. for(EVENT_QUEUE_ITER iter=m_requestList.begin() ;
  426. iter!=m_requestList.end(); ++iter, ++tmp) {
  427. if(pEvtReq->evtUniqueID == (*iter)->evtUniqueID
  428. && pEvtReq->evtCode == (*iter)->evtCode) {
  429. assert((*iter) == pEvtReq);
  430. offset = tmp;
  431. break;
  432. }
  433. }
  434. }
  435. if(offset != -1) {
  436. m_requestList.erase(m_requestList.begin()+offset);
  437. DestroyRequestEvent(&pEvtReq);
  438. return true;
  439. }
  440. return false;
  441. }
  442. int PostIntoRequestQueue(RequestEventPtr* ppEvtReq) {
  443. assert(ppEvtReq && *ppEvtReq);
  444. (*ppEvtReq)->evtStatus = EVTSTATUS_QUEUING;
  445. m_requestList.push_back(*ppEvtReq);
  446. return (int)(m_requestList.size());
  447. }
  448. void RequestQueueCleanup() {
  449. LOG_FUNCTION();
  450. if(!m_requestList.empty()) {
  451. for(EVENT_QUEUE_ITER iter=m_requestList.begin() ;
  452. iter!=m_requestList.end(); ++iter) {
  453. if((*iter) != NULL) {
  454. DestroyRequestEvent(&(*iter));
  455. }
  456. }
  457. m_requestList.clear();
  458. }
  459. }
  460. //Preview
  461. bool _executePreview();
  462. volatile bool m_fPreviewing;
  463. bool m_tpStopPreview;
  464. //Attributes
  465. uchar m_colorMode;
  466. uchar m_roiMode;
  467. float m_roiRate;
  468. BOOL m_bHide;
  469. cv::Rect m_winSize;
  470. void _resizeWindow() {
  471. if(m_defWnd != NULL) {
  472. BOOL bRet = ::SetWindowPos(m_defWnd, HWND_TOPMOST,
  473. m_winSize.x, m_winSize.y, m_winSize.width, m_winSize.height,
  474. m_bHide ? SWP_HIDEWINDOW : SWP_SHOWWINDOW);
  475. Area area = _getWindowRect();
  476. }
  477. }
  478. void _resetWinSize() {
  479. m_winSize.x = DR_X;
  480. m_winSize.y = DR_Y;
  481. m_winSize.width = DR_W;
  482. m_winSize.height = DR_H;
  483. }
  484. typedef Point Area;
  485. Area _getWindowRect() {
  486. Area res;
  487. if(m_defWnd != NULL) {
  488. RECT rect;
  489. GetClientRect(m_defWnd, &rect);
  490. res.x = rect.right - rect.left;
  491. res.y = rect.bottom - rect.top;
  492. }
  493. return res;
  494. }
  495. //Cut
  496. enum{ NOT_SET = 0, IN_PROCESS = 1, SET = 2 };
  497. static const int rectangle_thickness = 2;
  498. uchar rectStatus;
  499. void _setInterestArea();
  500. void _setResizeArea(float ratio = 1.0f);
  501. Rect rect;
  502. Rect drawableRect;
  503. // 后置摄像头对于画幅设置无效 -Josephus@2017126 14:51:14
  504. bool m_bHSPSType;
  505. CPortableScannerFSM* m_pFSM;
  506. void SetResetEvent() {
  507. if(m_pFSM) {
  508. m_pFSM->PostEventFIFO(new FSMEvent(USER_EVT_ERROR_IN_PREVIEW));
  509. }
  510. }
  511. };
  512. #endif //_TWINKLE_DOC_VIDEOCAP_H__