#include #include #include #include #include #include #include "mediaobj.h" #include "dmodshow.h" #include "filter.h" #include "inpin.h" #include "outpin.h" #include "wmcodecstrs.h" // from wm encoder group, not public currently CWrapperOutputPin::CWrapperOutputPin( CMediaWrapperFilter *pFilter, ULONG Id, BOOL bOptional, HRESULT *phr) : CBaseOutputPin(NAME("CWrapperOutputPin"), pFilter, pFilter->FilterLock(), phr, _PinName_(bOptional ? L"~out" : L"out", Id).Name() ), m_Id(Id), m_fNoPosPassThru(FALSE), m_pPosPassThru(NULL), m_pMediaSample(NULL), // compression setting default values, move to struct eventually m_lQuality( -1 ), m_lKeyFrameRate( -1 ), m_bUseIAMStreamConfigOnDMO( false ), m_bUseIAMVideoCompressionOnDMO( false ), m_pmtFromSetFormat( NULL ) { } CWrapperOutputPin::~CWrapperOutputPin() { delete m_pPosPassThru; if( m_pmtFromSetFormat ) { // clean up any media type we might have cached from a SetFormat call DeleteMediaType( m_pmtFromSetFormat ); } } HRESULT CWrapperOutputPin::NonDelegatingQueryInterface(REFGUID riid, void **ppv) { if (SUCCEEDED(CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv))) return NOERROR; if ((riid == IID_IMediaPosition) || (riid == IID_IMediaSeeking)) { CAutoLock l(&m_csPassThru); // The first time we get here, we attempt to create a CPosPassThru // object. If we succeed, we use the object in all subsequent QI // calls. If we fail, we set m_fNoPassThru to TRUE so that we never // try again. Trying again and succeeding would violate COM rules. if (m_fNoPosPassThru) return E_NOINTERFACE; // Create a CPosPassThru if we don't have one already if (!m_pPosPassThru) { CWrapperInputPin* pInPin = Filter()->GetInputPinForPassThru(); if (pInPin) { HRESULT hr = S_OK; m_pPosPassThru = new CPosPassThru(TEXT("DMO wrapper PosPassThru"), (IPin*)this, &hr, pInPin); if (m_pPosPassThru && (FAILED(hr))) { delete m_pPosPassThru; m_pPosPassThru = NULL; } } } if (m_pPosPassThru) { return m_pPosPassThru->NonDelegatingQueryInterface(riid, ppv); } else { m_fNoPosPassThru = TRUE; return E_NOINTERFACE; } } else if (riid == IID_IAMStreamConfig ) { // we support this interface for audio and video encoders if (IsAudioEncoder() || IsVideoEncoder() ) { if( 0 == m_Id && !m_bUseIAMStreamConfigOnDMO ) { // first check whether the dmo supports this natively and cache the interface pointer if so // BUGBUG needs to be per output stream!! // for now fail only ask if 1st output stream CComQIPtr< IAMStreamConfig, &IID_IAMStreamConfig > pStreamConfigOnDMO( Filter()->m_pMediaObject ); if( pStreamConfigOnDMO ) { // so it is supported natively, but we must release it since it winds up addref'ing the filter m_bUseIAMStreamConfigOnDMO = true; DbgLog((LOG_TRACE,3,TEXT("CWrapperOutputPin::NonDelegatingQI - DMO supports IAMStreamConfig natively"))); } } // either way it'll go through us return GetInterface( static_cast (this), ppv ); } } else if (riid == IID_IAMVideoCompression ) { // we support this interface for video encoders if ( IsVideoEncoder() ) { if( 0 == m_Id && !m_bUseIAMVideoCompressionOnDMO ) { // first check whether the dmo supports this natively and cache the interface pointer if so // BUGBUG needs to be per output stream!! // for now fail only ask if 1st output stream CComQIPtr< IAMVideoCompression, &IID_IAMVideoCompression > pVideoCompressionOnDMO( Filter()->m_pMediaObject ); if( pVideoCompressionOnDMO ) { // so it is supported natively, but we must release it since it winds up addref'ing the filter m_bUseIAMVideoCompressionOnDMO = true; DbgLog((LOG_TRACE,3,TEXT("CWrapperOutputPin::NonDelegatingQI - DMO supports IAMVideoCompression natively"))); } } // either way it'll go through us return GetInterface( static_cast (this), ppv); } } return E_NOINTERFACE; } HRESULT CWrapperOutputPin::CheckMediaType(const CMediaType *pmt) { return Filter()->OutputCheckMediaType(m_Id, pmt); } HRESULT CWrapperOutputPin::SetMediaType(const CMediaType *pmt) { CAutoLock l(&m_csStream); HRESULT hr = Filter()->OutputSetMediaType(m_Id, pmt); if (SUCCEEDED(hr)) { hr = CBaseOutputPin::SetMediaType(pmt); if (SUCCEEDED(hr)) { m_fVideo = pmt->majortype == MEDIATYPE_Video ? true : false; } } return hr; } HRESULT CWrapperOutputPin::GetMediaType(int iPosition, CMediaType *pMediaType) { if( m_pmtFromSetFormat ) { // our SetFormat has been called so only offer that type from now on if( iPosition != 0 ) return E_INVALIDARG; *pMediaType = *m_pmtFromSetFormat; return S_OK; } else { return Filter()->OutputGetMediaType(m_Id, (ULONG)iPosition, pMediaType); } } // // override primarily for the case where we're a wm dmo video encoder connecting directly // to the ASF writer, in a desparate attempt to get an output type which a wm video encoder // will accept in the default connection case // STDMETHODIMP CWrapperOutputPin::Connect(IPin *pReceivePin, const AM_MEDIA_TYPE *pmt) { DbgLog((LOG_TRACE,3,TEXT("CWrapperOutputPin::Connect"))); CAutoLock lck(&(Filter()->m_csFilter)); // // if connecting to the asf writer try getting a default type from the writer // // note that, although we'd like to do this only if SetFormat hasn't been called, // we have no guarantee that the writer format hasn't changed, so we need to // continually call SetFormat with the type we get from the downstream pin's GetFormat bool bSetFormatOnConnect = false; if( !pmt && !m_pmtFromSetFormat && IsVideoEncoder() ) { CComQIPtr< IAMStreamConfig, &IID_IAMStreamConfig > pStreamConfig( pReceivePin ); if( pStreamConfig ) { AM_MEDIA_TYPE *pmt2; HRESULT hrInt = pStreamConfig->GetFormat( &pmt2 ); if( SUCCEEDED( hrInt ) ) { // now we'll only offer this type! hrInt = SetFormat( pmt2 ); if( SUCCEEDED( hrInt ) ) { bSetFormatOnConnect = true; } } } } // call the base class connect HRESULT hr = CBaseOutputPin::Connect(pReceivePin,pmt); if( bSetFormatOnConnect ) { // whether we failed or not, unset the format if we set one here in connect if( m_pmtFromSetFormat ) { // clean up any media type we might have cached from a SetFormat call DeleteMediaType( m_pmtFromSetFormat ); m_pmtFromSetFormat = NULL; } } return hr; } // Remove any media type when breaking a connection HRESULT CWrapperOutputPin::BreakConnect() { HRESULT hr = CBaseOutputPin::BreakConnect(); Filter()->m_pMediaObject->SetOutputType(m_Id, &CMediaType(), DMO_SET_TYPEF_CLEAR); return hr; } HRESULT CWrapperOutputPin::DecideBufferSize( IMemAllocator * pAlloc, ALLOCATOR_PROPERTIES * ppropInputRequest ) { return Filter()->OutputDecideBufferSize(m_Id, pAlloc, ppropInputRequest); } HRESULT CWrapperOutputPin::Notify(IBaseFilter * pSender, Quality q) { LogPublicEntry(LOG_STREAM,"Quality Notify"); HRESULT hr; // If quality sink set, forward the quality request to it if (m_pQSink) { hr = m_pQSink->Notify(Filter(), q); LogHResult(hr, LOG_STREAM, "Quality Notify", "m_pQSink->Notify"); return hr; } // This will try the DMO, then the upstream pin return Filter()->QualityNotify(m_Id, q); } // // IAMStreamConfig // HRESULT CWrapperOutputPin::SetFormat(AM_MEDIA_TYPE *pmt) { DbgLog((LOG_TRACE,5,TEXT("CWrapperOutputPin - IAMStreamConfig::SetFormat"))); CAutoLock lck(&(Filter()->m_csFilter)); HRESULT hr = S_OK; if (NULL == pmt) { // I'd rather use this to "unset" the type, but that's not how other encoders work // previously they returned E_POINTER for this // can we break tradition? DeleteMediaType( m_pmtFromSetFormat ); m_pmtFromSetFormat = NULL; return S_OK; } if (Filter()->m_State != State_Stopped) return VFW_E_NOT_STOPPED; // ensure inputs connected to this output are connected // since our possible output formats depend on the input format if( !IsInputConnected() ) { return VFW_E_NOT_CONNECTED; } if( m_bUseIAMStreamConfigOnDMO ) { CComQIPtr< IAMStreamConfig, &IID_IAMStreamConfig > pStreamConfigOnDMO( Filter()->m_pMediaObject ); ASSERT( pStreamConfigOnDMO ); return pStreamConfigOnDMO->SetFormat( pmt ); } #ifdef DEBUG if(pmt->pbFormat && pmt->cbFormat > 0 ) { if( IsVideoEncoder() ) { DbgLog((LOG_TRACE,3,TEXT("CWrapperOutputPin - IAMStreamConfig::SetFormat %x %dbit %dx%d"), HEADER(pmt->pbFormat)->biCompression, HEADER(pmt->pbFormat)->biBitCount, HEADER(pmt->pbFormat)->biWidth, HEADER(pmt->pbFormat)->biHeight)); } else { DbgLog((LOG_TRACE,3,TEXT("CWrapperOutputPin - IAMStreamConfig::SetFormat to tag:%d %dbit %dchannel %dHz"), ((LPWAVEFORMATEX)(pmt->pbFormat))->wFormatTag, ((LPWAVEFORMATEX)(pmt->pbFormat))->wBitsPerSample, ((LPWAVEFORMATEX)(pmt->pbFormat))->nChannels, ((LPWAVEFORMATEX)(pmt->pbFormat))->nSamplesPerSec)); } } #endif // If this is the same format as we already are using, don't bother CMediaType cmt; hr = GetMediaType(0,&cmt); if (S_OK != hr) return hr; if (cmt == *pmt) { return NOERROR; } // see if we like this type if ((hr = CheckMediaType((CMediaType *)pmt)) != NOERROR) { DbgLog((LOG_TRACE,2,TEXT("IAMStreamConfig::SetFormat rejected"))); return hr; } // if we're connected, ask downstream if (IsConnected()) { hr = GetConnected()->QueryAccept(pmt); if (hr != NOERROR) { return VFW_E_INVALIDMEDIATYPE; } } // this is now the preferred type (type 0) hr = SetMediaType((CMediaType *)pmt); if( S_OK == hr ) { // only offer this type from now on! if( m_pmtFromSetFormat ) DeleteMediaType( m_pmtFromSetFormat ); m_pmtFromSetFormat = CreateMediaType( ( AM_MEDIA_TYPE * ) pmt ); if( !m_pmtFromSetFormat ) return E_OUTOFMEMORY; } ASSERT(hr == S_OK); // Changing the format means reconnecting if necessary if (IsConnected()) Filter()->m_pGraph->Reconnect(this); return NOERROR; } HRESULT CWrapperOutputPin::GetFormat(AM_MEDIA_TYPE **ppmt) { DbgLog((LOG_TRACE,2,TEXT("CWrapperOutputPin - IAMStreamConfig::GetFormat"))); if (ppmt == NULL) return E_POINTER; CAutoLock lck(&(Filter()->m_csFilter)); // ensure inputs connected to this output are connected // since our possible output formats depend on the input format if( !IsInputConnected() ) { return VFW_E_NOT_CONNECTED; } if( m_bUseIAMStreamConfigOnDMO ) { CComQIPtr< IAMStreamConfig, &IID_IAMStreamConfig > pStreamConfigOnDMO( Filter()->m_pMediaObject ); ASSERT( pStreamConfigOnDMO ); return pStreamConfigOnDMO->GetFormat( ppmt ); } // type 0 is always the preferred type // actually this isn't the case for at least wm encoders, but we'll fake it *ppmt = (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); if (*ppmt == NULL) return E_OUTOFMEMORY; ZeroMemory(*ppmt, sizeof(AM_MEDIA_TYPE)); HRESULT hr = GetMediaType(0, (CMediaType *)*ppmt); if (hr != NOERROR) { CoTaskMemFree(*ppmt); *ppmt = NULL; return hr; } return NOERROR; } HRESULT CWrapperOutputPin::GetNumberOfCapabilities(int *piCount, int *piSize) { DbgLog((LOG_TRACE,5,TEXT("CWrapperOutputPin - IAMStreamConfig::GetNumberOfCapabilities"))); if (piCount == NULL || piSize == NULL) return E_POINTER; if( m_bUseIAMStreamConfigOnDMO ) { CComQIPtr< IAMStreamConfig, &IID_IAMStreamConfig > pStreamConfigOnDMO( Filter()->m_pMediaObject ); ASSERT( pStreamConfigOnDMO ); return pStreamConfigOnDMO->GetNumberOfCapabilities( piCount, piSize ); } // find out how many output types the dmo enumerates // note that it's ok to show possible output types before connecting input int iType = 0; HRESULT hr = S_OK; while( S_OK == hr ) { // just enumerating, no need to get mt hr = GetMediaType( iType, NULL ); if( S_OK == hr ) iType++; } *piCount = iType; if( IsVideoEncoder() ) { *piSize = sizeof(VIDEO_STREAM_CONFIG_CAPS); } else { ASSERT( IsAudioEncoder() ); *piSize = sizeof(AUDIO_STREAM_CONFIG_CAPS); } return NOERROR; } HRESULT CWrapperOutputPin::GetStreamCaps(int i, AM_MEDIA_TYPE **ppmt, LPBYTE pSCC) { DbgLog((LOG_TRACE,5,TEXT("CWrapperOutputPin - IAMStreamConfig::GetStreamCaps"))); if (i < 0) return E_INVALIDARG; if (NULL == pSCC || NULL == ppmt) return E_POINTER; if( m_bUseIAMStreamConfigOnDMO ) { CComQIPtr< IAMStreamConfig, &IID_IAMStreamConfig > pStreamConfigOnDMO( Filter()->m_pMediaObject ); ASSERT( pStreamConfigOnDMO ); return pStreamConfigOnDMO->GetStreamCaps( i, ppmt, pSCC ); } *ppmt = (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); if (NULL == *ppmt) return E_OUTOFMEMORY; ZeroMemory(*ppmt, sizeof(AM_MEDIA_TYPE)); HRESULT hr = GetMediaType(i, (CMediaType *)*ppmt); if (hr != NOERROR) { CoTaskMemFree(*ppmt); *ppmt = NULL; if( DMO_E_NO_MORE_ITEMS == hr || E_INVALIDARG == hr ) { // is this spec'd to return S_FALSE if too high a type? Seems so from other encoders. return S_FALSE; } else { return hr; } } if( IsVideoEncoder() ) { VIDEO_STREAM_CONFIG_CAPS *pVSCC = (VIDEO_STREAM_CONFIG_CAPS *)pSCC; ZeroMemory(pVSCC, sizeof(VIDEO_STREAM_CONFIG_CAPS)); pVSCC->guid = MEDIATYPE_Video; if( (*ppmt)->pbFormat && (*ppmt)->cbFormat > 0 ) { BITMAPINFOHEADER *pbmih = HEADER((*ppmt)->pbFormat); pVSCC->InputSize.cx = pbmih->biWidth; pVSCC->InputSize.cy = pbmih->biHeight; pVSCC->MinCroppingSize.cx = pbmih->biWidth; pVSCC->MinCroppingSize.cy = pbmih->biHeight; pVSCC->MaxCroppingSize.cx = pbmih->biWidth; pVSCC->MaxCroppingSize.cy = pbmih->biHeight; } } else { AUDIO_STREAM_CONFIG_CAPS *pASCC = (AUDIO_STREAM_CONFIG_CAPS *)pSCC; ZeroMemory(pASCC, sizeof(AUDIO_STREAM_CONFIG_CAPS)); pASCC->guid = MEDIATYPE_Audio; if( (*ppmt)->pbFormat && (*ppmt)->cbFormat > 0 ) { LPWAVEFORMATEX pwfx = (LPWAVEFORMATEX)(*ppmt)->pbFormat; // rather let's just offer exactly what the dmo offers (if filled in?) pASCC->MinimumChannels = pwfx->nChannels; pASCC->MaximumChannels = pwfx->nChannels; pASCC->ChannelsGranularity = 1; pASCC->MinimumBitsPerSample = pwfx->wBitsPerSample; pASCC->MaximumBitsPerSample = pwfx->wBitsPerSample; pASCC->BitsPerSampleGranularity = 8; pASCC->MinimumSampleFrequency = pwfx->nSamplesPerSec; pASCC->MaximumSampleFrequency = pwfx->nSamplesPerSec; pASCC->SampleFrequencyGranularity = 1; //? } } return hr; } // // IAMVideoCompression // #define DMO_COMPRESSION_QUALITY_MAX 10000 // is this set in stone? Check this. // make key frames this often // HRESULT CWrapperOutputPin::put_KeyFrameRate(long KeyFrameRate) { DbgLog((LOG_TRACE,5,TEXT("CWrapperOutputPin - IAMVideoCompression::put_KeyFrameRate"))); CAutoLock lck(&(Filter()->m_csFilter)); if( m_bUseIAMVideoCompressionOnDMO ) { CComQIPtr< IAMVideoCompression, &IID_IAMVideoCompression > pVideoCompressionOnDMO( Filter()->m_pMediaObject ); ASSERT( pVideoCompressionOnDMO ); return pVideoCompressionOnDMO->put_KeyFrameRate( KeyFrameRate ); } HRESULT hr = S_OK; if( KeyFrameRate < 0 ) { // used to set default key frame rate, which we don't know // do nothing } else { // check whether units match! hr = SetCompressionParamUsingIPropBag( g_wszWMVCKeyframeDistance, KeyFrameRate ); if( SUCCEEDED( hr ) ) { // update our internal copy m_lKeyFrameRate = KeyFrameRate; } } return hr; } // make key frames this often // HRESULT CWrapperOutputPin::get_KeyFrameRate(long FAR* pKeyFrameRate) { DbgLog((LOG_TRACE,5,TEXT("CWrapperOutputPin - IAMVideoCompression::get_KeyFrameRate"))); if( NULL == pKeyFrameRate ) return E_POINTER; if( m_bUseIAMVideoCompressionOnDMO ) { CComQIPtr< IAMVideoCompression, &IID_IAMVideoCompression > pVideoCompressionOnDMO( Filter()->m_pMediaObject ); ASSERT( pVideoCompressionOnDMO ); return pVideoCompressionOnDMO->get_KeyFrameRate( pKeyFrameRate ); } // wm codecs don't support a get, so just return the current internal value *pKeyFrameRate = m_lKeyFrameRate; return NOERROR; } // compress with this quality // HRESULT CWrapperOutputPin::put_Quality(double Quality) { DbgLog((LOG_TRACE,5,TEXT("CWrapperOutputPin - IAMVideoCompression::put_Quality"))); CAutoLock lck(&(Filter()->m_csFilter)); if( m_bUseIAMVideoCompressionOnDMO ) { CComQIPtr< IAMVideoCompression, &IID_IAMVideoCompression > pVideoCompressionOnDMO( Filter()->m_pMediaObject ); ASSERT( pVideoCompressionOnDMO ); return pVideoCompressionOnDMO->put_Quality( Quality ); } HRESULT hr = S_OK; if (Quality < 0) { // used to set default quality, except we don't know how to find out what this is! // so do nothing, for now } else if (Quality >= 0. && Quality <= 1.) { // check whether units match! long lQuality = (long)( Quality * DMO_COMPRESSION_QUALITY_MAX ); hr = SetCompressionParamUsingIPropBag( g_wszWMVCCrisp, lQuality ); if( SUCCEEDED( hr ) ) { // update our internal copy m_lQuality = lQuality; } } else { hr = E_INVALIDARG; } return hr; } // compress with this quality // HRESULT CWrapperOutputPin::get_Quality(double FAR* pQuality) { DbgLog((LOG_TRACE,5,TEXT("CWrapperOutputPin - IAMVideoCompression::get_Quality"))); if( NULL == pQuality ) return E_POINTER; CAutoLock lck(&(Filter()->m_csFilter)); if( m_bUseIAMVideoCompressionOnDMO ) { CComQIPtr< IAMVideoCompression, &IID_IAMVideoCompression > pVideoCompressionOnDMO( Filter()->m_pMediaObject ); ASSERT( pVideoCompressionOnDMO ); return pVideoCompressionOnDMO->get_Quality( pQuality ); } // scale the dmo encoder's bounds to 0-1, hmm...? if( m_lQuality < 0 ) { // assume default *pQuality = -1.; } else { // wm codecs don't support a get, so just return the current internal value *pQuality = m_lQuality / (double)DMO_COMPRESSION_QUALITY_MAX; // ? } return NOERROR; } // every frame must fit in the data rate... // HRESULT CWrapperOutputPin::put_WindowSize(DWORDLONG WindowSize) { DbgLog((LOG_TRACE,5,TEXT("CWrapperOutputPin - IAMVideoCompression::put_WindowSize"))); CAutoLock lck(&(Filter()->m_csFilter)); if( m_bUseIAMVideoCompressionOnDMO ) { CComQIPtr< IAMVideoCompression, &IID_IAMVideoCompression > pVideoCompressionOnDMO( Filter()->m_pMediaObject ); ASSERT( pVideoCompressionOnDMO ); return pVideoCompressionOnDMO->put_WindowSize( WindowSize ); } return E_NOTIMPL; } // every frame must fit in the data rate... we don't do the WindowSize thing // HRESULT CWrapperOutputPin::get_WindowSize(DWORDLONG FAR* pWindowSize) { DbgLog((LOG_TRACE,5,TEXT("CWrapperOutputPin - IAMVideoCompression::get_WindowSize"))); if (pWindowSize == NULL) return E_POINTER; CAutoLock lck(&(Filter()->m_csFilter)); if( m_bUseIAMVideoCompressionOnDMO ) { CComQIPtr< IAMVideoCompression, &IID_IAMVideoCompression > pVideoCompressionOnDMO( Filter()->m_pMediaObject ); ASSERT( pVideoCompressionOnDMO ); return pVideoCompressionOnDMO->get_WindowSize( pWindowSize ); } *pWindowSize = 1; // we don't do windows return NOERROR; } // make this frame a key frame, whenever it comes by // HRESULT CWrapperOutputPin::OverrideKeyFrame(long FrameNumber) { DbgLog((LOG_TRACE,5,TEXT("CWrapperOutputPin - IAMVideoCompression::OverrideKeyFrame"))); if( m_bUseIAMVideoCompressionOnDMO ) { CComQIPtr< IAMVideoCompression, &IID_IAMVideoCompression > pVideoCompressionOnDMO( Filter()->m_pMediaObject ); ASSERT( pVideoCompressionOnDMO ); return pVideoCompressionOnDMO->OverrideKeyFrame( FrameNumber ); } // not needed currently return E_NOTIMPL; } // make this frame this size, whenever it comes by // HRESULT CWrapperOutputPin::OverrideFrameSize(long FrameNumber, long Size) { DbgLog((LOG_TRACE,5,TEXT("CWrapperOutputPin - IAMVideoCompression::OverrideFrameSize"))); if( m_bUseIAMVideoCompressionOnDMO ) { CComQIPtr< IAMVideoCompression, &IID_IAMVideoCompression > pVideoCompressionOnDMO( Filter()->m_pMediaObject ); ASSERT( pVideoCompressionOnDMO ); return pVideoCompressionOnDMO->OverrideFrameSize( FrameNumber, Size ); } // not needed currently return E_NOTIMPL; } // Get some information about the codec // HRESULT CWrapperOutputPin::GetInfo ( LPWSTR pstrVersion, int *pcbVersion, LPWSTR pstrDescription, int *pcbDescription, long FAR* pDefaultKeyFrameRate, long FAR* pDefaultPFramesPerKey, double FAR* pDefaultQuality, long FAR* pCapabilities ) { DbgLog((LOG_TRACE,5,TEXT("CWrapperOutputPin - IAMVideoCompression::GetInfo"))); if( m_bUseIAMVideoCompressionOnDMO ) { CComQIPtr< IAMVideoCompression, &IID_IAMVideoCompression > pVideoCompressionOnDMO( Filter()->m_pMediaObject ); ASSERT( pVideoCompressionOnDMO ); return pVideoCompressionOnDMO->GetInfo( pstrVersion, pcbVersion, pstrDescription, pcbDescription, pDefaultKeyFrameRate, pDefaultPFramesPerKey, pDefaultQuality, pCapabilities ); } // there's no way to query default settings for wm codecs currently? return E_NOTIMPL; #if 0 CAutoLock lck(&(Filter()->m_csFilter)); // for ICM we did this... if (pDefaultKeyFrameRate) *pDefaultKeyFrameRate = ICGetDefaultKeyFrameRate(hic); if (pDefaultPFramesPerKey) *pDefaultPFramesPerKey = 0; if (pDefaultQuality) // scale this 0-1 *pDefaultQuality = ICGetDefaultQuality(hic) / (double)ICQUALITY_HIGH; if (pCapabilities) { *pCapabilities = 0; if (dw > 0) { *pCapabilities |= ((icinfo.dwFlags & VIDCF_QUALITY) ? CompressionCaps_CanQuality : 0); *pCapabilities |= ((icinfo.dwFlags & VIDCF_CRUNCH) ? CompressionCaps_CanCrunch : 0); *pCapabilities |= ((icinfo.dwFlags & VIDCF_TEMPORAL) ? CompressionCaps_CanKeyFrame : 0); // we don't do b frames } } // We have no version string, but we have a description if (pstrVersion) *pstrVersion = 0; if (pcbVersion) *pcbVersion = 0; if (dw > 0) { if (pstrDescription && pcbDescription) lstrcpynW(pstrDescription, (LPCWSTR)&icinfo.szDescription, min(*pcbDescription / 2, lstrlenW((LPCWSTR)&icinfo.szDescription) + 1)); if (pcbDescription) // string length in bytes, incl. NULL *pcbDescription = lstrlenW((LPCWSTR)&icinfo.szDescription) * 2 + 2; } else { if (pstrDescription) { *pstrDescription = 0; if (pcbDescription) *pcbDescription = 0; } } return NOERROR; #endif } HRESULT CWrapperOutputPin::SetCompressionParamUsingIPropBag ( const WCHAR * wszParam, const LONG lValue ) { HRESULT hr = E_NOTIMPL; // // wm codecs support setting of compression properties through IPropertyBag, try this first // CComQIPtr< IPropertyBag, &IID_IPropertyBag > pPropBag( Filter()->m_pMediaObject ); if( !pPropBag ) { DbgLog((LOG_TRACE,2,TEXT("CWrapperOutputPin::SetCompressionParamUsingIPropBag - DMO doesn't support IPropertyBag for compression setting") ) ); } else { // attempt to set the property VARIANT var; V_VT( &var ) = VT_I4; V_I4( &var ) = lValue; hr = pPropBag->Write( wszParam, &var ); #ifdef DEBUG if( FAILED( hr ) ) { DbgLog((LOG_TRACE, 3, TEXT("CWrapperOutputPin::SetCompressionParamUsingIPropBag - DMO supports IPropertyBag but not %ls setting"), wszParam ) ); } #endif } return hr; } bool CWrapperOutputPin::IsAudioEncoder() { if(Filter()->m_guidCat == DMOCATEGORY_AUDIO_ENCODER) return true; else return false; } bool CWrapperOutputPin::IsVideoEncoder() { if(Filter()->m_guidCat == DMOCATEGORY_VIDEO_ENCODER) return true; else return false; } bool CWrapperOutputPin::IsInputConnected() { for (DWORD cIn = 0; cIn < Filter()->m_cInputPins; cIn++) { if (Filter()->InputMapsToOutput(cIn, m_Id) && !(Filter()->m_pInputPins[cIn]->IsConnected())) { // some input not connected return false; } } return true; }