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.

1404 lines
31 KiB

  1. /****************************************************************************
  2. *
  3. * FILE: Videoui.cpp
  4. *
  5. * CREATED: Mark MacLin (MMacLin) 10-17-96
  6. *
  7. * CONTENTS: CVideo object
  8. *
  9. ****************************************************************************/
  10. // File: VideoUI.cpp
  11. #include "precomp.h"
  12. #include "avdefs.h"
  13. #include "video.h"
  14. #include "h323.h"
  15. #include <mperror.h>
  16. #include <initguid.h>
  17. #include <nacguids.h>
  18. #define INITIAL_FRAMERATE 700
  19. #define DibHdrSize(lpbi) ((lpbi)->biSize + (int)(lpbi)->biClrUsed * sizeof(RGBQUAD))
  20. #define DibDataSize(lpbi) ((lpbi)->biSizeImage)
  21. #define DibSize(lpbi) (DibHdrSize(lpbi) + DibDataSize(lpbi))
  22. //
  23. // SortOrder() and SetVideoSize() are helper functions for reordering the video
  24. // based on the notion of a "small", "medium", or "large" user preference that is
  25. // exposed by a property setting in INmChannelVideo::Setproperty. This
  26. // notion is flawed because there may be more or less than three sizes.
  27. // We should expose the possible sizes and let the application choose
  28. // a format. Unil then, this hack has to be here. The code for these two functions
  29. // was originally in vidstrm.cpp (in NAC.DLL)
  30. //
  31. //
  32. // types & globals used by SortOrder() and SetVideoSize()
  33. //
  34. // Used to translate between frame sizes and the FRAME_* bit flags
  35. #define NON_STANDARD 0x80000000
  36. #define SIZE_TO_FLAG(s) (s == Small ? FRAME_SQCIF : s == Medium ? FRAME_QCIF: s == Large ? FRAME_CIF : NON_STANDARD)
  37. // FORMATORDER: structure used in ::SetVideoSize to
  38. // use predefined frame size orders for different set size requests
  39. typedef struct _FORMATORDER
  40. {
  41. WORD indexCIF;
  42. WORD indexQCIF;
  43. WORD indexSQCIF;
  44. } FORMATORDER;
  45. // Table of sizes in order
  46. const FORMATORDER g_fmtOrderTable[3] =
  47. {
  48. { 0, 1, 2 }, // requestor asked for CIF
  49. { 2, 0, 1 }, // requestor asked for QCIF
  50. { 2, 1, 0 } // requestor asked for SQCIF
  51. };
  52. // SortOrder
  53. // Helper function to search for the specific format type and set its sort
  54. // order to the desired number
  55. // THIS WAS MOVED HERE FROM vidstrm.cpp
  56. //
  57. BOOL
  58. SortOrder(
  59. IAppVidCap *pavc,
  60. BASIC_VIDCAP_INFO* pvidcaps,
  61. DWORD dwcFormats,
  62. DWORD dwFlags,
  63. WORD wDesiredSortOrder,
  64. int nNumFormats
  65. )
  66. {
  67. int i, j;
  68. int nNumSizes = 0;
  69. int *aFrameSizes = (int *)NULL;
  70. int *aMinFrameSizes = (int *)NULL;
  71. int iMaxPos;
  72. WORD wTempPos, wMaxSortIndex;
  73. // Scale sort value
  74. wDesiredSortOrder *= (WORD)nNumFormats;
  75. // Local buffer of sizes that match dwFlags
  76. if (!(aFrameSizes = (int *)LocalAlloc(LPTR,nNumFormats * sizeof (int))))
  77. goto out;
  78. // Look through all the formats until we find the ones we want
  79. // Save the position of these entries
  80. for (i=0; i<(int)dwcFormats; i++)
  81. if (SIZE_TO_FLAG(pvidcaps[i].enumVideoSize) == dwFlags)
  82. aFrameSizes[nNumSizes++] = i;
  83. // Now order those entries from highest to lowest sort index
  84. for (i=0; i<nNumSizes; i++)
  85. {
  86. for (iMaxPos = -1L, wMaxSortIndex=0UL, j=i; j<nNumSizes; j++)
  87. {
  88. if (pvidcaps[aFrameSizes[j]].wSortIndex > wMaxSortIndex)
  89. {
  90. wMaxSortIndex = pvidcaps[aFrameSizes[j]].wSortIndex;
  91. iMaxPos = j;
  92. }
  93. }
  94. if (iMaxPos != -1L)
  95. {
  96. wTempPos = (WORD)aFrameSizes[i];
  97. aFrameSizes[i] = aFrameSizes[iMaxPos];
  98. aFrameSizes[iMaxPos] = wTempPos;
  99. }
  100. }
  101. // Change the sort index of the sorted entries
  102. for (; nNumSizes--;)
  103. pvidcaps[aFrameSizes[nNumSizes]].wSortIndex = wDesiredSortOrder++;
  104. // Release memory
  105. LocalFree(aFrameSizes);
  106. return TRUE;
  107. out:
  108. return FALSE;
  109. }
  110. // ::SetVideoSize
  111. //
  112. // THIS WAS MOVED HERE FROM vidstrm.cpp
  113. HRESULT
  114. SetVideoSize(
  115. IH323CallControl *pH323CallControl,
  116. DWORD dwSizeFlags
  117. )
  118. {
  119. IAppVidCap* pavc;
  120. DWORD dwcFormats;
  121. DWORD dwcFormatsReturned;
  122. BASIC_VIDCAP_INFO* pvidcaps = NULL;
  123. BASIC_VIDCAP_INFO* pmin;
  124. DWORD *pvfx = NULL;
  125. DWORD i, j;
  126. int k;
  127. HRESULT hr = S_OK;
  128. int nNumFormatTags;
  129. // Validate parameters
  130. if (dwSizeFlags != FRAME_CIF && dwSizeFlags != FRAME_QCIF && dwSizeFlags != FRAME_SQCIF)
  131. return S_FALSE;;
  132. // Prepare for error
  133. hr = S_FALSE;
  134. // Get a vid cap interface
  135. if (pH323CallControl->QueryInterface(IID_IAppVidCap, (void **)&pavc) != S_OK)
  136. goto out;
  137. // Get the number of BASIC_VIDCAP_INFO structures available
  138. if (pavc->GetNumFormats((UINT*)&dwcFormats) != S_OK)
  139. goto out;
  140. // Allocate some memory to hold the list in
  141. if (!(pvidcaps = (BASIC_VIDCAP_INFO*)LocalAlloc(LPTR,dwcFormats * sizeof (BASIC_VIDCAP_INFO))))
  142. goto out;
  143. // Get the list
  144. if (pavc->EnumFormats(pvidcaps, dwcFormats * sizeof (BASIC_VIDCAP_INFO),
  145. (UINT*)&dwcFormatsReturned) != S_OK)
  146. goto out;
  147. // Use the preformatted list of choice here
  148. switch (dwSizeFlags)
  149. {
  150. default:
  151. case FRAME_CIF: i = 0; break;
  152. case FRAME_QCIF: i = 1; break;
  153. case FRAME_SQCIF: i = 2; break;
  154. }
  155. // Get the number of different format tags
  156. if (!(pvfx = (DWORD*)LocalAlloc(LPTR,dwcFormatsReturned * sizeof (DWORD))))
  157. goto out;
  158. ZeroMemory(pvfx,dwcFormatsReturned * sizeof (DWORD));
  159. if (dwcFormatsReturned)
  160. {
  161. for (nNumFormatTags = 1, pvfx[0] = pvidcaps[0].dwFormatTag, j=1; j<dwcFormatsReturned; j++)
  162. {
  163. for (k=0; k<nNumFormatTags; k++)
  164. if (pvidcaps[j].dwFormatTag == pvfx[k])
  165. break;
  166. if (k==nNumFormatTags)
  167. pvfx[nNumFormatTags++] = pvidcaps[j].dwFormatTag;
  168. }
  169. }
  170. // Set the sort order for the desired item
  171. if (!SortOrder(pavc, pvidcaps, dwcFormatsReturned, FRAME_CIF, g_fmtOrderTable[i].indexCIF, nNumFormatTags) ||
  172. !SortOrder(pavc, pvidcaps, dwcFormatsReturned, FRAME_QCIF, g_fmtOrderTable[i].indexQCIF, nNumFormatTags) ||
  173. !SortOrder(pavc, pvidcaps, dwcFormatsReturned, FRAME_SQCIF, g_fmtOrderTable[i].indexSQCIF, nNumFormatTags))
  174. {
  175. goto out;
  176. }
  177. // Always pack indices
  178. for (i=0; i<dwcFormatsReturned; i++)
  179. {
  180. // First find an entry with a sort index larger or equal to i
  181. for (j=0; j<dwcFormatsReturned; j++)
  182. {
  183. // if ((pvidcaps[j].wSortIndex >= i) || (!i && (pvidcaps[j].wSortIndex == 0)))
  184. if (pvidcaps[j].wSortIndex >= i)
  185. {
  186. pmin = &pvidcaps[j];
  187. break;
  188. }
  189. }
  190. // First the smallest entry larger or equal to i
  191. for (; j<dwcFormatsReturned; j++)
  192. {
  193. if ((pvidcaps[j].wSortIndex < pmin->wSortIndex) && (pvidcaps[j].wSortIndex >= i))
  194. pmin = &pvidcaps[j];
  195. }
  196. // Update sort index
  197. pmin->wSortIndex = (WORD)i;
  198. }
  199. // Ok, now submit this list
  200. if (pavc->ApplyAppFormatPrefs(pvidcaps, dwcFormats) != S_OK)
  201. {
  202. goto out;
  203. }
  204. hr = S_OK;
  205. out:
  206. // Free the memory, we're done
  207. if (pvidcaps)
  208. LocalFree(pvidcaps);
  209. if (pvfx)
  210. LocalFree(pvfx);
  211. // let the interface go
  212. if (pavc)
  213. pavc->Release();
  214. return hr;
  215. }
  216. CVideoPump::CVideoPump(BOOL fLocal) :
  217. m_fPaused(FALSE),
  218. m_dwUser(0),
  219. m_pfnCallback(NULL),
  220. m_dwLastFrameRate(0),
  221. m_fLocal(fLocal),
  222. m_fChannelOpen(FALSE),
  223. m_pImage(NULL),
  224. m_pVideoRender(NULL),
  225. m_BestFormat(INVALID_MEDIA_FORMAT),
  226. m_NewFormat(INVALID_MEDIA_FORMAT),
  227. m_fOpenPending(FALSE),
  228. m_fReopenPending(FALSE),
  229. m_fClosePending(FALSE)
  230. {
  231. }
  232. CVideoPump::~CVideoPump()
  233. {
  234. if (NULL != m_pVideoRender)
  235. {
  236. m_pVideoRender->Done();
  237. m_pVideoRender->Release();
  238. }
  239. ReleaseImage();
  240. if (NULL != m_pIVideoDevice)
  241. {
  242. m_pIVideoDevice->Release();
  243. }
  244. if (NULL != m_pMediaStream)
  245. {
  246. m_pMediaStream->Release();
  247. }
  248. if (NULL != m_pPreviewChannel)
  249. {
  250. m_pPreviewChannel->Release();
  251. }
  252. if (NULL != m_pCommChannel)
  253. {
  254. m_pCommChannel->Release();
  255. }
  256. }
  257. BOOL CVideoPump::ChanInitialize(ICommChannel* pCommChannel)
  258. {
  259. HRESULT hr;
  260. BOOL bRet = TRUE;
  261. if(m_pPreviewChannel && m_pPreviewChannel == pCommChannel)
  262. {
  263. ASSERT(m_pVideoRender && m_pCommChannel == pCommChannel);
  264. //m_pCommChannel = pCommChannel;
  265. }
  266. else
  267. {
  268. m_pCommChannel = pCommChannel;
  269. m_pCommChannel->AddRef();
  270. }
  271. return bRet;
  272. }
  273. BOOL CVideoPump::Initialize(IH323CallControl *pH323CallControl, IMediaChannel *pMC,
  274. IVideoDevice *pVideoDevice, DWORD_PTR dwUser, LPFNFRAMEREADY pfnCallback)
  275. {
  276. HRESULT hr;
  277. m_dwUser = dwUser;
  278. m_pfnCallback = pfnCallback;
  279. m_pMediaStream = pMC;
  280. m_pMediaStream->AddRef();
  281. if(m_fLocal)
  282. {
  283. GUID mediaID = MEDIA_TYPE_H323VIDEO;
  284. hr = pH323CallControl->CreateLocalCommChannel(&m_pPreviewChannel, &mediaID, m_pMediaStream);
  285. if(FAILED(hr))
  286. {
  287. ASSERT(0);
  288. return FALSE;
  289. }
  290. m_pCommChannel = m_pPreviewChannel;
  291. m_pCommChannel->AddRef();
  292. }
  293. hr = m_pMediaStream->QueryInterface(IID_IVideoRender, (void **)&m_pVideoRender);
  294. if(FAILED(hr))
  295. {
  296. ASSERT(0);
  297. return FALSE;
  298. }
  299. hr = m_pVideoRender->Init(m_dwUser, m_pfnCallback);
  300. if(FAILED(hr))
  301. {
  302. ASSERT(0);
  303. m_pVideoRender->Release();
  304. m_pVideoRender = NULL;
  305. return FALSE;
  306. }
  307. ASSERT(pVideoDevice);
  308. m_pIVideoDevice = pVideoDevice;
  309. m_pIVideoDevice->AddRef();
  310. m_fChannelOpen = FALSE;
  311. m_dwLastFrameRate = INITIAL_FRAMERATE;
  312. m_fPaused = TRUE;
  313. EnableXfer(FALSE); // need to store state locally, set it in OnChannelOpen
  314. return TRUE;
  315. }
  316. HRESULT CVideoPump::GetFrame(FRAMECONTEXT *pFrameContext)
  317. {
  318. HRESULT hr;
  319. // if we are paused m_pImage will be a pointer to the saved DIB
  320. if (NULL != m_pImage)
  321. {
  322. *pFrameContext = m_FrameContext;
  323. hr = S_OK;
  324. }
  325. else
  326. {
  327. if(m_pVideoRender)
  328. {
  329. hr = m_pVideoRender->GetFrame(pFrameContext);
  330. }
  331. else
  332. {
  333. hr = S_FALSE;
  334. }
  335. if (S_OK == hr)
  336. {
  337. // data pump may be sending a bogus lpClipRect, so ...
  338. // if lpClipRect is NULL, calculate rect from bmiHeader
  339. if (NULL == pFrameContext->lpClipRect) {
  340. // calculate clip rect from BITMAPINFOHEADER
  341. m_ClipRect.left = m_ClipRect.top = 0;
  342. m_ClipRect.right = pFrameContext->lpbmi->bmiHeader.biWidth;
  343. m_ClipRect.bottom = pFrameContext->lpbmi->bmiHeader.biHeight;
  344. pFrameContext->lpClipRect = &m_ClipRect;
  345. }
  346. }
  347. }
  348. return hr;
  349. }
  350. HRESULT CVideoPump::ReleaseFrame(FRAMECONTEXT *pFrameContext)
  351. {
  352. // release the frame if it is not the saved DIB
  353. if ((m_pImage != (LPBYTE)pFrameContext->lpbmi) && m_pVideoRender)
  354. {
  355. // if lpClipRect was NULL (see GetFrame), restore it
  356. if (&m_ClipRect == pFrameContext->lpClipRect)
  357. {
  358. pFrameContext->lpClipRect = NULL;
  359. }
  360. return m_pVideoRender->ReleaseFrame(pFrameContext);
  361. }
  362. return S_OK;
  363. }
  364. VOID CVideoPump::SnapImage ()
  365. {
  366. FRAMECONTEXT FrameContext;
  367. if ((NULL == m_pImage) && m_pVideoRender)
  368. {
  369. if (S_OK == m_pVideoRender->GetFrame(&FrameContext))
  370. {
  371. BITMAPINFOHEADER *pbmih;
  372. pbmih = &FrameContext.lpbmi->bmiHeader;
  373. m_pImage = (LPBYTE)LocalAlloc(LPTR, DibSize(pbmih));
  374. if (NULL != m_pImage)
  375. {
  376. int nHdrSize = DibHdrSize(pbmih);
  377. CopyMemory(m_pImage, pbmih, nHdrSize);
  378. CopyMemory(m_pImage + nHdrSize, FrameContext.lpData, DibDataSize(pbmih));
  379. m_FrameContext.lpbmi = (LPBITMAPINFO)m_pImage;
  380. m_FrameContext.lpData = (LPBYTE)m_pImage + nHdrSize;
  381. if (NULL != FrameContext.lpClipRect)
  382. {
  383. m_ClipRect = *FrameContext.lpClipRect;
  384. }
  385. else
  386. {
  387. m_ClipRect.left = m_ClipRect.top = 0;
  388. m_ClipRect.right = m_FrameContext.lpbmi->bmiHeader.biWidth;
  389. m_ClipRect.bottom = m_FrameContext.lpbmi->bmiHeader.biHeight;
  390. }
  391. m_FrameContext.lpClipRect = &m_ClipRect;
  392. }
  393. m_pVideoRender->ReleaseFrame(&FrameContext);
  394. }
  395. }
  396. }
  397. VOID CVideoPump::ReleaseImage ()
  398. {
  399. if (NULL != m_pImage)
  400. {
  401. LocalFree(m_pImage);
  402. m_pImage = NULL;
  403. }
  404. }
  405. VOID CVideoPump::Pause(BOOL fPause)
  406. {
  407. m_fPaused = fPause;
  408. // ideally we would like the data pump to hold onto the last frame
  409. // so that we don't have to do this
  410. if (m_fPaused)
  411. {
  412. if (m_fChannelOpen)
  413. {
  414. SnapImage();
  415. }
  416. EnableXfer(FALSE);
  417. }
  418. else
  419. {
  420. EnableXfer(TRUE);
  421. ReleaseImage();
  422. }
  423. }
  424. BOOL CVideoPump::IsXferEnabled()
  425. {
  426. if (m_fLocal)
  427. {
  428. return IsSendEnabled();
  429. }
  430. return IsReceiveEnabled();
  431. }
  432. VOID CVideoPump::Open(MEDIA_FORMAT_ID format_id)
  433. {
  434. if(!m_pCommChannel)
  435. {
  436. return;
  437. }
  438. m_pCommChannel->PauseNetworkStream(FALSE);
  439. m_pCommChannel->EnableOpen(TRUE);
  440. if (m_fLocal)
  441. {
  442. HRESULT hr;
  443. // if the channel is not open and a call is in progress, now is the time
  444. if(m_pConnection && m_pCommChannel)
  445. {
  446. // a call is in progress
  447. if(!IsChannelOpen()
  448. && !m_fOpenPending)
  449. {
  450. // so, the channel is not open
  451. if(format_id != INVALID_MEDIA_FORMAT)
  452. {
  453. // try to open a channel using specified format
  454. m_fOpenPending = TRUE; // do this first (callbacks!)
  455. hr = m_pCommChannel->Open(format_id, m_pConnection);
  456. if(FAILED(hr))
  457. m_fOpenPending = FALSE;
  458. }
  459. }
  460. else if (m_fClosePending)
  461. {
  462. m_NewFormat = format_id;
  463. if(format_id != INVALID_MEDIA_FORMAT)
  464. {
  465. m_fClosePending = FALSE;
  466. m_fReopenPending = TRUE;
  467. hr = m_pCommChannel->Close();
  468. }
  469. }
  470. }
  471. }
  472. }
  473. VOID CVideoPump::Close()
  474. {
  475. HRESULT hr;
  476. hr = m_pCommChannel->Close();
  477. // what to do about an error?
  478. }
  479. VOID CVideoPump::EnableXfer(BOOL fEnable)
  480. {
  481. if (m_fLocal)
  482. {
  483. if (fEnable)
  484. {
  485. HRESULT hr;
  486. SetFrameRate(m_dwLastFrameRate);
  487. EnablePreview(TRUE);
  488. EnableSend(TRUE);
  489. // if the channel is not open and a call is in progress, now is the time
  490. if(m_pConnection && m_pCommChannel)
  491. {
  492. // a call is in progress
  493. if(!IsChannelOpen()
  494. && !m_fOpenPending)
  495. {
  496. // so, the channel is not open
  497. m_BestFormat = m_NewFormat = CVideoProp::GetBestFormat();
  498. if(m_BestFormat != INVALID_MEDIA_FORMAT)
  499. {
  500. // try to open a channel using format m_BestFormat
  501. m_fOpenPending = TRUE; // do this first (callbacks!)
  502. hr = m_pCommChannel->Open(m_BestFormat, m_pConnection);
  503. if(FAILED(hr))
  504. m_fOpenPending = FALSE;
  505. }
  506. // else no common video formats exist and a channel cannot
  507. // be opened.
  508. }
  509. else if (m_fClosePending)
  510. {
  511. m_BestFormat = m_NewFormat = CVideoProp::GetBestFormat();
  512. if(m_BestFormat != INVALID_MEDIA_FORMAT)
  513. {
  514. m_fClosePending = FALSE;
  515. m_fReopenPending = TRUE;
  516. hr = m_pCommChannel->Close();
  517. }
  518. }
  519. }
  520. }
  521. else
  522. {
  523. if (IsSendEnabled())
  524. {
  525. m_dwLastFrameRate = GetFrameRate();
  526. }
  527. EnablePreview(FALSE);
  528. EnableSend(FALSE);
  529. }
  530. }
  531. else
  532. {
  533. EnableReceive(fEnable);
  534. }
  535. }
  536. VOID CVideoPump::SetFrameSize(DWORD dwValue)
  537. {
  538. CVideoProp::SetFrameSize(dwValue);
  539. ForceCaptureChange();
  540. }
  541. VOID CVideoPump::OnConnected(IH323Endpoint * lpConnection, ICommChannel *pIChannel)
  542. {
  543. m_pConnection = lpConnection;
  544. m_fOpenPending = m_fReopenPending = m_fClosePending = FALSE;
  545. }
  546. VOID CVideoPump::OnChannelOpened(ICommChannel *pIChannel)
  547. {
  548. HRESULT hr;
  549. m_fChannelOpen = TRUE;
  550. m_fOpenPending = FALSE;
  551. ChanInitialize(pIChannel);
  552. ASSERT(m_pMediaStream);
  553. if (m_fLocal)
  554. {
  555. m_fSend = TRUE;
  556. EnableXfer(TRUE);
  557. // if video size changed while waiting for the channel to be opened,
  558. // then need to close again, then reopen again using the new format
  559. if(m_BestFormat != m_NewFormat)
  560. {
  561. ForceCaptureChange();
  562. }
  563. else // make sure to track the video size
  564. {
  565. GetFrameSize();
  566. }
  567. }
  568. else
  569. {
  570. EnableXfer(m_fReceive);
  571. SetReceiveQuality(m_dwImageQuality);
  572. }
  573. ReleaseImage();
  574. }
  575. VOID CVideoPump::OnChannelError()
  576. {
  577. m_fOpenPending = FALSE;
  578. }
  579. NM_VIDEO_STATE CVideoPump::GetState()
  580. {
  581. NM_VIDEO_STATE state = NM_VIDEO_IDLE;
  582. if (IsChannelOpen())
  583. {
  584. if (IsXferEnabled())
  585. {
  586. if (IsRemotePaused())
  587. {
  588. state = NM_VIDEO_REMOTE_PAUSED;
  589. }
  590. else
  591. {
  592. state = NM_VIDEO_TRANSFERRING;
  593. }
  594. }
  595. else
  596. {
  597. if (IsRemotePaused())
  598. {
  599. state = NM_VIDEO_BOTH_PAUSED;
  600. }
  601. else
  602. {
  603. state = NM_VIDEO_LOCAL_PAUSED;
  604. }
  605. }
  606. }
  607. else
  608. {
  609. if (IsXferEnabled())
  610. {
  611. state = NM_VIDEO_PREVIEWING;
  612. }
  613. }
  614. return state;
  615. }
  616. VOID CVideoPump::OnChannelClosed()
  617. {
  618. m_fChannelOpen = FALSE;
  619. HRESULT hr;
  620. if(m_pPreviewChannel)
  621. {
  622. if(m_fReopenPending)
  623. {
  624. m_fReopenPending = FALSE;
  625. if(m_BestFormat != INVALID_MEDIA_FORMAT )
  626. {
  627. m_fOpenPending = TRUE;
  628. hr = m_pCommChannel->Open(m_BestFormat, m_pConnection);
  629. if(FAILED(hr))
  630. m_fOpenPending = FALSE;
  631. }
  632. }
  633. else if(CVideoProp::IsPreviewEnabled())
  634. {
  635. EnablePreview(TRUE);
  636. }
  637. }
  638. else
  639. {
  640. if(m_pCommChannel)
  641. {
  642. m_pCommChannel->Release();
  643. m_pCommChannel = NULL;
  644. }
  645. }
  646. }
  647. VOID CVideoPump::OnDisconnected()
  648. {
  649. m_pConnection = NULL;
  650. if(m_dwFrameSize != m_dwPreferredFrameSize)
  651. {
  652. SetFrameSize(m_dwPreferredFrameSize);
  653. }
  654. if (!IsLocal())
  655. {
  656. EnableXfer(FALSE);
  657. }
  658. ReleaseImage();
  659. }
  660. CVideoProp::CVideoProp() :
  661. m_pCommChannel(NULL),
  662. m_pPreviewChannel(NULL),
  663. m_pConnection(NULL),
  664. m_pMediaStream(NULL),
  665. m_pIVideoDevice(NULL)
  666. {
  667. }
  668. VOID CVideoProp::EnableSend(BOOL fEnable)
  669. {
  670. m_fSend = fEnable;
  671. BOOL bPause = (fEnable)? FALSE :TRUE;
  672. ASSERT(m_pCommChannel);
  673. m_pCommChannel->PauseNetworkStream(bPause);
  674. m_pCommChannel->EnableOpen(fEnable);
  675. }
  676. BOOL CVideoProp::IsSendEnabled()
  677. {
  678. return m_fSend;
  679. }
  680. VOID CVideoProp::EnableReceive(BOOL fEnable)
  681. {
  682. m_fReceive = fEnable;
  683. BOOL fPause = !fEnable;
  684. if(m_pCommChannel)
  685. {
  686. m_pCommChannel->PauseNetworkStream(fPause);
  687. }
  688. }
  689. BOOL CVideoProp::IsReceiveEnabled()
  690. {
  691. return m_fReceive;
  692. }
  693. VOID CVideoProp::EnablePreview(BOOL fEnable)
  694. {
  695. m_fPreview = fEnable;
  696. MEDIA_FORMAT_ID FormatID;
  697. if(m_pCommChannel)
  698. {
  699. if(m_fPreview)
  700. {
  701. // get format to preview, then do it
  702. FormatID = GetBestFormat();
  703. if(FormatID != INVALID_MEDIA_FORMAT)
  704. {
  705. m_pCommChannel->Preview(FormatID, m_pMediaStream);
  706. }
  707. }
  708. else
  709. {
  710. m_pCommChannel->Preview(INVALID_MEDIA_FORMAT, NULL);
  711. }
  712. }
  713. }
  714. BOOL CVideoProp::IsPreviewEnabled()
  715. {
  716. return m_fPreview;
  717. }
  718. BOOL CVideoProp::IsRemotePaused()
  719. {
  720. if(m_pCommChannel)
  721. return m_pCommChannel->IsRemotePaused();
  722. else
  723. return FALSE;
  724. }
  725. VOID CVideoProp::SetFrameRate(DWORD dwValue)
  726. {
  727. m_dwFrameRate = dwValue;
  728. ASSERT(m_pMediaStream);
  729. m_pMediaStream->SetProperty(
  730. PROP_VIDEO_FRAME_RATE,
  731. &dwValue,
  732. sizeof(dwValue));
  733. }
  734. DWORD CVideoProp::GetFrameRate()
  735. {
  736. DWORD dwValue;
  737. UINT uSize = sizeof(dwValue);
  738. ASSERT(m_pMediaStream);
  739. m_pMediaStream->GetProperty(
  740. PROP_VIDEO_FRAME_RATE,
  741. &dwValue,
  742. &uSize);
  743. TRACE_OUT(("GetFrameRate returns %d", dwValue));
  744. return dwValue;
  745. }
  746. MEDIA_FORMAT_ID CVideoProp::GetBestFormat()
  747. {
  748. IAppVidCap* pavc = NULL;
  749. UINT cFormats;
  750. BASIC_VIDCAP_INFO* pvidcaps = NULL;
  751. MEDIA_FORMAT_ID FormatID = INVALID_MEDIA_FORMAT;
  752. // Get a vid cap interface. If in a call, use the best common format
  753. //
  754. if(!m_pConnection)
  755. {
  756. // not in a call - use the best local format period
  757. if(!m_pCommChannel)
  758. goto out;
  759. if (m_pCommChannel->QueryInterface(IID_IAppVidCap, (void **)&pavc) != S_OK)
  760. goto out;
  761. // Get the number of BASIC_VIDCAP_INFO structures available
  762. if (pavc->GetNumFormats(&cFormats) != S_OK)
  763. goto out;
  764. if(cFormats < 1)
  765. goto out;
  766. // Allocate some memory to hold the list in
  767. if (!(pvidcaps = (BASIC_VIDCAP_INFO*)LocalAlloc(LPTR, cFormats * sizeof (BASIC_VIDCAP_INFO))))
  768. goto out;
  769. // Get the list of local capabilities
  770. // (by the way, this is never called for receive video)
  771. if (pavc->EnumFormats(pvidcaps, cFormats * sizeof (BASIC_VIDCAP_INFO),
  772. &cFormats) != S_OK)
  773. goto out;
  774. // the output of EnumCommonFormats is in preferred order
  775. FormatID = pvidcaps[0].Id;
  776. }
  777. else
  778. {
  779. if (m_pConnection->QueryInterface(IID_IAppVidCap, (void **)&pavc) != S_OK)
  780. goto out;
  781. // Get the number of BASIC_VIDCAP_INFO structures available
  782. if (pavc->GetNumFormats(&cFormats) != S_OK)
  783. goto out;
  784. if(cFormats < 1)
  785. goto out;
  786. // Allocate some memory to hold the list in
  787. if (!(pvidcaps = (BASIC_VIDCAP_INFO*)LocalAlloc(LPTR, cFormats * sizeof (BASIC_VIDCAP_INFO))))
  788. goto out;
  789. // Get the list of viable transmit capabilities
  790. // (by the way, this is never called for receive video)
  791. if (pavc->EnumCommonFormats(pvidcaps, cFormats * sizeof (BASIC_VIDCAP_INFO),
  792. &cFormats, TRUE) != S_OK)
  793. goto out;
  794. // the output of EnumCommonFormats is in preferred order
  795. FormatID = pvidcaps[0].Id;
  796. }
  797. out:
  798. // Free the memory, we're done
  799. if (pvidcaps)
  800. LocalFree(pvidcaps);
  801. // let the interface go
  802. if (pavc)
  803. pavc->Release();
  804. return FormatID;
  805. }
  806. VOID CVideoProp::SetFrameSize(DWORD dwValue)
  807. {
  808. IH323CallControl * pH323CallControl = g_pH323UI->GetH323CallControl();
  809. m_dwFrameSize = m_dwPreferredFrameSize = dwValue;
  810. ::SetVideoSize(pH323CallControl, m_dwFrameSize);
  811. }
  812. DWORD CVideoProp::GetFrameSize()
  813. {
  814. MEDIA_FORMAT_ID idCurrent;
  815. if(m_pCommChannel)
  816. {
  817. idCurrent = m_pCommChannel->GetConfiguredFormatID();
  818. m_dwFrameSize = GetFrameSizes(idCurrent);
  819. }
  820. return m_dwFrameSize;
  821. }
  822. DWORD CVideoProp::GetFrameSizes(MEDIA_FORMAT_ID idSpecificFormat)
  823. {
  824. DWORD dwValue = 0; //FRAME_SQCIF | FRAME_QCIF | FRAME_CIF;
  825. HRESULT hr;
  826. BOOL bOpen = FALSE;
  827. ASSERT(m_pCommChannel);
  828. // Used to translate between frame sizes and the FRAME_* bit flags
  829. #define NON_STANDARD 0x80000000
  830. #define SIZE_TO_FLAG(s) (s == Small ? FRAME_SQCIF : s == Medium ? FRAME_QCIF: s == Large ? FRAME_CIF : NON_STANDARD)
  831. IAppVidCap* pavc = NULL;
  832. DWORD dwcFormats;
  833. DWORD dwcFormatsReturned;
  834. BASIC_VIDCAP_INFO* pvidcaps = NULL;
  835. DWORD i;
  836. DWORD dwSizes = 0;
  837. DWORD dwThisSize;
  838. // Get a vid cap interface
  839. hr = m_pCommChannel->QueryInterface(IID_IAppVidCap, (void **)&pavc);
  840. if (hr != S_OK)
  841. goto out;
  842. // Get the number of BASIC_VIDCAP_INFO structures available
  843. hr = pavc->GetNumFormats((UINT*)&dwcFormats);
  844. if (hr != S_OK)
  845. goto out;
  846. // Allocate some memory to hold the list in
  847. if (!(pvidcaps = (BASIC_VIDCAP_INFO*)LocalAlloc(LPTR, dwcFormats * sizeof (BASIC_VIDCAP_INFO))))
  848. {
  849. // report that no sizes are available?
  850. // dwValue = 0FRAME_SQCIF | FRAME_QCIF | FRAME_CIF;
  851. goto out;
  852. }
  853. // if an active session, use common caps from that session
  854. hr = m_pCommChannel->IsChannelOpen(&bOpen);
  855. // if hr is an error, so what. it will take the channel not open path
  856. if(bOpen)
  857. {
  858. // Get the list of common formats
  859. hr = pavc->EnumCommonFormats(pvidcaps, dwcFormats * sizeof (BASIC_VIDCAP_INFO),
  860. (UINT*)&dwcFormatsReturned, m_fSend);
  861. if(hr != S_OK)
  862. {
  863. // if the error is simply because there are no remote video caps, get the local formats
  864. if(hr == CAPS_E_NOCAPS)
  865. {
  866. hr = pavc->EnumFormats(pvidcaps, dwcFormats * sizeof (BASIC_VIDCAP_INFO),
  867. (UINT*)&dwcFormatsReturned);
  868. if (hr != S_OK)
  869. goto out;
  870. }
  871. else
  872. goto out;
  873. }
  874. }
  875. else
  876. {
  877. hr = pavc->EnumFormats(pvidcaps, dwcFormats * sizeof (BASIC_VIDCAP_INFO),
  878. (UINT*)&dwcFormatsReturned);
  879. if (hr != S_OK)
  880. goto out;
  881. }
  882. if(bOpen && (idSpecificFormat != INVALID_MEDIA_FORMAT ))
  883. {
  884. // Now walk through the list to see what sizes are supported
  885. for (i = 0 ; i < dwcFormatsReturned ; i++)
  886. {
  887. if(pvidcaps[i].Id == idSpecificFormat)
  888. {
  889. dwThisSize = SIZE_TO_FLAG(pvidcaps[i].enumVideoSize);
  890. // As long as the macro found the size, return it to the property requester
  891. if (dwThisSize != NON_STANDARD)
  892. {
  893. dwSizes |= dwThisSize;
  894. }
  895. break;
  896. }
  897. }
  898. }
  899. else
  900. {
  901. // Now walk through the list to see what sizes are supported
  902. for (i = 0 ; i < dwcFormatsReturned ; i++)
  903. {
  904. if(m_fSend)
  905. {
  906. if(!pvidcaps[i].bSendEnabled)
  907. continue;
  908. }
  909. else
  910. {
  911. if(!pvidcaps[i].bRecvEnabled)
  912. continue;
  913. }
  914. // Convert to bit field sizes or NON_STANDARD
  915. dwThisSize = SIZE_TO_FLAG(pvidcaps[i].enumVideoSize);
  916. // As long as the macro found the size, return it to the property requester
  917. if (dwThisSize != NON_STANDARD)
  918. dwSizes |= dwThisSize;
  919. }
  920. }
  921. // Now that we've accumulated all the sizes, return them
  922. dwValue = dwSizes;
  923. out:
  924. // Free the memory, we're done
  925. if (pvidcaps)
  926. LocalFree(pvidcaps);
  927. // let the interface go
  928. if (pavc)
  929. pavc->Release();
  930. return dwValue;
  931. }
  932. BOOL CVideoProp::HasSourceDialog()
  933. {
  934. HRESULT hr;
  935. IVideoChannel *pVideoChannel=NULL;
  936. DWORD dwFlags;
  937. ASSERT(m_pMediaStream);
  938. hr = m_pMediaStream->QueryInterface(IID_IVideoChannel, (void**)&pVideoChannel);
  939. ASSERT(pVideoChannel);
  940. if (FAILED(hr))
  941. {
  942. return FALSE;
  943. }
  944. pVideoChannel->GetDeviceDialog(&dwFlags);
  945. pVideoChannel->Release();
  946. return dwFlags & CAPTURE_DIALOG_SOURCE;
  947. }
  948. BOOL CVideoProp::HasFormatDialog()
  949. {
  950. HRESULT hr;
  951. IVideoChannel *pVideoChannel=NULL;
  952. DWORD dwFlags;
  953. ASSERT(m_pMediaStream);
  954. hr = m_pMediaStream->QueryInterface(IID_IVideoChannel, (void**)&pVideoChannel);
  955. ASSERT(pVideoChannel);
  956. if (FAILED(hr))
  957. {
  958. return FALSE;
  959. }
  960. pVideoChannel->GetDeviceDialog(&dwFlags);
  961. pVideoChannel->Release();
  962. return dwFlags & CAPTURE_DIALOG_FORMAT;
  963. }
  964. VOID CVideoProp::ShowSourceDialog()
  965. {
  966. DWORD dwFlags = CAPTURE_DIALOG_SOURCE;
  967. HRESULT hr;
  968. IVideoChannel *pVideoChannel=NULL;
  969. ASSERT(m_pMediaStream);
  970. hr = m_pMediaStream->QueryInterface(IID_IVideoChannel, (void**)&pVideoChannel);
  971. ASSERT(pVideoChannel);
  972. if (SUCCEEDED(hr))
  973. {
  974. pVideoChannel->ShowDeviceDialog(dwFlags);
  975. pVideoChannel->Release();
  976. }
  977. }
  978. VOID CVideoProp::ShowFormatDialog()
  979. {
  980. DWORD dwFlags = CAPTURE_DIALOG_FORMAT;
  981. HRESULT hr;
  982. IVideoChannel *pVideoChannel=NULL;
  983. ASSERT(m_pMediaStream);
  984. hr = m_pMediaStream->QueryInterface(IID_IVideoChannel, (void**)&pVideoChannel);
  985. ASSERT(pVideoChannel);
  986. if (SUCCEEDED(hr))
  987. {
  988. pVideoChannel->ShowDeviceDialog(dwFlags);
  989. pVideoChannel->Release();
  990. }
  991. }
  992. VOID CVideoProp::SetReceiveQuality(DWORD dwValue)
  993. {
  994. m_dwImageQuality = dwValue;
  995. if(m_pCommChannel)
  996. {
  997. dwValue = MAX_VIDEO_QUALITY - dwValue;
  998. m_pCommChannel->SetProperty(
  999. PROP_TS_TRADEOFF,
  1000. &dwValue,
  1001. sizeof(dwValue));
  1002. }
  1003. }
  1004. DWORD CVideoProp::GetReceiveQuality()
  1005. {
  1006. return m_dwImageQuality;
  1007. }
  1008. BOOL CVideoProp::IsCaptureAvailable()
  1009. {
  1010. ULONG uNumCapDevs;
  1011. ASSERT(m_pIVideoDevice);
  1012. uNumCapDevs = m_pIVideoDevice->GetNumCapDev();
  1013. return (uNumCapDevs > 0);
  1014. }
  1015. BOOL CVideoProp::IsCaptureSuspended()
  1016. {
  1017. BOOL fStandby;
  1018. UINT uSize = sizeof(fStandby);
  1019. ASSERT(m_pCommChannel);
  1020. m_pCommChannel->GetProperty(
  1021. PROP_VIDEO_PREVIEW_STANDBY,
  1022. &fStandby,
  1023. &uSize);
  1024. return fStandby;
  1025. }
  1026. VOID CVideoProp::SuspendCapture(BOOL fSuspend)
  1027. {
  1028. ASSERT(m_pCommChannel);
  1029. if (fSuspend)
  1030. {
  1031. // Enable standby
  1032. m_pCommChannel->SetProperty(
  1033. PROP_VIDEO_PREVIEW_STANDBY,
  1034. &fSuspend,
  1035. sizeof(fSuspend));
  1036. m_pCommChannel->Preview(INVALID_MEDIA_FORMAT, NULL);
  1037. }
  1038. else
  1039. {
  1040. if(m_fPreview)
  1041. {
  1042. // get format to preview, then do it
  1043. MEDIA_FORMAT_ID FormatID = GetBestFormat();
  1044. if(FormatID != INVALID_MEDIA_FORMAT)
  1045. {
  1046. m_pCommChannel->Preview(FormatID, m_pMediaStream);
  1047. }
  1048. // Disable standby
  1049. m_pCommChannel->SetProperty(
  1050. PROP_VIDEO_PREVIEW_STANDBY,
  1051. &fSuspend,
  1052. sizeof(fSuspend));
  1053. }
  1054. else
  1055. {
  1056. m_pCommChannel->Preview(INVALID_MEDIA_FORMAT, NULL);
  1057. }
  1058. }
  1059. }
  1060. // Gets the number of enabled capture devices
  1061. // Returns -1L on error
  1062. int CVideoProp::GetNumCapDev()
  1063. {
  1064. ASSERT(m_pIVideoDevice);
  1065. return (m_pIVideoDevice->GetNumCapDev());
  1066. }
  1067. // Gets the max size of the captuire device name
  1068. // Returns -1L on error
  1069. int CVideoProp::GetMaxCapDevNameLen()
  1070. {
  1071. ASSERT(m_pIVideoDevice);
  1072. return (m_pIVideoDevice->GetMaxCapDevNameLen());
  1073. }
  1074. // Enum list of enabled capture devices
  1075. // Fills up 1st buffer with device IDs, 2nd buffer with device names
  1076. // Third parameter is the number of devices to enum
  1077. // Returns -1L on error
  1078. BOOL CVideoProp::EnumCapDev(DWORD *pdwCapDevIDs, TCHAR *pszCapDevNames, DWORD dwNumCapDev)
  1079. {
  1080. ASSERT(m_pIVideoDevice);
  1081. return (S_OK != m_pIVideoDevice->EnumCapDev(pdwCapDevIDs, pszCapDevNames, dwNumCapDev));
  1082. }
  1083. // Returns the ID of the currently selected device
  1084. // Returns -1L on error
  1085. int CVideoProp::GetCurrCapDevID()
  1086. {
  1087. ASSERT(m_pIVideoDevice);
  1088. return (m_pIVideoDevice->GetCurrCapDevID());
  1089. }
  1090. // Selects the current capture device
  1091. // Returns -1L on error
  1092. BOOL CVideoProp::SetCurrCapDevID(int nCapDevID)
  1093. {
  1094. ASSERT(m_pIVideoDevice);
  1095. return (S_OK != m_pIVideoDevice->SetCurrCapDevID(nCapDevID));
  1096. }
  1097. // Selects the current capture device
  1098. // Returns -1L on error
  1099. BOOL CVideoPump::SetCurrCapDevID(int nCapDevID)
  1100. {
  1101. if (nCapDevID == -1)
  1102. {
  1103. WARNING_OUT(("CVideoPump::SetCurrCapDevID called with %d", nCapDevID));
  1104. // This will release the capture device for Exchange RTC video stuff
  1105. if (m_pMediaStream)
  1106. {
  1107. m_pMediaStream->Configure(NULL, 0, NULL, 0, NULL);
  1108. }
  1109. return TRUE;
  1110. }
  1111. else
  1112. {
  1113. HRESULT hr;
  1114. IDualPubCap *pCapability = NULL;
  1115. LPAPPVIDCAPPIF pVidCap = NULL;
  1116. IH323CallControl * pH323CallControl = g_pH323UI->GetH323CallControl();
  1117. // change the capture device
  1118. CVideoProp::SetCurrCapDevID(nCapDevID);
  1119. // reinitialize local capability data
  1120. hr = pH323CallControl->QueryInterface(IID_IDualPubCap, (void **)&pCapability);
  1121. if(FAILED(hr))
  1122. goto out;
  1123. ASSERT(pCapability);
  1124. hr = pCapability->QueryInterface(IID_IAppVidCap, (void **)&pVidCap);
  1125. if(FAILED(hr))
  1126. goto out;
  1127. ASSERT(pVidCap);
  1128. hr = pVidCap->SetDeviceID(nCapDevID);
  1129. if(FAILED(hr))
  1130. goto out;
  1131. hr = pCapability->ReInitialize();
  1132. out:
  1133. if (pVidCap)
  1134. pVidCap->Release();
  1135. if (pCapability)
  1136. pCapability->Release();
  1137. return ForceCaptureChange();
  1138. }
  1139. }
  1140. BOOL CVideoPump::ForceCaptureChange()
  1141. {
  1142. HRESULT hr = S_OK;
  1143. if (m_fLocal)
  1144. {
  1145. if (m_pConnection)
  1146. {
  1147. if (IsXferEnabled())
  1148. {
  1149. if (!m_fReopenPending && !m_fOpenPending)
  1150. {
  1151. // if the send channel, and a call exists and the channel is open, and not
  1152. // already closing or opening .....
  1153. if(IsChannelOpen())
  1154. {
  1155. ASSERT(m_pCommChannel);
  1156. // need to close and re-open
  1157. // don't lose a good channel if there is no longer
  1158. // a compatible format, otherwise, close and reopen
  1159. m_BestFormat = m_NewFormat = CVideoProp::GetBestFormat();
  1160. if(m_BestFormat != INVALID_MEDIA_FORMAT)
  1161. {
  1162. m_fReopenPending = TRUE;
  1163. hr = m_pCommChannel->Close();
  1164. }
  1165. }
  1166. else
  1167. {
  1168. if(m_BestFormat != INVALID_MEDIA_FORMAT )
  1169. {
  1170. m_fOpenPending = TRUE;
  1171. hr = m_pCommChannel->Open(m_BestFormat, m_pConnection);
  1172. if(FAILED(hr))
  1173. m_fOpenPending = FALSE;
  1174. }
  1175. }
  1176. }
  1177. else // already waiting for channel to be opened using some format
  1178. {
  1179. m_NewFormat = CVideoProp::GetBestFormat();
  1180. }
  1181. }
  1182. else
  1183. {
  1184. if(IsChannelOpen())
  1185. {
  1186. m_fClosePending = TRUE;
  1187. }
  1188. }
  1189. }
  1190. else
  1191. {
  1192. if (!IsChannelOpen() && IsPreviewEnabled())
  1193. {
  1194. // togle preview to commit size change
  1195. EnablePreview(FALSE);
  1196. EnablePreview(TRUE);
  1197. }
  1198. }
  1199. }
  1200. if (FAILED(hr))
  1201. return FALSE;
  1202. else
  1203. return TRUE;
  1204. }