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

/*
Copyright (c) 1998-1999 Microsoft Corporation
*/
#include "stdafx.h"
#include "atlconv.h"
#include "termmgr.h"
#include "meterf.h"
#include "newmes.h"
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// These will be obsolete when we derive from CSingleFilterTerminal
HRESULT CMediaTerminal::GetNumExposedPins(
IN IGraphBuilder * pGraph,
OUT DWORD * pdwNumPins)
{
LOG((MSP_TRACE, "CMediaTerminal::GetNumExposedPins - enter"));
//
// We ignote pGraph because we don't need to do anything special to find
// out how many pins we have.
//
*pdwNumPins = 1;
LOG((MSP_TRACE, "CMediaTerminal::GetNumExposedPins - exit S_OK"));
return S_OK;
}
HRESULT CMediaTerminal::GetExposedPins(
OUT IPin ** ppPins
)
{
LOG((MSP_TRACE, "CMediaTerminal::GetExposedPins - enter"));
TM_ASSERT( ! TM_IsBadWritePtr(ppPins, 1 * sizeof(IPin *) ) );
//
// Return our single pin.
//
*ppPins = m_pOwnPin;
(*ppPins)->AddRef();
LOG((MSP_TRACE, "CMediaTerminal::GetExposedPins - exit S_OK"));
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// for CLSID_MediaStreamFilter
// "amguids.h" has the guid value
// but requires #define INITGUID before including compobj.h
EXTERN_C const GUID CLSID_MediaStreamFilter = {
0x49c47ce0,
0x9ba4,
0x11d0,
{0x82, 0x12, 0x00, 0xc0, 0x4f, 0xc3, 0x2c, 0x45}
};
// this is used for indexing into the friendly name array
// it is needed because neither the tapi media type (string guid) nor
// the IMediaStream media consts (not an enum) can be used
enum MEDIA_STREAM_TERMINAL_MEDIA
{
MEDIA_STREAM_TERMINAL_AUDIO=0,
MEDIA_STREAM_TERMINAL_VIDEO
};
// the MEDIA_STREAM_TERMINAL_MEDIA and TERMINAL_DIRECTION values are used as
// indices into this array to determine the friendly name
// these should ideally be const WCHAR *, but the base class member m_szName is
// a pointer to BSTR (should be const WCHAR * as per current usage)
DWORD gs_MSTFriendlyName[2][2] =
{
{
IDS_MSTR_AUDIO_WRITE, // capture
IDS_MSTR_AUDIO_READ, // render
},
{
IDS_MSTR_VIDEO_WRITE, // capture
IDS_MSTR_VIDEO_READ, // render
}
};
// CMediaTerminal
STDMETHODIMP CMediaTerminal::InitializeDynamic (
IN IID iidTerminalClass,
IN DWORD dwMediaType,
IN TERMINAL_DIRECTION Direction,
IN MSP_HANDLE htAddress
)
{
LOG((MSP_TRACE, "CMediaTerminal::Initialize - enter"));
//
// We are OK with either direction. Just do the base class method...
//
HRESULT hr;
hr = CBaseTerminal::Initialize(iidTerminalClass,
dwMediaType,
Direction,
htAddress);
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "CVideoRenderTerminal::Initialize - "
"base class method failed - returning 0x%08x", hr));
return hr;
}
//
// Now do our own initialization:
//
// sets certain member variables
// ex. m_TerminalType, m_szName
// initialize the aggregated filter
//
MSPID PurposeId;
STREAM_TYPE StreamType;
const GUID *pAmovieMajorType;
// uses pTapiMediaType, TerminalDirection to determine the
// purpose id and stream type.
// sets PurposeId, StreamType, pAmovieMajorType among others
hr = SetNameInfo(
(long) dwMediaType,
Direction,
PurposeId,
StreamType,
pAmovieMajorType
);
BAIL_ON_FAILURE(hr);
ASSERT(NULL != pAmovieMajorType);
// initialize the aggregated filter
ASSERT(NULL != m_pAggTerminalFilter);
hr = m_pAggTerminalFilter->Init(PurposeId, StreamType, *pAmovieMajorType);
BAIL_ON_FAILURE(hr);
LOG((MSP_TRACE, "CMediaTerminal::Initialize - exit S_OK"));
return S_OK;
}
// free the allocated member variables
HRESULT
CMediaTerminal::FinalConstruct(
)
{
LOG((MSP_TRACE, "CMediaTerminal::FinalConstruct called"));
HRESULT hr;
m_pAggInstance = new FILTER_COM_OBJECT(GetControllingUnknown());
BAIL_IF_NULL(m_pAggInstance, E_OUTOFMEMORY);
hr = m_pAggInstance->FinalConstruct();
if (HRESULT_FAILURE(hr))
{
// delete the aggregating instance
delete m_pAggInstance;
return hr;
}
// we get the nondelegating IUnknown i/f of the aggregating shell
// around the contained object. keep this refcnt around during our
// lifetime
hr = m_pAggInstance->QueryInterface(
IID_IUnknown,
(void **)&m_pIUnkTerminalFilter
);
if ( FAILED(hr) )
{
// must call final release
m_pAggInstance->FinalRelease();
// delete the aggregating instance
delete m_pAggInstance;
return hr;
}
// these query interface calls increase our own refcnt
// release the refcnt as soon as the interface is obtained
// these shouldn't be CComPtrs as they are weak references
hr = m_pAggInstance->QueryInterface(
IID_IPin,
(void **)&m_pOwnPin
);
if ( FAILED(hr) )
{
goto error;
}
if (NULL != m_pOwnPin)
{
m_pOwnPin->Release();
}
hr = m_pAggInstance->QueryInterface(
IID_IAMMediaStream,
(void **)&m_pIAMMediaStream
);
if ( FAILED(hr) )
{
goto error;
}
if (NULL != m_pIAMMediaStream)
{
m_pIAMMediaStream->Release();
}
// point m_pAggTerminalFilter to the contained member of the
// aggregating instance
m_pAggTerminalFilter = &m_pAggInstance->m_contained;
LOG((MSP_TRACE, "CMediaTerminal::FinalConstruct succeeded"));
return S_OK;
error: // we come here in case of errors after calling FinalConstruct
ASSERT( FAILED(hr) );
// final release the aggregating shell
ASSERT(NULL != m_pAggInstance);
m_pAggInstance->FinalRelease();
// null any CComPtrs
// this should destroy the aggregated instance and the contained
// media terminal filter
m_pIUnkTerminalFilter = NULL;
LOG((MSP_TRACE, "CMediaTerminal::FinalConstruct failed"));
return hr;
}
void
CMediaTerminal::FinalRelease(
)
{
LOG((MSP_TRACE, "CMediaTerminal::FinalRelease called"));
// final release the aggregating shell
ASSERT(NULL != m_pAggInstance);
m_pAggInstance->FinalRelease();
// null any CComPtrs
// this should destroy the aggregating instance and the contained
// media terminal filter
m_pIUnkTerminalFilter = NULL;
LOG((MSP_TRACE, "CMediaTerminal::FinalRelease succeeded"));
}
// we only have a destructor with debug bits
#ifdef DEBUG
// free the allocated member variables
// virtual
CMediaTerminal::~CMediaTerminal(
)
{
LOG((MSP_TRACE, "CMediaTerminal::~CMediaTerminal called"));
}
#endif // DEBUG
// point to the m_ppTapiMediaType,
// copies friendly name into m_szName
void
CMediaTerminal::SetMemberInfo(
IN DWORD dwFriendlyName,
IN long lMediaType
)
{
LOG((MSP_TRACE, "CMediaTerminal::SetMemberInfo(%d, &(%l)) called", \
dwFriendlyName,lMediaType));
// copy the friendly terminal name into the member name
// the max number of TCHARs to copy is MAX_PATH+1 (it includes
// the terminating NULL character)
TCHAR szTemp[MAX_PATH];
if (::LoadString(_Module.GetResourceInstance(), dwFriendlyName, szTemp, MAX_PATH))
{
lstrcpyn(m_szName, szTemp, MAX_PATH);
}
else
{
LOG((MSP_ERROR, "CMediaTerminal::SetMemberInfo (LoadString) failed"));
}
m_lMediaType = lMediaType;
LOG((MSP_TRACE, "CMediaTerminal::SetMemberInfo(%d, &(%d)) succeeded", \
dwFriendlyName,lMediaType));
};
// uses the purpose id and the stream type to figure out the name
// and terminal class id.
// sets PurposeId, StreamType, m_szName, m_TerminalClassID
// m_ppTapiMediaType, m_TerminalType, m_TerminalDirection
HRESULT
CMediaTerminal::SetNameInfo(
IN long lMediaType,
IN TERMINAL_DIRECTION TerminalDirection,
OUT MSPID &PurposeId,
OUT STREAM_TYPE &StreamType,
OUT const GUID *&pAmovieMajorType
)
{
LOG((MSP_TRACE, "CMediaTerminal::SetNameInfo(%d, %u, %p, %p, %p) called", \
lMediaType, TerminalDirection, &PurposeId, &StreamType, pAmovieMajorType));
//
// Check arguments
//
if ( ( TerminalDirection != TD_CAPTURE ) &&
( TerminalDirection != TD_RENDER ) )
{
return E_INVALIDARG;
}
// set the stream type
// if its a capture terminal, the user has to write the samples
StreamType = (TD_CAPTURE == TerminalDirection)? STREAMTYPE_WRITE : STREAMTYPE_READ;
if (lMediaType == TAPIMEDIATYPE_AUDIO)
{
// set the PurposeId, major media type
PurposeId = MSPID_PrimaryAudio;
pAmovieMajorType = &MEDIATYPE_Audio;
// copy the name and point to the tapi media type
SetMemberInfo(
gs_MSTFriendlyName[MEDIA_STREAM_TERMINAL_AUDIO][TerminalDirection],
TAPIMEDIATYPE_AUDIO
);
}
else if (lMediaType == TAPIMEDIATYPE_VIDEO)
{
// set the PurposeId, major media type
PurposeId = MSPID_PrimaryVideo;
pAmovieMajorType = &MEDIATYPE_Video;
// copy the name and point to the tapi media type
SetMemberInfo(
gs_MSTFriendlyName[MEDIA_STREAM_TERMINAL_VIDEO][TerminalDirection],
TAPIMEDIATYPE_VIDEO
);
}
else
{
return E_INVALIDARG;
}
// its a dynamic terminal
m_TerminalType = TT_DYNAMIC;
LOG((MSP_TRACE, "CMediaTerminal::SetNameInfo[%p] (%u, %u, %p, %p, %p) succeeded", \
this, lMediaType, TerminalDirection, &PurposeId, &StreamType, pAmovieMajorType));
return S_OK;
}
// implement using the aggregated filter's public GetFormat method
STDMETHODIMP
CMediaTerminal::GetFormat(
OUT AM_MEDIA_TYPE **ppmt
)
{
CLock lock(m_CritSec);
LOG((MSP_TRACE, "CMediaTerminal::GetFormat(%p) called", ppmt));
return m_pAggTerminalFilter->GetFormat(ppmt);
}
// implement using the aggregated filter's public SetFormat method
STDMETHODIMP
CMediaTerminal::SetFormat(
IN AM_MEDIA_TYPE *pmt
)
{
CLock lock(m_CritSec);
LOG((MSP_TRACE, "CMediaTerminal::SetFormat(%p) called", pmt));
return m_pAggTerminalFilter->SetFormat(pmt);
}
// an IAMBufferNegotiation method - passed to our filter
STDMETHODIMP
CMediaTerminal::GetAllocatorProperties(
OUT ALLOCATOR_PROPERTIES *pProperties
)
{
CLock lock(m_CritSec);
LOG((MSP_TRACE, "CMediaTerminal::GetAllocatorProperties(%p) called", pProperties));
return m_pAggTerminalFilter->GetAllocatorProperties(pProperties);
}
// an IAMBufferNegotiation method - used to be not implemented
// but now we must return S_OK to work with IP
STDMETHODIMP
CMediaTerminal::SuggestAllocatorProperties(
IN const ALLOCATOR_PROPERTIES *pProperties
)
{
CLock lock(m_CritSec);
LOG((MSP_TRACE, "CMediaTerminal::SuggestAllocatorProperties - enter"));
HRESULT hr = m_pAggTerminalFilter->SuggestAllocatorProperties(pProperties);
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "CMediaTerminal::SuggestAllocatorProperties - "
"method on filter failed - exit 0x%08x", hr));
return hr;
}
LOG((MSP_TRACE, "CMediaTerminal::SuggestAllocatorProperties - exit S_OK"));
return S_OK;
}
// since there is only one filter in this base class implementation (i.e. the two
// ends of the terminal have the same media format), both of
// the get and set methods are redirected to Get/Set Format
STDMETHODIMP
CMediaTerminal::get_MediaFormat(
OUT AM_MEDIA_TYPE **ppFormat
)
{
CLock lock(m_CritSec);
LOG((MSP_TRACE, "CMediaTerminal::get_MediaFormat(%p) called", ppFormat));
return GetFormat(ppFormat);
}
// cast the input format to a non-const as we know that we won't change the struct
// in SetFormat (this problem exists because IAMStreamConfig::SetFormat expects a
// non-const). this saves creating, copying and then destroying a struct for this call
STDMETHODIMP
CMediaTerminal::put_MediaFormat(
IN const AM_MEDIA_TYPE *pFormat
)
{
CLock lock(m_CritSec);
LOG((MSP_TRACE, "CMediaTerminal::put_MediaFormat(%p) called", pFormat));
return SetFormat((AM_MEDIA_TYPE *)pFormat);
}
HRESULT
CMediaTerminal::CreateAndJoinMediaStreamFilter(
)
{
LOG((MSP_TRACE, "CMediaTerminal::CreateAndJoinMediaStreamFilter called"));
ASSERT(m_pICreatedMediaStreamFilter == NULL);
// in case of an error at any stage, no clean-up of member variables
// or filter logic (JoinFilter(NULL) etc.) needs to be done as the
// driving CBaseTerminal::ConnectTerminal would call DisconnectTerminal
// which performs that work
// create the media stream filter
HRESULT hr;
hr = CoCreateInstance(
CLSID_MediaStreamFilter,
NULL,
CLSCTX_INPROC_SERVER,
IID_IMediaStreamFilter,
(void **)&m_pICreatedMediaStreamFilter
);
BAIL_ON_FAILURE(hr);
hr = m_pICreatedMediaStreamFilter->QueryInterface(
IID_IBaseFilter, (void **)&m_pBaseFilter
);
BAIL_ON_FAILURE(hr);
// tell the aggregated filter of our media stream filter, so that
// it can reject any other media stream filter if proposed
m_pAggTerminalFilter->SetMediaStreamFilter(m_pICreatedMediaStreamFilter);
// add the IAMMediaStream i/f of the aggregated terminal filter
// to the media stream filter
hr = m_pICreatedMediaStreamFilter->AddMediaStream(m_pIAMMediaStream);
BAIL_ON_FAILURE(hr);
LOG((MSP_TRACE, "CMediaTerminal::CreateAndJoinMediaStreamFilter succeeded"));
return S_OK;
}
// if m_pFilter is null, return error
// add m_pFilter to graph
HRESULT
CMediaTerminal::AddFiltersToGraph(
)
{
LOG((MSP_TRACE, "CMediaTerminal::AddFiltersToGraph called"));
HRESULT hr;
hr = CreateAndJoinMediaStreamFilter();
BAIL_ON_FAILURE(hr);
ASSERT(m_pGraph != NULL);
BAIL_IF_NULL(m_pBaseFilter, MS_E_NOTINIT);
try
{
USES_CONVERSION;
hr = m_pGraph->AddFilter(m_pBaseFilter, T2CW(m_szName));
}
catch (...)
{
LOG((MSP_ERROR, "CMediaTerminal::AddFiltersToGraph - T2CW threw an exception - "
"return E_OUTOFMEMORY"));
return E_OUTOFMEMORY;
}
if ( ( hr != S_OK ) && ( VFW_S_DUPLICATE_NAME != hr ) )
{
return hr;
}
LOG((MSP_TRACE, "CMediaTerminal::AddFiltersToGraph succeeded"));
return S_OK;
}
// if m_pFilter is null, return success
// remove m_pFilter from graph
HRESULT
CMediaTerminal::RemoveFiltersFromGraph(
)
{
LOG((MSP_TRACE, "CMediaTerminal::RemoveFiltersFromGraph called"));
// the base filter is set when CreateAndJoinMediaStreamFilter succeeds
// in it, the media stream filter is created and the IAMMediaStream
// interface is added to the filter. During addition, the media stream filter
// calls JoinFilter on the IAMMediaStream and thus sets the m_pBaseFilter
HRESULT hr = S_OK;
if ((m_pGraph != NULL) && (m_pBaseFilter != NULL))
{
hr = m_pGraph->RemoveFilter(m_pBaseFilter);
}
// inform the aggregate media terminal filter that we don't have a
// media stream filter any longer
m_pAggTerminalFilter->SetMediaStreamFilter(NULL);
// remove associated properties of the media stream filter
m_pIAMMediaStream->JoinFilter(NULL);
m_pIAMMediaStream->JoinFilterGraph(NULL);
// null m_pBaseFilter and m_pICreatedMediaStreamFilter
// which hold the last reference to the filter
m_pBaseFilter = NULL;
m_pICreatedMediaStreamFilter = NULL;
return hr;
}
// eof