GUID
过滤器图管理器的类标识;过滤器类标识;媒体类型中的主要类型,子类型,格式类型;过滤器类别;它们的类型都为GUID。
前面使用CoCreateInstance函数创建过滤器图管理器时,参数1为CLSID_FilterGraph,它为过滤器图管理器的类标识,类型为GUID。GUID由4个参数组成,第1个参数类型为unsigned long;第2个参数类型为unsigned short;第3个参数类型为unsigned short;第4个参数类型为unsigned char数组,数组大小为8。
GUID guid = CLSID_FilterGraph;
guid.Data1;//unsigned long guid.Data1==0xe436ebb3
guid.Data2;//unsigned short guid.Data2==0x524f
guid.Data3;//unsigned short guid.Data3==0x11ce
guid.Data4;//unsigned char* guid.Data4=={0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}
CLSID_FilterGraph是过滤器图管理器的类标识定义。
如果将CLSID_FilterGraph转换为值表示形式,则为:
{0xe436ebb3, 0x524f, 0x11ce, 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}
它的字符表示形式为:
{E436EBB3-524F-11CE-9F53-0020AF0BA770}
几种表示形式之间的转换方法如下:
将GUID转换为字符串表示形式
GUID guid = CLSID_FilterGraph;
//或
GUID guid = { 0xe436ebb3, 0x524f, 0x11ce, 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 };
LPWSTR lp = NULL;
HRESULT hr = StringFromCLSID(guid, (LPOLESTR*)(&lp));//将GUID转换为字符串形式
//lp=={E436EBB3-524F-11CE-9F53-0020AF0BA770}
CoTaskMemFree(lp);//释放StringFromCLSID分配的内存
将字符串表示形式转换为GUID
GUID guid;
LPWSTR lp = L"{E436EBB3-524F-11CE-9F53-0020AF0BA770}";
HRESULT hr = CLSIDFromString((LPCOLESTR)lp, &guid);//guid==CLSID_FilterGraph
将GUID转换为值形式
GUID guid = CLSID_FilterGraph;
CString ss;
ss.Format(L"{0x%0*x, 0x%0*x, 0x%0*x, 0x%0*x, 0x%0*x, 0x%0*x, 0x%0*x, 0x%0*x, 0x%0*x, 0x%0*x, 0x%0*x}", 8, guid.Data1, 4, guid.Data2, 4, guid.Data3, 2, guid.Data4[0], 2, guid.Data4[1], 2, guid.Data4[2], 2, guid.Data4[3], 2, guid.Data4[4], 2, guid.Data4[5], 2, guid.Data4[6], 2, guid.Data4[7]);//ss=={ 0xe436ebb3, 0x524f, 0x11ce, 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 }
如果你要编写自己的过滤器,可能还需要创建GUID。
创建GUID
使用代码创建GUID:
GUID guid;
HRESULT hr = CoCreateGuid(&guid);
使用Visual Studio创建GUID:
在Visual Studio界面,选择主菜单“工具”,在弹出菜单中,选择“创建GUID”;弹出创建GUID窗口,选择GUID格式,点击“新建GUID”按钮。然后点击“复制”;粘贴到你的代码中。

使用上面方法创建GUID,可以确保GUID在你的系统中是唯一的。
过滤器类别
CLSID_ActiveMovieCategories是过滤器元类别,我们使用系统设备枚举器,枚举元类别下的类别:
HRESULT hr;
ICreateDevEnum* pSysDevEnum = NULL;
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pSysDevEnum));//创建系统设备枚举器
if (hr != S_OK)
{
return S_FALSE;
}
IEnumMoniker* pEnumCat;
hr = pSysDevEnum->CreateClassEnumerator(CLSID_ActiveMovieCategories, &pEnumCat, 0);//获取元类别的类枚举器
if (hr == S_OK)
{
IMoniker* pMoniker = NULL;
ULONG cFetched;
while (pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK)
{
IPropertyBag* pPropBag;
hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pPropBag);
if (hr == S_OK)
{
VARIANT varName;
VariantInit(&varName);//初始化变量
pPropBag->Read(L"FriendlyName", &varName, 0);//获取类别名称
CString str1 = varName.bstrVal;
//pPropBag->Read(L"CLSID", &varName, 0);//也可获取类别类标识
//CString str2 = varName.bstrVal;
InsertStr(str1);//InsertStr是自定义函数,将过滤器的名称按子母顺序插入字符串数组
VariantClear(&varName);//清除变量
pPropBag->Release();//释放IPropertyBag接口
}
pMoniker->Release();//释放IMoniker接口
}
pEnumCat->Release();//释放IEnumMoniker接口
}
else
{
AfxMessageBox(_T("创建类枚举器失败!"));
pSysDevEnum->Release();//释放ICreateDevEnum接口
return S_FALSE;
}
pSysDevEnum->Release();//释放ICreateDevEnum接口
return S_OK;
//下面是辅助函数定义:
CStringArray strary;//声明保存过滤器名称使用的字符串数组
void InsertStr(CString str)//InsertStr函数定义;按字母顺序插入过滤器名称
{
if (strary.IsEmpty())
{
strary.Add(str);
}
else
{
for (int i = 0; i < strary.GetCount(); i++)
{
if (strary.GetAt(i).CompareNoCase(str) > 0)
{
strary.InsertAt(i, str); return;
}
}
strary.Add(str);
}
}
获得的结果如下:(它们是过滤器类别名称)
Audio Capture Sources //音频捕获类别
Audio Compressors // 音频压缩类别
Audio Renderers //音频渲染类别
BDA Network Providers
BDA Receiver Components
BDA Rendering Filters
BDA Source Filters
BDA Transport Information Renderers
Device Control Filters
DirectShow Filters //DirectShow过滤器类别
External Renderers
Midi Renderers
Multi-Instance Capable VBI Codecs
PBDA CP Filters
Video Capture Sources //视频捕获类别
Video Compressors //视频压缩类别
WDM Stream Decompression Devices
WDM Streaming Capture Devices
WDM Streaming Communication Transforms
WDM Streaming Crossbar Devices
WDM Streaming Data Transforms
WDM Streaming Encoder Devices
WDM Streaming Interface Transforms
WDM Streaming Mixer Devices
WDM Streaming Multiplexer Devices
WDM Streaming Rendering Devices
WDM Streaming System Devices
WDM Streaming Tee/Splitter Devices
WDM Streaming TV Audio Devices
WDM Streaming TV Tuner Devices
WDM Streaming VBI Codec
过滤器类别列表
类别名称 类别类标识 声明文件
过滤器元类别 CLSID_ActiveMovieCategories Uuids.h
以下是元类别下的类别:
Audio Capture Sources CLSID_AudioInputDeviceCategory Uuids.h
音频捕获源
Audio Compressors CLSID_AudioCompressorCategory Uuids.h
音频压缩器
Audio Renderers CLSID_AudioRendererCategory Uuids.h
音频渲染器
Device Control Filters CLSID_DeviceControlCategory Uuids.h
设备控制过滤器
DirectShow Filters CLSID_LegacyAmFilterCategory Uuids.h
DirectShow过滤器
External Renderers CLSID_TransmitCategory Uuids.h
外部渲染器
Midi Renderers CLSID_MidiRendererCategory Uuids.h
Midi渲染器
Video Capture Sources CLSID_VideoInputDeviceCategory Uuids.h
视频捕获源
Video Compressors CLSID_VideoCompressorCategory Uuids.h
视频压缩器
WDM Stream Decompression Devices CLSID_DVDHWDecodersCategory Uuids.h
WDM流解压缩设备
WDM Streaming Capture Devices AM_KSCATEGORY_CAPTURE Uuids.h
WDM流捕获设备
WDM Streaming Crossbar Devices AM_KSCATEGORY_CROSSBAR Uuids.h
WDM流交叉开关设备
WDM Streaming Rendering Devices AM_KSCATEGORY_RENDER Uuids.h
WDM流渲染设备
WDM Streaming Tee/Splitter Devices AM_KSCATEGORY_SPLITTER Uuids.h
WDM流分支/分离器设备
WDM Streaming TV Audio Devices AM_KSCATEGORY_TVAUDIO Uuids.h
WDM流电视音频设备
WDM Streaming TV Tuner Devices AM_KSCATEGORY_TVTUNER Uuids.h
WDM流电视调谐器设备
WDM Streaming VBI Codecs AM_KSCATEGORY_VBICODEC Uuids.h
WDM流VBI编解码器
EncAPI Encoders CLSID_MediaEncoderCategory Uuids.h
EncAPI编码器
EncAPI Multiplexers CLSID_MediaMultiplexerCategory Uuids.h
EncAPI多路复用器
WDM Streaming Communication Transforms KSCATEGORY_COMMUNICATIONSTRANSFORM Ks.h
WDM流通信转换
WDM Streaming Data Transforms KSCATEGORY_DATATRANSFORM Ks.h
WDM流数据转换
WDM Streaming Interface Transforms KSCATEGORY_INTERFACETRANSFORM Ks.h
WDM流接口转换
WDM Streaming Mixer Devices KSCATEGORY_MIXER Ks.h
WDM流混合器设备
BDA Network Providers KSCATEGORY_BDA_NETWORK_PROVIDER Bdamedia.h
BDA网络提供程序
BDA Receiver Components KSCATEGORY_BDA_RECEIVER_COMPONENT Bdamedia.h
BDA接收器组件
BDA Rendering Filters KSCATEGORY_IP_SINK Bdamedia.h
BDA渲染过滤器
BDA Source Filters KSCATEGORY_BDA_NETWORK_TUNER Bdamedia.h
BDA源过滤器
BDA Transport Information Renderers KSCATEGORY_BDA_TRANSPORT_INFORMATION Bdamedia.h
BDA转换信息渲染器
Video Effects (1 input) CLSID_VideoEffects1Category Qedit.h
视频效果(1个输入)
Video Effects (2 inputs) CLSID_VideoEffects2Category Qedit.h
视频效果(2个输入)
DMO类别 GUID
Audio decoder DMOCATEGORY_AUDIO_DECODER Dmoreg.h
音频解码器
Audio effect DMOCATEGORY_AUDIO_EFFECT Dmoreg.h
音频效果
Audio encoder DMOCATEGORY_AUDIO_ENCODER Dmoreg.h
音频编码器
Video decoder DMOCATEGORY_VIDEO_DECODER Dmoreg.h
视频解码器
Video effect DMOCATEGORY_VIDEO_EFFECT Dmoreg.h
视频效果
Video encoder DMOCATEGORY_VIDEO_ENCODER Dmoreg.h
视频编码器
Audio capture effect DMOCATEGORY_AUDIO_CAPTURE_EFFECT Dmoreg.h
音频捕获效果
当我们使用系统设备枚举器创建过滤器时,会使用到过滤器所属类别的GUID。
枚举DirectShow Filters类别下的过滤器
HRESULT hr;
ICreateDevEnum* pSysDevEnum = NULL;
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pSysDevEnum));//创建系统设备枚举器
if (hr != S_OK)
{
return S_FALSE;
}
IEnumMoniker* pEnumCat;
hr = pSysDevEnum->CreateClassEnumerator(CLSID_LegacyAmFilterCategory, &pEnumCat, 0);//创建DirectShow Filters类别的类枚举器。参数CLSID_LegacyAmFilterCategory是DirectShow Filters类别的GUID
if (hr == S_OK)
{
IMoniker* pMoniker = NULL;
ULONG cFetched;
while (pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK)
{
IPropertyBag* pPropBag;
hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pPropBag);
if (hr == S_OK)
{
VARIANT varName;
VariantInit(&varName);
pPropBag->Read(L"FriendlyName", &varName, 0);//获取过滤器名称
CString str1 = varName.bstrVal;
//pPropBag->Read(L"CLSID", &varName, 0);//也可获取过滤器类标识
//CString str2 = varName.bstrVal;
InsertStr(str1);//InsertStr是自定义函数,将过滤器的名称按子母顺序插入字符串数组
VariantClear(&varName);//清除变量
pPropBag->Release();//释放IPropertyBag接口
}
pMoniker->Release();//释放IMoniker接口
}
pEnumCat->Release();//释放IEnumMoniker接口
}
else
{
AfxMessageBox(_T("创建类枚举器失败!"));
pSysDevEnum->Release();//释放ICreateDevEnum接口
return S_FALSE;
}
pSysDevEnum->Release();//释放ICreateDevEnum接口
return S_OK;
获得的结果如下:(DirectShow Filters类别的所有过滤器名称。在win10系统下获取)
AAC Parser
AC3 Parser Filter
ACM Wrapper
AVI Decompressor
AVI Draw
AVI Mux
AVI Splitter
AVI/WAV File Source
BDA MPEG2 Transport Information Filter
Closed Captions Analysis Filter
Color Space Converter
CoreAVC Video Decoder
CoreVorbis Audio Decoder
CyberLink AudioCD Filter (PDVD10)
CyberLink Video/SP Decoder (PDVD7)
DC-Bass Source
DivX Decoder Filter
DScaler Audio Decoder
DScaler Mpeg2 Video Decoder
DTSWAVSource
Dump
DV Muxer
DV Splitter
DV Video Decoder
DVD Navigator
Enhanced Video Renderer
ffdshow Audio Decoder
ffdshow Audio Processor
ffdshow DXVA Video Decoder
ffdshow raw video filter
ffdshow subtitles filter
ffdshow Video Decoder
File Source (Async.)
File Source (Monkey Audio)
File Source (URL)
File stream renderer
File writer
FLAC Audio Decoder
FLAC Audio Filter
FLV Source
FLV Splitter
FLV Video Decoder
H264 Decoder DMO
H26L Decompressor
H26L DecompressorRGB
Haali Matroska Muxer
Haali Media Splitter
Haali Media Splitter (AR)
Haali Simple Media Splitter
Haali Video Sink
Infinite Pin Tee Filter
Internal Script Command Renderer
Kylin Render Filter
Kylin Source
Kylin Source Filter(Local)
LAME Audio Encoder
LAV Audio Decoder
LAV Splitter
LAV Splitter Source
Line 21 Decoder
Line 21 Decoder 2
madFlac Decoder
madFlac Source
Matroska Muxer
Microsoft AC3 Encoder
Microsoft DTV-DVD Audio Decoder
Microsoft DTV-DVD Video Decoder
Microsoft MPEG-2 Audio Encoder
Microsoft MPEG-2 Encoder
Microsoft MPEG-2 Video Encoder
MIDI Parser
MJPEG Decompressor
MONOGRAM Musepack Decoder
MONOGRAM Musepack Splitter
MP3 Decoder DMO
MPC AVI<->AC3/DTS
MPC DSM Source
MPC DSM Splitter
MPC DTS/AC3/DD+ Source
MPC MPEG Source
MPC MPEG Splitter
MPC Ogg/Opus Source
MPC Ogg/Opus Splitter
MPEG Audio Decoder
MPEG Layer-3 Decoder
MPEG Video Decoder
MPEG-2 Demultiplexer
MPEG-2 Sections and Tables
MPEG-2 Splitter
MPEG-2 Video Stream Analyzer
MPEG-I Stream Splitter
Mpeg4 Decoder DMO
Mpeg43 Decoder DMO
Mpeg4s Decoder DMO
Multi-file Parser
Null Renderer
Ogg Multiplexer
Ogg Splitter
Overlay Mixer
Overlay Mixer2
Pmp Source
Pmp Splitter
RadGt Source
RadGt Splitter
RealAudio Decoder
RealMedia Source
RealMedia Splitter
RealVideo Decoder
SAMI (CC) Parser
SampleGrabber
SBE2FileScan
SBE2MediaTypeProfile
Smart Tee
StreamBufferSink
StreamBufferSink2
StreamBufferSource
TAK SourceFilter
True Audio Decoder
TTL2 Decompressor
TTL2 DecompressorRGB
VBI Codec
VBI Surface Allocator
VGA 16 Color Ditherer
VGM - Audio Decoder
VGM - BGR Converter
VGM - Splitter
VGM - Video Decoder
Video Mixing Renderer 9
Video Port Manager
Video Renderer
Video Renderer
Vorbis Decoder
Vorbis Encoder
Voxware MetaSound Audio Decoder
Voxware MetaVoice Audio Decoder
VP7 Decompressor
VPS Decoder
WAV Dest
Wave Parser
WavPack Audio Decoder
WavPack Audio Splitter
WM ASF Reader
WM ASF Writer
WMAPro over S/PDIF DMO
WMAudio Decoder DMO
WMSpeech Decoder DMO
WMV Screen decoder DMO
WMVideo Decoder DMO
WST Pager
Xvid MPEG-4 Video Decoder
有关过滤器的操作
获取过滤器的类标识
使用IPersist::GetClassID方法获取过滤器GUID。
GUID guid;
hr=pFilter->GetClassID(&guid);//获取过滤器的GUID。pFilter的类型为IBaseFilter*
获取过滤器指针
不管是使用CoCreateInstance函数或使用系统设备枚举器创建过滤器,都获取了过滤器的IBaseFilter接口指针。
还可以通过过滤器在图中的名称,获取过滤器IBaseFilter接口指针:
IBaseFilter* pFilter = NULL;
hr = pGraph->FindFilterByName(L"过滤器在图中的名称", &pFilter);//调用者必须释放IBaseFilter接口。
获取过滤器信息
FILTER_INFO f_info;
HRESULT hr=pFilter->QueryFilterInfo(&f_info);//pFilter类型为IBaseFilter*
f_info.achName;//WCHAR* 过滤器的名称
f_info.pGraph;//IFilterGraph* 如果过滤器是过滤器图的成员,则为过滤器图的IFilterGraph接口的指针。如果过滤器不是过滤器图的成员,则为NULL
if(f_info.pGraph!=NULL)f_info.pGraph->Release();//如果pGraph成员不为NULL,需释放该接口
枚举过滤器的引脚
IEnumPins *pEnum = NULL;
HRESULT hr = pFilter->EnumPins(&pEnum);//获取IEnumPins接口指针。pFilter的类型为IBaseFilter*
IPin *pPin = NULL;
while(pEnum->Next(1, &pPin, 0)==S_OK)
{
//在这里执行对获取到的引脚的操作
pPin->Release();//在下一次循环前释放该引脚
}
pEnum->Release();//释放枚举引脚接口
此代码获取过滤器所有引脚的IPin接口指针。此代码可以衍生为:获取过滤器所有引脚数量;获取过滤器输入引脚数量;获取过滤器输出引脚数量。
获取过滤器所有引脚的名称
HRESULT hr;
IEnumPins* pEnum = NULL;
hr = pFilter->EnumPins(&pEnum);//获取IEnumPins接口指针。pFilter的类型为IBaseFilter*
IPin* pPin = NULL; CString item;
while (pEnum->Next(1, &pPin, 0) == S_OK)
{
PIN_INFO info;
hr = pPin->QueryPinInfo(&info);
if (hr == S_OK)
{
item += info.achName + (CString)"\r\n";
info.pFilter->Release();
}
pPin->Release();//在下一次循环前释放该引脚
}
pEnum->Release();//释放枚举引脚接口
item字符串将包含过滤器所有引脚名称。
获取过滤器所有引脚的标识
IEnumPins* pEnum = NULL;
hr = pFilter->EnumPins(&pEnum);//获取IEnumPins接口指针。pFilter的类型为IBaseFilter*
IPin* pPin = NULL; CString item;
while (pEnum->Next(1, &pPin, 0) == S_OK)
{
LPWSTR lp;
hr = pPin->QueryId(&lp);
if (hr == S_OK)
{
item += lp + (CString)"\r\n";
CoTaskMemFree(lp);
}
pPin->Release();//在下一次循环前释放该引脚
}
pEnum->Release();//释放枚举引脚接口
item字符串将包含过滤器所有引脚标识。
将过滤器添加到过滤器图
hr =pGraph->AddFilter(pFilter,_T("过滤器名称"));//添加过滤器。要求pFilter指定的过滤器已创建成功
//参数1,过滤器的IBaseFilter接口的指针
//参数2,指定过滤器的名称,可以为NULL
在过滤器图中删除过滤器
hr=pGraph->RemoveFilter(pFilter);//pGraph类型为IGraphBuilder*,pFilter类型为IBaseFilter*
显示过滤器的属性页
ShowPage(pFilter);//ShowPage函数是自定义函数
//参数pFilter指定过滤器,类型为IBaseFilter*
void ShowPage(IBaseFilter* pFilter)//ShowPage函数定义
{
ISpecifyPropertyPages* pProp;
HRESULT hr = pFilter->QueryInterface(IID_ISpecifyPropertyPages, (void**)&pProp);//获取过滤器ISpecifyPropertyPages接口
if (SUCCEEDED(hr))
{
//获取过滤器的名称和IUnknown指针
FILTER_INFO FilterInfo;
hr = pFilter->QueryFilterInfo(&FilterInfo);
IUnknown* pFilterUnk;
pFilter->QueryInterface(IID_IUnknown, (void**)&pFilterUnk);
//显示页面
CAUUID caGUID;
pProp->GetPages(&caGUID);
pProp->Release();//释放ISpecifyPropertyPages接口
OleCreatePropertyFrame(
theApp.m_pMainWnd->GetSafeHwnd(), //父窗口
0, 0, //保留
FilterInfo.achName, //对话框的标题
1, //对象数(仅是过滤器)
&pFilterUnk, //对象指针数组。
caGUID.cElems, //属性页数
caGUID.pElems, //属性页CLSID的数组
0, //语言环境标识符
0,
NULL
);
// 清理。
pFilterUnk->Release();
if (FilterInfo.pGraph != NULL)FilterInfo.pGraph->Release(); //如果pGraph成员不为NULL,则应释放它
CoTaskMemFree(caGUID.pElems);
}
else
AfxMessageBox(_T("获取属性页失败!"));
}
属性页为模态对话框。判断过滤器是否有属性页,就是获取其ISpecifyPropertyPages接口,如果存在该接口,就有属性页。
有关引脚的操作
连接引脚
hr = pGraph->Connect(pOutPin, pInPin);//pGraph为过滤器图管理器指针,类型为IGraphBuilder*
//参数1,输出引脚的指针。类型为IPin*
//参数2,输入引脚的指针。类型为IPin*
//或
hr = pGraph->ConnectDirect(pOutPin, pInPin, NULL);
断开引脚连接
pOutPin为输出引脚,pInPin为输入引脚;两引脚已成功连接。如果要断开此连接,须对两个引脚分别调用IFilterGraph::Disconnect方法。
hr = pGraph->Disconnect(pOutPin);
hr = pGraph->Disconnect(pInPin);
获取引脚的方向(输入或输出)
PIN_DIRECTION pinDir;
HRESULT hr = pPin->QueryDirection(&pinDir);//pPin为引脚的IPin接口指针
//如果成功,返回值为S_OK。
//参数是输出参数,值为PINDIR_INPUT时,引脚为输入引脚;为PINDIR_OUTPUT时,引脚为输出引脚
获取引脚的标识
LPWSTR lp;
HRESULT hr = pPin->QueryId(&lp);//pPin类型为IPin*。如果成功,返回S_OK
//参数lp包含输出引脚的标识
CoTaskMemFree(lp);//在使用完成后,释放引脚标识字符串
获取引脚信息
PIN_INFO info;
HRESULT hr=pPin->QueryPinInfo(&info);//pPin类型为IPin*;如果成功,返回S_OK
info.pFilter;//类型IBaseFilter*,所属过滤器的IBaseFilter接口的指针
info.dir;//PIN_DIRECTION枚举,值PINDIR_INPUT表示引脚为输入引脚;值PINDIR_OUTPUT输出引脚
info.achName;//WCHAR* 引脚名称
if(info.pFilter!=NULL)info.pFilter->Release();//IBaseFilter接口使用完成后,应释放该接口
获取与引脚连接的另一个引脚
如果引脚已经连接,获取与其连接的另一个引脚:
IPin* pOther = NULL;
HRESULT hr = pPin->ConnectedTo(&pOther);//如果成功,返回S_OK
//参数输出另一个引脚的IPin接口指针
if (hr == S_OK && pOther != NULL)
{
pOther->Release();//必须释放另一个引脚的指针
}
可以使用此代码判断引脚是否已连接。如果pOther != NULL,已连接;为NULL,没有连接。
枚举引脚的媒体类型
IEnumMediaTypes* pEnum = NULL;
HRESULT hr = pPin->EnumMediaTypes(&pEnum);
if (FAILED(hr))return hr;
AM_MEDIA_TYPE* pmt = NULL;
while (hr = pEnum->Next(1, &pmt, NULL), hr == S_OK)
{
pmt->majortype;//GUID 主要类型
pmt->subtype;//GUID 子类型
pmt->formattype;//GUID 格式类型
pmt->pbFormat;//BYTE* 格式块的指针
_DeleteMediaType(pmt);//必须删除获取到的媒体类型结构,包括它的格式块
}
pEnum->Release();
//辅助函数定义:
void _FreeMediaType(AM_MEDIA_TYPE& mt)//释放媒体类型的格式块。
{
if (mt.cbFormat != 0)
{
CoTaskMemFree((PVOID)mt.pbFormat);
mt.cbFormat = 0;
mt.pbFormat = NULL;
}
if (mt.pUnk != NULL)
{
mt.pUnk->Release();
mt.pUnk = NULL;
}
}
void _DeleteMediaType(AM_MEDIA_TYPE* pmt)//删除在堆上分配的媒体类型结构
{
if (pmt != NULL)
{
_FreeMediaType(*pmt);
CoTaskMemFree(pmt);
}
}
可以将此代码衍生为获取引脚媒体类型的总数。
测试引脚是否支持某些媒体类型
要求引脚所属过滤器已经创建,并且所有引脚没有连接。过滤器已加入过滤器图,或没有加入图中都可以。通常对输入引脚使用此方法。
使用IPin接口的QueryAccept方法,测试引脚是否支持某个媒体类型。参数为媒体类型结构AM_MEDIA_TYPE的指针,要求初始化结构的所有参数,并为格式块分配内存,初始化格式块所有参数;保证所有参数为有效参数。
AM_MEDIA_TYPE mt_16PCM;//16位2声道PCM
mt_16PCM.majortype = MEDIATYPE_Audio;
mt_16PCM.subtype = MEDIASUBTYPE_PCM;
mt_16PCM.formattype = FORMAT_WaveFormatEx;
mt_16PCM.bFixedSizeSamples = 1;//样本是固定大小
mt_16PCM.bTemporalCompression = 0;//使用时间压缩
mt_16PCM.lSampleSize = 4;//样本块大小
mt_16PCM.pUnk = NULL;//IUnknown指针
mt_16PCM.cbFormat = sizeof(WAVEFORMATEX);//格式块的大小
WAVEFORMATEX* p_16PCM = (WAVEFORMATEX*)CoTaskMemAlloc(sizeof(WAVEFORMATEX));//为格式块分配内存
//省略了删除格式块代码。实际应用程序中,格式块使用完成后,必须删除格式块
mt_16PCM.pbFormat = (BYTE*)p_16PCM;//格式块的指针
p_16PCM->wFormatTag = WAVE_FORMAT_PCM;//编码方式
p_16PCM->nChannels = 2;//声道数
p_16PCM->nSamplesPerSec = 48000;//采样率
p_16PCM->nAvgBytesPerSec = 48000 * 4;//数据传输率
p_16PCM->nBlockAlign = 4;//块对齐
p_16PCM->wBitsPerSample = 16;//样本位数
p_16PCM->cbSize = 0;//附加信息大小
CString item;
HRESULT hr = pInPin->QueryAccept(&mt_16PCM);//pInPin类型IPin*
if (hr == S_OK)item += L"MEDIASUBTYPE_PCM\r\n";//返回S_OK,说明引脚支持此媒体类型
示例只使用一个媒体类型进行测试,实际使用中可以使用多个媒体类型进行测试。编者使用的媒体类型参数,都是从实际过滤器图中获取的。
获取引脚的当前媒体类型
如果引脚已经连接,获取引脚连接使用的媒体类型:
AM_MEDIA_TYPE mt;
HRESULT hr = pPin->ConnectionMediaType(&mt);//pPin为IPin*类型,成功返回S_OK
_FreeMediaType(mt);//_FreeMediaType是自定义函数,调用者必须释放媒体类型的格式块
void _FreeMediaType(AM_MEDIA_TYPE& mt)//_FreeMediaType函数定义
{
if (mt.cbFormat != 0)
{
CoTaskMemFree((PVOID)mt.pbFormat);
mt.cbFormat = 0;
mt.pbFormat = NULL;
}
if (mt.pUnk != NULL)
{
mt.pUnk->Release();
mt.pUnk = NULL;
}
}
获取引脚类别
如果引脚具有IKsPropertySet接口,可以使用Get方法获取引脚类别。
IKsPropertySet* pKs = NULL;
hr = pPin->QueryInterface(IID_PPV_ARGS(&pKs));
DWORD cbReturned = 0; GUID* pPinCategory = NULL;
hr = pKs->Get(AMPROPSETID_Pin, AMPROPERTY_PIN_CATEGORY, NULL, 0,
pPinCategory, sizeof(GUID), &cbReturned);//pPinCategory将包含引脚类别GUID
pKs->Release();
渲染引脚
渲染指定的引脚:
HRESULT hr=pGraph->Render(pPin);//成功返回S_OK
pGraph为过滤器图管理器;pPin为输出引脚。此方法将创建新的过滤器并进行连接。此方法属于过滤器图的智能创建。
有关过滤器图管理器的操作
枚举过滤器图中的过滤器
下面代码将图中所有过滤器名称添加到字符串数组。将所有过滤器名称显示在编辑框中。
EnumFilters(pGraph);//EnumFilters是自定义函数
CString item;
for (int i = 0; i < strary.GetCount(); i++)
{
item += strary.GetAt(i) + L"\r\n";
}
SetDlgItemText(IDC_EDIT1, item);
HRESULT EnumFilters(IFilterGraph* pGraph)//EnumFilters函数定义
{
IEnumFilters* pEnum = NULL;
IBaseFilter* pFilter;
ULONG cFetched;
HRESULT hr = pGraph->EnumFilters(&pEnum);//获取IEnumFilters接口
if (FAILED(hr)) return hr;
while (pEnum->Next(1, &pFilter, &cFetched) == S_OK)
{
FILTER_INFO FilterInfo;
hr = pFilter->QueryFilterInfo(&FilterInfo);
if (FAILED(hr))
{
InsertStr(L"某个过滤器信息获取失败!");//InsertStr为自定义函数
continue;
}
InsertStr(FilterInfo.achName);//InsertStr为自定义函数;将过滤器名称插入字符串数组
if (FilterInfo.pGraph != NULL)
{
FilterInfo.pGraph->Release(); //FILTER_INFO结构包含指向过滤器图管理器的指针,必须释放,以减少过滤器图管理器引用计数
}
pFilter->Release();
}
pEnum->Release();
return S_OK;
}
//辅助函数定义:
CStringArray strary;//声明保存过滤器名称使用的字符串数组
void InsertStr(CString str)//InsertStr函数定义;按字母顺序插入过滤器名称
{
if (strary.IsEmpty())
{
strary.Add(str);
}
else
{
for (int i = 0; i < strary.GetCount(); i++)
{
if (strary.GetAt(i).CompareNoCase(str) > 0)
{
strary.InsertAt(i, str); return;
}
}
strary.Add(str);
}
}
将过滤器图保存到GRF文件
将已创建的过滤器图保存到磁盘文件:
HRESULT hr =SaveGraphFile(pGraph, L"D:\\MyGraph.grf"); //SaveGraphFile是自定义函数
//参数1,为已创建的过滤器图管理器的指针,类型为IGraphBuilder*
//参数2,指定GRF文件路径
HRESULT SaveGraphFile(IGraphBuilder *pGraph, WCHAR *wszPath)//SaveGraphFile函数定义
{
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;
}
保存后的GRF文件可以使用过滤器图编辑器(graphedt.exe)打开。
加载GRF文件初始化过滤器图
加载GRF文件,初始化过滤器图:
IGraphBuilder *pGraph=NULL;
HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL,CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pGraph));//创建过滤器图管理器
hr = LoadGraphFile(pGraph, L"D:\\MyGraph.grf");//加载文件,初始化过滤器图。LoadGraphFile是自定义函数
//参数1,过滤器图管理器指针;类型为IGraphBuilder*
//参数2,要加载的GRF文件路径
HRESULT LoadGraphFile(IGraphBuilder *pGraph, const WCHAR* wszName)//LoadGraphFile函数定义
{
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 = NULL;
hr = pGraph->QueryInterface(IID_IPersistStream,(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;
}
此方法同样可以加载过滤器图编辑器(graphedt.exe)创建的GRF文件。
复制过滤器图
下面代码将图pGraph复制到pGraph2:
IGraphBuilder* pGraph2 = NULL;
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pGraph2));//创建一个空的图
MyCopyGraph(pGraph2,pGraph);//MyCopyGraph是自定义函数。参数1是目标过滤器图;参数2为源过滤器图
HRESULT MyCopyGraph(IGraphBuilder* pDestinationGraph, IGraphBuilder* pSourceGraph)//MyCopyGraph函数定义
{
IStorage* pStorage = NULL;
HRESULT hr;
hr = StgCreateDocfile(NULL, STGM_CREATE | STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
0, &pStorage);//创建临时复合文件
if (FAILED(hr))return hr;
IStream* pSourceStream;
hr = pStorage->CreateStream(L"ActiveMovieGraph", STGM_WRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE,
0, 0, &pSourceStream);
if (FAILED(hr))
{
pStorage->Release(); return hr;
}
IPersistStream* pSourcePersist = NULL;
hr = pSourceGraph->QueryInterface(IID_IPersistStream, (void**)&pSourcePersist);
if (FAILED(hr))
{
pSourceStream->Release(); pStorage->Release(); return hr;
}
hr = pSourcePersist->Save(pSourceStream, TRUE);
if (FAILED(hr))
{
pSourcePersist->Release(); pSourceStream->Release(); pStorage->Release(); return hr;
}
pSourcePersist->Release(); pSourceStream->Release();
IPersistStream* pDestPersist = NULL;
hr = pDestinationGraph->QueryInterface(IID_IPersistStream, (void**)(&pDestPersist));
if (FAILED(hr))
{
pStorage->Release(); return hr;
}
IStream* pDestStream = NULL;
hr = pStorage->OpenStream(L"ActiveMovieGraph", 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pDestStream);
if (FAILED(hr))
{
pDestPersist->Release(); pStorage->Release(); return hr;
}
hr = pDestPersist->Load(pDestStream);
pDestStream->Release(); pDestPersist->Release(); pStorage->Release();
return hr;
}
文章详细介绍了DirectShow中过滤器图管理器的使用,包括创建、枚举过滤器,以及处理GUID的方法。内容涵盖GUID的结构、转换,以及如何通过CoCreateInstance函数创建和操作过滤器。此外,还讨论了过滤器类别、过滤器的属性和操作,如获取过滤器的类标识、连接引脚等。
1万+

被折叠的 条评论
为什么被折叠?



