DirectShow编程基础2

文章详细介绍了DirectShow中过滤器图管理器的使用,包括创建、枚举过滤器,以及处理GUID的方法。内容涵盖GUID的结构、转换,以及如何通过CoCreateInstance函数创建和操作过滤器。此外,还讨论了过滤器类别、过滤器的属性和操作,如获取过滤器的类标识、连接引脚等。

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;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

h3968

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值