Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

709 lines
18 KiB

  1. /*****************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORPORATION, 1999-2000
  4. *
  5. * TITLE: StillPrc.cpp
  6. *
  7. * VERSION: 1.0
  8. *
  9. * AUTHOR: OrenR
  10. *
  11. * DATE: 2000/10/27
  12. *
  13. * DESCRIPTION: Implements Still Image Processing.
  14. *
  15. *****************************************************************************/
  16. #include <precomp.h>
  17. #pragma hdrstop
  18. #include <gphelper.h>
  19. using namespace Gdiplus;
  20. ///////////////////////////////
  21. // CStillProcessor Constructor
  22. //
  23. CStillProcessor::CStillProcessor() :
  24. m_bTakePicturePending(FALSE),
  25. m_hSnapshotReadyEvent(NULL),
  26. m_uiFileNumStartPoint(0)
  27. {
  28. DBG_FN("CStillProcessor::CStillProcessor");
  29. //
  30. // This event is used to wait for a picture to be returned to us from the
  31. // still pin on the capture filter (if it exists)
  32. //
  33. m_hSnapshotReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  34. ASSERT(m_hSnapshotReadyEvent != NULL);
  35. }
  36. ///////////////////////////////
  37. // CStillProcessor Destructor
  38. //
  39. CStillProcessor::~CStillProcessor()
  40. {
  41. DBG_FN("CStillProcessor::~CStillProcessor");
  42. if (m_hSnapshotReadyEvent)
  43. {
  44. CloseHandle(m_hSnapshotReadyEvent);
  45. m_hSnapshotReadyEvent = NULL;
  46. }
  47. }
  48. ///////////////////////////////
  49. // Init
  50. //
  51. HRESULT CStillProcessor::Init(CPreviewGraph *pPreviewGraph)
  52. {
  53. HRESULT hr = S_OK;
  54. m_pPreviewGraph = pPreviewGraph;
  55. return hr;
  56. }
  57. ///////////////////////////////
  58. // Term
  59. //
  60. HRESULT CStillProcessor::Term()
  61. {
  62. HRESULT hr = S_OK;
  63. m_pPreviewGraph = NULL;
  64. return hr;
  65. }
  66. ///////////////////////////////
  67. // SetTakePicturePending
  68. //
  69. HRESULT CStillProcessor::SetTakePicturePending(BOOL bTakePicturePending)
  70. {
  71. HRESULT hr = S_OK;
  72. m_bTakePicturePending = bTakePicturePending;
  73. return hr;
  74. }
  75. ///////////////////////////////
  76. // IsTakePicturePending
  77. //
  78. BOOL CStillProcessor::IsTakePicturePending()
  79. {
  80. return m_bTakePicturePending;
  81. }
  82. ///////////////////////////////
  83. // CreateImageDir
  84. //
  85. HRESULT CStillProcessor::CreateImageDir(
  86. const CSimpleString *pstrImagesDirectory)
  87. {
  88. DBG_FN("CStillProcessor::CreateImageDir");
  89. HRESULT hr = S_OK;
  90. ASSERT(pstrImagesDirectory != NULL);
  91. if (pstrImagesDirectory == NULL)
  92. {
  93. hr = E_POINTER;
  94. CHECK_S_OK2(hr, ("CStillProcessor::CreateImage received a NULL "
  95. "param"));
  96. return hr;
  97. }
  98. if (hr == S_OK)
  99. {
  100. m_strImageDir = *pstrImagesDirectory;
  101. m_uiFileNumStartPoint = 0;
  102. if (!RecursiveCreateDirectory(pstrImagesDirectory))
  103. {
  104. DBG_ERR(("ERROR: Failed to create directory '%ls', last "
  105. "error = %d",
  106. m_strImageDir.String(),
  107. ::GetLastError()));
  108. }
  109. else
  110. {
  111. DBG_TRC(("*** Images will be stored in '%ls' ***",
  112. m_strImageDir.String()));
  113. }
  114. }
  115. return hr;
  116. }
  117. ///////////////////////////////
  118. // DoesDirectoryExist
  119. //
  120. // Checks to see whether the given
  121. // fully qualified directory exists.
  122. BOOL CStillProcessor::DoesDirectoryExist(LPCTSTR pszDirectoryName)
  123. {
  124. DBG_FN("CStillProcessor::DoesDirectoryExist");
  125. BOOL bExists = FALSE;
  126. if (pszDirectoryName)
  127. {
  128. //
  129. // Try to determine if this directory exists
  130. //
  131. DWORD dwFileAttributes = GetFileAttributes(pszDirectoryName);
  132. if ((dwFileAttributes == 0xFFFFFFFF) ||
  133. !(dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
  134. {
  135. bExists = FALSE;
  136. }
  137. else
  138. {
  139. bExists = TRUE;
  140. }
  141. }
  142. else
  143. {
  144. bExists = FALSE;
  145. }
  146. return bExists;
  147. }
  148. ///////////////////////////////
  149. // RecursiveCreateDirectory
  150. //
  151. // Take a fully qualified path and
  152. // create the directory in pieces as
  153. // needed.
  154. //
  155. BOOL CStillProcessor::RecursiveCreateDirectory(
  156. const CSimpleString *pstrDirectoryName)
  157. {
  158. DBG_FN("CStillProcessor::RecursiveCreateDirectory");
  159. ASSERT(pstrDirectoryName != NULL);
  160. //
  161. // If this directory already exists, return true.
  162. //
  163. if (DoesDirectoryExist(*pstrDirectoryName))
  164. {
  165. return TRUE;
  166. }
  167. //
  168. // Otherwise try to create it.
  169. //
  170. CreateDirectory(*pstrDirectoryName, NULL);
  171. //
  172. // If it now exists, return true
  173. //
  174. if (DoesDirectoryExist(*pstrDirectoryName))
  175. {
  176. return TRUE;
  177. }
  178. else
  179. {
  180. //
  181. // Remove the last subdir and try again
  182. //
  183. int nFind = pstrDirectoryName->ReverseFind(TEXT('\\'));
  184. if (nFind >= 0)
  185. {
  186. RecursiveCreateDirectory(&(pstrDirectoryName->Left(nFind)));
  187. //
  188. // Now try to create it.
  189. //
  190. CreateDirectory(*pstrDirectoryName, NULL);
  191. }
  192. }
  193. //
  194. //Does it exist now?
  195. //
  196. return DoesDirectoryExist(*pstrDirectoryName);
  197. }
  198. ///////////////////////////////
  199. // RegisterStillProcessor
  200. //
  201. HRESULT CStillProcessor::RegisterStillProcessor(
  202. IStillSnapshot *pFilterOnCapturePin,
  203. IStillSnapshot *pFilterOnStillPin)
  204. {
  205. DBG_FN("CStillProcessor::RegisterStillProcessor");
  206. HRESULT hr = S_OK;
  207. m_CaptureCallbackParams.pStillProcessor = this;
  208. m_StillCallbackParams.pStillProcessor = this;
  209. if (pFilterOnCapturePin)
  210. {
  211. hr = pFilterOnCapturePin->RegisterSnapshotCallback(
  212. CStillProcessor::SnapshotCallback,
  213. (LPARAM) &m_CaptureCallbackParams);
  214. CHECK_S_OK2(hr, ("Failed to register for callbacks with WIA filter "
  215. " on capture pin"));
  216. }
  217. if (pFilterOnStillPin)
  218. {
  219. hr = pFilterOnStillPin->RegisterSnapshotCallback(
  220. CStillProcessor::SnapshotCallback,
  221. (LPARAM) &m_StillCallbackParams);
  222. CHECK_S_OK2(hr, ("Failed to register for callbacks with WIA filter "
  223. "on still pin"));
  224. }
  225. //
  226. // Reset our file name starting point number
  227. //
  228. m_uiFileNumStartPoint = 0;
  229. return hr;
  230. }
  231. ///////////////////////////////
  232. // WaitForNewImage
  233. //
  234. HRESULT CStillProcessor::WaitForNewImage(UINT uiTimeout,
  235. CSimpleString *pstrNewImageFullPath)
  236. {
  237. DBG_FN("CStillProcessor::WaitForCompletion");
  238. HRESULT hr = S_OK;
  239. //
  240. // Wait for callback function to return from Still Filter which will
  241. // trigger this event.
  242. //
  243. if (SUCCEEDED(hr) && m_hSnapshotReadyEvent)
  244. {
  245. DWORD dwRes = 0;
  246. //
  247. // Wait for snapshot to complete for dwTimeout seconds.
  248. //
  249. dwRes = WaitForSingleObject(m_hSnapshotReadyEvent, uiTimeout );
  250. if (dwRes == WAIT_OBJECT_0)
  251. {
  252. if (pstrNewImageFullPath)
  253. {
  254. pstrNewImageFullPath->Assign(m_strLastSavedFile);
  255. }
  256. }
  257. else
  258. {
  259. hr = E_FAIL;
  260. if (pstrNewImageFullPath)
  261. {
  262. pstrNewImageFullPath->Assign(TEXT(""));
  263. }
  264. if (dwRes == WAIT_TIMEOUT)
  265. {
  266. CHECK_S_OK2(hr, ("***Timed out waiting for "
  267. "m_hSnapshotReadyEvent!***"));
  268. }
  269. else if (dwRes == WAIT_ABANDONED)
  270. {
  271. CHECK_S_OK2(hr, ("***WAIT_ABANDONED while waiting for "
  272. "m_hSnapshotReadyEvent!***"));
  273. }
  274. else
  275. {
  276. CHECK_S_OK2(hr, ("***Unknown error (dwRes = %d) waiting "
  277. "for m_hSnapshotReadyEvent***", dwRes));
  278. }
  279. }
  280. }
  281. return hr;
  282. }
  283. ///////////////////////////////
  284. // ProcessImage
  285. //
  286. HRESULT CStillProcessor::ProcessImage(HGLOBAL hDIB)
  287. {
  288. DBG_FN("CStillProcessor::ProcessImage");
  289. HRESULT hr = S_OK;
  290. ASSERT(hDIB != NULL);
  291. if (hDIB == NULL)
  292. {
  293. hr = E_FAIL;
  294. CHECK_S_OK2(hr, ("CStillProcessor::ProcessImage, received NULL "
  295. "image data"));
  296. return hr;
  297. }
  298. if (SUCCEEDED(hr))
  299. {
  300. CSimpleString strJPEG;
  301. CSimpleString strBMP;
  302. hr = CreateFileName(&strJPEG, &strBMP);
  303. //
  304. // Save the new image to a file
  305. //
  306. hr = SaveToFile(hDIB, &strJPEG, &strBMP);
  307. //
  308. // Let people know the image is available...
  309. //
  310. if (IsTakePicturePending())
  311. {
  312. if (m_hSnapshotReadyEvent)
  313. {
  314. m_strLastSavedFile = strJPEG;
  315. SetEvent(m_hSnapshotReadyEvent);
  316. }
  317. else
  318. {
  319. DBG_WRN(("CStillProcessor::ProcessImage, failed to Set "
  320. "SnapshotReady event because it was NULL"));
  321. }
  322. }
  323. else
  324. {
  325. if (m_pPreviewGraph)
  326. {
  327. hr = m_pPreviewGraph->ProcessAsyncImage(&strJPEG);
  328. }
  329. else
  330. {
  331. DBG_WRN(("CStillProcessor::ProcessImage failed to call "
  332. "ProcessAsyncImage, m_pPreviewGraph is NULL"));
  333. }
  334. }
  335. }
  336. return hr;
  337. }
  338. ///////////////////////////////
  339. // SnapshotCallback
  340. //
  341. // Static Fn
  342. //
  343. // This function is called by the
  344. // WIA StreamSnapshot Filter
  345. // in wiasf.ax. It delivers to us
  346. // the newly captured still image.
  347. //
  348. BOOL CStillProcessor::SnapshotCallback(HGLOBAL hDIB,
  349. LPARAM lParam)
  350. {
  351. DBG_FN("CStillProcessor::SnapshotCallback");
  352. BOOL bSuccess = TRUE;
  353. SnapshotCallbackParam_t *pCallbackParam =
  354. (SnapshotCallbackParam_t*) lParam;
  355. if (pCallbackParam)
  356. {
  357. if (pCallbackParam->pStillProcessor)
  358. {
  359. pCallbackParam->pStillProcessor->ProcessImage(hDIB);
  360. }
  361. }
  362. else
  363. {
  364. bSuccess = FALSE;
  365. DBG_ERR(("CStillProcessor::SnapshotCallback, pCallbackParam is "
  366. "NULL when it should contain the snapshot callback params"));
  367. }
  368. return bSuccess;
  369. }
  370. ///////////////////////////////
  371. // ConvertToJPEG
  372. //
  373. // Takes a .bmp file and converts
  374. // it to a .jpg file
  375. HRESULT CStillProcessor::ConvertToJPEG(LPCTSTR pszInputFilename,
  376. LPCTSTR pszOutputFilename)
  377. {
  378. DBG_FN("CStillProcessor::ConvertToJPEG");
  379. HRESULT hr = CGdiPlusHelper().Convert(
  380. CSimpleStringConvert::WideString(
  381. CSimpleString(pszInputFilename)).String(),
  382. CSimpleStringConvert::WideString(
  383. CSimpleString(pszOutputFilename)).String(),
  384. ImageFormatJPEG);
  385. CHECK_S_OK(hr);
  386. return hr;
  387. }
  388. ///////////////////////////////
  389. // CreateFileName
  390. //
  391. HRESULT CStillProcessor::CreateFileName(CSimpleString *pstrJPEG,
  392. CSimpleString *pstrBMP)
  393. {
  394. HRESULT hr = S_OK;
  395. UINT uiNum = 0;
  396. ASSERT(pstrJPEG != NULL);
  397. ASSERT(pstrBMP != NULL);
  398. if ((pstrJPEG == NULL) ||
  399. (pstrBMP == NULL))
  400. {
  401. hr = E_POINTER;
  402. CHECK_S_OK2(hr, ("CStillProcessor::CreateFileName received "
  403. "NULL param"));
  404. return hr;
  405. }
  406. TCHAR szJPG[MAX_PATH + 1] = {0};
  407. CSimpleString strBaseName(IDS_SNAPSHOT, _Module.GetModuleInstance());
  408. CSimpleString strNumberFormat(IDS_NUM_FORMAT, _Module.GetModuleInstance());
  409. //
  410. // Get the lowest number JPG file name we can find.
  411. //
  412. m_uiFileNumStartPoint = NumberedFileName::GenerateLowestAvailableNumberedFileName(0,
  413. szJPG,
  414. (sizeof(szJPG) / sizeof(szJPG[0])) - 1,
  415. m_strImageDir,
  416. strBaseName,
  417. strNumberFormat,
  418. TEXT("jpg"),
  419. false,
  420. m_uiFileNumStartPoint);
  421. //
  422. // Save the returned JPG file name.
  423. //
  424. *pstrJPEG = szJPG;
  425. //
  426. // Give the BMP file, which is a temp file, the same name as the JPG
  427. // but strip off the JPG extension and attach the BMP extension instead.
  428. //
  429. pstrBMP->Assign(*pstrJPEG);
  430. *pstrBMP = pstrBMP->Left(pstrBMP->ReverseFind(TEXT(".jpg")));
  431. pstrBMP->Concat(TEXT(".bmp"));
  432. return hr;
  433. }
  434. ///////////////////////////////
  435. // SaveToFile
  436. //
  437. // This method is called when the
  438. // DShow filter driver delivers us
  439. // a new set of bits from a snapshot
  440. // that was just taken. We write these
  441. // bits out to a file.
  442. //
  443. HRESULT CStillProcessor::SaveToFile(HGLOBAL hDib,
  444. const CSimpleString *pstrJPEG,
  445. const CSimpleString *pstrBMP)
  446. {
  447. DBG_FN("CStillProcessor::SaveToFile");
  448. ASSERT(hDib != NULL);
  449. ASSERT(pstrJPEG != NULL);
  450. ASSERT(pstrBMP != NULL);
  451. HRESULT hr = S_OK;
  452. BITMAPINFO * pbmi = NULL;
  453. LPBYTE pImageBits = NULL;
  454. LPBYTE pColorTable = NULL;
  455. LPBYTE pFileBits = NULL;
  456. UINT uNum = 1;
  457. UINT uFileSize = 0;
  458. UINT uDibSize = 0;
  459. UINT uColorTableSize = 0;
  460. if ((hDib == NULL) ||
  461. (pstrJPEG == NULL) ||
  462. (pstrBMP == NULL))
  463. {
  464. hr = E_POINTER;
  465. CHECK_S_OK2(hr, ("CStillProcessor::SaveToFile, received NULL param"));
  466. return hr;
  467. }
  468. //
  469. // calculate where the bits are -- basically,
  470. // right after BITMAPINFOHEADER + color table
  471. //
  472. pbmi = (BITMAPINFO *)GlobalLock(hDib);
  473. if (pbmi)
  474. {
  475. //
  476. // Find the image bits
  477. //
  478. pImageBits = (LPBYTE)pbmi + sizeof(BITMAPINFOHEADER);
  479. if (pbmi->bmiHeader.biClrUsed)
  480. {
  481. pImageBits += pbmi->bmiHeader.biClrUsed * sizeof(RGBQUAD);
  482. }
  483. else if (pbmi->bmiHeader.biBitCount <= 8)
  484. {
  485. pImageBits += (1 << pbmi->bmiHeader.biBitCount) * sizeof(RGBQUAD);
  486. }
  487. else if (pbmi->bmiHeader.biCompression == BI_BITFIELDS)
  488. {
  489. pImageBits += (3 * sizeof(DWORD));
  490. }
  491. pColorTable = (LPBYTE)pbmi + pbmi->bmiHeader.biSize;
  492. uColorTableSize = (DWORD)(pImageBits - pColorTable);
  493. //
  494. // calculate the size of the image bits & size of full file
  495. //
  496. UINT uiSrcScanLineWidth = 0;
  497. UINT uiScanLineWidth = 0;
  498. // Align scanline to ULONG boundary
  499. uiSrcScanLineWidth = (pbmi->bmiHeader.biWidth *
  500. pbmi->bmiHeader.biBitCount) / 8;
  501. uiScanLineWidth = (uiSrcScanLineWidth + 3) & 0xfffffffc;
  502. //
  503. // Calculate DIB size and allocate memory for the DIB.
  504. uDibSize = (pbmi->bmiHeader.biHeight > 0) ?
  505. pbmi->bmiHeader.biHeight * uiScanLineWidth :
  506. -(pbmi->bmiHeader.biHeight) * uiScanLineWidth;
  507. uFileSize = sizeof(BITMAPFILEHEADER) +
  508. pbmi->bmiHeader.biSize +
  509. uColorTableSize +
  510. uDibSize;
  511. }
  512. else
  513. {
  514. hr = E_FAIL;
  515. CHECK_S_OK2(hr, ("Unable to lock hDib"));
  516. return hr;
  517. }
  518. //
  519. // Create a mapped view to the new file so we can start writing out
  520. // the bits...
  521. //
  522. CMappedView cmv(pstrBMP->String(), uFileSize, OPEN_ALWAYS);
  523. pFileBits = cmv.Bits();
  524. if (!pFileBits)
  525. {
  526. hr = E_FAIL;
  527. CHECK_S_OK2(hr, ("Filemapping failed"));
  528. return hr;
  529. }
  530. //
  531. // Write out BITMAPFILEHEADER
  532. //
  533. BITMAPFILEHEADER bmfh;
  534. bmfh.bfType = (WORD)'MB';
  535. bmfh.bfSize = sizeof(BITMAPFILEHEADER);
  536. bmfh.bfReserved1 = 0;
  537. bmfh.bfReserved2 = 0;
  538. bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) +
  539. (DWORD)(pImageBits - (LPBYTE)pbmi);
  540. memcpy( pFileBits, &bmfh, sizeof(BITMAPFILEHEADER));
  541. pFileBits += sizeof(BITMAPFILEHEADER);
  542. //
  543. // Write out BITMAPINFOHEADER
  544. //
  545. memcpy( pFileBits, pbmi, pbmi->bmiHeader.biSize );
  546. pFileBits += pbmi->bmiHeader.biSize;
  547. //
  548. // If there's a color table or color mask, write it out
  549. //
  550. if (pImageBits > pColorTable)
  551. {
  552. memcpy( pFileBits, pColorTable, pImageBits - pColorTable );
  553. pFileBits += (pImageBits - pColorTable);
  554. }
  555. //
  556. // Write out the image bits
  557. //
  558. memcpy(pFileBits, pImageBits, uDibSize );
  559. //
  560. // We're done w/the image bits now & the file mapping
  561. //
  562. GlobalUnlock( hDib );
  563. cmv.CloseAndRelease();
  564. //
  565. // Convert image to .jpg file
  566. //
  567. if (SUCCEEDED(ConvertToJPEG(*pstrBMP, *pstrJPEG )))
  568. {
  569. DeleteFile(*pstrBMP);
  570. }
  571. else
  572. {
  573. DBG_ERR(("CStillProcessor::SaveToFile, failed to create image file '%ls'",
  574. pstrJPEG->String()));
  575. }
  576. return hr;
  577. }