📄 netpushsource.cpp
字号:
//------------------------------------------------------------------------------
// File: NetPushSource.cpp
//
// Desc: DirectShow sample code - In-memory push mode source filter
// Provides a static bitmap as the video output stream.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------------------------
#include "mediastream.h"
#include "streams.h"
#include "PushSource.h"
#include "PushGuids.h"
#include "MemSafe.h"
#include "atlbase.h"
#include <INITGUID.H>
// 30323449-0000-0010-8000-00AA00389B71 'YV12' == MEDIASUBTYPE_I420
EXTERN_GUID(WMMEDIASUBTYPE_I420,
0x30323449, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
/**********************************************
* CNetPushSourcePin Class
**********************************************/
CNetPushSourcePin::CNetPushSourcePin(HRESULT *phr, CSource *pFilter)
:CSourceStream(NAME("Video Output Pin"), phr, pFilter, L"Out")
,m_iFrameNumber(0)
,m_iVideoTrack(0)
,m_iMaxW(352)
,m_iMaxH(288)
,m_hEvent(NULL)
{
g_pMediaRcv=NULL;
m_VidoeHeader=new FRAMEHDR;
m_pVideoData=new BYTE[256<<10];
m_iRcvFNum=0;
m_rtSampleTime=0;
m_rtFrameLength=40;
m_wRtpAddr=0;
m_wRtpPort=64000;
mediastreamStartup();
m_hEvent=CreateEvent(NULL, FALSE, FALSE, NULL);
}
CNetPushSourcePin::~CNetPushSourcePin()
{
if(m_VidoeHeader){
delete[] m_VidoeHeader;
m_VidoeHeader=NULL;
}
if(m_pVideoData){
delete[] m_pVideoData;
m_pVideoData;
}
mediastreamCleanup();
if(m_hEvent){
CloseHandle(m_hEvent);
}
}
STDMETHODIMP CNetPushSourcePin::NonDelegatingQueryInterface(REFIID riid, void** ppv)
{
CheckPointer(ppv, E_POINTER);
if(IID_IiFlyNetParams == riid){
return GetInterface((IiFlyNetParams*)this, ppv);
}else{
return CSourceStream::NonDelegatingQueryInterface(riid, ppv);
}
}
////////////////////////////////////////////////////////////////////////////////////////
// GetMediaType: This method tells the downstream pin what types we support.
// Here is how CSourceStream deals with media types:
// If you support exactly one type, override GetMediaType(CMediaType*). It will then be
// called when (a) our filter proposes a media type, (b) the other filter proposes a
// type and we have to check that type.
// If you support > 1 type, override GetMediaType(int,CMediaType*) AND CheckMediaType.
// In this case we support only one type, which we obtain from the bitmap file.
HRESULT CNetPushSourcePin::GetMediaType(CMediaType *pMediaType)
{
CAutoLock cAutoLock(m_pFilter->pStateLock());
CheckPointer(pMediaType, E_POINTER);
pMediaType->SetType(&MEDIATYPE_Video);
pMediaType->SetSubtype(&WMMEDIASUBTYPE_I420);//&MEDIASUBTYPE_IYUV;
pMediaType->SetTemporalCompression(TRUE);
pMediaType->SetSampleSize(1);
pMediaType->SetFormatType(&FORMAT_VideoInfo);
VIDEOINFOHEADER vf;
ZeroMemory(&vf, sizeof(vf));
vf.bmiHeader.biCompression=mmioFOURCC('X','V','I','D');
vf.bmiHeader.biWidth=m_iMaxW;//352
vf.bmiHeader.biHeight=m_iMaxH;//288
SetRectEmpty(&vf.rcSource);
SetRectEmpty(&vf.rcTarget);
/*
ULARGE_INTEGER uliSize;
if (!m_pMp4 || m_pMp4->stream == INVALID_HANDLE_VALUE)
{
*/
vf.bmiHeader.biBitCount = 0;
/*
}else{
uliSize.LowPart = GetFileSize(m_pMp4->stream, &uliSize.HighPart);
vf.bmiHeader.biBitCount=(WORD)uliSize.LowPart;
}
*/
pMediaType->SetFormat((BYTE*)&vf, sizeof(vf));
m_mt=*pMediaType;
return S_OK;
}
HRESULT CNetPushSourcePin::DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pRequest)
{
CAutoLock cAutoLock(m_pFilter->pStateLock());
HRESULT hr=E_POINTER;
CheckPointer(pAlloc, hr);
CheckPointer(pRequest, hr);
// Ensure a minimum number of buffers
if (pRequest->cBuffers == 0)
{
pRequest->cBuffers = 2;
}
pRequest->cbBuffer = m_iMaxW*m_iMaxH;
ALLOCATOR_PROPERTIES Actual;
hr = pAlloc->SetProperties(pRequest, &Actual);
if (FAILED(hr))
{
return hr;
}
// Is this allocator unsuitable?
if (Actual.cbBuffer < pRequest->cbBuffer)
{
return E_FAIL;
}
return S_OK;
}
// This is where we insert the DIB bits into the video stream.
// FillBuffer is called once for every sample in the stream.
HRESULT CNetPushSourcePin::FillBuffer(IMediaSample* pSample)
{
if(m_iRcvFNum==-1){
m_iRcvFNum=0;
return E_FAIL;
}
BYTE* pData;
long cbData;
CheckPointer(pSample, E_POINTER);
CAutoLock cAutoLockShared(&m_cSharedState);
// Access the sample's data buffer
pSample->GetPointer(&pData);
CheckPointer(pData, E_POINTER);
cbData = pSample->GetSize();
// Check that we're still using video
ASSERT(m_mt.formattype == FORMAT_VideoInfo);
if(WaitForSingleObject(m_hEvent, 100)==WAIT_TIMEOUT)
return E_FAIL;
memcpy(pData, m_VidoeHeader->m_pData, m_VidoeHeader->m_dwDataSize);
m_iFrameNumber++;
if(m_VidoeHeader->m_tVideoParam.m_bKeyFrame==1)
pSample->SetSyncPoint(TRUE);
else
pSample->SetSyncPoint(FALSE);
return S_OK;
}
void DealMediaFrame(PFRAMEHDR pFrmHdr, u32 dwContext)
{
CNetPushSourcePin* lpPin=(CNetPushSourcePin*)dwContext;
if(!lpPin){
return;
}
if(lpPin->m_iRcvFNum==0){
if(pFrmHdr->m_tVideoParam.m_bKeyFrame==1){
lpPin->m_iRcvFNum=1;
}else{
return;
}
}
*(lpPin->m_VidoeHeader)=*pFrmHdr;
memcpy(lpPin->m_pVideoData, pFrmHdr->m_pData, pFrmHdr->m_dwDataSize);
lpPin->m_VidoeHeader->m_pData=lpPin->m_pVideoData;
SetEvent(lpPin->m_hEvent);
}
// OnThreadCreate()
// As we go active reset the stream time to zero
HRESULT CNetPushSourcePin::OnThreadCreate()
{
CAutoLock cAutoLockShared(&m_cSharedState);
m_rtSampleTime = 0;
m_rtFrameLength=40;
g_pMediaRcv = CreateMediaRcv(MAX_FRAME_SIZE, DealMediaFrame, (u32)this, 0);
if(!g_pMediaRcv)
return E_FAIL;
TLocalNetParam tLocalNetParam;
tLocalNetParam.m_tLocalNet.m_wRTPPort = m_wRtpPort;
tLocalNetParam.m_tLocalNet.m_dwRTPAddr = m_wRtpAddr;
WORD wRet = SetMediaRcvLocalParam(g_pMediaRcv, tLocalNetParam);
if(wRet!=S_OK)
return E_FAIL;
wRet = StartMediaRcv(g_pMediaRcv);
if(wRet!=S_OK)
return E_FAIL;
return NOERROR;
}
HRESULT CNetPushSourcePin::OnThreadStartPlay(void)
{
// if(!g_pMediaRcv)
// return E_POINTER;
return NOERROR;
}
HRESULT CNetPushSourcePin::OnThreadDestroy(void)
{
m_iRcvFNum=0;
if(g_pMediaRcv){
WORD wRet=StopMediaRcv(g_pMediaRcv);
DestroyMediaRcv(g_pMediaRcv);
g_pMediaRcv=NULL;
}
return NOERROR;
}
HRESULT CNetPushSourcePin::DoBufferProcessingLoop(void)
{
Command com;
OnThreadStartPlay();
do {
while(!CheckRequest(&com)){
IMediaSample *pSample;
HRESULT hr=GetDeliveryBuffer(&pSample,NULL,NULL,0);
if(FAILED(hr)){
Sleep(1);
continue; // go round again. Perhaps the error will go away
// or the allocator is decommited & we will be asked to
// exit soon.
}
// Virtual function user will override.
hr = FillBuffer(pSample);
if(hr == S_OK){
hr = Deliver(pSample);
pSample->Release();
// downstream filter returns S_FALSE if it wants us to
// stop or an error if it's reporting an error.
if(hr != S_OK)
{
DbgLog((LOG_TRACE, 2, TEXT("Deliver() returned %08x; stopping"), hr));
return S_OK;
}
}else if (hr == S_FALSE){
// derived class wants us to stop pushing data
pSample->Release();
DeliverEndOfStream();
}else if(hr==E_FAIL){
pSample->Release();
}else{
// derived class encountered an error
pSample->Release();
DbgLog((LOG_ERROR, 1, TEXT("Error %08lX from FillBuffer!!!"), hr));
DeliverEndOfStream();
m_pFilter->NotifyEvent(EC_ERRORABORT, hr, 0);
return hr;
}
// all paths release the sample
}
// For all commands sent to us there must be a Reply call!
if(com == CMD_RUN || com == CMD_PAUSE){
Reply(NOERROR);
}else if (com != CMD_STOP) {
Reply((DWORD) E_UNEXPECTED);
DbgLog((LOG_ERROR, 1, TEXT("Unexpected command!!!")));
}
}while(com!=CMD_STOP);
return S_FALSE;
}
STDMETHODIMP CNetPushSourcePin::put_RtpPort(const TCHAR* inRtpPort, UINT inStrLength)
{
CheckPointer(inRtpPort, E_INVALIDARG);
for(UINT i=0;i<inStrLength;i++){
if(inRtpPort[i]<TEXT('0') || inRtpPort[i]>TEXT('9')){
return E_FAIL;
}
}
long lPort=(long)
#ifdef UNICODE
_wtol
#else
atol
#endif
(inRtpPort);
if(lPort<=0 || lPort>65535){
return E_FAIL;
}
m_wRtpPort=(WORD)lPort;
return S_OK;
}
STDMETHODIMP CNetPushSourcePin::get_RtpPort(TCHAR* outRtpPort, UINT* outBufLength)
{
CheckPointer(outBufLength, E_INVALIDARG);
UINT MaxLen=
#ifdef UNICODE
wcslen
#else
strlen
#endif
(TEXT("18446744073709551615"))+1;
TCHAR* ch=new TCHAR[MaxLen];
if(!ch){
return E_OUTOFMEMORY;
}
MaxLen=0;
#ifdef UNICODE
_ltow
#else
ltoa
#endif
(m_wRtpPort, ch, 10);
if(outRtpPort){
#ifdef UNICODE
wcscpy
#else
strcpy
#endif
(outRtpPort, ch);
MaxLen=
#ifdef UNICODE
min(wcslen(outRtpPort), wcslen(ch));
#else
min(strlen(outRtpPort), strlen(ch));
#endif
}else{
MaxLen=
#ifdef UNICODE
wcslen
#else
strlen
#endif
(ch);
}
*outBufLength=(MaxLen+1)*sizeof(TCHAR);
delete[] ch;
return S_OK;
}
STDMETHODIMP CNetPushSourcePin::put_VideoHeight(const UINT inVideoHeight)
{
m_iMaxH=inVideoHeight;
return S_OK;
}
STDMETHODIMP CNetPushSourcePin::get_VideoHeight(UINT* outVideoHeight)
{
CheckPointer(outVideoHeight, E_INVALIDARG);
*outVideoHeight=m_iMaxH;
return S_OK;
}
STDMETHODIMP CNetPushSourcePin::put_VideoWidth(const UINT inVideoWidth)
{
m_iMaxW=inVideoWidth;
return S_OK;
}
STDMETHODIMP CNetPushSourcePin::get_VideoWidth(UINT* outVideoWidth)
{
CheckPointer(outVideoWidth, E_INVALIDARG);
*outVideoWidth=m_iMaxW;
return S_OK;
}
/**********************************************
* CNetPushSource Class
**********************************************/
CNetPushSource::CNetPushSource(IUnknown *pUnk, HRESULT *phr)
:CSource(NAME("iFly Net Push Source"), pUnk, CLSID_iFlyNetPushSource)
,m_pPin(NULL)
,m_ptsURL(NULL)
{
m_pPin = new CNetPushSourcePin(phr, this);
if (phr)
{
if (m_pPin == NULL)
*phr = E_OUTOFMEMORY;
else
*phr = S_OK;
}
}
CNetPushSource::~CNetPushSource()
{
if(m_ptsURL){
CoTaskMemFree(m_ptsURL);
m_ptsURL=NULL;
}
//SAFE_DELETE(m_pPin);//父类会释放。
}
CUnknown * WINAPI CNetPushSource::CreateInstance(IUnknown *pUnk, HRESULT *phr)
{
CNetPushSource *pNewFilter = new CNetPushSource(pUnk, phr);
if (phr)
{
if (pNewFilter == NULL)
*phr = E_OUTOFMEMORY;
else
*phr = S_OK;
}
return pNewFilter;
}
STDMETHODIMP CNetPushSource::NonDelegatingQueryInterface(REFIID riid, void** ppv)
{
CheckPointer(ppv, E_POINTER);
if(IID_ISpecifyPropertyPages==riid){
return GetInterface((ISpecifyPropertyPages*)this, ppv);
}else if(IID_IFileSourceFilter==riid){
return GetInterface((IFileSourceFilter*)this, ppv);
}else if(IID_IiFlyNetParams==riid){
if(!m_pPin){
return E_FAIL;
}
return m_pPin->QueryInterface(riid, ppv);
}else{
return CSource::NonDelegatingQueryInterface(riid, ppv);
}
}
STDMETHODIMP CNetPushSource::Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE *pmt)
{
CheckPointer(pszFileName, E_INVALIDARG);
CAutoLock lckit(&m_cStateLock);
int iBufLen=WideCharToMultiByte(GetACP(), NULL, pszFileName, -1, NULL, 0, NULL, NULL);
if(iBufLen<=0)
return E_INVALIDARG;
if(m_ptsURL){
CoTaskMemFree(m_ptsURL);
m_ptsURL=NULL;
}
m_ptsURL=(TCHAR*)CoTaskMemAlloc(sizeof(TCHAR)*(iBufLen));
if(!m_ptsURL)
return E_OUTOFMEMORY;
#ifdef UNICODE
CopyMemory(m_ptsURL, pszFileName, sizeof(WCHAR)*iBufLen);
#else
WideCharToMultiByte(GetACP(), NULL, pszFileName, -1, m_ptsURL, iBufLen, NULL, NULL);
#endif
//对m_ptsURL解析:设置Filter其它参量:
//...
if(pmt)
m_mt=*pmt;
return NOERROR;
}
STDMETHODIMP CNetPushSource::GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE *pmt)
{
CheckPointer(ppszFileName, E_INVALIDARG);
*ppszFileName=NULL;
CAutoLock lckit(&m_cStateLock);
if(m_ptsURL){
DWORD n=
#ifdef UNICODE
(wcslen
#else
(strlen
#endif
(m_ptsURL)+1);
*ppszFileName=(LPOLESTR)CoTaskMemAlloc(sizeof(WCHAR)*n);
if (*ppszFileName!=NULL) {
//ZeroMemory(*ppszFileName,sizeof(WCHAR)*n);//测试语句。
#ifdef UNICODE
CopyMemory(*ppszFileName, m_ptsURL, sizeof(WCHAR)*n);
#else
MultiByteToWideChar(GetACP(), 0, m_ptsURL, -1, *ppszFileName,n);
#endif
}
if (pmt!=NULL) {
CopyMediaType(pmt, &m_mt);
}
}
return NOERROR;
}
STDMETHODIMP CNetPushSource::Pause()
{
HRESULT hr=S_OK;
FILTER_STATE ost, cst;
if(GetState(INFINITE, &ost)!=S_OK){
return E_FAIL;
}
hr=CSource::Pause();
/*
if(ost==State_Paused){
return hr;
}
*/
if(GetState(INFINITE, &cst)!=S_OK){
return E_FAIL;
}
if(cst==State_Paused){
m_pPin->m_iRcvFNum=-1;
}else if(cst==State_Running){
m_pPin->m_iRcvFNum=0;
}
return hr;
}
//Implement ISpecifyPropertyPages Interface:
STDMETHODIMP CNetPushSource::GetPages(CAUUID *pPages)
{
pPages->cElems = 1;
pPages->pElems = (GUID *) CoTaskMemAlloc(sizeof(GUID));
if (pPages->pElems == NULL)
{
return E_OUTOFMEMORY;
}
*(pPages->pElems) = CLSID_iFlyNetParamsProp;
return NOERROR;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -