📄 tvsourcefilter.cpp
字号:
#include "stdafx.h"
#include <process.h>
#include <Dmoreg.h>
#include <dmodshow.h>
#include <atlconv.h>
#include "networkproxy.h"
#include "graphrebuildhelper.h"
//
extern HANDLE g_hModule;
HRESULT CTVStreamSource::EnumFilters (IFilterGraph *pGraph)
{
IEnumFilters* pEnum = NULL;
IBaseFilter* pFilter = NULL;;
ULONG cFetched;
HRESULT hr = pGraph->EnumFilters(&pEnum);
if (FAILED(hr))
return hr;
//
while(pEnum->Next(1, &pFilter, &cFetched) == S_OK)
{
FILTER_INFO FilterInfo;
hr = pFilter->QueryFilterInfo(&FilterInfo);
if (FAILED(hr))
{
ASSERT(FALSE);
// Maybe the next one will work.
continue;
}
//
GUID guid;
HRESULT hr = pFilter->GetClassID(&guid);
if (hr == S_OK)
{
if (CLSID_DSoundRender == guid ||
CLSID_AudioRender == guid )
{
if (NULL != m_pAudioRender)
{
m_pAudioRender->Release();
m_pAudioRender = NULL;
}
//
m_pAudioRender = pFilter;
pFilter->AddRef();
}
//
if (CLSID_VideoMixingRenderer == guid ||
CLSID_VideoRendererDefault == guid||
CLSID_VideoRenderer == guid)
{
if (NULL != m_pVideoRender)
{
m_pVideoRender->Release();
m_pVideoRender = NULL;
}
//
m_pVideoRender = pFilter;
pFilter->AddRef();
}
}
// The FILTER_INFO structure holds a pointer to the Filter Graph
// Manager, with a reference count that must be released.
if (FilterInfo.pGraph != NULL)
{
FilterInfo.pGraph->Release();
}
pFilter->Release();
}
//
pEnum->Release();
return S_OK;
}
//
unsigned __stdcall CTVStreamSource::ThreadFunc( void* pArguments )
{
ASSERT(NULL != pArguments);
CTVStreamSource* pTVSS = (CTVStreamSource*)pArguments;
//
CoInitialize(NULL);
//
MSG msg;
WORD m_accRequest = 0; //累积的请求数目
WORD m_needRequest = 2;
BOOL m_videoavaible = FALSE;
BOOL m_audioavaible = FALSE;
while(GetMessage(&msg, NULL, 0, 0))
{
if(msg.message == MEDIA_ERROR_STOP)
{
pTVSS->m_pAudioPin->KillPin();
pTVSS->m_pVideoPin->KillPin();
IGraphConfig* pConfig = pTVSS->GetGCF();
if(!pConfig) {
assert(0);
continue;
}
IMediaControl* pIMediaControl = NULL;
pConfig->QueryInterface(IID_IMediaControl, (void**)&pIMediaControl);
//错误信息因此停止图。
HRESULT hr = pIMediaControl->Stop();
pIMediaControl->Release();
}
else if (msg.message == MEDIATYPE_CHANGED)
{
m_accRequest++;
if(LOWORD(msg.wParam) == 0)
m_audioavaible = HIWORD(msg.wParam) == 1? TRUE:FALSE;
else
m_videoavaible = HIWORD(msg.wParam) == 1? TRUE:FALSE;
if(m_accRequest < m_needRequest) //如果需要等待,我们要开始一个flush操作,以避免另一个pin卡死在deliver上面!
{
HRESULT hr;
if(m_audioavaible == FALSE)
{
hr = pTVSS->m_pAudioPin->BeginFlushData();
assert(!FAILED(hr));
}
if(m_videoavaible == FALSE)
{
hr = pTVSS->m_pVideoPin->BeginFlushData();
assert(!FAILED(hr));
}
}
else //累积请求数目足够,开始动态重连
{
m_needRequest = m_accRequest = 0;
if(m_audioavaible)
m_needRequest++;
if(m_videoavaible)
m_needRequest++;
//flush停止
pTVSS->m_pAudioPin->EndFlushData();
pTVSS->m_pVideoPin->EndFlushData();
//预先加入filter到cache里面以提高重连的成功率
/* pTVSS->AddFilterToCache();
GraphRebuildHelper helper;
// IMediaControl* pIMediaControl = NULL;
// pConfig->QueryInterface(IID_IMediaControl, (void**)&pIMediaControl);
pTVSS->m_bDoRealStop = false;
HRESULT hr = helper.stopgraph(pTVSS->GetFG());
pTVSS->m_bDoRealStop = true;
BOOL anypinOK = TRUE;
if(m_videoavaible == TRUE)
{
hr = helper.startbuilding(pTVSS->GetFG(), pTVSS->m_pVideoPin, false);
if(FAILED(hr))
{
char msg[100];
wsprintf(msg, "在连接视频时的DShow错误%X", hr);
MessageBox(NULL,msg,"错误", MB_OK);
anypinOK = FALSE;
pTVSS->m_pVideoPin->KillPin();
m_needRequest--;
}
}
if(m_audioavaible == TRUE)
{
hr = helper.startbuilding(pTVSS->GetFG(), pTVSS->m_pAudioPin, true);
if(FAILED(hr))
{
char msg[100];
wsprintf(msg, "在连接音频时的DShow错误%X", hr);
MessageBox(NULL,msg,"错误", MB_OK);
anypinOK = FALSE;
pTVSS->m_pAudioPin->KillPin();
m_needRequest--;
}
}*/
IGraphConfig* pConfig = pTVSS->GetGCF();
if(!pConfig) {
assert(0);
continue;
}
//先把Audio和Video Renderer Filter枚举到
pTVSS->EnumFilters (pTVSS->GetFG());
//
IMediaControl* pIMediaControl = NULL;
pConfig->QueryInterface(IID_IMediaControl, (void**)&pIMediaControl);
//动态重连前,先把图stop or pause
pTVSS->m_bDoRealStop = false;
HRESULT hr = pIMediaControl->Stop();
// HRESULT hr = pTVSS->Stop();
assert(hr == S_OK);
pTVSS->m_bDoRealStop = true;
Sleep(500);
//
if (FALSE == pTVSS->m_iSAddFilterToCache)
pTVSS->AddFilterToCache();
BOOL anypinOK = TRUE;
if(m_audioavaible == TRUE)
{
//
IPin* pin = NULL;
ULONG cFetched = 0;
//
IEnumPins* ppEnum = NULL;
//
if (S_OK == pTVSS->m_pAudioRender->EnumPins(&ppEnum))
{
ppEnum->Reset();
ppEnum->Next(1, &pin, &cFetched);
//
HRESULT hr = S_FALSE;
const AM_MEDIA_TYPE *pmtFirstConnection = pTVSS->m_pAudioPin->GetType();
hr = pConfig->Reconnect(pTVSS->m_pAudioPin,
pin,
pmtFirstConnection,
NULL,
NULL,
AM_GRAPH_CONFIG_RECONNECT_CACHE_REMOVED_FILTERS |
AM_GRAPH_CONFIG_RECONNECT_USE_ONLY_CACHED_FILTERS);
//
if(FAILED(hr))
{
anypinOK = FALSE;
char msg[100];
wsprintf(msg, "在连接音频时的DShow错误%X", hr);
MessageBox(NULL,msg,"错误", MB_OK);
pTVSS->m_pAudioPin->KillPin();
m_needRequest--;
}
}
if(ppEnum)
ppEnum->Release();
if(pin)
pin->Release();
}
if(m_videoavaible == TRUE)
{
//
IPin* pin = NULL;
ULONG cFetched = 0;
//
IEnumPins* ppEnum = NULL;
//
if (S_OK == pTVSS->m_pVideoRender->EnumPins(&ppEnum))
{
ppEnum->Reset();
if (S_OK == ppEnum->Next(1, &pin, &cFetched))
{
hr = S_FALSE;
const AM_MEDIA_TYPE *pmtFirstConnection = pTVSS->m_pVideoPin->GetType();
hr= pConfig->Reconnect((IPin*)(pTVSS->m_pVideoPin),
pin,
pmtFirstConnection,
NULL,
NULL,
AM_GRAPH_CONFIG_RECONNECT_CACHE_REMOVED_FILTERS |
AM_GRAPH_CONFIG_RECONNECT_USE_ONLY_CACHED_FILTERS);
if(FAILED(hr))
{
anypinOK = FALSE;
char msg[100];
wsprintf(msg, "在连接音频时的DShow错误%X", hr);
MessageBox(NULL,msg,"错误", MB_OK);
pTVSS->m_pAudioPin->KillPin();
m_needRequest--;
}
}
}
if(ppEnum)
ppEnum->Release();
if(pin)
pin->Release();
}
m_audioavaible = m_videoavaible = FALSE;
/* if (!anypinOK)
{
MessageBox(NULL, "由于一个DShow错误,播放将无法继续,需要停止后重新播放","错误", MB_OK);
}*/
// hr = helper.rungraph(pTVSS->GetFG());
hr = pIMediaControl->Run();
if(FAILED(hr))
{
char msg[100];
wsprintf(msg, "由于DShow错误%X, 无法重新运行", hr);
MessageBox(NULL,msg,"错误", MB_OK);
}
// CRefTime rf;
// pTVSS->Run(rf.GetUnits());
if(pIMediaControl)
pIMediaControl->Release();
if(pConfig)
pConfig->Release();
}
}
//
TranslateMessage(&msg);
DispatchMessage(&msg);
}
//
//
CoUninitialize();
//
// _endthreadex( 0 );
//
return 0;
}
// filter info
const AMOVIESETUP_MEDIATYPE sudPinTypes =
{
&MEDIATYPE_Video, // Major type
&MEDIASUBTYPE_NULL // Minor type
};
const AMOVIESETUP_PIN sudPins =
{
L"Video", // Pin string name
FALSE, // Is it rendered
TRUE, // Is it an output
FALSE, // Allowed none
FALSE, // Likewise many
&CLSID_NULL, // Connects to filters
NULL, // Connects to pin
1, // Number of types
&sudPinTypes // Pin information
};
const AMOVIESETUP_FILTER sudTVStreamSource =
{
&CLSID_TVStreamSource, // clsID
L"Chaos Filter", // strName
MERIT_DO_NOT_USE, // dwMerit
1, // nPins
&sudPins // lpPin
};
// Global data
CFactoryTemplate g_Templates[] =
{
{ L"Chaos Filter", &CLSID_TVStreamSource,
CTVStreamSource::CreateInstance, NULL,
&sudTVStreamSource },
};
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
CTVStreamSource* g_pfilter = NULL;
//
CTVStreamSource::CTVStreamSource(LPUNKNOWN pUnk, HRESULT *phr)
: CSource(NAME("Chaos filter"), pUnk, CLSID_TVStreamSource),
m_pComm(NULL), m_pFileReader(NULL),
m_pFileName(NULL), m_isAudioOnly(FALSE), m_bCanDynamicReconnect(FALSE),
m_bUpdateComplete(FALSE), m_pVideoPin(NULL), m_pAudioPin(NULL)
{
m_pAudioRender = NULL;
m_pVideoRender = NULL;
// Try calling GetVersionEx using the OSVERSIONINFOEX structure.
// If that fails, try using the OSVERSIONINFO structure.
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
if(!GetVersionEx ((OSVERSIONINFO *) &osvi)) {
osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
if(!GetVersionEx ((OSVERSIONINFO*) &osvi)) {
assert(0);
}
}
//
g_pfilter = this;
//
m_hThread = NULL;
m_iSAddFilterToCache = FALSE;
//
//
SetLastError(0);
m_bDoRealStop = true;
}
//
CTVStreamSource::~CTVStreamSource()
{
if(m_hThread != NULL)
{
PostThreadMessage(m_iThreadID, WM_QUIT, 0, NULL);
if (WAIT_TIMEOUT == WaitForSingleObject(m_hThread, 5000))
{
TerminateThread(m_hThread, 0);
}
}
//
if (NULL != m_pAudioRender)
{
m_pAudioRender->Release();
m_pAudioRender = NULL;
}
//
if (NULL != m_pVideoRender)
{
m_pVideoRender->Release();
m_pVideoRender = NULL;
}
//
SAFE_DELETE(m_pVideoPin);
SAFE_DELETE(m_pAudioPin);
//
if(NULL != m_pComm)
m_pComm->Stop();
//
g_pfilter = NULL;
//
SAFE_DELETE(m_pComm);
SAFE_DELETE(m_pFileReader);
//
SAFE_ARRAYDELETE(m_pFileName);
}
//
STDMETHODIMP CTVStreamSource::JoinFilterGraph(IFilterGraph *pGraph, LPCWSTR pName)
{
CBaseFilter::JoinFilterGraph(pGraph, pName);
if(pGraph != NULL)
{
IGraphConfig* pGCF = GetGCF();
if(pGCF != NULL)
{
m_bCanDynamicReconnect = TRUE;
pGCF->Release();
}
}
if(m_bCanDynamicReconnect == FALSE)
{
MessageBox(NULL, "DirectX版本太低, 请安装9.0以上的版本", "错误", MB_OK);
return E_FAIL;
}
// m_bCanDynamicReconnect = FALSE;
SAFE_DELETE(m_pVideoPin);
SAFE_DELETE(m_pAudioPin);
//
HRESULT hr;
HRESULT* phr = &hr;
m_pVideoPin = new CTVStreamSourceVideoPin(phr, this);
if (phr)
{
*phr = (NULL == m_pVideoPin) ? E_OUTOFMEMORY : S_OK;
}
//
m_pAudioPin = new CTVStreamSourceAudioPin(phr, this);
//
if (phr)
{
*phr = (NULL == m_pAudioPin) ? E_OUTOFMEMORY : S_OK;
}
//
m_pAudioPin->SetAnotherPin(m_pVideoPin);
m_pVideoPin->SetAnotherPin(m_pAudioPin);
if (NULL != pGraph && NULL == m_hThread)
{
/*
IMediaFilter* pIMediaFilter = NULL;
//
pGraph->QueryInterface(IID_IMediaFilter, (void**)&pIMediaFilter);
pIMediaFilter->SetSyncSource(NULL);
pIMediaFilter->Release();*/
// AddFilterToCache();
//create thread
m_hThread = (HANDLE) _beginthreadex( NULL, 0, &ThreadFunc, this, 0, &m_iThreadID );
}
//
return S_OK;
}
//
IBaseFilter* CTVStreamSource::CreateDMO( REFCLSID clsidDMO, REFCLSID catDMO)
{
// Create the DMO Wrapper filter.
IBaseFilter *pFilter = NULL;
HRESULT hr = CoCreateInstance(CLSID_DMOWrapperFilter,
NULL,
CLSCTX_INPROC_SERVER,
IID_IBaseFilter,
reinterpret_cast<void**>(&pFilter));
//
if (SUCCEEDED(hr))
{
// Query for IDMOWrapperFilter.
IDMOWrapperFilter *pDmoWrapper = NULL;
hr = pFilter->QueryInterface(IID_IDMOWrapperFilter,
reinterpret_cast<void**>(&pDmoWrapper));
if (SUCCEEDED(hr))
{
// Initialize the filter.
hr = pDmoWrapper->Init(clsidDMO, catDMO);
pDmoWrapper->Release();
if (SUCCEEDED(hr))
{
return pFilter;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -