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.
487 lines
11 KiB
487 lines
11 KiB
/*++
|
|
|
|
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);
|
|
}
|