|
|
/*++
Copyright (C) Microsoft Corporation, 1996 - 1999
Module Name:
render.cpp
Abstract:
Implementation of CRtpRenderFilter class.
Environment:
User Mode - Win32
Revision History:
06-Nov-1996 DonRyan Created.
--*/ ///////////////////////////////////////////////////////////////////////////////
// //
// Include files //
// //
///////////////////////////////////////////////////////////////////////////////
#include "globals.h"
///////////////////////////////////////////////////////////////////////////////
// //
// CRtpRenderFilter methods //
// //
///////////////////////////////////////////////////////////////////////////////
CRtpRenderFilter::CRtpRenderFilter( LPUNKNOWN pUnk, HRESULT * phr // MUST be a valid pointer
)
/*++
Routine Description:
Constructor for CRtpRenderFilter class.
Arguments:
pUnk - IUnknown interface of the delegating object.
phr - pointer to the general OLE return value.
Return Values:
Returns an HRESULT value.
--*/
: CBaseFilter( NAME("CRtpRenderFilter"), pUnk, &m_cStateLock, CLSID_RTPRenderFilter, phr // No point passing this, base class doesn't even touch it
), CPersistStream(pUnk, phr), m_iPins(0), m_paStreams(NULL) { TraceDebug(( TRACE_TRACE, TRACE_DEVELOP, TEXT("[%x:0x%X]CRtpRenderFilter::CRtpRenderFilter]"), GetCurrentThreadId(), this ));
WSADATA WSAData; WORD VersionRequested = MAKEWORD(2,0); // initialize winsock first
if (WSAStartup(VersionRequested, &WSAData)) {
TraceDebug(( TRACE_ERROR, TRACE_DEVELOP, TEXT("WSAStartup returned %d"), WSAGetLastError() ));
*phr = E_FAIL; return; // bail...
}
// create default input pin object
CRtpInputPin * pPin = new CRtpInputPin( this, GetOwner(), phr );
if (FAILED(*phr)) { TraceDebug(( TRACE_ERROR, TRACE_DEVELOP, TEXT("CRtpRenderFilter::CRtpRenderFilter: " "new CRtpInputPin() failed: 0x%X"), *phr )); return; }
// validate pointer
if (pPin == NULL) {
TraceDebug(( TRACE_ERROR, TRACE_DEVELOP, TEXT("Could not create CRtpInputPin") ));
// return default
*phr = E_OUTOFMEMORY;
return; // bail...
}
ASSERT(m_paStreams != NULL);
//
// pins add themselves to filters's array...
//
}
CRtpRenderFilter::~CRtpRenderFilter( )
/*++
Routine Description:
Destructor for CRtpRenderFilter class.
Arguments:
None.
Return Values:
None.
--*/
{ TraceDebug(( TRACE_TRACE, TRACE_DEVELOP, TEXT("[%x:0x%X]CRtpRenderFilter::~CRtpRenderFilter"), GetCurrentThreadId(), this ));
// rally thru pins
while (m_iPins != 0) {
// nuke each pin in array
delete m_paStreams[m_iPins - 1]; }
// shutdown now
if (WSACleanup()) {
TraceDebug(( TRACE_ERROR, TRACE_DEVELOP, TEXT("WSACleanup returned %d"), WSAGetLastError() )); }
ASSERT(m_paStreams == NULL);
//
// pins delete themselves from filter's array
//
}
CUnknown * CRtpRenderFilter::CreateInstance( LPUNKNOWN punk, HRESULT * phr )
/*++
Routine Description:
Called by COM to create a CRtpRenderFilter object.
Arguments:
pUnk - pointer to the owner of this object.
phr - pointer to an HRESULT value for resulting information.
Return Values:
None.
--*/
{ TraceDebug(( TRACE_TRACE, TRACE_ALWAYS, TEXT("CRtpRenderFilter::CreateInstance") ));
// attempt to create rtp sender object
CRtpRenderFilter * pNewObject = new CRtpRenderFilter(punk, phr);
// validate pointer
if (pNewObject == NULL) {
TraceDebug(( TRACE_ERROR, TRACE_DEVELOP, TEXT("Could not create CRtpRenderFilter") ));
// return default
*phr = E_OUTOFMEMORY; }
// return object
return pNewObject; }
HRESULT CRtpRenderFilter::AddPin( CRtpInputPin * pPin )
/*++
Routine Description:
Adds a pin to the network sink filter.
Arguments:
pPin - input pin to be added to the filter.
Return Values:
Returns an HRESULT value.
--*/
{ TraceDebug(( TRACE_TRACE, TRACE_ALWAYS, TEXT("CRtpRenderFilter::AddPin") ));
// object lock on this object
CAutoLock LockThis(&m_cStateLock);
// allocate temporary array to hold the stream pointers
CRtpInputPin ** paStreams = new CRtpInputPin *[m_iPins + 1];
// validate pointer
if (paStreams == NULL) {
TraceDebug(( TRACE_ERROR, TRACE_DEVELOP, TEXT("Could not create CRtpInputPin array") ));
return E_OUTOFMEMORY; // bail...
}
// see if array exists
if (m_paStreams != NULL) {
// transfer existing pointers
CopyMemory( (PVOID)paStreams, (PVOID)m_paStreams, m_iPins * sizeof(m_paStreams[0]) );
// nuke old array
delete [] m_paStreams; }
// save new array pointer
m_paStreams = paStreams;
// add new pin to array
m_paStreams[m_iPins] = pPin;
// add
m_iPins++;
return S_OK; }
HRESULT CRtpRenderFilter::RemovePin( CRtpInputPin * pPin )
/*++
Routine Description:
Removes a pin from the network sink filter.
Arguments:
pPin - input pin to be removed from the filter.
Return Values:
Returns an HRESULT value.
--*/
{ TraceDebug(( TRACE_TRACE, TRACE_ALWAYS, TEXT("CRtpRenderFilter::RemovePin") ));
// object lock on this object
CAutoLock LockThis(&m_cStateLock);
int i;
// process each pin
for (i = 0; i < m_iPins; i++) {
// see if this is the one
if (m_paStreams[i] == pPin) {
// single pin?
if (m_iPins == 1) { // need to nuke array
delete [] m_paStreams;
// re-initialize
m_paStreams = NULL;
} else { // adjust rest of pins
while (++i < m_iPins) {
// slide pointers over one slot
m_paStreams[i - 1] = m_paStreams[i]; } } // delete
m_iPins--;
return S_OK; } }
return S_FALSE; }
///////////////////////////////////////////////////////////////////////////////
// //
// CBaseFilter overrided methods //
// //
///////////////////////////////////////////////////////////////////////////////
CBasePin * CRtpRenderFilter::GetPin( int n )
/*++
Routine Description:
Obtains specific CBasePin object associated with filter.
Arguments:
n - number of the specified pin.
Return Values:
Returns pointer to specified pin.
--*/
{ TraceDebug(( TRACE_TRACE, TRACE_ALWAYS, TEXT("CRtpRenderFilter::GetPin %d"), n ));
// object lock on filter object
CAutoLock LockThis(&m_cStateLock);
// validate index passed in
if ((n >= 0) && (n < m_iPins)) {
ASSERT(m_paStreams[n]);
// return input pin
return m_paStreams[n]; } return NULL; }
int CRtpRenderFilter::GetPinCount( )
/*++
Routine Description:
Obtains number of pins supported by filter.
Arguments:
None.
Return Values:
Returns the number of supported pins.
--*/
{ TraceDebug(( TRACE_TRACE, TRACE_ALWAYS, TEXT("CRtpRenderFilter::GetPinCount") ));
// object lock on filter object
CAutoLock LockThis(&m_cStateLock);
// return count
return m_iPins; }
LPAMOVIESETUP_FILTER CRtpRenderFilter::GetSetupData( )
/*++
Routine Description:
Called by ActiveMovie to retrieve filter setup information.
Arguments:
None.
Return Values:
Returns pointer to filter info structure.
--*/
{ TraceDebug(( TRACE_TRACE, TRACE_ALWAYS, TEXT("CRtpRenderFilter::GetSetupData") ));
// get sink filter info
return &g_RtpRenderFilter; }
///////////////////////////////////////////////////////////////////////////////
// //
// IBaseFilter implemented methods //
// //
///////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CRtpRenderFilter::QueryVendorInfo( LPWSTR * ppVendorInfo )
/*++
Routine Description:
Returns a vendor information string.
Arguments:
ppVendorInfo - Pointer to a string containing vendor information.
Return Values:
Returns an HRESULT value.
--*/
{ TraceDebug(( TRACE_TRACE, TRACE_ALWAYS, TEXT("CRtpRenderFilter::QueryVendorInfo") ));
// validate pointer
CheckPointer(ppVendorInfo,E_POINTER);
// allocate the description string
*ppVendorInfo = (LPWSTR)CoTaskMemAlloc( (lstrlenW(g_VendorInfo)+1) * sizeof(WCHAR) );
// validate pointer
if (*ppVendorInfo == NULL) { TraceDebug(( TRACE_ERROR, TRACE_ALWAYS, TEXT("Could not allocate vendor info") ));
return E_OUTOFMEMORY; // bail...
} // copy vendor description string
lstrcpyW(*ppVendorInfo,g_VendorInfo);
return S_OK; }
//-----------------------------------------------------------------------//
// IAMFilterMiscFlags implemented methods //
//-----------------------------------------------------------------------//
/*++
Routine Description:
Implement the IAMFilterMiscFlags::GetMiscFlags method. Retrieves the miscelaneous flags. This consists of whether or not the filter moves data out of the graph system through a Bridge or None pin.
Arguments:
None. --*/
STDMETHODIMP_(ULONG) CRtpRenderFilter::GetMiscFlags(void) { return(AM_FILTER_MISC_FLAGS_IS_RENDERER); }
///////////////////////////////////////////////////////////////////////////////
// //
// IPersistStream implemented methods //
// //
///////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CRtpRenderFilter::GetClassID( CLSID *pClsid )
/*++
Routine Description:
Retrieves the class identifier for this filter.
Arguments:
pClsid - Pointer to a CLSID structure.
Return Values:
Returns an HRESULT value.
--*/
{ TraceDebug(( TRACE_TRACE, TRACE_ALWAYS, TEXT("CRtpRenderFilter::GetClassID") ));
// transfer filter class id
*pClsid = CLSID_RTPRenderFilter;
return S_OK; }
// ZCS: 6-22-97: copied this from the Demux filter code and modified it...
//
// Name : WriteEntry
// Purpose : A macro that implements the stuff we do to write
// a property of this filter to its persistent stream.
// Context : Used in WriteToStream() to improve readability.
// Returns : Will only return if an error is detected.
// Params :
// Entry Pointer to a buffer containing the value to write.
// InSize Integer indicating the length of the buffer
// OutSize Integer to store the written length.
// Description Char string used to describe the entry.
// Notes :
#define WriteEntry(Entry, InSize, OutSize, Description) \
{ TraceDebug((TRACE_TRACE, 4, TEXT("CRtpRenderFilter::WriteToStream: Writing %s"), Description)); \ hr = pStream->Write(Entry, InSize, &OutSize); \ if (FAILED(hr)) { \ TraceDebug((TRACE_ERROR, 2, TEXT("CRtpRenderFilter::WriteToStream: Error 0x%08x writing %s"), hr, Description)); \ return hr; \ } else if (OutSize != InSize) { \ TraceDebug((TRACE_ERROR, 2, \ TEXT("CRtpRenderFilter::WriteToStream: Too few (%d/%d) bytes written for %s"), \ uBytesWritten, sizeof(int), Description)); \ return E_INVALIDARG; \ } /* if */ }
HRESULT CRtpRenderFilter::WriteToStream( IStream *pStream )
/*++
Routine Description:
Writes the filter's data to the given stream.
Arguments:
pStream - Pointer to an IStream to write the filter's data to.
Return Values:
Returns an HRESULT value.
--*/
{ TraceDebug(( TRACE_TRACE, TRACE_ALWAYS, TEXT("CRtpRenderFilter::WriteToStream") ));
// validate pointer
CheckPointer(pStream,E_POINTER);
// obtain lock to this object
CAutoLock LockThis(&m_cStateLock);
//
// Rest of this function added 6-22-97 by ZCS
//
HRESULT hr; // used in the WriteEntry macro
ULONG uBytesWritten = 0; DWORD dwRtpAddr; WORD wRtpPort; DWORD dwMulticastScope; DWORD dwQOSstate; DWORD dwMCLoopBack;
// get the RTP session object so we can see the address, port, scope
CRtpSession *pCRtpSession; ASSERT(m_iPins == 1); EXECUTE_ASSERT(SUCCEEDED((**m_paStreams).GetSession(&pCRtpSession)));
// retrieve the address of the rtp stream object
// for a sender, remote port matters
EXECUTE_ASSERT(SUCCEEDED(pCRtpSession->GetAddress(NULL, &wRtpPort, &dwRtpAddr))); // retrieve multicast scope of rtp stream object
EXECUTE_ASSERT(SUCCEEDED(pCRtpSession->GetMulticastScope(&dwMulticastScope))); // retrieve QOS state of rtp stream object
EXECUTE_ASSERT(SUCCEEDED(pCRtpSession->GetQOSstate(&dwQOSstate)));
// retrieve Multicast Loopback state of rtp stream object
EXECUTE_ASSERT(SUCCEEDED(pCRtpSession->GetMulticastLoopBack(&dwMCLoopBack)));
// write RTP address/port and multicast to the PersistStream
WriteEntry(&dwRtpAddr, sizeof(dwRtpAddr), uBytesWritten, "RTP address"); WriteEntry(&wRtpPort, sizeof(wRtpPort), uBytesWritten, "RTP port"); WriteEntry(&dwMulticastScope, sizeof(dwMulticastScope), uBytesWritten, "multicast scope"); WriteEntry(&dwQOSstate, sizeof(dwQOSstate), uBytesWritten, "QOS state"); WriteEntry(&dwMCLoopBack, sizeof(dwMCLoopBack), uBytesWritten, "Multicast Loopback state");
return S_OK; }
// ZCS: 6-22-97: copied this from the Demux filter code and modified it...
//
// Name : ReadEntry
// Purpose : A macro that implements the stuff we do to read
// a property of this filter from its persistent stream.
// Context : Used in ReadFromStream() to improve readability.
// Returns : Will only return if an error is detected.
// Params :
// Entry Pointer to a buffer containing the value to read.
// InSize Integer indicating the length of the buffer
// OutSize Integer to store the written length.
// Description Char string used to describe the entry.
// Notes :
#define ReadEntry(Entry, InSize, OutSize, Description) \
{ TraceDebug((TRACE_TRACE, 4, TEXT("CRtpRenderFilter::ReadFromStream: Reading %s"), Description)); \ hr = pStream->Read(Entry, InSize, &OutSize); \ if (FAILED(hr)) { \ TraceDebug((TRACE_ERROR, 2, TEXT("CRtpRenderFilter::ReadFromStream: Error 0x%08x reading %s"), hr, Description)); \ return hr; \ } else if (OutSize != InSize) { \ TraceDebug((TRACE_ERROR, 2, \ TEXT("CRtpRenderFilter::ReadFromStream: Too few (%d/%d) bytes read for %s"), \ OutSize, InSize, Description)); \ return E_INVALIDARG; \ } /* if */ }
HRESULT CRtpRenderFilter::ReadFromStream( IStream *pStream )
/*++
Routine Description:
Reads the filter's data from the given stream.
Arguments:
pStream - Pointer to an IStream to read the filter's data from.
Return Values:
Returns an HRESULT value.
--*/
{ TraceDebug(( TRACE_TRACE, TRACE_ALWAYS, TEXT("CRtpRenderFilter::ReadFromStream") ));
// validate pointer
CheckPointer(pStream,E_POINTER);
// obtain lock to this object
CAutoLock LockThis(&m_cStateLock);
//
// Rest of this function added 6-22-97 by ZCS based mostly on
// Don Ryan's property page code...
//
HRESULT hr; ULONG uBytesWritten = 0; DWORD dwRtpAddr; WORD wRtpPort; DWORD RtpScope; DWORD QOSstate; DWORD MCLoopBack;
// get the RTP session object so we can see the address, port, scope
CRtpSession *pCRtpSession = NULL; ASSERT(m_iPins == 1); EXECUTE_ASSERT(SUCCEEDED((**m_paStreams).GetSession(&pCRtpSession))); ASSERT(!IsBadReadPtr(pCRtpSession, sizeof(pCRtpSession)));
// retrieve RTP address and port from stream
ReadEntry(&dwRtpAddr, sizeof(dwRtpAddr), uBytesWritten, "RTP address"); ReadEntry(&wRtpPort, sizeof(wRtpPort), uBytesWritten, "RTP port");
// attempt to modify the rtp address
// in unicast, the local port is what matters for a receiver
// in multicast, they have to be the same, SetAddress takes care
hr = pCRtpSession->SetAddress(wRtpPort, wRtpPort, dwRtpAddr);
// validate
if (FAILED(hr)) { TraceDebug(( TRACE_ERROR, TRACE_ALWAYS, TEXT("IRTPStream::SetAddress returns 0x%08lx"), hr ));
return hr; // bail...
}
// retrieve multicast scope from stream
ReadEntry(&RtpScope, sizeof(RtpScope), uBytesWritten, "multicast scope");
// attempt to modify the scope
hr = pCRtpSession->SetMulticastScope(RtpScope);
// validate
if (FAILED(hr)) { TraceDebug(( TRACE_ERROR, TRACE_ALWAYS, TEXT("IRTPStream::SetScope returns 0x%08lx"), hr ));
return hr; // bail...
}
// retrieve QOS state from stream
ReadEntry(&QOSstate, sizeof(QOSstate), uBytesWritten, "QOS state");
// attempt to modify the QOS state
hr = pCRtpSession->SetQOSstate(QOSstate);
// validate
if (FAILED(hr)) { TraceDebug(( TRACE_ERROR, TRACE_ALWAYS, TEXT("IRTPStream::SetQOSstate returns 0x%08lx"), hr ));
return hr; // bail...
}
// retrieve Multicast Loopback state from stream
ReadEntry(&MCLoopBack, sizeof(MCLoopBack), uBytesWritten, "Multicast Loopback state");
// attempt to modify the Multicast Loopback state
MCLoopBack = (MCLoopBack)? TRUE:FALSE; hr = pCRtpSession->SetMulticastLoopBack(MCLoopBack);
// validate
if (FAILED(hr)) { TraceDebug(( TRACE_ERROR, TRACE_ALWAYS, TEXT("IRTPStream::SetMulticastLoopBack returns 0x%08lx"), hr ));
return hr; // bail...
} return S_OK; }
int CRtpRenderFilter::SizeMax( )
/*++
Routine Description:
Returns an interface and increments the reference count.
Arguments:
riid - reference identifier.
ppv - pointer to the interface.
Return Values:
Returns a pointer to the interface.
--*/
{ TraceDebug(( TRACE_TRACE, TRACE_ALWAYS, TEXT("CRtpRenderFilter::SizeMax") ));
// object lock on this object
CAutoLock LockThis(&m_cStateLock);
//
// CODEWORK...
//
return S_OK; }
///////////////////////////////////////////////////////////////////////////////
// //
// ISpecifyPropertyPages implemented methods //
// //
///////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CRtpRenderFilter::GetPages( CAUUID * pPages )
/*++
Routine Description:
Returns property class id associated with filter.
Arguments:
pPages - pointer to received property page class id.
Return Values:
Returns an HRESULT value.
--*/
{ TraceDebug(( TRACE_TRACE, TRACE_ALWAYS, TEXT("CRtpRenderFilter::GetPages") ));
// object lock on this object
CAutoLock LockThis(&m_cStateLock);
// number of pages
pPages->cElems = 1; // allocate space to place property page guid
pPages->pElems = (GUID *)CoTaskMemAlloc(sizeof(GUID));
// validate pointer
if (pPages->pElems == NULL) {
TraceDebug(( TRACE_ERROR, TRACE_ALWAYS, TEXT("Could not allocate property page guid") ));
return E_OUTOFMEMORY; } // transfer property page guid to caller
*(pPages->pElems) = CLSID_RTPRenderFilterProperties;
return S_OK; }
///////////////////////////////////////////////////////////////////////////////
// //
// INonDelegatingUnknown implemented methods //
// //
///////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CRtpRenderFilter::NonDelegatingQueryInterface( REFIID riid, void ** ppv )
/*++
Routine Description:
Returns an interface and increments the reference count.
Arguments:
riid - reference identifier.
ppv - pointer to the interface.
Return Values:
Returns a pointer to the interface.
--*/
{ #ifdef DEBUG_CRITICAL_PATH
TraceDebug(( TRACE_TRACE, TRACE_CRITICAL, TEXT("CRtpRenderFilter::NonDelegatingQueryInterface") ));
#endif // DEBUG_CRITICAL_PATH
// validate pointer
CheckPointer(ppv,E_POINTER);
// obtain proper interface
if (riid == IID_IPersistStream) { // return pointer to this object
return GetInterface((IPersistStream *)this, ppv);
} else if (riid == IID_ISpecifyPropertyPages) { // return pointer to this object
return GetInterface((ISpecifyPropertyPages *)this, ppv);
} else if ((riid == IID_IBaseFilter) || (riid == IID_IMediaFilter)) {
// return pointer to this object
return GetInterface((IBaseFilter *)this, ppv);
} else if (riid == IID_IAMFilterMiscFlags) {
// return pointer to this object
return GetInterface((IAMFilterMiscFlags *)this, ppv);
} else if (riid == IID_IRTPStream || riid == IID_IRTCPStream || riid == IID_IRTPParticipant) {
// obtain pointer to default output pin object
CRtpInputPin * pRtpInputPin = (CRtpInputPin *)GetPin(0);
// forward request to default pin object
return pRtpInputPin->NonDelegatingQueryInterface(riid, ppv);
} else {
// forward this request to the base object
return CBaseFilter::NonDelegatingQueryInterface(riid, ppv); } }
|