人工建立一个Filter Graph
自己手动产生一个Filter Graph,首先要产生一个Filter Graph Manager的对象,然后产生两个基本点Filters: a source filter(指向媒体文件),a audio renderer filter.之后我们要使用智能化connect来连接source filter里的输出接口和audio renderer的输入接口.产生一个必要的中间的transform filter用来提供在source和renderer之间的路径.一旦这个路径被建立了,这个Filter Graph就开始执行了,它会播放媒体文件直到结束,然后停止.
以下的程序是在DSBuild.cpp里,它有四个方法.其中三个都和DSRender.cpp里的犯法是一样.这里额外的方法就是GetPin,它会在“Locating Pins and GetPins“里被详细的检查.
// DSBuild implements a very simple program to render audio files
// or the audio portion of movies.
//
int main(int argc, char* argv[])
{
IGraphBuilder *pGraph = NULL;
IMediaControl *pControl = NULL;
IMediaEvent *pEvent = NULL;
IBaseFilter *pInputFileFilter = NULL;
IBaseFilter *pDSoundRenderer = NULL;
IPin *pFileOut = NULL, *pWAVIn = NULL;
// Get the name of an audio or movie file to play.
if (!GetMediaFileName()) {
return(0);
}
// Initialize the COM library.
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if (FAILED(hr))
{
printf("ERROR - Could not initialize COM library");
return hr;
}
// Create the Filter Graph Manager object and retrieve its
// IGraphBuilder interface.
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void **)&pGraph);
if (FAILED(hr))
{
printf("ERROR - Could not create the Filter Graph Manager.");
CoUninitialize();
return hr;
}
// Now get the media control interface...
hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
if (FAILED(hr)) {
pGraph->Release();
CoUninitialize();
return hr;
}
// And the media event interface.
hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);
if (FAILED(hr)) {
pControl->Release();
pGraph->Release();
CoUninitialize();
return hr;
}
// Build the graph.
// Step one is to invoke AddSourceFilter
// with the file name we picked out earlier.
Seite 11 von 15 Chapter 3: Programming DirectShow Applications
30.10.2005 file://C:\Dokumente%20und%20Einstellungen\awolf2\Lokale%20Einstellungen\Tem...
// Should be an audio file (or a movie file with an audio track).
// AddSourceFilter instantiates the source filter,
// adds it to the graph, and returns a pointer to the filter's
// IBaseFilter interface.
#ifndef UNICODE
WCHAR wFileName[MAX_PATH];
MultiByteToWideChar(CP_ACP, 0, g_PathFileName, -1, wFileName, MAX_PATH);
hr = pGraph->AddSourceFilter(wFileName, wFileName, &pInputFileFilter);
#else
hr = pGraph->AddSourceFilter(wFileName, wFileName, &pInputFileFilter);
#endif
if (SUCCEEDED(hr)) {
// Now create an instance of the audio renderer
// and obtain a pointer to its IBaseFilter interface.
hr = CoCreateInstance(CLSID_DSoundRender, NULL,
CLSCTX_INPROC_SERVER, IID_IBaseFilter,
(void **)&pDSoundRenderer);
if (SUCCEEDED(hr)) {
// And add the filter to the filter graph
// using the member function AddFilter.
hr = pGraph->AddFilter(pDSoundRenderer, L"Audio Renderer");
if (SUCCEEDED(hr)) {
// Now we need to connect the output pin of the source
// to the input pin of the renderer.
// Obtain the output pin of the source filter.
// The local function GetPin does this.
pFileOut = GetPin(pInputFileFilter, PINDIR_OUTPUT);
if (pFileOut != NULL) { // Is the pin good?
// Obtain the input pin of the WAV renderer.
pWAVIn = GetPin(pDSoundRenderer, PINDIR_INPUT);
if (pWAVIn != NULL) { // Is the pin good?
// Connect the pins together:
// We use the Filter Graph Manager's
// member function Connect,
// which uses Intelligent Connect.
// If this fails, DirectShow couldn't
// render the media file.
hr = pGraph->Connect(pFileOut, pWAVIn);
}
}
}
}
}
if (SUCCEEDED(hr))
{
// Run the graph.
hr = pControl->Run();
if (SUCCEEDED(hr))
{
// Wait for completion.
long evCode;
pEvent->WaitForCompletion(INFINITE, &evCode);
Seite 12 von 15 Chapter 3: Programming DirectShow Applications
30.10.2005 file://C:\Dokumente%20und%20Einstellungen\awolf2\Lokale%20Einstellungen\Tem...
// Note: Do not use INFINITE in a real application
// because it can block indefinitely.
}
hr = pControl->Stop();
}
// Before we finish, save the filter graph to a file.
SaveGraphFile(pGraph, L"C:\\MyGraph.GRF");
// Now release everything we instantiated--
// that is, if it got instantiated.
if(pFileOut) { // If it exists, non-NULL
pFileOut->Release(); // Then release it
}
if (pWAVIn) {
pWAVIn->Release();
}
if (pInputFileFilter) {
pInputFileFilter->Release();
}
if (pDSoundRenderer) {
pDSoundRenderer->Release();
}
pControl->Release();
pEvent->Release();
pGraph->Release();
CoUninitialize();
return 0;
}
一开始所有做的一切都是为了建立filter graph.在这点上,我们需要使用一个IGraphBuilder的新方法AddSourceFilter,这个方法是把文件名作为一个参数并且返回一个指向IbaseFilter的指针.
紧接着我们使用CoCreateInstance来建立audio renderer filter,其中我们使用Class ID CLSID_DsoundRender作为参数并且返回IBaseFilter接口.一旦filter被成功地建立起来之后,我们就使用IGraphBuilder::AddFilter将它添加到filter graph里去.
AddFilter里有两个参数.第一个是要被添加的指向IbaseFilter的指针.
现在我们在filter graph里有两个filters:一个只指向文件的source filter,一个是输出文件的audio output filter.它们需要通过transform filter被连接到一起.我们使用智能化的connect来达成这一目的.
首先我们需要获得Ipin接口,对于source filter的输出和render的输入都需要.我们使用GetPin方法来获得我们想要连接的Pins上的接口.一旦我们得到了,我们就可以执行IGraphBuilder::Connect了. Connect里面的两个参数是你想连接的两个Pins.如果成功的话,这两个Pins就会通过一系列的中间filters被连接起来.如果失败的话,就不能够建立起source和renderer之间的路径.有可能是因为source file中的媒体类型不被DirectShow所支持或者是因为文件里本身不包括任何audio.
和DSRender一样.这个应用程序也使用IMediaControl::Run来开始filter graph的执行...................