Loading a Graph From an External Process

GraphEdit可以加载其他进程创建的filter Graph,利用这个特性,只使用少量的代码,你可以清楚地看到你的应用程序创建的所有的filter Graph。

这个特性只有win2000,XP才支持。

应用程序首先必须在Running Object Table (ROT).中注册一个filter graph的实例。ROT是一个全局的对象表,用来查看所有正在运行的对象。对象都是通过moniker注册到rot上。Graph Edit通过搜索ROT中和指定名字moniker就ok。

!FilterGraph X pid Y

这里,x是Filter Graph Manager的地址,y是进程ID,也是16进制。

当你的应用程序创建filter graph的时候,调用下面的代码:

				
  1. HRESULT AddToRot(IUnknown *pUnkGraph, DWORD *pdwRegister) 
  2. IMoniker * pMoniker; 
  3. IRunningObjectTable *pROT; 
  4. if (FAILED(GetRunningObjectTable(0, &pROT))) { 
  5. return E_FAIL; 
  6. WCHAR wsz[256]; 
  7. wsprintfW(wsz, L"FilterGraph x pid x", (DWORD_PTR)pUnkGraph, GetCurrentProcessId()); 
  8. HRESULT hr = CreateItemMoniker(L"!", wsz, &pMoniker); 
  9. if (SUCCEEDED(hr)) { 
  10. hr = pROT->Register(ROTFLAGS_REGISTRATIONKEEPSALIVE, pUnkGraph, 
  11. pMoniker, pdwRegister); 
  12. pMoniker->Release(); 
  13. pROT->Release(); 
  14. return hr; 

  这个函数创建了一个moniker作为filter graph在ROT中的入口,第一个参数是指向filter Graph的指针,第二个参数返回filter graph在ROT中的入口。当应用程序销毁filter graph的时候,一定要调用下面的函数来删除这个ROT入口:

				
  1. void RemoveFromRot(DWORD pdwRegister) 
  2. IRunningObjectTable *pROT; 
  3. if (SUCCEEDED(GetRunningObjectTable(0, &pROT))) { 
  4. pROT->Revoke(pdwRegister); 
  5. pROT->Release(); 

  下面的代码演示了如何调用上面的两个函数:

				
  1. IGraphBuilder *pGraph; 
  2. DWORD dwRegister; 
  3.  
  4. // Create the filter graph manager. 
  5. CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, 
  6. IID_IGraphBuilder, (void **)&pGraph); 
  7. #ifdef _DEBUG 
  8. hr = AddToRot(pGraph, &dwRegister); 
  9. #endif 
  10.  
  11. // Rest of the application (not shown). 
  12.  
  13. #ifdef _DEBUG 
  14. RemoveFromRot(dwRegister); 
  15. #endif 
  16. pGraph->Release(); 

  同时运行你的应用程序和GraphEdit,你就可以在GraphEdit中查看你应用程序中的filter graph了。在GraphEdit中,如下:

DirectShow入门之模拟构建Graph(2)
图8

 然后就出现了下面的对话框

DirectShow入门之模拟构建Graph(2)
图9

   Saving a Filter Graph to a GraphEdit File

  下面的代码演示了如何保存一个GraphEdit(.gif)文件,这个可以用来调试你的应用程序。

				
  1. HRESULT SaveGraphFile(IGraphBuilder *pGraph, WCHAR *wszPath) 
  2. const WCHAR wszStreamName[] = L"ActiveMovieGraph"
  3. HRESULT hr; 
  4.  
  5. IStorage *pStorage = NULL; 
  6. hr = StgCreateDocfile( 
  7. wszPath, 
  8. STGM_CREATE | STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 
  9. 0, &pStorage); 
  10. if(FAILED(hr)) 
  11. return hr; 
  12.  
  13. IStream *pStream; 
  14. hr = pStorage->CreateStream( 
  15. wszStreamName, 
  16. STGM_WRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE, 
  17. 0, 0, &pStream); 
  18. if (FAILED(hr)) 
  19. pStorage->Release(); 
  20. return hr; 
  21.  
  22. IPersistStream *pPersist = NULL; 
  23. pGraph->QueryInterface(IID_IPersistStream, (void**)&pPersist); 
  24. hr = pPersist->Save(pStream, TRUE); 
  25. pStream->Release(); 
  26. pPersist->Release(); 
  27. if (SUCCEEDED(hr)) 
  28. hr = pStorage->Commit(STGC_DEFAULT); 
  29. pStorage->Release(); 
  30. return hr; 

  例如,下面的代码创建了文件回放的graph并保存为MyGraph.grf:

				
  1. void __cdecl main(void
  2. HRESULT hr; 
  3. IGraphBuilder *pGraph; 
  4. CoInitialize(NULL); 
  5.  
  6. // Create the Filter Graph Manager and render a file. 
  7. CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, 
  8. IID_IGraphBuilder, reinterpret_cast<void**>(&pGraph)); 
  9. hr = pGraph->RenderFile(L"C:\Video.avi", NULL); 
  10.  
  11. if (SUCCEEDED(hr)) 
  12. hr = SaveGraphFile(pGraph, L"C:\MyGraph.grf"); 
  13.  
  14. pGraph->Release(); 
  15. CoUninitialize(); 

  Loading a GraphEdit File Programmatically

  在应用程序中可以通过IPersistStream接口来加载一个GraphEdit (.grf) file,实例代码如下:

				
  1. HRESULT LoadGraphFile(IGraphBuilder *pGraph, const WCHAR* wszName) 
  2. IStorage *pStorage = 0; 
  3. if (S_OK != StgIsStorageFile(wszName)) 
  4. return E_FAIL; 
  5. HRESULT hr = StgOpenStorage(wszName, 0, 
  6. STGM_TRANSACTED | STGM_READ | STGM_SHARE_DENY_WRITE, 
  7. 0, 0, &pStorage); 
  8. if (FAILED(hr)) 
  9. return hr; 
  10. IPersistStream *pPersistStream = 0; 
  11. hr = pGraph->QueryInterface(IID_IPersistStream, 
  12. reinterpret_cast<void**>(&pPersistStream)); 
  13. if (SUCCEEDED(hr)) 
  14. IStream *pStream = 0; 
  15. hr = pStorage->OpenStream(L"ActiveMovieGraph", 0, 
  16. STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream); 
  17. if(SUCCEEDED(hr)) 
  18. hr = pPersistStream->Load(pStream); 
  19. pStream->Release(); 
  20. pPersistStream->Release(); 
  21. pStorage->Release(); 
  22. return hr; 

  必须要注意的是,GraphEdit文件只是用来测试或者调试用的,并不是为了让终端客户用的。

  作者:智慧的鱼

  摘要:本篇文档主要讲述如何使用GraphEdit来模拟构建graph图,测试你的filter。

GraphEdit概述

GraphEdit是一个很有用的工具,可以用来构建graph图。通过GraphEdit,你可以在开发代码之前进行一下体验,你也可以装载一个你的应用程序创建的Graph文件。如果你想开发一个自己的filter,GraphEdit 给你提供了一个快速测试的方法:将你的filter添加到graph中,然后运行graph。如果你是一个Directshow的初学者,那么通过GraphEdit你可以熟悉Filter和Dshow的特性。

下面图表演示了GraphEdit如何构建了一个简单的graph。

DirectShow入门之模拟构建Graph
图1


每一个矩形代表一个Filter,每一个filter的边上的小矩形代表了pin,输入pin在filter的左边,输出pin在Filter的右边,箭头代表两个pin的连接方向。

通过GraphEdit,你可以做到下面的事情:

1、可视化的创建一个Graph,可以动态的拖拉来调整filter。

2、可以模拟如何构建一个graph。

3、运行,停止,暂停,see一个graph。

4、可以看看你的机器上都注册了那些filter,以及这些filter的信息

5、查看filter的属性页

6、查看pin连接时采用的媒体类型。

使用GraphEdit

如果你安装了DirectX的SDK,GraphEdit就会出现在你的开始菜单中找到GraphEdit,启动它。如下图

DirectShow入门之模拟构建Graph
图2


构建一个文件回放的Graph

GraphEdit可以自动的构建一个文件回放Graph。这个特性其实类似于在应用程序中调用
IGraphBuilder::RenderFile方法。从文件菜单中,选择Render Media File,然后出现一个文件选择对话框,选择一个多媒体文件后单击打开,GraphEdit会自动地建立一个Filter Graph来播放你选择的文件。

你也可以播放一个网络上媒体文件,从文件菜单中,选择Render URL,也会出现一个选择URL的对话框。其他同上。

构建一个普通的Graph图

使用你机器上注册的filter,GraphEdit可以构建一个普通的Filter graph,从Graph菜单中,选择Insert Filters,会出现一个对话框,如下图:

DirectShow入门之模拟构建Graph
图3


在这个对话框中列出了所有在你机器上注册的Filter的信息。选择filter的名字,然后单击Insert Filters按钮,或者双击filter的名字,filter就会自动添加到graph中,添加完filter以后,你就拖动鼠标,将一个Filter 的输出pin和另一个Fiter的输入pin连接起来。如果pin接受这个连接,GraphEdite就会用一个带箭头的

下面的图是一个捕捉桌面的graph图

DirectShow入门之模拟构建Graph
图4


Run the Graph

当你在GraphEdit中构建好一个Filter graph的时候,你可以让你的graph运行一下看是否和你期望的一样。Graph菜单中包含了Play,Pause,和Stop命令,这些命令会触发IMediaControl。

接口的Run, Pause, and Stop,GraphEdit的工具栏也有代表这三个命令的按钮,见下图,单击第一个按钮就开始运行你的Graph图了

DirectShow入门之模拟构建Graph
图 5


注:GraphEdit的Stop命令首先会暂停Graph,然后Seek到时间的零点(我们坚定graph是可Seek的)。对于文件的回放,这个命令会将视频窗口的图像设置为第一桢,然后GraphEdit才调用IMediaControl::Stop.

查看属性View Property Pages

一些Filter提供了属性页可以让用户设置Filter的属性。鼠标右键单击filter,在弹出的菜单上选择Properties,就会弹出Filter的属性页设置对话框,用户可以从这里设置属性。

DirectShow入门之模拟构建Graph
图6

DirectShow入门之模拟构建Graph
图7
 

 

Loading a Graph From an External Process

  GraphEdit可以加载其他进程创建的filter Graph,利用这个特性,只使用少量的代码,你可以清楚地看到你的应用程序创建的所有的filter Graph。

这个特性只有win2000,XP才支持。

应用程序首先必须在Running Object Table (ROT).中注册一个filter graph的实例。ROT是一个全局的对象表,用来查看所有正在运行的对象。对象都是通过moniker注册到rot上。Graph Edit通过搜索ROT中和指定名字moniker就ok。

!FilterGraph X pid Y

这里,x是Filter Graph Manager的地址,y是进程ID,也是16进制。

当你的应用程序创建filter graph的时候,调用下面的代码:

HRESULT AddToRot(IUnknown *pUnkGraph, DWORD *pdwRegister)
{
IMoniker * pMoniker;
IRunningObjectTable *pROT;
if (FAILED(GetRunningObjectTable(0, &pROT))) {
return E_FAIL;
}
WCHAR wsz[256];
wsprintfW(wsz, L"FilterGraph x pid x", (DWORD_PTR)pUnkGraph, GetCurrentProcessId());
HRESULT hr = CreateItemMoniker(L"!", wsz, &pMoniker);
if (SUCCEEDED(hr)) {
hr = pROT->Register(ROTFLAGS_REGISTRATIONKEEPSALIVE, pUnkGraph,
pMoniker, pdwRegister);
pMoniker->Release();
}
pROT->Release();
return hr;
}


这个函数创建了一个moniker作为filter graph在ROT中的入口,第一个参数是指向filter Graph的指针,第二个参数返回filter graph在ROT中的入口。当应用程序销毁filter graph的时候,一定要调用下面的函数来删除这个ROT入口:

void RemoveFromRot(DWORD pdwRegister)
{
IRunningObjectTable *pROT;
if (SUCCEEDED(GetRunningObjectTable(0, &pROT))) {
pROT->Revoke(pdwRegister);
pROT->Release();
}
}


下面的代码演示了如何调用上面的两个函数:

IGraphBuilder *pGraph;
DWORD dwRegister;

// Create the filter graph manager.
CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void **)&pGraph);
#ifdef _DEBUG
hr = AddToRot(pGraph, &dwRegister);
#endif

// Rest of the application (not shown).

#ifdef _DEBUG
RemoveFromRot(dwRegister);
#endif
pGraph->Release();


同时运行你的应用程序和GraphEdit,你就可以在GraphEdit中查看你应用程序中的filter graph了。在GraphEdit中,如下:

DirectShow入门之模拟构建Graph(2)
图8


然后就出现了下面的对话框

DirectShow入门之模拟构建Graph(2)
图9


Saving a Filter Graph to a GraphEdit File

下面的代码演示了如何保存一个GraphEdit(.gif)文件,这个可以用来调试你的应用程序。

HRESULT SaveGraphFile(IGraphBuilder *pGraph, WCHAR *wszPath)
{
const WCHAR wszStreamName[] = L"ActiveMovieGraph";
HRESULT hr;

IStorage *pStorage = NULL;
hr = StgCreateDocfile(
wszPath,
STGM_CREATE | STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
0, &pStorage);
if(FAILED(hr))
{
return hr;
}

IStream *pStream;
hr = pStorage->CreateStream(
wszStreamName,
STGM_WRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE,
0, 0, &pStream);
if (FAILED(hr))
{
pStorage->Release();
return hr;
}

IPersistStream *pPersist = NULL;
pGraph->QueryInterface(IID_IPersistStream, (void**)&pPersist);
hr = pPersist->Save(pStream, TRUE);
pStream->Release();
pPersist->Release();
if (SUCCEEDED(hr))
{
hr = pStorage->Commit(STGC_DEFAULT);
}
pStorage->Release();
return hr;
}


例如,下面的代码创建了文件回放的graph并保存为MyGraph.grf:

void __cdecl main(void)
{
HRESULT hr;
IGraphBuilder *pGraph;
CoInitialize(NULL);

// Create the Filter Graph Manager and render a file.
CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, reinterpret_cast<void**>(&pGraph));
hr = pGraph->RenderFile(L"C:\Video.avi", NULL);

if (SUCCEEDED(hr))
{
hr = SaveGraphFile(pGraph, L"C:\MyGraph.grf");
}

pGraph->Release();
CoUninitialize();
}


Loading a GraphEdit File Programmatically

在应用程序中可以通过IPersistStream接口来加载一个GraphEdit (.grf) file,实例代码如下:

HRESULT LoadGraphFile(IGraphBuilder *pGraph, const WCHAR* wszName)
{
IStorage *pStorage = 0;
if (S_OK != StgIsStorageFile(wszName))
{
return E_FAIL;
}
HRESULT hr = StgOpenStorage(wszName, 0,
STGM_TRANSACTED | STGM_READ | STGM_SHARE_DENY_WRITE,
0, 0, &pStorage);
if (FAILED(hr))
{
return hr;
}
IPersistStream *pPersistStream = 0;
hr = pGraph->QueryInterface(IID_IPersistStream,
reinterpret_cast<void**>(&pPersistStream));
if (SUCCEEDED(hr))
{
IStream *pStream = 0;
hr = pStorage->OpenStream(L"ActiveMovieGraph", 0,
STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream);
if(SUCCEEDED(hr))
{
hr = pPersistStream->Load(pStream);
pStream->Release();
}
pPersistStream->Release();
}
pStorage->Release();
return hr;
}


必须要注意的是,GraphEdit文件只是用来测试或者调试用的,并不是为了让终端客户用的。

(caiweihui)