转载请标明是引用于 http://blog.csdn.net/chenyujing1234
例子代码:(包括asynbase asyncflt baseclasses memfile)(编译工具:VS2005)
http://www.rayfile.com/zh-cn/files/d2b6051c-73ed-11e1-8768-0015c55db73d/
参考书<<DirectShow开发指南>>
工程介绍:
它位于目录 Samples\C++\DirectShow\Filters\Async下
asynbase:是一个静态项目,实现了异步读写的基类;
async: 使用了asynbase库,实现了一个拉模式的source Filter;
memfile:使用了asynbase库,在应用程序中实现了一个不注册的拉模式source filter,然后进行媒体文件的播放.
DirectShow提供了一个标准的File Source(Async.)(CLSID为CLSDID_AysncReader),作为一般媒体文件播放的Source Filter,
async也实现了类似的功能。可以把它看成是一个简化了的File Source(Async)
将C:\DX90SDK\Samples\C++\DirectShow\Filters\Async\Filter\asyncflt.reg注入注册表.
然后用程序->Microsoft DirectX 9.0 SDK Update (->DirectX Utilities->GraphEdit可以看到,如下图
1.1.1实现要点.
请参考我上传的源码里的注释。
1.1.2编译过程。
把工程asynbase asyncflt memfile的C++->命令行里加 /wd4430
在memfile.cpp里的 _tmain( int argc, TCHAR* argv[] )文件里直接定义媒体文件。
- argc = 2;
- CHAR *tPlayFile = "D:\\自己的经验总结\\自己的经验总结\\DX90DK_Samples\\Samples\\C++\\DirectShow\\Filters_vs2005\\Async\\MEMFile\\Debug\\test.avi";
argc = 2;
TCHAR *tPlayFile = "D:\\自己的经验总结\\自己的经验总结\\DX90DK_Samples\\Samples\\C++\\DirectShow\\Filters_vs2005\\Async\\MEMFile\\Debug\\test.avi";
1.1.3 调试过程
为方便调试,把三个工程组织在一个解决方案里,且修改asynbase asyncflt 工程的属性:
调试-> 命令->D:\自己的经验总结\自己的经验总结\DX90DK_Samples\Samples\C++\DirectShow\Filters_vs2005\Async\MEMFile\Debug\memfile.exe
这里请大家注意了:asyncflt 作为一个filter,产生的ax目标文件注不注册对调试memFile没有影响。
但为了学习注册ax文件,我还是做了注册.
把注册表asyncflt.reg注入注册表中,且把asyncflt.ax文件注册到系统中(参考:http://blog.csdn.net/chenyujing1234/article/details/7382232)
1.1.4
调试分析:
1、memfile.cpp里的SelectAndRender(CMemReader *pReader, IFilterGraph **ppFG)函数里的
hr = pBuilder->Render(pReader->GetPin(0));中的GetPin会调用到
CBasePin * CAsyncReader::GetPin(int n)四次
pBuilder->Render调用到了以下函数:
CAsyncOutputPin::Connect(
HRESULT CAsyncOutputPin::CheckMediaType(const CMediaType* pType)
CAsyncOutputPin::SyncRead(
CAsyncIo::SyncRead(
CAsyncIo::SyncReadAligned(
CAsyncRequest::Complete()
CAsyncOutputPin::Connect(
HRESULT CAsyncOutputPin::CheckMediaType(const CMediaType* pType)
CAsyncOutputPin::SyncRead(
CAsyncIo::SyncRead(
CAsyncIo::SyncReadAligned(
CAsyncRequest::Complete()
CAsyncOutputPin::SyncRead(
CAsyncIo::SyncRead(
CAsyncIo::SyncReadAligned(
CAsyncRequest::Complete()
CAsyncOutputPin::SyncRead(
CAsyncIo::SyncRead(
CAsyncIo::SyncReadAligned(
CAsyncRequest::Complete()
CAsyncOutputPin::SyncRead(
CAsyncIo::SyncRead(
CAsyncIo::SyncReadAligned(
CAsyncRequest::Complete()
CAsyncOutputPin::RequestAllocator( )
// ----------------------这个函数一直没有调用hr = InitAllocator(&pAlloc);
// ----------------------而是到了
if(SUCCEEDED(hr) && m_pIo->IsAligned(Actual.cbAlign))
{
pPreferred->AddRef();
*ppActual = pPreferred;
return S_OK;
}
就跳出来了
- // we need to return an addrefed allocator, even if it is the preferred
- // one, since he doesn't know whether it is the preferred one or not.
- STDMETHODIMP
- CAsyncOutputPin::RequestAllocator(
- IMemAllocator* pPreferred,
- ALLOCATOR_PROPERTIES* pProps,
- IMemAllocator ** ppActual)
- {
- CheckPointer(pPreferred,E_POINTER);
- CheckPointer(pProps,E_POINTER);
- CheckPointer(ppActual,E_POINTER);
- ASSERT(m_pIo);
- _tprintf(_T("------------FILE %s CAsyncOutputPin::RequestAllocator\n"), __FILE__);
- // we care about alignment but nothing else
- if(!pProps->cbAlign || !m_pIo->IsAligned(pProps->cbAlign))
- {
- m_pIo->Alignment(&pProps->cbAlign);
- }
- ALLOCATOR_PROPERTIES Actual;
- HRESULT hr;
- if(pPreferred)
- {
- hr = pPreferred->SetProperties(pProps, &Actual);
- if(SUCCEEDED(hr) && m_pIo->IsAligned(Actual.cbAlign))
- {
- pPreferred->AddRef();
- *ppActual = pPreferred;
- return S_OK;
- }
- }
- // create our own allocator
- IMemAllocator* pAlloc;
- hr = InitAllocator(&pAlloc);
- if(FAILED(hr))
- {
- return hr;
- }
- //...and see if we can make it suitable
- hr = pAlloc->SetProperties(pProps, &Actual);
- if(SUCCEEDED(hr) && m_pIo->IsAligned(Actual.cbAlign))
- {
- // we need to release our refcount on pAlloc, and addref
- // it to pass a refcount to the caller - this is a net nothing.
- *ppActual = pAlloc;
- return S_OK;
- }
- // failed to find a suitable allocator
- pAlloc->Release();
- // if we failed because of the IsAligned test, the error code will
- // not be failure
- if(SUCCEEDED(hr))
- {
- hr = VFW_E_BADALIGN;
- }
- return hr;
- }
// we need to return an addrefed allocator, even if it is the preferred
// one, since he doesn't know whether it is the preferred one or not.
STDMETHODIMP
CAsyncOutputPin::RequestAllocator(
IMemAllocator* pPreferred,
ALLOCATOR_PROPERTIES* pProps,
IMemAllocator ** ppActual)
{
CheckPointer(pPreferred,E_POINTER);
CheckPointer(pProps,E_POINTER);
CheckPointer(ppActual,E_POINTER);
ASSERT(m_pIo);
_tprintf(_T("------------FILE %s CAsyncOutputPin::RequestAllocator\n"), __FILE__);
// we care about alignment but nothing else
if(!pProps->cbAlign || !m_pIo->IsAligned(pProps->cbAlign))
{
m_pIo->Alignment(&pProps->cbAlign);
}
ALLOCATOR_PROPERTIES Actual;
HRESULT hr;
if(pPreferred)
{
hr = pPreferred->SetProperties(pProps, &Actual);
if(SUCCEEDED(hr) && m_pIo->IsAligned(Actual.cbAlign))
{
pPreferred->AddRef();
*ppActual = pPreferred;
return S_OK;
}
}
// create our own allocator
IMemAllocator* pAlloc;
hr = InitAllocator(&pAlloc);
if(FAILED(hr))
{
return hr;
}
//...and see if we can make it suitable
hr = pAlloc->SetProperties(pProps, &Actual);
if(SUCCEEDED(hr) && m_pIo->IsAligned(Actual.cbAlign))
{
// we need to release our refcount on pAlloc, and addref
// it to pass a refcount to the caller - this is a net nothing.
*ppActual = pAlloc;
return S_OK;
}
// failed to find a suitable allocator
pAlloc->Release();
// if we failed because of the IsAligned test, the error code will
// not be failure
if(SUCCEEDED(hr))
{
hr = VFW_E_BADALIGN;
}
return hr;
}
CAsyncOutputPin::Length(
CAsyncReader::GetPin(int n)
CAsyncReader::GetPin(int n)
CAsyncReader::GetPin(int n)
CAsyncOutputPin::Connect(
HRESULT CAsyncOutputPin::CheckMediaType(const CMediaType* pType)
CAsyncOutputPin::SyncRead(
CAsyncIo::SyncRead(
CAsyncIo::SyncReadAligned(
CAsyncRequest::Complete()
CAsyncOutputPin::SyncRead(
CAsyncIo::SyncRead(
CAsyncIo::SyncReadAligned(
CAsyncRequest::Complete()
............
结束SelectAndRender(CMemReader *pReader, IFilterGraph **ppFG)函数
CAsyncReader::GetPin(int n)
CAsyncReader::GetPin(int n)
CAsyncOutputPin::WaitForNext(
CAsyncOutputPin::SyncRead(
CAsyncReader::GetPin(int
CAsyncIo::WaitForNext(
CAsyncOutputPin::SyncRead(
CAsyncReader::GetPin(int n)
CAsyncIo::WaitForNext(
hr = pME->WaitForCompletion(INFINITE, &levCode);
CAsyncOutputPin::Request(
CAsyncIo::Request(
CAsyncIo::PutWorkItem(CAsyncRequest* pRequest)
hr = StartThread();
m_hThread = CreateThread(NULL, 0,
InitialThreadProc, // InitialThreadProc : 在线程中调用来处理一个活动的请求
this,
。。。。。。。
接下来就一直在线程中取请求,等待,处理请求中
表现在运行结果就是发现停在hr = pME->WaitForCompletion(INFINITE, &levCode);没反应了。
由于是拉模式的例子,为了调试pullpin.cpp,我们也把baseclasses放到解决方案中。
===========================================================================================================
总结:
在《DircctShow开发指南》一书中有下面一段话:
DirectShow为局部存储器传输定义了两种机制:推模式(push model)和拉模式(pull model)。在推模式中,源过滤器生成数据并提交给下一级过滤器。下一级过滤器被动的接收数据,完成处理后再传送给再下一级过滤器。在拉模式中,源过滤器与一个分析过滤器相连。分析过滤器向源过滤器请求数据后,源过滤器才传送数据以响应请求。推模式使用的是IMemInputPin接口,拉模式使用IAsyncReader接口,推模式比拉模式要更常用。
大家可以比较我的两篇文章:
<<DX90SDK SDK源码分析(二) 推模式的例子>> http://blog.csdn.net/chenyujing1234/article/details/7402831
<<DX90SDK SDK源码分析(一) 拉模式的例子>>
就可以发现上面这段话的内容了.
- // CAsyncOutputPin实现了一个输出Pin
- // 继承自IAsyncReader、CBasePin,这是对拉模式的Source Filter的基本要求
- /* IAsyncReader接口方法及描述如下:
- BeginFlush 放弃所有正在进行的数据读取
- EndFlush 与BeginFlush配对,标示Flush过程结束
- Length 得到数据总长度和当前可以读取的长度
- RequestAlloctor 要求一个输入Pin上的Sample管理器
- Request 发出一个数据请求
- SyncReadAligned 同步读取数据(边界对齐)
- SyncRead 同步读取数据
- WaitForNext 等待一个请求的完成
- ======================================================================
- 可以看出CAsyOutputPin类上实现的IAsyncReader的各个接口方法,都“委托”
- 给了CAsyncIo类对象的同名成员函数
- */
- class CAsyncOutputPin
- : public IAsyncReader,
- public CBasePin
- {