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.

509 lines
15 KiB

  1. // Copyright (c) 1998 - 1999 Microsoft Corporation. All Rights Reserved.
  2. #include <streams.h>
  3. #include <ddraw.h>
  4. #include <VPManager.h>
  5. #include <VPMPin.h>
  6. #include <VPMUtil.h>
  7. // VIDEOINFOHDR2
  8. #include <dvdmedia.h>
  9. static HRESULT GetSurfaceFromSample( LPDIRECTDRAWSURFACE7* ppDDSurf7, IMediaSample* pSample )
  10. {
  11. AMTRACE((TEXT("GetSurfaceFromSample")));
  12. HRESULT hr = E_FAIL;
  13. {
  14. // make sure its a VMRSurfaceAlloc or a DirectDrawSurfaceAlloc for now
  15. IVMRSurface* pVMRSurf;
  16. hr = pSample->QueryInterface( IID_IVMRSurface, (VOID **) &pVMRSurf );
  17. if( SUCCEEDED( hr )) {
  18. // the AM_GBF_NODDSURFACELOCK flag avoids the need to lock the surface
  19. hr = pVMRSurf->GetSurface( ppDDSurf7 );
  20. }
  21. pVMRSurf->Release();
  22. }
  23. #if 0
  24. // try direct draw sample alloc
  25. if( FAILED(hr)) {
  26. // make sure its a VMRSurfaceAlloc or a DirectDrawSurfaceAlloc for now
  27. IDirectDrawMediaSample* pDDSample;
  28. HRESULT hr = pSample->QueryInterface( IID_IDirectDrawMediaSample, (VOID **) &pDDSample );
  29. if( SUCCEEDED( hr )) {
  30. LPDIRECTDRAWSURFACE pDDSurf;
  31. hr = pDDSample->GetSurfaceAndReleaseLock( &pDDSurf, NULL );
  32. if( SUCCEEDED( hr )) {
  33. hr = pDDSurf->QueryInterface( IID_IDirectDrawSurface7, (VOID **) &ppDDSurf7 );
  34. pDDSurf->Release();
  35. }
  36. pDDSample->Release();
  37. }
  38. }
  39. #endif
  40. if( FAILED(hr)) {
  41. // TBD: create a DDraw wrapper for the surface
  42. ASSERT(!"VPM: Can't handle non-DDraw sample from downstream filter");
  43. }
  44. return hr;
  45. }
  46. // constructor
  47. CVPMOutputPin::CVPMOutputPin(TCHAR *pObjectName, CVPMFilter& pFilter,
  48. HRESULT *phr, LPCWSTR pPinName, DWORD dwPinNo)
  49. : CBaseOutputPin(pObjectName, &pFilter, &pFilter.GetFilterLock(), phr, pPinName)
  50. , CVPMPin( dwPinNo, pFilter )
  51. , m_pPosition( NULL )
  52. {
  53. AMTRACE((TEXT("CVPMOutputPin::Constructor")));
  54. return;
  55. }
  56. // destructor
  57. CVPMOutputPin::~CVPMOutputPin()
  58. {
  59. AMTRACE((TEXT("CVPMOutputPin::Destructor")));
  60. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  61. RELEASE( m_pPosition );
  62. return;
  63. }
  64. // overriden to expose IMediaPosition and IMediaSeeking control interfaces
  65. STDMETHODIMP CVPMOutputPin::NonDelegatingQueryInterface(REFIID riid, void **ppv)
  66. {
  67. HRESULT hr = NOERROR;
  68. if (riid == IID_IMediaPosition || riid == IID_IMediaSeeking)
  69. {
  70. // we should have an input pin by now
  71. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  72. if (m_pPosition == NULL)
  73. {
  74. hr = CreatePosPassThru(GetOwner(), FALSE, (IPin *)m_pVPMFilter.GetPin(0), &m_pPosition);
  75. if (FAILED(hr))
  76. {
  77. DbgLog((LOG_ERROR, 1, TEXT("CreatePosPassThru failed, hr = 0x%x"), hr));
  78. goto CleanUp;
  79. }
  80. }
  81. hr = m_pPosition->QueryInterface(riid, ppv);
  82. goto CleanUp;
  83. }
  84. // This gets annoying since IMediaSeeking is polled, so move below it
  85. {
  86. AMTRACE((TEXT("CVPMOutputPin::NonDelegatingQueryInterface")));
  87. DbgLog((LOG_TRACE, 5, TEXT("QI'ing CBaseOutputPin")));
  88. hr = CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv);
  89. if (FAILED(hr))
  90. {
  91. DbgLog((LOG_ERROR, 2, TEXT("CBaseOutputPin::NonDelegatingQueryInterface(riid) failed, hr = 0x%x"), hr));
  92. goto CleanUp;
  93. }
  94. }
  95. CleanUp:
  96. return hr;
  97. }
  98. // check a given transform
  99. HRESULT CVPMOutputPin::CheckMediaType(const CMediaType* pmt)
  100. {
  101. HRESULT hr = NOERROR;
  102. AMTRACE((TEXT("CVPMOutputPin::CheckMediaType")));
  103. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  104. // we only allow a VideoInfoHeader2 connections
  105. if( pmt->majortype != MEDIATYPE_Video ||
  106. !VPMUtil::GetVideoInfoHeader2( pmt ) )
  107. {
  108. hr = S_FALSE;
  109. goto CleanUp;
  110. }
  111. // Only accept VideoInfoHeader2 format types
  112. // tell the owning filter
  113. hr = m_pVPMFilter.CheckMediaType(m_dwPinId, pmt);
  114. if (FAILED(hr))
  115. {
  116. DbgLog((LOG_TRACE, 5, TEXT("m_pVPMFilter.CheckMediaType failed, hr = 0x%x"), hr));
  117. goto CleanUp;
  118. }
  119. CleanUp:
  120. return hr;
  121. }
  122. enum ENUM_MEDIA_TYPE {MT_RGB32, MT_RGB24, MT_RGB565, MT_RGB555,
  123. MT_LAST };
  124. HRESULT CVPMOutputPin::GetMediaType(int iPosition,CMediaType *pmt)
  125. {
  126. AMTRACE((TEXT("CVPMOutputPin::GetMediaType")));
  127. // Can't be < 0 - it's the base classes calling us
  128. ASSERT(iPosition >= 0);
  129. if (iPosition < 0) {
  130. return E_INVALIDARG;
  131. }
  132. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  133. DDPIXELFORMAT ddOutputVideoFormat;
  134. HRESULT hr = m_pVPMFilter.GetOutputFormat( &ddOutputVideoFormat );
  135. if( FAILED( hr )) {
  136. // when input pin is not connected, it returns VFW_E_NOT_CONNECTED
  137. return hr;
  138. }
  139. // limit scope of cmt & associated pointers to it
  140. {
  141. CMediaType cmt;
  142. hr = m_pVPMFilter.CurrentInputMediaType( &cmt );
  143. if( FAILED( hr )) {
  144. return hr;
  145. }
  146. VIDEOINFOHEADER2 *pVideoInfoHeader2;
  147. if (*cmt.Type() != MEDIATYPE_Video) {
  148. ASSERT( !"none video type from VPE" );
  149. pVideoInfoHeader2 = VPMUtil::SetToVideoInfoHeader2( &cmt, sizeof(TRUECOLORINFO) );
  150. if (pVideoInfoHeader2 == NULL) {
  151. return E_OUTOFMEMORY;
  152. }
  153. } else {
  154. pVideoInfoHeader2 = VPMUtil::GetVideoInfoHeader2( &cmt );
  155. }
  156. // only support the connected VPE format, ignore the lists
  157. // match the VPE pin for now
  158. BITMAPINFOHEADER *pHeader = VPMUtil::GetbmiHeader( &cmt );
  159. if ( ! pHeader )
  160. {
  161. return E_FAIL;
  162. }
  163. const DDPIXELFORMAT& ddFormat = ddOutputVideoFormat; // (*pddAllOutputVideoFormats)[iPosition];
  164. DWORD dwFourCC = ddFormat.dwFourCC;
  165. switch( dwFourCC ) {
  166. case mmioFOURCC('Y','V','1','2'):
  167. case mmioFOURCC('Y','U','Y','2'):
  168. case mmioFOURCC('U','Y','V','Y'):
  169. pHeader->biBitCount = (USHORT) ddFormat.dwYUVBitCount;
  170. break;
  171. default:
  172. pHeader->biBitCount = (USHORT) ddFormat.dwRGBBitCount;
  173. break;
  174. }
  175. // map the FourCC code into a guid
  176. FOURCCMap guid( dwFourCC );
  177. cmt.SetSubtype(&guid);
  178. pHeader->biCompression = dwFourCC;
  179. *pmt = cmt;
  180. if (pmt->pbFormat == NULL) {
  181. return E_OUTOFMEMORY;
  182. }
  183. }
  184. // get mode info so we know how many interlace formats to propose
  185. VPInfo vpInfo;
  186. hr = m_pVPMFilter.GetVPInfo( &vpInfo );
  187. VIDEOINFOHEADER2 *pVideoInfoHeader2 = VPMUtil::GetVideoInfoHeader2( pmt );
  188. pVideoInfoHeader2->dwInterlaceFlags = 0;
  189. // TBD: we should query the video port for a list of available modes
  190. // and set it using the mode. Right now we'll assume the hardware
  191. // can support the videoport's output.
  192. //
  193. DWORD dwNumFormats = 1;
  194. if( iPosition >= (int) dwNumFormats ) {
  195. return VFW_S_NO_MORE_ITEMS;
  196. }
  197. if( SUCCEEDED( hr )) {
  198. pVideoInfoHeader2->dwPictAspectRatioX = vpInfo.vpDataInfo.dwPictAspectRatioX;
  199. pVideoInfoHeader2->dwPictAspectRatioY = vpInfo.vpDataInfo.dwPictAspectRatioY;
  200. switch( vpInfo.mode ) {
  201. case AMVP_MODE_BOBNONINTERLEAVED:
  202. pVideoInfoHeader2->dwInterlaceFlags = AMINTERLACE_IsInterlaced | AMINTERLACE_1FieldPerSample | AMINTERLACE_DisplayModeBobOnly;
  203. break;
  204. case AMVP_MODE_BOBINTERLEAVED:
  205. pVideoInfoHeader2->dwInterlaceFlags = AMINTERLACE_IsInterlaced | AMINTERLACE_DisplayModeBobOnly;
  206. pVideoInfoHeader2->bmiHeader.biHeight *= 2;
  207. break;
  208. case AMVP_MODE_WEAVE:
  209. pVideoInfoHeader2->dwInterlaceFlags = AMINTERLACE_IsInterlaced | AMINTERLACE_FieldPatBothRegular | AMINTERLACE_DisplayModeWeaveOnly;
  210. pVideoInfoHeader2->bmiHeader.biHeight *= 2;
  211. break;
  212. case AMVP_MODE_SKIPEVEN:
  213. pVideoInfoHeader2->dwInterlaceFlags = AMINTERLACE_1FieldPerSample | AMINTERLACE_FieldPatField1Only;
  214. break;
  215. case AMVP_MODE_SKIPODD:
  216. pVideoInfoHeader2->dwInterlaceFlags = AMINTERLACE_1FieldPerSample | AMINTERLACE_FieldPatField2Only;
  217. break;
  218. default:
  219. ASSERT( !"VPM in an invalid state" );
  220. pVideoInfoHeader2->dwInterlaceFlags = 0;
  221. break;
  222. }
  223. // AMINTERLACE_Field1First 0x00000004 // else Field 2 is first; top field in PAL is field 1, top field in NTSC is field 2?
  224. if( vpInfo.vpDataInfo.bFieldPolarityInverted ) { // Device inverts the polarity by default
  225. pVideoInfoHeader2->dwInterlaceFlags |= AMINTERLACE_Field1First;
  226. }
  227. } else {
  228. pVideoInfoHeader2->dwPictAspectRatioX = 1; // (DWORD)(pVideoInfoHeader22->bmiHeader.biWidth * m_seqInfo.lYPelsPerMeter);
  229. pVideoInfoHeader2->dwPictAspectRatioY = 1; // (DWORD)(pVideoInfoHeader22->bmiHeader.biHeight * m_seqInfo.lXPelsPerMeter);
  230. }
  231. return hr;
  232. }
  233. // called after we have agreed a media type to actually set it
  234. HRESULT CVPMOutputPin::SetMediaType(const CMediaType* pmt)
  235. {
  236. HRESULT hr = NOERROR;
  237. AMTRACE((TEXT("CVPMOutputPin::SetMediaType")));
  238. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  239. // make sure the mediatype is correct
  240. hr = CheckMediaType(pmt);
  241. if (FAILED(hr))
  242. {
  243. DbgLog((LOG_ERROR, 1, TEXT("CheckMediaType failed, hr = 0x%x"), hr));
  244. goto CleanUp;
  245. }
  246. // Set the base class media type (should always succeed)
  247. // Sets m_mt = *pmt;
  248. hr = CBaseOutputPin::SetMediaType(pmt);
  249. if (FAILED(hr))
  250. {
  251. DbgLog((LOG_ERROR, 1, TEXT("CBaseOutputPin::SetMediaType failed, hr = 0x%x"), hr));
  252. goto CleanUp;
  253. }
  254. // tell the owning filter
  255. hr = m_pVPMFilter.SetMediaType(m_dwPinId, pmt);
  256. if (FAILED(hr))
  257. {
  258. DbgLog((LOG_ERROR, 1, TEXT("m_pVPMFilter.SetMediaType failed, hr = 0x%x"), hr));
  259. goto CleanUp;
  260. }
  261. CleanUp:
  262. return hr;
  263. }
  264. // Complete Connect
  265. HRESULT CVPMOutputPin::CompleteConnect(IPin *pReceivePin)
  266. {
  267. HRESULT hr = NOERROR;
  268. DWORD dwAdvise = 0, dwInputPinCount = 0, i = 0;
  269. DDSURFACEDESC SurfaceDescP;
  270. CVPMInputPin *pInputPin = NULL;
  271. BOOL bDoDeletePrimSurface = TRUE;
  272. AMTRACE((TEXT("CVPMOutputPin::CompleteConnect")));
  273. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  274. // call the base class
  275. hr = CBaseOutputPin::CompleteConnect(pReceivePin);
  276. if (FAILED(hr))
  277. {
  278. DbgLog((LOG_ERROR, 1, TEXT("CBaseOutputPin::CompleteConnect failed, hr = 0x%x"),
  279. hr));
  280. goto CleanUp;
  281. }
  282. ASSERT(m_pAllocator);
  283. // tell the owning filter
  284. hr = m_pVPMFilter.CompleteConnect(m_dwPinId);
  285. if (FAILED(hr))
  286. {
  287. DbgLog((LOG_ERROR, 1, TEXT("m_pVPMFilter.CompleteConnect failed, hr = 0x%x"), hr));
  288. goto CleanUp;
  289. }
  290. CleanUp:
  291. return hr;
  292. }
  293. HRESULT CVPMOutputPin::BreakConnect()
  294. {
  295. HRESULT hr = NOERROR;
  296. DWORD dwInputPinCount = 0, i = 0;
  297. CVPMInputPin *pInputPin;
  298. AMTRACE((TEXT("CVPMOutputPin::BreakConnect")));
  299. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  300. // call the base class
  301. hr = CBaseOutputPin::BreakConnect();
  302. if (FAILED(hr))
  303. {
  304. DbgLog((LOG_ERROR, 1, TEXT("CBaseOutputPin::BreakConnect failed, hr = 0x%x"), hr));
  305. goto CleanUp;
  306. }
  307. // tell the owning filter
  308. hr = m_pVPMFilter.BreakConnect(m_dwPinId);
  309. if (FAILED(hr))
  310. {
  311. DbgLog((LOG_ERROR, 1, TEXT("m_pVPMFilter.BreakConnect failed, hr = 0x%x"), hr));
  312. goto CleanUp;
  313. }
  314. CleanUp:
  315. return hr;
  316. }
  317. HRESULT CVPMOutputPin::CheckConnect(IPin* pPin)
  318. {
  319. AMTRACE((TEXT("CVPMOutputPin::CheckConnect")));
  320. CAutoLock cLock(&m_pVPMFilter.GetFilterLock());
  321. HRESULT hr = CBaseOutputPin::CheckConnect( pPin );
  322. if (FAILED(hr))
  323. {
  324. DbgLog((LOG_ERROR, 1, TEXT("CBaseOutputPin::CheckConnect failed, hr = 0x%x"), hr));
  325. goto CleanUp;
  326. }
  327. CleanUp:
  328. return hr;
  329. }
  330. STDMETHODIMP CVPMOutputPin::Notify(IBaseFilter * pSender, Quality q)
  331. {
  332. return S_OK;
  333. }
  334. HRESULT CVPMOutputPin::GetNextBuffer( LPDIRECTDRAWSURFACE7* ppSurface, IMediaSample** ppSample )
  335. {
  336. AMTRACE((TEXT("CVPMOutputPin::GetNextBuffer")));
  337. CAutoLock cLock(&m_pVPMFilter.GetReceiveLock());
  338. HRESULT hr = E_FAIL;
  339. if( m_pAllocator ) {
  340. hr = m_pAllocator->GetBuffer( ppSample, NULL, NULL, AM_GBF_NODDSURFACELOCK );
  341. if( SUCCEEDED( hr )) {
  342. // now see if we can get the surface
  343. hr = GetSurfaceFromSample( ppSurface, *ppSample );
  344. }
  345. }
  346. return hr;
  347. }
  348. HRESULT CVPMOutputPin::SendSample( IMediaSample* pSample )
  349. {
  350. AMTRACE((TEXT("CVPMOutputPin::SendSample")));
  351. // DbgLog((LOG_TRACE, 1, TEXT("CVPMOutputPin::SendSample %x%x"), DWORD( rtStart>>32), DWORD(rtStart) ));
  352. CAutoLock cLock(&m_pVPMFilter.GetReceiveLock());
  353. HRESULT hr = E_FAIL;
  354. if( m_pInputPin ) {
  355. hr = m_pInputPin->Receive( pSample );
  356. }
  357. return hr;
  358. }
  359. // we don't have an allocator, so fail any connections that don't supply one for us
  360. // (we don't want the default one for now);
  361. HRESULT CVPMOutputPin::InitAllocator(IMemAllocator **ppAlloc)
  362. {
  363. return E_FAIL;
  364. }
  365. HRESULT CVPMOutputPin::DecideBufferSize(IMemAllocator * pAllocator,
  366. ALLOCATOR_PROPERTIES *pRequestedProperties)
  367. {
  368. AMTRACE((TEXT("CVPMOutputPin::DecideBufferSize")));
  369. // set the size of buffers based on the expected output frame size, and
  370. // the count of buffers to 1.
  371. pRequestedProperties->cBuffers = 1;
  372. pRequestedProperties->cbBuffer = m_mt.GetSampleSize();
  373. ASSERT(pRequestedProperties->cbBuffer > 0);
  374. ALLOCATOR_PROPERTIES propActual;
  375. HRESULT hr = pAllocator->SetProperties(pRequestedProperties, &propActual );
  376. if (FAILED(hr)) {
  377. return hr;
  378. }
  379. // if (propActual.cbBuffer < (LONG)m_pOutput->CurrentMediaType().GetSampleSize()) {
  380. // // can't use this allocator
  381. // return E_INVALIDARG;
  382. // }
  383. // We don't really mind if we get > 1 buffer because we always
  384. // blt the entire image
  385. return S_OK;
  386. }
  387. static bool IsVMR( IMemInputPin *pMemPin )
  388. {
  389. IPin* pPin;
  390. HRESULT hr = pMemPin->QueryInterface( IID_IPin, (LPVOID*) &pPin );
  391. if( SUCCEEDED(hr )) {
  392. PIN_INFO PinInfo;
  393. hr = pPin->QueryPinInfo(&PinInfo);
  394. if (SUCCEEDED(hr)) {
  395. IVMRFilterConfig* pVMRFilterConfig = NULL;
  396. hr = PinInfo.pFilter->QueryInterface(IID_IVMRFilterConfig, (LPVOID*)&pVMRFilterConfig);
  397. PinInfo.pFilter->Release();
  398. if( SUCCEEDED( hr )) {
  399. pVMRFilterConfig->Release();
  400. }
  401. }
  402. pPin->Release();
  403. }
  404. return SUCCEEDED( hr );
  405. }
  406. HRESULT CVPMOutputPin::DecideAllocator(
  407. IMemInputPin *pPin,
  408. IMemAllocator **ppAlloc
  409. )
  410. {
  411. HRESULT hr = NOERROR;
  412. // make sure downstream filter support IVPMAlloc
  413. if( IsVMR( pPin ) )
  414. {
  415. return CBaseOutputPin::DecideAllocator( pPin, ppAlloc );
  416. } else {
  417. return E_FAIL;
  418. }
  419. }