Source code of Windows XP (NT5)
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.

609 lines
16 KiB

  1. /*
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. */
  4. #include "stdafx.h"
  5. #include "atlconv.h"
  6. #include "termmgr.h"
  7. #include "meterf.h"
  8. #include "newmes.h"
  9. ///////////////////////////////////////////////////////////////////////////////
  10. ///////////////////////////////////////////////////////////////////////////////
  11. ///////////////////////////////////////////////////////////////////////////////
  12. ///////////////////////////////////////////////////////////////////////////////
  13. // These will be obsolete when we derive from CSingleFilterTerminal
  14. HRESULT CMediaTerminal::GetNumExposedPins(
  15. IN IGraphBuilder * pGraph,
  16. OUT DWORD * pdwNumPins)
  17. {
  18. LOG((MSP_TRACE, "CMediaTerminal::GetNumExposedPins - enter"));
  19. //
  20. // We ignote pGraph because we don't need to do anything special to find
  21. // out how many pins we have.
  22. //
  23. *pdwNumPins = 1;
  24. LOG((MSP_TRACE, "CMediaTerminal::GetNumExposedPins - exit S_OK"));
  25. return S_OK;
  26. }
  27. HRESULT CMediaTerminal::GetExposedPins(
  28. OUT IPin ** ppPins
  29. )
  30. {
  31. LOG((MSP_TRACE, "CMediaTerminal::GetExposedPins - enter"));
  32. TM_ASSERT( ! TM_IsBadWritePtr(ppPins, 1 * sizeof(IPin *) ) );
  33. //
  34. // Return our single pin.
  35. //
  36. *ppPins = m_pOwnPin;
  37. (*ppPins)->AddRef();
  38. LOG((MSP_TRACE, "CMediaTerminal::GetExposedPins - exit S_OK"));
  39. return S_OK;
  40. }
  41. ///////////////////////////////////////////////////////////////////////////////
  42. ///////////////////////////////////////////////////////////////////////////////
  43. ///////////////////////////////////////////////////////////////////////////////
  44. ///////////////////////////////////////////////////////////////////////////////
  45. // for CLSID_MediaStreamFilter
  46. // "amguids.h" has the guid value
  47. // but requires #define INITGUID before including compobj.h
  48. EXTERN_C const GUID CLSID_MediaStreamFilter = {
  49. 0x49c47ce0,
  50. 0x9ba4,
  51. 0x11d0,
  52. {0x82, 0x12, 0x00, 0xc0, 0x4f, 0xc3, 0x2c, 0x45}
  53. };
  54. // this is used for indexing into the friendly name array
  55. // it is needed because neither the tapi media type (string guid) nor
  56. // the IMediaStream media consts (not an enum) can be used
  57. enum MEDIA_STREAM_TERMINAL_MEDIA
  58. {
  59. MEDIA_STREAM_TERMINAL_AUDIO=0,
  60. MEDIA_STREAM_TERMINAL_VIDEO
  61. };
  62. // the MEDIA_STREAM_TERMINAL_MEDIA and TERMINAL_DIRECTION values are used as
  63. // indices into this array to determine the friendly name
  64. // these should ideally be const WCHAR *, but the base class member m_szName is
  65. // a pointer to BSTR (should be const WCHAR * as per current usage)
  66. DWORD gs_MSTFriendlyName[2][2] =
  67. {
  68. {
  69. IDS_MSTR_AUDIO_WRITE, // capture
  70. IDS_MSTR_AUDIO_READ, // render
  71. },
  72. {
  73. IDS_MSTR_VIDEO_WRITE, // capture
  74. IDS_MSTR_VIDEO_READ, // render
  75. }
  76. };
  77. // CMediaTerminal
  78. STDMETHODIMP CMediaTerminal::InitializeDynamic (
  79. IN IID iidTerminalClass,
  80. IN DWORD dwMediaType,
  81. IN TERMINAL_DIRECTION Direction,
  82. IN MSP_HANDLE htAddress
  83. )
  84. {
  85. LOG((MSP_TRACE, "CMediaTerminal::Initialize - enter"));
  86. //
  87. // We are OK with either direction. Just do the base class method...
  88. //
  89. HRESULT hr;
  90. hr = CBaseTerminal::Initialize(iidTerminalClass,
  91. dwMediaType,
  92. Direction,
  93. htAddress);
  94. if ( FAILED(hr) )
  95. {
  96. LOG((MSP_ERROR, "CVideoRenderTerminal::Initialize - "
  97. "base class method failed - returning 0x%08x", hr));
  98. return hr;
  99. }
  100. //
  101. // Now do our own initialization:
  102. //
  103. // sets certain member variables
  104. // ex. m_TerminalType, m_szName
  105. // initialize the aggregated filter
  106. //
  107. MSPID PurposeId;
  108. STREAM_TYPE StreamType;
  109. const GUID *pAmovieMajorType;
  110. // uses pTapiMediaType, TerminalDirection to determine the
  111. // purpose id and stream type.
  112. // sets PurposeId, StreamType, pAmovieMajorType among others
  113. hr = SetNameInfo(
  114. (long) dwMediaType,
  115. Direction,
  116. PurposeId,
  117. StreamType,
  118. pAmovieMajorType
  119. );
  120. BAIL_ON_FAILURE(hr);
  121. ASSERT(NULL != pAmovieMajorType);
  122. // initialize the aggregated filter
  123. ASSERT(NULL != m_pAggTerminalFilter);
  124. hr = m_pAggTerminalFilter->Init(PurposeId, StreamType, *pAmovieMajorType);
  125. BAIL_ON_FAILURE(hr);
  126. LOG((MSP_TRACE, "CMediaTerminal::Initialize - exit S_OK"));
  127. return S_OK;
  128. }
  129. // free the allocated member variables
  130. HRESULT
  131. CMediaTerminal::FinalConstruct(
  132. )
  133. {
  134. LOG((MSP_TRACE, "CMediaTerminal::FinalConstruct called"));
  135. HRESULT hr;
  136. m_pAggInstance = new FILTER_COM_OBJECT(GetControllingUnknown());
  137. BAIL_IF_NULL(m_pAggInstance, E_OUTOFMEMORY);
  138. hr = m_pAggInstance->FinalConstruct();
  139. if (HRESULT_FAILURE(hr))
  140. {
  141. // delete the aggregating instance
  142. delete m_pAggInstance;
  143. return hr;
  144. }
  145. // we get the nondelegating IUnknown i/f of the aggregating shell
  146. // around the contained object. keep this refcnt around during our
  147. // lifetime
  148. hr = m_pAggInstance->QueryInterface(
  149. IID_IUnknown,
  150. (void **)&m_pIUnkTerminalFilter
  151. );
  152. if ( FAILED(hr) )
  153. {
  154. // must call final release
  155. m_pAggInstance->FinalRelease();
  156. // delete the aggregating instance
  157. delete m_pAggInstance;
  158. return hr;
  159. }
  160. // these query interface calls increase our own refcnt
  161. // release the refcnt as soon as the interface is obtained
  162. // these shouldn't be CComPtrs as they are weak references
  163. hr = m_pAggInstance->QueryInterface(
  164. IID_IPin,
  165. (void **)&m_pOwnPin
  166. );
  167. if ( FAILED(hr) )
  168. {
  169. goto error;
  170. }
  171. if (NULL != m_pOwnPin)
  172. {
  173. m_pOwnPin->Release();
  174. }
  175. hr = m_pAggInstance->QueryInterface(
  176. IID_IAMMediaStream,
  177. (void **)&m_pIAMMediaStream
  178. );
  179. if ( FAILED(hr) )
  180. {
  181. goto error;
  182. }
  183. if (NULL != m_pIAMMediaStream)
  184. {
  185. m_pIAMMediaStream->Release();
  186. }
  187. // point m_pAggTerminalFilter to the contained member of the
  188. // aggregating instance
  189. m_pAggTerminalFilter = &m_pAggInstance->m_contained;
  190. LOG((MSP_TRACE, "CMediaTerminal::FinalConstruct succeeded"));
  191. return S_OK;
  192. error: // we come here in case of errors after calling FinalConstruct
  193. ASSERT( FAILED(hr) );
  194. // final release the aggregating shell
  195. ASSERT(NULL != m_pAggInstance);
  196. m_pAggInstance->FinalRelease();
  197. // null any CComPtrs
  198. // this should destroy the aggregated instance and the contained
  199. // media terminal filter
  200. m_pIUnkTerminalFilter = NULL;
  201. LOG((MSP_TRACE, "CMediaTerminal::FinalConstruct failed"));
  202. return hr;
  203. }
  204. void
  205. CMediaTerminal::FinalRelease(
  206. )
  207. {
  208. LOG((MSP_TRACE, "CMediaTerminal::FinalRelease called"));
  209. // final release the aggregating shell
  210. ASSERT(NULL != m_pAggInstance);
  211. m_pAggInstance->FinalRelease();
  212. // null any CComPtrs
  213. // this should destroy the aggregating instance and the contained
  214. // media terminal filter
  215. m_pIUnkTerminalFilter = NULL;
  216. LOG((MSP_TRACE, "CMediaTerminal::FinalRelease succeeded"));
  217. }
  218. // we only have a destructor with debug bits
  219. #ifdef DEBUG
  220. // free the allocated member variables
  221. // virtual
  222. CMediaTerminal::~CMediaTerminal(
  223. )
  224. {
  225. LOG((MSP_TRACE, "CMediaTerminal::~CMediaTerminal called"));
  226. }
  227. #endif // DEBUG
  228. // point to the m_ppTapiMediaType,
  229. // copies friendly name into m_szName
  230. void
  231. CMediaTerminal::SetMemberInfo(
  232. IN DWORD dwFriendlyName,
  233. IN long lMediaType
  234. )
  235. {
  236. LOG((MSP_TRACE, "CMediaTerminal::SetMemberInfo(%d, &(%l)) called", \
  237. dwFriendlyName,lMediaType));
  238. // copy the friendly terminal name into the member name
  239. // the max number of TCHARs to copy is MAX_PATH+1 (it includes
  240. // the terminating NULL character)
  241. TCHAR szTemp[MAX_PATH];
  242. if (::LoadString(_Module.GetResourceInstance(), dwFriendlyName, szTemp, MAX_PATH))
  243. {
  244. lstrcpyn(m_szName, szTemp, MAX_PATH);
  245. }
  246. else
  247. {
  248. LOG((MSP_ERROR, "CMediaTerminal::SetMemberInfo (LoadString) failed"));
  249. }
  250. m_lMediaType = lMediaType;
  251. LOG((MSP_TRACE, "CMediaTerminal::SetMemberInfo(%d, &(%d)) succeeded", \
  252. dwFriendlyName,lMediaType));
  253. };
  254. // uses the purpose id and the stream type to figure out the name
  255. // and terminal class id.
  256. // sets PurposeId, StreamType, m_szName, m_TerminalClassID
  257. // m_ppTapiMediaType, m_TerminalType, m_TerminalDirection
  258. HRESULT
  259. CMediaTerminal::SetNameInfo(
  260. IN long lMediaType,
  261. IN TERMINAL_DIRECTION TerminalDirection,
  262. OUT MSPID &PurposeId,
  263. OUT STREAM_TYPE &StreamType,
  264. OUT const GUID *&pAmovieMajorType
  265. )
  266. {
  267. LOG((MSP_TRACE, "CMediaTerminal::SetNameInfo(%d, %u, %p, %p, %p) called", \
  268. lMediaType, TerminalDirection, &PurposeId, &StreamType, pAmovieMajorType));
  269. //
  270. // Check arguments
  271. //
  272. if ( ( TerminalDirection != TD_CAPTURE ) &&
  273. ( TerminalDirection != TD_RENDER ) )
  274. {
  275. return E_INVALIDARG;
  276. }
  277. // set the stream type
  278. // if its a capture terminal, the user has to write the samples
  279. StreamType = (TD_CAPTURE == TerminalDirection)? STREAMTYPE_WRITE : STREAMTYPE_READ;
  280. if (lMediaType == TAPIMEDIATYPE_AUDIO)
  281. {
  282. // set the PurposeId, major media type
  283. PurposeId = MSPID_PrimaryAudio;
  284. pAmovieMajorType = &MEDIATYPE_Audio;
  285. // copy the name and point to the tapi media type
  286. SetMemberInfo(
  287. gs_MSTFriendlyName[MEDIA_STREAM_TERMINAL_AUDIO][TerminalDirection],
  288. TAPIMEDIATYPE_AUDIO
  289. );
  290. }
  291. else if (lMediaType == TAPIMEDIATYPE_VIDEO)
  292. {
  293. // set the PurposeId, major media type
  294. PurposeId = MSPID_PrimaryVideo;
  295. pAmovieMajorType = &MEDIATYPE_Video;
  296. // copy the name and point to the tapi media type
  297. SetMemberInfo(
  298. gs_MSTFriendlyName[MEDIA_STREAM_TERMINAL_VIDEO][TerminalDirection],
  299. TAPIMEDIATYPE_VIDEO
  300. );
  301. }
  302. else
  303. {
  304. return E_INVALIDARG;
  305. }
  306. // its a dynamic terminal
  307. m_TerminalType = TT_DYNAMIC;
  308. LOG((MSP_TRACE, "CMediaTerminal::SetNameInfo[%p] (%u, %u, %p, %p, %p) succeeded", \
  309. this, lMediaType, TerminalDirection, &PurposeId, &StreamType, pAmovieMajorType));
  310. return S_OK;
  311. }
  312. // implement using the aggregated filter's public GetFormat method
  313. STDMETHODIMP
  314. CMediaTerminal::GetFormat(
  315. OUT AM_MEDIA_TYPE **ppmt
  316. )
  317. {
  318. CLock lock(m_CritSec);
  319. LOG((MSP_TRACE, "CMediaTerminal::GetFormat(%p) called", ppmt));
  320. return m_pAggTerminalFilter->GetFormat(ppmt);
  321. }
  322. // implement using the aggregated filter's public SetFormat method
  323. STDMETHODIMP
  324. CMediaTerminal::SetFormat(
  325. IN AM_MEDIA_TYPE *pmt
  326. )
  327. {
  328. CLock lock(m_CritSec);
  329. LOG((MSP_TRACE, "CMediaTerminal::SetFormat(%p) called", pmt));
  330. return m_pAggTerminalFilter->SetFormat(pmt);
  331. }
  332. // an IAMBufferNegotiation method - passed to our filter
  333. STDMETHODIMP
  334. CMediaTerminal::GetAllocatorProperties(
  335. OUT ALLOCATOR_PROPERTIES *pProperties
  336. )
  337. {
  338. CLock lock(m_CritSec);
  339. LOG((MSP_TRACE, "CMediaTerminal::GetAllocatorProperties(%p) called", pProperties));
  340. return m_pAggTerminalFilter->GetAllocatorProperties(pProperties);
  341. }
  342. // an IAMBufferNegotiation method - used to be not implemented
  343. // but now we must return S_OK to work with IP
  344. STDMETHODIMP
  345. CMediaTerminal::SuggestAllocatorProperties(
  346. IN const ALLOCATOR_PROPERTIES *pProperties
  347. )
  348. {
  349. CLock lock(m_CritSec);
  350. LOG((MSP_TRACE, "CMediaTerminal::SuggestAllocatorProperties - enter"));
  351. HRESULT hr = m_pAggTerminalFilter->SuggestAllocatorProperties(pProperties);
  352. if ( FAILED(hr) )
  353. {
  354. LOG((MSP_ERROR, "CMediaTerminal::SuggestAllocatorProperties - "
  355. "method on filter failed - exit 0x%08x", hr));
  356. return hr;
  357. }
  358. LOG((MSP_TRACE, "CMediaTerminal::SuggestAllocatorProperties - exit S_OK"));
  359. return S_OK;
  360. }
  361. // since there is only one filter in this base class implementation (i.e. the two
  362. // ends of the terminal have the same media format), both of
  363. // the get and set methods are redirected to Get/Set Format
  364. STDMETHODIMP
  365. CMediaTerminal::get_MediaFormat(
  366. OUT AM_MEDIA_TYPE **ppFormat
  367. )
  368. {
  369. CLock lock(m_CritSec);
  370. LOG((MSP_TRACE, "CMediaTerminal::get_MediaFormat(%p) called", ppFormat));
  371. return GetFormat(ppFormat);
  372. }
  373. // cast the input format to a non-const as we know that we won't change the struct
  374. // in SetFormat (this problem exists because IAMStreamConfig::SetFormat expects a
  375. // non-const). this saves creating, copying and then destroying a struct for this call
  376. STDMETHODIMP
  377. CMediaTerminal::put_MediaFormat(
  378. IN const AM_MEDIA_TYPE *pFormat
  379. )
  380. {
  381. CLock lock(m_CritSec);
  382. LOG((MSP_TRACE, "CMediaTerminal::put_MediaFormat(%p) called", pFormat));
  383. return SetFormat((AM_MEDIA_TYPE *)pFormat);
  384. }
  385. HRESULT
  386. CMediaTerminal::CreateAndJoinMediaStreamFilter(
  387. )
  388. {
  389. LOG((MSP_TRACE, "CMediaTerminal::CreateAndJoinMediaStreamFilter called"));
  390. ASSERT(m_pICreatedMediaStreamFilter == NULL);
  391. // in case of an error at any stage, no clean-up of member variables
  392. // or filter logic (JoinFilter(NULL) etc.) needs to be done as the
  393. // driving CBaseTerminal::ConnectTerminal would call DisconnectTerminal
  394. // which performs that work
  395. // create the media stream filter
  396. HRESULT hr;
  397. hr = CoCreateInstance(
  398. CLSID_MediaStreamFilter,
  399. NULL,
  400. CLSCTX_INPROC_SERVER,
  401. IID_IMediaStreamFilter,
  402. (void **)&m_pICreatedMediaStreamFilter
  403. );
  404. BAIL_ON_FAILURE(hr);
  405. hr = m_pICreatedMediaStreamFilter->QueryInterface(
  406. IID_IBaseFilter, (void **)&m_pBaseFilter
  407. );
  408. BAIL_ON_FAILURE(hr);
  409. // tell the aggregated filter of our media stream filter, so that
  410. // it can reject any other media stream filter if proposed
  411. m_pAggTerminalFilter->SetMediaStreamFilter(m_pICreatedMediaStreamFilter);
  412. // add the IAMMediaStream i/f of the aggregated terminal filter
  413. // to the media stream filter
  414. hr = m_pICreatedMediaStreamFilter->AddMediaStream(m_pIAMMediaStream);
  415. BAIL_ON_FAILURE(hr);
  416. LOG((MSP_TRACE, "CMediaTerminal::CreateAndJoinMediaStreamFilter succeeded"));
  417. return S_OK;
  418. }
  419. // if m_pFilter is null, return error
  420. // add m_pFilter to graph
  421. HRESULT
  422. CMediaTerminal::AddFiltersToGraph(
  423. )
  424. {
  425. LOG((MSP_TRACE, "CMediaTerminal::AddFiltersToGraph called"));
  426. HRESULT hr;
  427. hr = CreateAndJoinMediaStreamFilter();
  428. BAIL_ON_FAILURE(hr);
  429. ASSERT(m_pGraph != NULL);
  430. BAIL_IF_NULL(m_pBaseFilter, MS_E_NOTINIT);
  431. try
  432. {
  433. USES_CONVERSION;
  434. hr = m_pGraph->AddFilter(m_pBaseFilter, T2CW(m_szName));
  435. }
  436. catch (...)
  437. {
  438. LOG((MSP_ERROR, "CMediaTerminal::AddFiltersToGraph - T2CW threw an exception - "
  439. "return E_OUTOFMEMORY"));
  440. return E_OUTOFMEMORY;
  441. }
  442. if ( ( hr != S_OK ) && ( VFW_S_DUPLICATE_NAME != hr ) )
  443. {
  444. return hr;
  445. }
  446. LOG((MSP_TRACE, "CMediaTerminal::AddFiltersToGraph succeeded"));
  447. return S_OK;
  448. }
  449. // if m_pFilter is null, return success
  450. // remove m_pFilter from graph
  451. HRESULT
  452. CMediaTerminal::RemoveFiltersFromGraph(
  453. )
  454. {
  455. LOG((MSP_TRACE, "CMediaTerminal::RemoveFiltersFromGraph called"));
  456. // the base filter is set when CreateAndJoinMediaStreamFilter succeeds
  457. // in it, the media stream filter is created and the IAMMediaStream
  458. // interface is added to the filter. During addition, the media stream filter
  459. // calls JoinFilter on the IAMMediaStream and thus sets the m_pBaseFilter
  460. HRESULT hr = S_OK;
  461. if ((m_pGraph != NULL) && (m_pBaseFilter != NULL))
  462. {
  463. hr = m_pGraph->RemoveFilter(m_pBaseFilter);
  464. }
  465. // inform the aggregate media terminal filter that we don't have a
  466. // media stream filter any longer
  467. m_pAggTerminalFilter->SetMediaStreamFilter(NULL);
  468. // remove associated properties of the media stream filter
  469. m_pIAMMediaStream->JoinFilter(NULL);
  470. m_pIAMMediaStream->JoinFilterGraph(NULL);
  471. // null m_pBaseFilter and m_pICreatedMediaStreamFilter
  472. // which hold the last reference to the filter
  473. m_pBaseFilter = NULL;
  474. m_pICreatedMediaStreamFilter = NULL;
  475. return hr;
  476. }
  477. // eof