windows-nt/Source/XPSP1/NT/multimedia/dshow/dmo/wrapper/outpin.cpp

880 lines
27 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
#include <wchar.h>
#include <streams.h>
#include <atlbase.h>
#include <wmsecure.h>
#include <dmoreg.h>
#include <mediaerr.h>
#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<IAMStreamConfig *> (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<IAMVideoCompression *> (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;
}