转载地址 http://blog.csdn.net/bwmwm/article/details/4562709
MSDN一开始介绍DirectShwo的时候就给出了一个列子“How To Play a File“,代码如下:
- #include <dshow.h>
- void main(void)
- {
- IGraphBuilder *pGraph = NULL;
- IMediaControl *pControl = NULL;
- IMediaEvent *pEvent = NULL;
- // Initialize the COM library.
- HRESULT hr = CoInitialize(NULL);
- if (FAILED(hr))
- {
- printf("ERROR - Could not initialize COM library");
- return;
- }
- // Create the filter graph manager and query for interfaces.
- hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
- IID_IGraphBuilder, (void **)&pGraph);
- if (FAILED(hr))
- {
- printf("ERROR - Could not create the Filter Graph Manager.");
- return;
- }
- hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
- hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);
- // Build the graph. IMPORTANT: Change this string to a file on your system.
- hr = pGraph->RenderFile(L"C://Example.avi", NULL);
- if (SUCCEEDED(hr))
- {
- // Run the graph.
- hr = pControl->Run();
- if (SUCCEEDED(hr))
- {
- // Wait for completion.
- long evCode;
- pEvent->WaitForCompletion(INFINITE, &evCode);
- // Note: Do not use INFINITE in a real application, because it
- // can block indefinitely.
- }
- }
- pControl->Release();
- pEvent->Release();
- pGraph->Release();
- CoUninitialize();
- }
这是一个控制台程序,Render会创建一个自己的窗口来播放视频。如果在MFC的对话框中执行这段代码,就会出现两个窗口,一个是Render创建的播放窗口,一个是程序的主窗口。MSDN告诉我们,可以把Render创建的窗口设置为主窗口的子窗口。这样,播放窗口就会贴附在主窗口上。使用IVideoWindow接口实现,代码如下:
- void RenderFile()
- {
- IGraphBuilder *pGraph = NULL;
- IMediaControl *pControl = NULL;
- IMediaEvent *pEvent = NULL;
- // Initialize the COM library.
- HRESULT hr = CoInitialize(NULL);
- if (FAILED(hr))
- {
- printf("ERROR - Could not initialize COM library");
- return;
- }
- // Create the filter graph manager and query for interfaces.
- hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
- IID_IGraphBuilder, (void **)&pGraph);
- if (FAILED(hr))
- {
- printf("ERROR - Could not create the Filter Graph Manager.");
- return;
- }
- hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
- hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);
- IVideoWindow* pWnd = NULL;
- hr = pGraph->QueryInterface(IID_IVideoWindow,(void**)&pWnd);
- hr = pWnd->put_Owner((OAHWND)m_hWnd);
- pWnd->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS);
- CRect rc;
- GetClientRect(&rc);
- pWnd->SetWindowPosition(rc.left,rc.top,rc.Width(),rc.Height());
- // Build the graph. IMPORTANT: Change this string to a file on your system.
- hr = pGraph->RenderFile(L"C://Example.avi", NULL);
- if (SUCCEEDED(hr))
- {
- // Run the graph.
- hr = pControl->Run();
- if (SUCCEEDED(hr))
- {
- // Wait for completion.
- long evCode;
- pEvent->WaitForCompletion(INFINITE, &evCode);
- // Note: Do not use INFINITE in a real application, because it
- // can block indefinitely.
- }
- }
- pControl->Release();
- pEvent->Release();
- pGraph->Release();
- CoUninitialize();
- }
运行程序,执行RenderFile()函数,发现效果没变,还是两个窗口,怎么回事呢?单步调试跟踪发现,pWnd->put_Owner没有返回S_OK,而是返回E_NOINTERFACE,无效的接口指针,很奇怪,pWnd是一个有效的值,但是随后的几个函数执行都是返回E_NOINTERFACE。很明显,窗口设置不成功,没辙,只好世界各地寻找不成功的原因。
对比了DXSDK/Samples/C++/DirectShow/Editing/StillCap中的例子发现,pGraph->RenderFile()函数与pWnd->put_Owner()的执行顺序反了。于是把hr = pGraph->RenderFile(L"C://Example.avi", NULL)放到hr = pGraph->QueryInterface(IID_IVideoWindow,(void**)&pWnd)之前执行,OK,达到了效果,所有执行都返回S_OK。
虽然找到了错误的地方,也达到了效果,不过,使用一项技术,总还是要弄明白原理。于是我把MSDN中相关的内容又好好的看了一遍,发现原来如此:
在这个例子中,看不到添加任何filter的影子,既没有Source Filter ,又没有Render Filter,仅仅一句RenderFile()。是的,RenderFile()干了所有的事情。
首先IGraphBuilder::RenderFile()调用IGraphBuilder::AddSourceFilter()向Graph中添加一个Source Filter。IGraphBuilder::AddSourceFilter()会根据文件扩展名或者是文件头等信息智能选取一个匹配文件的Source Filter。
然后IGraphBuilder::RenderFile()调用IGraphBuilder::Render()完成剩下的Graph的生成。IGraphBuilder::Render()会从Source Filter的output pin开始寻找每一个匹配此pin的Filter加入到链路中来,直到找到一个Render Filter为止。当整个链路完成,也就代表Graph生成,可以调用pControl->Run()运行Graph了。
虽然IVideoWindow是由Filter Graph Manager暴露,但是IVideoWindow设置属性却是对Render Filter。在没有执行RenderFile之前,Graph中没有连接RenderFile,因此IVideoWindow的设置无效。
参考资料来自MSDN:
ms-help://MS.MSDNQTR.v90.en/directshow/htm/intelligentconnect.htm
ms-help://MS.MSDNQTR.v90.en/directshow/htm/igraphbuilderaddsourcefilter.htm
ms-help://MS.MSDNQTR.v90.en/directshow/htm/igraphbuilderrenderfile.htm
ms-help://MS.MSDNQTR.v90.en/directshow/htm/usingwindowedmode.htm