DocScannerCap.h 13 KB

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