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.

879 lines
27 KiB

  1. #include <wchar.h>
  2. #include <streams.h>
  3. #include <atlbase.h>
  4. #include <wmsecure.h>
  5. #include <dmoreg.h>
  6. #include <mediaerr.h>
  7. #include "mediaobj.h"
  8. #include "dmodshow.h"
  9. #include "filter.h"
  10. #include "inpin.h"
  11. #include "outpin.h"
  12. #include "wmcodecstrs.h" // from wm encoder group, not public currently
  13. CWrapperOutputPin::CWrapperOutputPin(
  14. CMediaWrapperFilter *pFilter,
  15. ULONG Id,
  16. BOOL bOptional,
  17. HRESULT *phr) :
  18. CBaseOutputPin(NAME("CWrapperOutputPin"),
  19. pFilter,
  20. pFilter->FilterLock(),
  21. phr,
  22. _PinName_(bOptional ? L"~out" : L"out", Id).Name()
  23. ),
  24. m_Id(Id),
  25. m_fNoPosPassThru(FALSE),
  26. m_pPosPassThru(NULL),
  27. m_pMediaSample(NULL),
  28. // compression setting default values, move to struct eventually
  29. m_lQuality( -1 ),
  30. m_lKeyFrameRate( -1 ),
  31. m_bUseIAMStreamConfigOnDMO( false ),
  32. m_bUseIAMVideoCompressionOnDMO( false ),
  33. m_pmtFromSetFormat( NULL )
  34. {
  35. }
  36. CWrapperOutputPin::~CWrapperOutputPin() {
  37. delete m_pPosPassThru;
  38. if( m_pmtFromSetFormat )
  39. {
  40. // clean up any media type we might have cached from a SetFormat call
  41. DeleteMediaType( m_pmtFromSetFormat );
  42. }
  43. }
  44. HRESULT CWrapperOutputPin::NonDelegatingQueryInterface(REFGUID riid, void **ppv) {
  45. if (SUCCEEDED(CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv)))
  46. return NOERROR;
  47. if ((riid == IID_IMediaPosition) || (riid == IID_IMediaSeeking)) {
  48. CAutoLock l(&m_csPassThru);
  49. // The first time we get here, we attempt to create a CPosPassThru
  50. // object. If we succeed, we use the object in all subsequent QI
  51. // calls. If we fail, we set m_fNoPassThru to TRUE so that we never
  52. // try again. Trying again and succeeding would violate COM rules.
  53. if (m_fNoPosPassThru)
  54. return E_NOINTERFACE;
  55. // Create a CPosPassThru if we don't have one already
  56. if (!m_pPosPassThru) {
  57. CWrapperInputPin* pInPin = Filter()->GetInputPinForPassThru();
  58. if (pInPin) {
  59. HRESULT hr = S_OK;
  60. m_pPosPassThru = new CPosPassThru(TEXT("DMO wrapper PosPassThru"),
  61. (IPin*)this,
  62. &hr,
  63. pInPin);
  64. if (m_pPosPassThru && (FAILED(hr))) {
  65. delete m_pPosPassThru;
  66. m_pPosPassThru = NULL;
  67. }
  68. }
  69. }
  70. if (m_pPosPassThru) {
  71. return m_pPosPassThru->NonDelegatingQueryInterface(riid, ppv);
  72. }
  73. else {
  74. m_fNoPosPassThru = TRUE;
  75. return E_NOINTERFACE;
  76. }
  77. }
  78. else if (riid == IID_IAMStreamConfig )
  79. {
  80. // we support this interface for audio and video encoders
  81. if (IsAudioEncoder() || IsVideoEncoder() )
  82. {
  83. if( 0 == m_Id && !m_bUseIAMStreamConfigOnDMO )
  84. {
  85. // first check whether the dmo supports this natively and cache the interface pointer if so
  86. // BUGBUG needs to be per output stream!!
  87. // for now fail only ask if 1st output stream
  88. CComQIPtr< IAMStreamConfig, &IID_IAMStreamConfig > pStreamConfigOnDMO( Filter()->m_pMediaObject );
  89. if( pStreamConfigOnDMO )
  90. {
  91. // so it is supported natively, but we must release it since it winds up addref'ing the filter
  92. m_bUseIAMStreamConfigOnDMO = true;
  93. DbgLog((LOG_TRACE,3,TEXT("CWrapperOutputPin::NonDelegatingQI - DMO supports IAMStreamConfig natively")));
  94. }
  95. }
  96. // either way it'll go through us
  97. return GetInterface( static_cast<IAMStreamConfig *> (this), ppv );
  98. }
  99. }
  100. else if (riid == IID_IAMVideoCompression )
  101. {
  102. // we support this interface for video encoders
  103. if ( IsVideoEncoder() )
  104. {
  105. if( 0 == m_Id && !m_bUseIAMVideoCompressionOnDMO )
  106. {
  107. // first check whether the dmo supports this natively and cache the interface pointer if so
  108. // BUGBUG needs to be per output stream!!
  109. // for now fail only ask if 1st output stream
  110. CComQIPtr< IAMVideoCompression, &IID_IAMVideoCompression > pVideoCompressionOnDMO( Filter()->m_pMediaObject );
  111. if( pVideoCompressionOnDMO )
  112. {
  113. // so it is supported natively, but we must release it since it winds up addref'ing the filter
  114. m_bUseIAMVideoCompressionOnDMO = true;
  115. DbgLog((LOG_TRACE,3,TEXT("CWrapperOutputPin::NonDelegatingQI - DMO supports IAMVideoCompression natively")));
  116. }
  117. }
  118. // either way it'll go through us
  119. return GetInterface( static_cast<IAMVideoCompression *> (this), ppv);
  120. }
  121. }
  122. return E_NOINTERFACE;
  123. }
  124. HRESULT CWrapperOutputPin::CheckMediaType(const CMediaType *pmt)
  125. {
  126. return Filter()->OutputCheckMediaType(m_Id, pmt);
  127. }
  128. HRESULT CWrapperOutputPin::SetMediaType(const CMediaType *pmt)
  129. {
  130. CAutoLock l(&m_csStream);
  131. HRESULT hr = Filter()->OutputSetMediaType(m_Id, pmt);
  132. if (SUCCEEDED(hr)) {
  133. hr = CBaseOutputPin::SetMediaType(pmt);
  134. if (SUCCEEDED(hr)) {
  135. m_fVideo = pmt->majortype == MEDIATYPE_Video ? true : false;
  136. }
  137. }
  138. return hr;
  139. }
  140. HRESULT CWrapperOutputPin::GetMediaType(int iPosition, CMediaType *pMediaType)
  141. {
  142. if( m_pmtFromSetFormat )
  143. {
  144. // our SetFormat has been called so only offer that type from now on
  145. if( iPosition != 0 )
  146. return E_INVALIDARG;
  147. *pMediaType = *m_pmtFromSetFormat;
  148. return S_OK;
  149. }
  150. else
  151. {
  152. return Filter()->OutputGetMediaType(m_Id, (ULONG)iPosition, pMediaType);
  153. }
  154. }
  155. //
  156. // override primarily for the case where we're a wm dmo video encoder connecting directly
  157. // to the ASF writer, in a desparate attempt to get an output type which a wm video encoder
  158. // will accept in the default connection case
  159. //
  160. STDMETHODIMP CWrapperOutputPin::Connect(IPin *pReceivePin, const AM_MEDIA_TYPE *pmt)
  161. {
  162. DbgLog((LOG_TRACE,3,TEXT("CWrapperOutputPin::Connect")));
  163. CAutoLock lck(&(Filter()->m_csFilter));
  164. //
  165. // if connecting to the asf writer try getting a default type from the writer
  166. //
  167. // note that, although we'd like to do this only if SetFormat hasn't been called,
  168. // we have no guarantee that the writer format hasn't changed, so we need to
  169. // continually call SetFormat with the type we get from the downstream pin's GetFormat
  170. bool bSetFormatOnConnect = false;
  171. if( !pmt && !m_pmtFromSetFormat && IsVideoEncoder() )
  172. {
  173. CComQIPtr< IAMStreamConfig, &IID_IAMStreamConfig > pStreamConfig( pReceivePin );
  174. if( pStreamConfig )
  175. {
  176. AM_MEDIA_TYPE *pmt2;
  177. HRESULT hrInt = pStreamConfig->GetFormat( &pmt2 );
  178. if( SUCCEEDED( hrInt ) )
  179. {
  180. // now we'll only offer this type!
  181. hrInt = SetFormat( pmt2 );
  182. if( SUCCEEDED( hrInt ) )
  183. {
  184. bSetFormatOnConnect = true;
  185. }
  186. }
  187. }
  188. }
  189. // call the base class connect
  190. HRESULT hr = CBaseOutputPin::Connect(pReceivePin,pmt);
  191. if( bSetFormatOnConnect )
  192. {
  193. // whether we failed or not, unset the format if we set one here in connect
  194. if( m_pmtFromSetFormat )
  195. {
  196. // clean up any media type we might have cached from a SetFormat call
  197. DeleteMediaType( m_pmtFromSetFormat );
  198. m_pmtFromSetFormat = NULL;
  199. }
  200. }
  201. return hr;
  202. }
  203. // Remove any media type when breaking a connection
  204. HRESULT CWrapperOutputPin::BreakConnect()
  205. {
  206. HRESULT hr = CBaseOutputPin::BreakConnect();
  207. Filter()->m_pMediaObject->SetOutputType(m_Id, &CMediaType(), DMO_SET_TYPEF_CLEAR);
  208. return hr;
  209. }
  210. HRESULT CWrapperOutputPin::DecideBufferSize(
  211. IMemAllocator * pAlloc,
  212. ALLOCATOR_PROPERTIES * ppropInputRequest
  213. )
  214. {
  215. return Filter()->OutputDecideBufferSize(m_Id, pAlloc, ppropInputRequest);
  216. }
  217. HRESULT CWrapperOutputPin::Notify(IBaseFilter * pSender, Quality q)
  218. {
  219. LogPublicEntry(LOG_STREAM,"Quality Notify");
  220. HRESULT hr;
  221. // If quality sink set, forward the quality request to it
  222. if (m_pQSink) {
  223. hr = m_pQSink->Notify(Filter(), q);
  224. LogHResult(hr, LOG_STREAM, "Quality Notify", "m_pQSink->Notify");
  225. return hr;
  226. }
  227. // This will try the DMO, then the upstream pin
  228. return Filter()->QualityNotify(m_Id, q);
  229. }
  230. //
  231. // IAMStreamConfig
  232. //
  233. HRESULT CWrapperOutputPin::SetFormat(AM_MEDIA_TYPE *pmt)
  234. {
  235. DbgLog((LOG_TRACE,5,TEXT("CWrapperOutputPin - IAMStreamConfig::SetFormat")));
  236. CAutoLock lck(&(Filter()->m_csFilter));
  237. HRESULT hr = S_OK;
  238. if (NULL == pmt)
  239. {
  240. // I'd rather use this to "unset" the type, but that's not how other encoders work
  241. // previously they returned E_POINTER for this
  242. // can we break tradition?
  243. DeleteMediaType( m_pmtFromSetFormat );
  244. m_pmtFromSetFormat = NULL;
  245. return S_OK;
  246. }
  247. if (Filter()->m_State != State_Stopped)
  248. return VFW_E_NOT_STOPPED;
  249. // ensure inputs connected to this output are connected
  250. // since our possible output formats depend on the input format
  251. if( !IsInputConnected() )
  252. {
  253. return VFW_E_NOT_CONNECTED;
  254. }
  255. if( m_bUseIAMStreamConfigOnDMO )
  256. {
  257. CComQIPtr< IAMStreamConfig, &IID_IAMStreamConfig > pStreamConfigOnDMO( Filter()->m_pMediaObject );
  258. ASSERT( pStreamConfigOnDMO );
  259. return pStreamConfigOnDMO->SetFormat( pmt );
  260. }
  261. #ifdef DEBUG
  262. if(pmt->pbFormat && pmt->cbFormat > 0 )
  263. {
  264. if( IsVideoEncoder() )
  265. {
  266. DbgLog((LOG_TRACE,3,TEXT("CWrapperOutputPin - IAMStreamConfig::SetFormat %x %dbit %dx%d"),
  267. HEADER(pmt->pbFormat)->biCompression,
  268. HEADER(pmt->pbFormat)->biBitCount,
  269. HEADER(pmt->pbFormat)->biWidth,
  270. HEADER(pmt->pbFormat)->biHeight));
  271. }
  272. else
  273. {
  274. DbgLog((LOG_TRACE,3,TEXT("CWrapperOutputPin - IAMStreamConfig::SetFormat to tag:%d %dbit %dchannel %dHz"),
  275. ((LPWAVEFORMATEX)(pmt->pbFormat))->wFormatTag,
  276. ((LPWAVEFORMATEX)(pmt->pbFormat))->wBitsPerSample,
  277. ((LPWAVEFORMATEX)(pmt->pbFormat))->nChannels,
  278. ((LPWAVEFORMATEX)(pmt->pbFormat))->nSamplesPerSec));
  279. }
  280. }
  281. #endif
  282. // If this is the same format as we already are using, don't bother
  283. CMediaType cmt;
  284. hr = GetMediaType(0,&cmt);
  285. if (S_OK != hr)
  286. return hr;
  287. if (cmt == *pmt)
  288. {
  289. return NOERROR;
  290. }
  291. // see if we like this type
  292. if ((hr = CheckMediaType((CMediaType *)pmt)) != NOERROR)
  293. {
  294. DbgLog((LOG_TRACE,2,TEXT("IAMStreamConfig::SetFormat rejected")));
  295. return hr;
  296. }
  297. // if we're connected, ask downstream
  298. if (IsConnected())
  299. {
  300. hr = GetConnected()->QueryAccept(pmt);
  301. if (hr != NOERROR)
  302. {
  303. return VFW_E_INVALIDMEDIATYPE;
  304. }
  305. }
  306. // this is now the preferred type (type 0)
  307. hr = SetMediaType((CMediaType *)pmt);
  308. if( S_OK == hr )
  309. {
  310. // only offer this type from now on!
  311. if( m_pmtFromSetFormat )
  312. DeleteMediaType( m_pmtFromSetFormat );
  313. m_pmtFromSetFormat = CreateMediaType( ( AM_MEDIA_TYPE * ) pmt );
  314. if( !m_pmtFromSetFormat )
  315. return E_OUTOFMEMORY;
  316. }
  317. ASSERT(hr == S_OK);
  318. // Changing the format means reconnecting if necessary
  319. if (IsConnected())
  320. Filter()->m_pGraph->Reconnect(this);
  321. return NOERROR;
  322. }
  323. HRESULT CWrapperOutputPin::GetFormat(AM_MEDIA_TYPE **ppmt)
  324. {
  325. DbgLog((LOG_TRACE,2,TEXT("CWrapperOutputPin - IAMStreamConfig::GetFormat")));
  326. if (ppmt == NULL)
  327. return E_POINTER;
  328. CAutoLock lck(&(Filter()->m_csFilter));
  329. // ensure inputs connected to this output are connected
  330. // since our possible output formats depend on the input format
  331. if( !IsInputConnected() )
  332. {
  333. return VFW_E_NOT_CONNECTED;
  334. }
  335. if( m_bUseIAMStreamConfigOnDMO )
  336. {
  337. CComQIPtr< IAMStreamConfig, &IID_IAMStreamConfig > pStreamConfigOnDMO( Filter()->m_pMediaObject );
  338. ASSERT( pStreamConfigOnDMO );
  339. return pStreamConfigOnDMO->GetFormat( ppmt );
  340. }
  341. // type 0 is always the preferred type
  342. // actually this isn't the case for at least wm encoders, but we'll fake it
  343. *ppmt = (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
  344. if (*ppmt == NULL)
  345. return E_OUTOFMEMORY;
  346. ZeroMemory(*ppmt, sizeof(AM_MEDIA_TYPE));
  347. HRESULT hr = GetMediaType(0, (CMediaType *)*ppmt);
  348. if (hr != NOERROR)
  349. {
  350. CoTaskMemFree(*ppmt);
  351. *ppmt = NULL;
  352. return hr;
  353. }
  354. return NOERROR;
  355. }
  356. HRESULT CWrapperOutputPin::GetNumberOfCapabilities(int *piCount, int *piSize)
  357. {
  358. DbgLog((LOG_TRACE,5,TEXT("CWrapperOutputPin - IAMStreamConfig::GetNumberOfCapabilities")));
  359. if (piCount == NULL || piSize == NULL)
  360. return E_POINTER;
  361. if( m_bUseIAMStreamConfigOnDMO )
  362. {
  363. CComQIPtr< IAMStreamConfig, &IID_IAMStreamConfig > pStreamConfigOnDMO( Filter()->m_pMediaObject );
  364. ASSERT( pStreamConfigOnDMO );
  365. return pStreamConfigOnDMO->GetNumberOfCapabilities( piCount, piSize );
  366. }
  367. // find out how many output types the dmo enumerates
  368. // note that it's ok to show possible output types before connecting input
  369. int iType = 0;
  370. HRESULT hr = S_OK;
  371. while( S_OK == hr )
  372. {
  373. // just enumerating, no need to get mt
  374. hr = GetMediaType( iType, NULL );
  375. if( S_OK == hr )
  376. iType++;
  377. }
  378. *piCount = iType;
  379. if( IsVideoEncoder() )
  380. {
  381. *piSize = sizeof(VIDEO_STREAM_CONFIG_CAPS);
  382. }
  383. else
  384. {
  385. ASSERT( IsAudioEncoder() );
  386. *piSize = sizeof(AUDIO_STREAM_CONFIG_CAPS);
  387. }
  388. return NOERROR;
  389. }
  390. HRESULT CWrapperOutputPin::GetStreamCaps(int i, AM_MEDIA_TYPE **ppmt, LPBYTE pSCC)
  391. {
  392. DbgLog((LOG_TRACE,5,TEXT("CWrapperOutputPin - IAMStreamConfig::GetStreamCaps")));
  393. if (i < 0)
  394. return E_INVALIDARG;
  395. if (NULL == pSCC || NULL == ppmt)
  396. return E_POINTER;
  397. if( m_bUseIAMStreamConfigOnDMO )
  398. {
  399. CComQIPtr< IAMStreamConfig, &IID_IAMStreamConfig > pStreamConfigOnDMO( Filter()->m_pMediaObject );
  400. ASSERT( pStreamConfigOnDMO );
  401. return pStreamConfigOnDMO->GetStreamCaps( i, ppmt, pSCC );
  402. }
  403. *ppmt = (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
  404. if (NULL == *ppmt)
  405. return E_OUTOFMEMORY;
  406. ZeroMemory(*ppmt, sizeof(AM_MEDIA_TYPE));
  407. HRESULT hr = GetMediaType(i, (CMediaType *)*ppmt);
  408. if (hr != NOERROR)
  409. {
  410. CoTaskMemFree(*ppmt);
  411. *ppmt = NULL;
  412. if( DMO_E_NO_MORE_ITEMS == hr || E_INVALIDARG == hr )
  413. {
  414. // is this spec'd to return S_FALSE if too high a type? Seems so from other encoders.
  415. return S_FALSE;
  416. }
  417. else
  418. {
  419. return hr;
  420. }
  421. }
  422. if( IsVideoEncoder() )
  423. {
  424. VIDEO_STREAM_CONFIG_CAPS *pVSCC = (VIDEO_STREAM_CONFIG_CAPS *)pSCC;
  425. ZeroMemory(pVSCC, sizeof(VIDEO_STREAM_CONFIG_CAPS));
  426. pVSCC->guid = MEDIATYPE_Video;
  427. if( (*ppmt)->pbFormat && (*ppmt)->cbFormat > 0 )
  428. {
  429. BITMAPINFOHEADER *pbmih = HEADER((*ppmt)->pbFormat);
  430. pVSCC->InputSize.cx = pbmih->biWidth;
  431. pVSCC->InputSize.cy = pbmih->biHeight;
  432. pVSCC->MinCroppingSize.cx = pbmih->biWidth;
  433. pVSCC->MinCroppingSize.cy = pbmih->biHeight;
  434. pVSCC->MaxCroppingSize.cx = pbmih->biWidth;
  435. pVSCC->MaxCroppingSize.cy = pbmih->biHeight;
  436. }
  437. }
  438. else
  439. {
  440. AUDIO_STREAM_CONFIG_CAPS *pASCC = (AUDIO_STREAM_CONFIG_CAPS *)pSCC;
  441. ZeroMemory(pASCC, sizeof(AUDIO_STREAM_CONFIG_CAPS));
  442. pASCC->guid = MEDIATYPE_Audio;
  443. if( (*ppmt)->pbFormat && (*ppmt)->cbFormat > 0 )
  444. {
  445. LPWAVEFORMATEX pwfx = (LPWAVEFORMATEX)(*ppmt)->pbFormat;
  446. // rather let's just offer exactly what the dmo offers (if filled in?)
  447. pASCC->MinimumChannels = pwfx->nChannels;
  448. pASCC->MaximumChannels = pwfx->nChannels;
  449. pASCC->ChannelsGranularity = 1;
  450. pASCC->MinimumBitsPerSample = pwfx->wBitsPerSample;
  451. pASCC->MaximumBitsPerSample = pwfx->wBitsPerSample;
  452. pASCC->BitsPerSampleGranularity = 8;
  453. pASCC->MinimumSampleFrequency = pwfx->nSamplesPerSec;
  454. pASCC->MaximumSampleFrequency = pwfx->nSamplesPerSec;
  455. pASCC->SampleFrequencyGranularity = 1; //?
  456. }
  457. }
  458. return hr;
  459. }
  460. //
  461. // IAMVideoCompression
  462. //
  463. #define DMO_COMPRESSION_QUALITY_MAX 10000 // is this set in stone? Check this.
  464. // make key frames this often
  465. //
  466. HRESULT CWrapperOutputPin::put_KeyFrameRate(long KeyFrameRate)
  467. {
  468. DbgLog((LOG_TRACE,5,TEXT("CWrapperOutputPin - IAMVideoCompression::put_KeyFrameRate")));
  469. CAutoLock lck(&(Filter()->m_csFilter));
  470. if( m_bUseIAMVideoCompressionOnDMO )
  471. {
  472. CComQIPtr< IAMVideoCompression, &IID_IAMVideoCompression > pVideoCompressionOnDMO( Filter()->m_pMediaObject );
  473. ASSERT( pVideoCompressionOnDMO );
  474. return pVideoCompressionOnDMO->put_KeyFrameRate( KeyFrameRate );
  475. }
  476. HRESULT hr = S_OK;
  477. if( KeyFrameRate < 0 )
  478. {
  479. // used to set default key frame rate, which we don't know
  480. // do nothing
  481. }
  482. else
  483. {
  484. // check whether units match!
  485. hr = SetCompressionParamUsingIPropBag( g_wszWMVCKeyframeDistance, KeyFrameRate );
  486. if( SUCCEEDED( hr ) )
  487. {
  488. // update our internal copy
  489. m_lKeyFrameRate = KeyFrameRate;
  490. }
  491. }
  492. return hr;
  493. }
  494. // make key frames this often
  495. //
  496. HRESULT CWrapperOutputPin::get_KeyFrameRate(long FAR* pKeyFrameRate)
  497. {
  498. DbgLog((LOG_TRACE,5,TEXT("CWrapperOutputPin - IAMVideoCompression::get_KeyFrameRate")));
  499. if( NULL == pKeyFrameRate )
  500. return E_POINTER;
  501. if( m_bUseIAMVideoCompressionOnDMO )
  502. {
  503. CComQIPtr< IAMVideoCompression, &IID_IAMVideoCompression > pVideoCompressionOnDMO( Filter()->m_pMediaObject );
  504. ASSERT( pVideoCompressionOnDMO );
  505. return pVideoCompressionOnDMO->get_KeyFrameRate( pKeyFrameRate );
  506. }
  507. // wm codecs don't support a get, so just return the current internal value
  508. *pKeyFrameRate = m_lKeyFrameRate;
  509. return NOERROR;
  510. }
  511. // compress with this quality
  512. //
  513. HRESULT CWrapperOutputPin::put_Quality(double Quality)
  514. {
  515. DbgLog((LOG_TRACE,5,TEXT("CWrapperOutputPin - IAMVideoCompression::put_Quality")));
  516. CAutoLock lck(&(Filter()->m_csFilter));
  517. if( m_bUseIAMVideoCompressionOnDMO )
  518. {
  519. CComQIPtr< IAMVideoCompression, &IID_IAMVideoCompression > pVideoCompressionOnDMO( Filter()->m_pMediaObject );
  520. ASSERT( pVideoCompressionOnDMO );
  521. return pVideoCompressionOnDMO->put_Quality( Quality );
  522. }
  523. HRESULT hr = S_OK;
  524. if (Quality < 0)
  525. {
  526. // used to set default quality, except we don't know how to find out what this is!
  527. // so do nothing, for now
  528. }
  529. else if (Quality >= 0. && Quality <= 1.)
  530. {
  531. // check whether units match!
  532. long lQuality = (long)( Quality * DMO_COMPRESSION_QUALITY_MAX );
  533. hr = SetCompressionParamUsingIPropBag( g_wszWMVCCrisp, lQuality );
  534. if( SUCCEEDED( hr ) )
  535. {
  536. // update our internal copy
  537. m_lQuality = lQuality;
  538. }
  539. }
  540. else
  541. {
  542. hr = E_INVALIDARG;
  543. }
  544. return hr;
  545. }
  546. // compress with this quality
  547. //
  548. HRESULT CWrapperOutputPin::get_Quality(double FAR* pQuality)
  549. {
  550. DbgLog((LOG_TRACE,5,TEXT("CWrapperOutputPin - IAMVideoCompression::get_Quality")));
  551. if( NULL == pQuality )
  552. return E_POINTER;
  553. CAutoLock lck(&(Filter()->m_csFilter));
  554. if( m_bUseIAMVideoCompressionOnDMO )
  555. {
  556. CComQIPtr< IAMVideoCompression, &IID_IAMVideoCompression > pVideoCompressionOnDMO( Filter()->m_pMediaObject );
  557. ASSERT( pVideoCompressionOnDMO );
  558. return pVideoCompressionOnDMO->get_Quality( pQuality );
  559. }
  560. // scale the dmo encoder's bounds to 0-1, hmm...?
  561. if( m_lQuality < 0 )
  562. {
  563. // assume default
  564. *pQuality = -1.;
  565. }
  566. else
  567. {
  568. // wm codecs don't support a get, so just return the current internal value
  569. *pQuality = m_lQuality / (double)DMO_COMPRESSION_QUALITY_MAX; // ?
  570. }
  571. return NOERROR;
  572. }
  573. // every frame must fit in the data rate...
  574. //
  575. HRESULT CWrapperOutputPin::put_WindowSize(DWORDLONG WindowSize)
  576. {
  577. DbgLog((LOG_TRACE,5,TEXT("CWrapperOutputPin - IAMVideoCompression::put_WindowSize")));
  578. CAutoLock lck(&(Filter()->m_csFilter));
  579. if( m_bUseIAMVideoCompressionOnDMO )
  580. {
  581. CComQIPtr< IAMVideoCompression, &IID_IAMVideoCompression > pVideoCompressionOnDMO( Filter()->m_pMediaObject );
  582. ASSERT( pVideoCompressionOnDMO );
  583. return pVideoCompressionOnDMO->put_WindowSize( WindowSize );
  584. }
  585. return E_NOTIMPL;
  586. }
  587. // every frame must fit in the data rate... we don't do the WindowSize thing
  588. //
  589. HRESULT CWrapperOutputPin::get_WindowSize(DWORDLONG FAR* pWindowSize)
  590. {
  591. DbgLog((LOG_TRACE,5,TEXT("CWrapperOutputPin - IAMVideoCompression::get_WindowSize")));
  592. if (pWindowSize == NULL)
  593. return E_POINTER;
  594. CAutoLock lck(&(Filter()->m_csFilter));
  595. if( m_bUseIAMVideoCompressionOnDMO )
  596. {
  597. CComQIPtr< IAMVideoCompression, &IID_IAMVideoCompression > pVideoCompressionOnDMO( Filter()->m_pMediaObject );
  598. ASSERT( pVideoCompressionOnDMO );
  599. return pVideoCompressionOnDMO->get_WindowSize( pWindowSize );
  600. }
  601. *pWindowSize = 1; // we don't do windows
  602. return NOERROR;
  603. }
  604. // make this frame a key frame, whenever it comes by
  605. //
  606. HRESULT CWrapperOutputPin::OverrideKeyFrame(long FrameNumber)
  607. {
  608. DbgLog((LOG_TRACE,5,TEXT("CWrapperOutputPin - IAMVideoCompression::OverrideKeyFrame")));
  609. if( m_bUseIAMVideoCompressionOnDMO )
  610. {
  611. CComQIPtr< IAMVideoCompression, &IID_IAMVideoCompression > pVideoCompressionOnDMO( Filter()->m_pMediaObject );
  612. ASSERT( pVideoCompressionOnDMO );
  613. return pVideoCompressionOnDMO->OverrideKeyFrame( FrameNumber );
  614. }
  615. // not needed currently
  616. return E_NOTIMPL;
  617. }
  618. // make this frame this size, whenever it comes by
  619. //
  620. HRESULT CWrapperOutputPin::OverrideFrameSize(long FrameNumber, long Size)
  621. {
  622. DbgLog((LOG_TRACE,5,TEXT("CWrapperOutputPin - IAMVideoCompression::OverrideFrameSize")));
  623. if( m_bUseIAMVideoCompressionOnDMO )
  624. {
  625. CComQIPtr< IAMVideoCompression, &IID_IAMVideoCompression > pVideoCompressionOnDMO( Filter()->m_pMediaObject );
  626. ASSERT( pVideoCompressionOnDMO );
  627. return pVideoCompressionOnDMO->OverrideFrameSize( FrameNumber, Size );
  628. }
  629. // not needed currently
  630. return E_NOTIMPL;
  631. }
  632. // Get some information about the codec
  633. //
  634. HRESULT CWrapperOutputPin::GetInfo
  635. (
  636. LPWSTR pstrVersion,
  637. int *pcbVersion,
  638. LPWSTR pstrDescription,
  639. int *pcbDescription,
  640. long FAR* pDefaultKeyFrameRate,
  641. long FAR* pDefaultPFramesPerKey,
  642. double FAR* pDefaultQuality,
  643. long FAR* pCapabilities
  644. )
  645. {
  646. DbgLog((LOG_TRACE,5,TEXT("CWrapperOutputPin - IAMVideoCompression::GetInfo")));
  647. if( m_bUseIAMVideoCompressionOnDMO )
  648. {
  649. CComQIPtr< IAMVideoCompression, &IID_IAMVideoCompression > pVideoCompressionOnDMO( Filter()->m_pMediaObject );
  650. ASSERT( pVideoCompressionOnDMO );
  651. return pVideoCompressionOnDMO->GetInfo(
  652. pstrVersion,
  653. pcbVersion,
  654. pstrDescription,
  655. pcbDescription,
  656. pDefaultKeyFrameRate,
  657. pDefaultPFramesPerKey,
  658. pDefaultQuality,
  659. pCapabilities );
  660. }
  661. // there's no way to query default settings for wm codecs currently?
  662. return E_NOTIMPL;
  663. #if 0
  664. CAutoLock lck(&(Filter()->m_csFilter));
  665. // for ICM we did this...
  666. if (pDefaultKeyFrameRate)
  667. *pDefaultKeyFrameRate = ICGetDefaultKeyFrameRate(hic);
  668. if (pDefaultPFramesPerKey)
  669. *pDefaultPFramesPerKey = 0;
  670. if (pDefaultQuality)
  671. // scale this 0-1
  672. *pDefaultQuality = ICGetDefaultQuality(hic) / (double)ICQUALITY_HIGH;
  673. if (pCapabilities)
  674. {
  675. *pCapabilities = 0;
  676. if (dw > 0)
  677. {
  678. *pCapabilities |= ((icinfo.dwFlags & VIDCF_QUALITY) ?
  679. CompressionCaps_CanQuality : 0);
  680. *pCapabilities |= ((icinfo.dwFlags & VIDCF_CRUNCH) ?
  681. CompressionCaps_CanCrunch : 0);
  682. *pCapabilities |= ((icinfo.dwFlags & VIDCF_TEMPORAL) ?
  683. CompressionCaps_CanKeyFrame : 0);
  684. // we don't do b frames
  685. }
  686. }
  687. // We have no version string, but we have a description
  688. if (pstrVersion)
  689. *pstrVersion = 0;
  690. if (pcbVersion)
  691. *pcbVersion = 0;
  692. if (dw > 0)
  693. {
  694. if (pstrDescription && pcbDescription)
  695. lstrcpynW(pstrDescription, (LPCWSTR)&icinfo.szDescription,
  696. min(*pcbDescription / 2,
  697. lstrlenW((LPCWSTR)&icinfo.szDescription) + 1));
  698. if (pcbDescription)
  699. // string length in bytes, incl. NULL
  700. *pcbDescription = lstrlenW((LPCWSTR)&icinfo.szDescription) * 2 + 2;
  701. }
  702. else
  703. {
  704. if (pstrDescription)
  705. {
  706. *pstrDescription = 0;
  707. if (pcbDescription)
  708. *pcbDescription = 0;
  709. }
  710. }
  711. return NOERROR;
  712. #endif
  713. }
  714. HRESULT CWrapperOutputPin::SetCompressionParamUsingIPropBag
  715. (
  716. const WCHAR * wszParam,
  717. const LONG lValue
  718. )
  719. {
  720. HRESULT hr = E_NOTIMPL;
  721. //
  722. // wm codecs support setting of compression properties through IPropertyBag, try this first
  723. //
  724. CComQIPtr< IPropertyBag, &IID_IPropertyBag > pPropBag( Filter()->m_pMediaObject );
  725. if( !pPropBag )
  726. {
  727. DbgLog((LOG_TRACE,2,TEXT("CWrapperOutputPin::SetCompressionParamUsingIPropBag - DMO doesn't support IPropertyBag for compression setting") ) );
  728. }
  729. else
  730. {
  731. // attempt to set the property
  732. VARIANT var;
  733. V_VT( &var ) = VT_I4;
  734. V_I4( &var ) = lValue;
  735. hr = pPropBag->Write( wszParam, &var );
  736. #ifdef DEBUG
  737. if( FAILED( hr ) )
  738. {
  739. DbgLog((LOG_TRACE,
  740. 3,
  741. TEXT("CWrapperOutputPin::SetCompressionParamUsingIPropBag - DMO supports IPropertyBag but not %ls setting"),
  742. wszParam ) );
  743. }
  744. #endif
  745. }
  746. return hr;
  747. }
  748. bool CWrapperOutputPin::IsAudioEncoder()
  749. {
  750. if(Filter()->m_guidCat == DMOCATEGORY_AUDIO_ENCODER)
  751. return true;
  752. else
  753. return false;
  754. }
  755. bool CWrapperOutputPin::IsVideoEncoder()
  756. {
  757. if(Filter()->m_guidCat == DMOCATEGORY_VIDEO_ENCODER)
  758. return true;
  759. else
  760. return false;
  761. }
  762. bool CWrapperOutputPin::IsInputConnected()
  763. {
  764. for (DWORD cIn = 0; cIn < Filter()->m_cInputPins; cIn++)
  765. {
  766. if (Filter()->InputMapsToOutput(cIn, m_Id) &&
  767. !(Filter()->m_pInputPins[cIn]->IsConnected()))
  768. {
  769. // some input not connected
  770. return false;
  771. }
  772. }
  773. return true;
  774. }