/*++ Copyright (c) 1998 Microsoft Corporation Module Name: bgvideo.cpp Abstract: Implementation of the Video bridge filters. Author: Mu Han (muhan) 11/16/1998 --*/ #include "stdafx.h" CTAPIVideoBridgeSinkFilter::CTAPIVideoBridgeSinkFilter( IN LPUNKNOWN pUnk, IN IDataBridge * pIDataBridge, OUT HRESULT * phr ) : CTAPIBridgeSinkFilter(pUnk, pIDataBridge, phr) { } HRESULT CTAPIVideoBridgeSinkFilter::CreateInstance( IN IDataBridge * pIDataBridge, OUT IBaseFilter ** ppIBaseFilter ) /*++ Routine Description: This method create a instance of the bridge's sink filter. Arguments: ppIBaseFilter - the returned filter interface pointer. Return Value: E_OUTOFMEMORY - no memory for the new object. --*/ { ENTER_FUNCTION("CTAPIVideoBridgeSinkFilter::CreateInstance"); BGLOG((BG_TRACE, "%s entered.", __fxName)); HRESULT hr = S_OK; CUnknown* pUnknown = new CTAPIVideoBridgeSinkFilter(NULL, pIDataBridge, &hr); if (pUnknown == NULL) { hr = E_OUTOFMEMORY; DbgLog((LOG_ERROR, 0, "%s, out of memory creating the filter", __fxName)); } else if (FAILED(hr)) { DbgLog((LOG_ERROR, 0, "%s, the filter's constructor failed, hr:%d", __fxName, hr)); delete pUnknown; } else { pUnknown->NonDelegatingAddRef(); hr = pUnknown->NonDelegatingQueryInterface( __uuidof(IBaseFilter), (void **)ppIBaseFilter ); pUnknown->NonDelegatingRelease(); } BGLOG((BG_TRACE, "%s, returning:%p, hr:%x", __fxName, *ppIBaseFilter, hr)); return hr; } HRESULT CTAPIVideoBridgeSinkFilter::GetMediaType( IN int iPosition, OUT CMediaType *pMediaType ) /*++ Routine Description: Get the media type that this filter wants to support. Currently we only support RTP H263 data. Arguments: IN int iPosition, the index of the media type, zero based.. In CMediaType *pMediaType Pointer to a CMediaType object to save the returned media type. Return Value: S_OK - success E_OUTOFMEMORY - no memory --*/ { ENTER_FUNCTION("CTAPIVideoBridgeSinkFilter::GetMediaType"); BGLOG((BG_TRACE, "%s, iPosition:%d, pMediaType:%p", __fxName, iPosition, pMediaType)); ASSERT(!IsBadWritePtr(pMediaType, sizeof(AM_MEDIA_TYPE))); HRESULT hr; if (iPosition == 0) { pMediaType->majortype = __uuidof(MEDIATYPE_RTP_Single_Stream); pMediaType->subtype = GUID_NULL; hr = S_OK; } else { hr = VFW_S_NO_MORE_ITEMS; } BGLOG((BG_TRACE, "%s returns %d", __fxName, hr)); return hr; } HRESULT CTAPIVideoBridgeSinkFilter::CheckMediaType( const CMediaType *pMediaType ) /*++ Routine Description: Check the media type that this filter wants to support. Currently we only support RTP H263 data. Arguments: In CMediaType *pMediaType Pointer to a CMediaType object to save the returned media type. Return Value: S_OK - success E_OUTOFMEMORY - no memory VFW_E_TYPE_NOT_ACCEPTED - media type rejected VFW_E_INVALIDMEDIATYPE - bad media type --*/ { ENTER_FUNCTION("CTAPIVideoBridgeSinkFilter::CheckMediaType"); BGLOG((BG_TRACE, "%s, pMediaType:%p", __fxName, pMediaType)); ASSERT(!IsBadReadPtr(pMediaType, sizeof(AM_MEDIA_TYPE))); // H.263 is not published, ignore checking here HRESULT hr = S_OK; BGLOG((BG_TRACE, "%s returns %d", __fxName, hr)); return hr; } CTAPIVideoBridgeSourceFilter::CTAPIVideoBridgeSourceFilter( IN LPUNKNOWN pUnk, OUT HRESULT * phr ) : CTAPIBridgeSourceFilter(pUnk, phr), m_dwSSRC(0), m_lWaitTimer(I_FRAME_TIMER), m_fWaitForIFrame(FALSE) { } HRESULT CTAPIVideoBridgeSourceFilter::CreateInstance( OUT IBaseFilter ** ppIBaseFilter ) /*++ Routine Description: This method create a instance of the bridge's sink filter. Arguments: ppIBaseFilter - the returned filter interface pointer. Return Value: E_OUTOFMEMORY - no memory for the new object. --*/ { ENTER_FUNCTION("CTAPIVideoBridgeSourceFilter::CreateInstance"); BGLOG((BG_TRACE, "%s entered.", __fxName)); HRESULT hr = S_OK; CUnknown* pUnknown = new CTAPIVideoBridgeSourceFilter(NULL, &hr); if (pUnknown == NULL) { hr = E_OUTOFMEMORY; DbgLog((LOG_ERROR, 0, "%s, out of memory creating the filter", __fxName)); } else if (FAILED(hr)) { DbgLog((LOG_ERROR, 0, "%s, the filter's constructor failed, hr:%d", __fxName, hr)); delete pUnknown; } else { pUnknown->NonDelegatingAddRef(); hr = pUnknown->NonDelegatingQueryInterface( __uuidof(IBaseFilter), (void **)ppIBaseFilter ); pUnknown->NonDelegatingRelease(); } BGLOG((BG_TRACE, "%s, returning:%p, hr:%x", __fxName, *ppIBaseFilter, hr)); return hr; } HRESULT CTAPIVideoBridgeSourceFilter::GetMediaType( IN int iPosition, OUT CMediaType *pMediaType ) /*++ Routine Description: Get the media type that this filter wants to support. Currently we only support RTP H263 data. Arguments: IN int iPosition, the index of the media type, zero based.. In CMediaType *pMediaType Pointer to a CMediaType object to save the returned media type. Return Value: S_OK - success E_OUTOFMEMORY - no memory --*/ { ENTER_FUNCTION("CTAPIVideoBridgeSourceFilter::GetMediaType"); BGLOG((BG_TRACE, "%s, iPosition:%d, pMediaType:%p", __fxName, iPosition, pMediaType)); ASSERT(!IsBadWritePtr(pMediaType, sizeof(AM_MEDIA_TYPE))); HRESULT hr; if (iPosition == 0) { pMediaType->majortype = __uuidof(MEDIATYPE_RTP_Single_Stream); pMediaType->subtype = GUID_NULL; hr = S_OK; } else { hr = VFW_S_NO_MORE_ITEMS; } BGLOG((BG_TRACE, "%s returns %d", __fxName, hr)); return hr; } HRESULT CTAPIVideoBridgeSourceFilter::CheckMediaType( const CMediaType *pMediaType ) /*++ Routine Description: Check the media type that this filter wants to support. Currently we only support RTP H263 data. Arguments: In CMediaType *pMediaType Pointer to a CMediaType object to save the returned media type. Return Value: S_OK - success E_OUTOFMEMORY - no memory VFW_E_TYPE_NOT_ACCEPTED - media type rejected VFW_E_INVALIDMEDIATYPE - bad media type --*/ { ENTER_FUNCTION("CTAPIVideoBridgeSourceFilter::CheckMediaType"); BGLOG((BG_TRACE, "%s, pMediaType:%p", __fxName, pMediaType)); ASSERT(!IsBadReadPtr(pMediaType, sizeof(AM_MEDIA_TYPE))); // media type H.263 is not published, ignore checking HRESULT hr = S_OK; BGLOG((BG_TRACE, "%s returns %d", __fxName, hr)); return hr; } BOOL IsIFrame(IN const BYTE * pPacket, IN long lPacketLength) { BYTE *pH263PayloadHeader = (BYTE*)(pPacket + sizeof(RTP_HEADER)); // Header in mode A // 0 1 2 3 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ //|F|P|SBIT |EBIT | SRC | R |I|A|S|DBQ| TRB | TR | //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // If I is 1, it is a key frame. return (BOOL)(pH263PayloadHeader[2] & 0x80); } STDMETHODIMP CTAPIVideoBridgeSourceFilter::Run(REFERENCE_TIME tStart) /*++ Routine Description: start the filter Arguments: Nothing. Return Value: S_OK. --*/ { m_dwSSRC = 0; m_fWaitForIFrame = FALSE; m_lWaitTimer = 0; return CBaseFilter::Run(tStart); } HRESULT CTAPIVideoBridgeSourceFilter::SendSample( IN IMediaSample *pSample ) /*++ Routine Description: Process a sample from the bridge sink filter. We need to look for I-frames when the SSRC changes. Arguments: pSample - The media sample object. Assumption: it has to contain an RTP packet that has H.263 data in it. Return Value: HRESULT. --*/ { ENTER_FUNCTION("CTAPIVideoBridgeSourceFilter::SendSample"); CAutoLock Lock(m_pLock); // we don't deliver anything if the filter is not in running state. if (m_State != State_Running) { return S_OK; } ASSERT(pSample != NULL); BYTE *pPacket; HRESULT hr; if (FAILED (hr = pSample->GetPointer (&pPacket))) { BGLOG ((BG_ERROR, "%s failed to get buffer pointer from input sample %p", __fxName, pSample)); return hr; } long lPacketSize = pSample->GetActualDataLength(); const long H263PayloadHeaderLength = 4; if (lPacketSize < sizeof(RTP_HEADER) + H263PayloadHeaderLength) { BGLOG ((BG_ERROR, "%s get a bad RTP packet %p", __fxName, pSample)); return E_UNEXPECTED; } RTP_HEADER *pRTPHeader = (RTP_HEADER *)pPacket; if (m_dwSSRC == 0) { m_dwSSRC = pRTPHeader->dwSSRC; } else if (m_dwSSRC != pRTPHeader->dwSSRC) { m_dwSSRC = pRTPHeader->dwSSRC; BGLOG ((BG_TRACE, "%s new SSRC detected", __fxName, m_dwSSRC)); // the source changed, we need to wait for an I-frame if (IsIFrame(pPacket, lPacketSize)) { // we got an I-Frame m_fWaitForIFrame = FALSE; BGLOG ((BG_TRACE, "%s switched to %x", __fxName, m_dwSSRC)); } else { m_fWaitForIFrame = TRUE; m_lWaitTimer = I_FRAME_TIMER; // discard the frame. return S_FALSE; } } else if (m_fWaitForIFrame) { if (IsIFrame(pPacket, lPacketSize)) { // we got an I-Frame m_fWaitForIFrame = FALSE; BGLOG ((BG_TRACE, "%s switched to %x", __fxName, m_dwSSRC)); } else { // this is not an I frame, m_lWaitTimer --; if (m_lWaitTimer > 0) { // discard the frame. return S_FALSE; } BGLOG ((BG_TRACE, "%s switched to because of timeout %x", __fxName, m_dwSSRC)); } } _ASSERT(m_pOutputPin != NULL); return m_pOutputPin->Deliver(pSample); }