昨天努了一天,終於搞完了一個全手動連接的filter graph 程序,雖然很簡單,但是還是費了老大的勁。不扯了,上菜……
開發環境:Vista+VS2008+DX9.0,控制檯應用程序(便於調試)
第一步:在GraphEdit中模擬視頻播放過程。
我的graph圖如下,如果不能正常播放,先要註冊需要的filter,我就註冊了MPEG Layer-3 Decoder:
第二步:動手編程吧。
1、包含文件:
#include "stdafx.h"
#include <dshow.h>
#include <dshow.h>
#pragma comment(lib, "strmiids.lib")
2、定義自己註冊的filter,在main()函數前進行定義:
static const GUID CLSID_AudioDecoder=
{ 0x38BE3000,0xDBF4,0x11D0,{0x86,0x0e,0x00,0xa0,0x24,0xcf,0xef,0x6d}};
{ 0x38BE3000,0xDBF4,0x11D0,{0x86,0x0e,0x00,0xa0,0x24,0xcf,0xef,0x6d}};
3、定義需要用到的COM組件:
IGraphBuilder *pGraph = NULL;
IMediaControl *pControl = NULL;
IMediaEvent *pEvent = NULL;
IBaseFilter *pInputFileFilter = NULL;
IBaseFilter *pAviSplitter= NULL;
IBaseFilter *pVideoDecoder= NULL;
IBaseFilter *pVideoColour= NULL;
IBaseFilter *pAudioDecoder= NULL;
IBaseFilter *pDVideoRenderer=NULL;
IBaseFilter *pDSoundRenderer = NULL;
IPin *pFileOut = NULL, *pSplitterIn=NULL,
*pSplitterOut1=NULL,*pSplitterOut2=NULL,
*pVideoDecIn = NULL,*pVideoDecOut = NULL,*pVideoColIn = NULL,*pVideoColOut = NULL,
*pVideoRenIn = NULL,*pAudioDecIn = NULL,*pAudioDecOut = NULL,*pAudioRenIn = NULL;
IMediaControl *pControl = NULL;
IMediaEvent *pEvent = NULL;
IBaseFilter *pInputFileFilter = NULL;
IBaseFilter *pAviSplitter= NULL;
IBaseFilter *pVideoDecoder= NULL;
IBaseFilter *pVideoColour= NULL;
IBaseFilter *pAudioDecoder= NULL;
IBaseFilter *pDVideoRenderer=NULL;
IBaseFilter *pDSoundRenderer = NULL;
IPin *pFileOut = NULL, *pSplitterIn=NULL,
*pSplitterOut1=NULL,*pSplitterOut2=NULL,
*pVideoDecIn = NULL,*pVideoDecOut = NULL,*pVideoColIn = NULL,*pVideoColOut = NULL,
*pVideoRenIn = NULL,*pAudioDecIn = NULL,*pAudioDecOut = NULL,*pAudioRenIn = NULL;
4、COM庫初始化:
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if (FAILED(hr))
{
printf("ERROR - Could not initialize COM library");
return hr;
}
if (FAILED(hr))
{
printf("ERROR - Could not initialize COM library");
return hr;
}
5、創建濾波器鏈表管理器(Filter Graph Manager),獲得控制、事件的接口
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;
}
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;
}
6、添加源濾波器,我指定了我的D盤上的start.avi文件:
hr = pGraph->AddSourceFilter(L"d://start.avi",L"source",&pInputFileFilter);
7、創建連接AVI分流器
hr = CoCreateInstance(CLSID_AviSplitter, NULL,CLSCTX_INPROC_SERVER,
IID_IBaseFilter,(void **)&pAviSplitter);
if (SUCCEEDED(hr))
{
hr = pGraph->AddFilter(pAviSplitter, L"Avi Splitter");
//連接Source和splitter
if (SUCCEEDED(hr))
{
hr = CoCreateInstance(CLSID_AviSplitter, NULL,CLSCTX_INPROC_SERVER,
IID_IBaseFilter,(void **)&pAviSplitter);
if (SUCCEEDED(hr))
{
hr = pGraph->AddFilter(pAviSplitter, L"Avi Splitter");
//連接Source和splitter
if (SUCCEEDED(hr))
{
//獲得空閒(未連接)的輸出引腳
pFileOut = GetPin(pInputFileFilter, PINDIR_OUTPUT);//GetPin函數很重要,在最後面講
if (pFileOut!= NULL)
{
// Is the pin unconnected? Obtain the input pin of the Avi Splitter.
pSplitterIn= GetPin(pAviSplitter,PINDIR_INPUT);
if (pSplitterIn!= NULL)
{
// Is the pin good? Connect the pins together:
hr = pGraph->ConnectDirect(pFileOut, pSplitterIn,NULL);
}
}
}
}
pFileOut = GetPin(pInputFileFilter, PINDIR_OUTPUT);//GetPin函數很重要,在最後面講
if (pFileOut!= NULL)
{
// Is the pin unconnected? Obtain the input pin of the Avi Splitter.
pSplitterIn= GetPin(pAviSplitter,PINDIR_INPUT);
if (pSplitterIn!= NULL)
{
// Is the pin good? Connect the pins together:
hr = pGraph->ConnectDirect(pFileOut, pSplitterIn,NULL);
}
}
}
}
8、創建連接視頻解碼器
hr = CoCreateInstance(CLSID_AVIDec, NULL,CLSCTX_INPROC_SERVER,
IID_IBaseFilter,(void **)&pVideoDecoder);
if (SUCCEEDED(hr))
{
hr = pGraph->AddFilter(pVideoDecoder, L"Video Decoder");
//連接splitter和Video Decoder
if (SUCCEEDED(hr))
{
pSplitterOut1= GetPin(pAviSplitter,PINDIR_OUTPUT);//獲取分流器輸出引腳1
if (pSplitterOut1!= NULL)
{
// Is the pin good? Obtain the input pin of the Avi Decoder.
pVideoDecIn=GetPin(pVideoDecoder,PINDIR_INPUT);//獲取AVI解碼器輸入引腳
if (pVideoDecIn!= NULL)
{
hr = pGraph->ConnectDirect(pSplitterOut1,pVideoDecIn,NULL);
}
}
}
}
hr = CoCreateInstance(CLSID_AVIDec, NULL,CLSCTX_INPROC_SERVER,
IID_IBaseFilter,(void **)&pVideoDecoder);
if (SUCCEEDED(hr))
{
hr = pGraph->AddFilter(pVideoDecoder, L"Video Decoder");
//連接splitter和Video Decoder
if (SUCCEEDED(hr))
{
pSplitterOut1= GetPin(pAviSplitter,PINDIR_OUTPUT);//獲取分流器輸出引腳1
if (pSplitterOut1!= NULL)
{
// Is the pin good? Obtain the input pin of the Avi Decoder.
pVideoDecIn=GetPin(pVideoDecoder,PINDIR_INPUT);//獲取AVI解碼器輸入引腳
if (pVideoDecIn!= NULL)
{
hr = pGraph->ConnectDirect(pSplitterOut1,pVideoDecIn,NULL);
}
}
}
}
9、創建連接視頻色彩轉換器
hr = CoCreateInstance(CLSID_Colour, NULL,CLSCTX_INPROC_SERVER,
IID_IBaseFilter,(void **)&pVideoColour);
if (SUCCEEDED(hr))
{
hr = pGraph->AddFilter(pVideoColour, L"Video Colour");
//連接Video Decoder和Video Colour
if (SUCCEEDED(hr))
{
pVideoDecOut= GetPin(pVideoDecoder,PINDIR_OUTPUT);//獲取解碼器輸出引腳
if (pVideoDecOut!= NULL)
{
pVideoColIn=GetPin(pVideoColour,PINDIR_INPUT);//獲取色彩轉換器輸入引腳
if (pVideoColIn!= NULL)
{
hr = pGraph->ConnectDirect(pVideoDecOut,pVideoColIn,NULL);
}
}
}
}
hr = CoCreateInstance(CLSID_Colour, NULL,CLSCTX_INPROC_SERVER,
IID_IBaseFilter,(void **)&pVideoColour);
if (SUCCEEDED(hr))
{
hr = pGraph->AddFilter(pVideoColour, L"Video Colour");
//連接Video Decoder和Video Colour
if (SUCCEEDED(hr))
{
pVideoDecOut= GetPin(pVideoDecoder,PINDIR_OUTPUT);//獲取解碼器輸出引腳
if (pVideoDecOut!= NULL)
{
pVideoColIn=GetPin(pVideoColour,PINDIR_INPUT);//獲取色彩轉換器輸入引腳
if (pVideoColIn!= NULL)
{
hr = pGraph->ConnectDirect(pVideoDecOut,pVideoColIn,NULL);
}
}
}
}
10、創建連接視頻渲染器
hr = CoCreateInstance(CLSID_VideoRendererDefault, NULL,CLSCTX_INPROC_SERVER,
IID_IBaseFilter,(void **)&pDVideoRenderer);
if (SUCCEEDED(hr))
{
hr = pGraph->AddFilter(pDVideoRenderer, L"Video Renderer");
//連接Video Decoder和Video Renderer
if (SUCCEEDED(hr))
{
pVideoColOut= GetPin(pVideoColour,PINDIR_OUTPUT);//獲取AVI解碼器輸出引腳
if (pVideoColOut!= NULL)
{
pVideoRenIn=GetPin(pDVideoRenderer,PINDIR_INPUT);//獲取AVI渲染器輸入引腳
if (pVideoRenIn!= NULL)
{
hr = pGraph->ConnectDirect(pVideoColOut,pVideoRenIn,NULL);
}
}
}
}
hr = CoCreateInstance(CLSID_VideoRendererDefault, NULL,CLSCTX_INPROC_SERVER,
IID_IBaseFilter,(void **)&pDVideoRenderer);
if (SUCCEEDED(hr))
{
hr = pGraph->AddFilter(pDVideoRenderer, L"Video Renderer");
//連接Video Decoder和Video Renderer
if (SUCCEEDED(hr))
{
pVideoColOut= GetPin(pVideoColour,PINDIR_OUTPUT);//獲取AVI解碼器輸出引腳
if (pVideoColOut!= NULL)
{
pVideoRenIn=GetPin(pDVideoRenderer,PINDIR_INPUT);//獲取AVI渲染器輸入引腳
if (pVideoRenIn!= NULL)
{
hr = pGraph->ConnectDirect(pVideoColOut,pVideoRenIn,NULL);
}
}
}
}
11、視頻流連接完畢,音頻流類似,所以在此一步到位。
// 創建連接音頻解碼器
hr = CoCreateInstance(CLSID_AudioDecoder, NULL,CLSCTX_INPROC_SERVER,
IID_IBaseFilter,(void **)&pAudioDecoder);
if (SUCCEEDED(hr))
{
hr = pGraph->AddFilter(pAudioDecoder, L"Audio Decoder");
//連接splitter和Video Decoder
if (SUCCEEDED(hr))
{
pSplitterOut2= GetPin(pAviSplitter,PINDIR_OUTPUT);//獲取分流器輸出引腳2,兩個輸出引腳啊開始不知道怎麼搞
hr = CoCreateInstance(CLSID_AudioDecoder, NULL,CLSCTX_INPROC_SERVER,
IID_IBaseFilter,(void **)&pAudioDecoder);
if (SUCCEEDED(hr))
{
hr = pGraph->AddFilter(pAudioDecoder, L"Audio Decoder");
//連接splitter和Video Decoder
if (SUCCEEDED(hr))
{
pSplitterOut2= GetPin(pAviSplitter,PINDIR_OUTPUT);//獲取分流器輸出引腳2,兩個輸出引腳啊開始不知道怎麼搞
if (pSplitterOut2!= NULL)
{
pAudioDecIn=GetPin(pAudioDecoder,PINDIR_INPUT);//獲取AVI解碼器輸入引腳
if (pAudioDecIn!= NULL)
{
// Is the pin good? Connect the pins together:
hr = pGraph->ConnectDirect(pSplitterOut2,pAudioDecIn,NULL);
}
}
}
}
//// 創建連接音頻渲染器
hr = CoCreateInstance(CLSID_DSoundRender, NULL,CLSCTX_INPROC_SERVER,
IID_IBaseFilter,(void **)&pDSoundRenderer);
if (SUCCEEDED(hr))
{
hr = pGraph->AddFilter(pDSoundRenderer, L"Audio Renderer");
if (SUCCEEDED(hr))
{
pAudioDecOut= GetPin(pAudioDecoder, PINDIR_OUTPUT);//獲取音頻解碼器輸出引腳
if (pAudioDecOut!= NULL)
{
pAudioRenIn= GetPin(pDSoundRenderer,PINDIR_INPUT);//獲取音頻渲染器輸入引腳
if (pAudioRenIn!= NULL)
{
hr = pGraph->ConnectDirect(pAudioDecOut,pAudioRenIn,NULL);
}
}
}
}
//音頻渲染器創建連接完畢
{
pAudioDecIn=GetPin(pAudioDecoder,PINDIR_INPUT);//獲取AVI解碼器輸入引腳
if (pAudioDecIn!= NULL)
{
// Is the pin good? Connect the pins together:
hr = pGraph->ConnectDirect(pSplitterOut2,pAudioDecIn,NULL);
}
}
}
}
//// 創建連接音頻渲染器
hr = CoCreateInstance(CLSID_DSoundRender, NULL,CLSCTX_INPROC_SERVER,
IID_IBaseFilter,(void **)&pDSoundRenderer);
if (SUCCEEDED(hr))
{
hr = pGraph->AddFilter(pDSoundRenderer, L"Audio Renderer");
if (SUCCEEDED(hr))
{
pAudioDecOut= GetPin(pAudioDecoder, PINDIR_OUTPUT);//獲取音頻解碼器輸出引腳
if (pAudioDecOut!= NULL)
{
pAudioRenIn= GetPin(pDSoundRenderer,PINDIR_INPUT);//獲取音頻渲染器輸入引腳
if (pAudioRenIn!= NULL)
{
hr = pGraph->ConnectDirect(pAudioDecOut,pAudioRenIn,NULL);
}
}
}
}
//音頻渲染器創建連接完畢
12、所有的都連接好了,下面的控制就根據自己需要定,我就不寫了大同小異,還有釋放部分,我還不太懂就不誤導大家了。下面看GetPin()函數,特別注意這個函數適合處理多個同方向的引腳查詢。
IPin* GetPin(IBaseFilter *pFilter, PIN_DIRECTION dir)//查找 dir方向上的空閒PIN
{
IEnumPins* pEnumPins;
IPin* pOutpin;
PIN_DIRECTION pDir;
pFilter->EnumPins(&pEnumPins);
{
IEnumPins* pEnumPins;
IPin* pOutpin;
PIN_DIRECTION pDir;
pFilter->EnumPins(&pEnumPins);
while (pEnumPins->Next(1,&pOutpin,NULL)==S_OK)
{
pOutpin->QueryDirection(&pDir);
if (pDir==dir)//方向對了
{
IPin *pTmp=0;
HRESULT hr=pOutpin->ConnectedTo(&pTmp);
if (SUCCEEDED(hr))// 已經連接了,不是我們想要的
{
pOutpin->QueryDirection(&pDir);
if (pDir==dir)//方向對了
{
IPin *pTmp=0;
HRESULT hr=pOutpin->ConnectedTo(&pTmp);
if (SUCCEEDED(hr))// 已經連接了,不是我們想要的
;
else //第一個未連接的,就是它了
{
pEnumPins->Release();
return pOutpin;
}
}
pOutpin->Release();
}
pEnumPins->Release();
return 0;
}
else //第一個未連接的,就是它了
{
pEnumPins->Release();
return pOutpin;
}
}
pOutpin->Release();
}
pEnumPins->Release();
return 0;
}
結束語:
一切OK,調試一下沒問題就可以收工了,我的反正沒問題,呵呵
參考資料:
1、Visual C++音頻/視頻處理技術及工程實踐。路錦正,周冬梅。電子工業出版社,