您的位置:首页 > 其它

DirectShow_基础与简单示例说明

2015-07-09 17:08 330 查看
DirectShow 是一个 Windows 平台上的流媒体框架,提供了高质量的多媒体流采集和回放功能。

Filter 实质是一个 COM 组件,所以学习开发 Filter 前你应该对 COM 相关知识有点了解。COM 组件的实质是实现了纯虚指针接口的 C++ 对象。

应用程序开发者只需要基本的 COM 组件知识:实例化COM组件、调用接口、管理接口的引用计数。Filter 开发者则需要更多。

选择一个基类,声明自己的类。

应该清楚这个 Filter 在整个 Filter Graph 的位置,这个 Filter 的输入是什么数据,输出是什么数据,有几个输入 Pin、几个输出 Pin 等,可以画出这个 Filter 的草图。

Win7: DirectShow SDK 做为 Windows SDK(GRMSDK_EN_DVD.iso) 的一部分,不再有单独的 DirectX SDK 包。

在 DirectShow 中,应用程序要实现功能就必须将这些 Filter 链接在一起,因而一个 Filter 的输出就变成了另一个 Filter 的输入。这一系列串在一起的 Filter 称为 Filter Graph。

使用 VS2008 建立 Filter 开发工程的过程如下:

(1) 新建

Visual C++/Win32 项目,工程名如:FilterSample。点击“确定”进入下一步;

(2) 应用程序类型选择:DLL,一般不选择 MFC 和 ATL;

工程的建立完成,编译后可以先将输入文件改名。方法如下:

属性页/链接器/常规/输出文件,修改为:$(OutDir)/FilterSample.ax

DirectShow 必须用到以下头文件的库文件:

#include "streams.h"

#include "initguid.h"

strmbasd.lib

winmm.lib

uuid.lib

Quartz.lib 输出 AMGetErrorText 函数,如果不调用此函数,此库不是必需的。

FilterSample.def 文件的内容:

LIBRARY FilterSample.ax

EXPORTS

; 需要定义的导出函数

DllMain PRIVATE

DllRegisterServer PRIVATE

DllUnregisterServer PRIVATE

; 在基类中已经定义的导出函数

DllGetClassObject PRIVATE

DllCanUnloadNow PRIVATE

dllmain.cpp 的代码如下:

// dllmain.cpp : 定义 DLL 应用程序的入口点。

#include "stdafx.h"

#include "streams.h"

// BOOL APIENTRY DllMain( HMODULE hModule,

// DWORD ul_reason_for_call,

// LPVOID lpReserved

// )

// {

// switch (ul_reason_for_call)

// {

// case DLL_PROCESS_ATTACH:

// case DLL_THREAD_ATTACH:

// case DLL_THREAD_DETACH:

// case DLL_PROCESS_DETACH:

// break;

// }

// return TRUE;

// }

STDAPI DllRegisterServer()

{

return AMovieDllRegisterServer2(TRUE);

}

STDAPI DllUnregisterServer()

{

return AMovieDllRegisterServer2(FALSE);

}

extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);

BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)

{

return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved);

}

编译时,可能会遇到如下问题:

1>e:\work\sourcecode\testcode\filtersample\dllmain.cpp(23) : error C3861: “AMovieDllRegisterServer2”: 找不到标识符

1>e:\work\sourcecode\testcode\filtersample\dllmain.cpp(27) : error C3861: “AMovieDllRegisterServer2”: 找不到标识符

编译错误, 一般是头文件没有包含。所以,包含: #include "streams.h"

1>dllmain.obj : error LNK2019: 无法解析的外部符号 _AMovieDllRegisterServer2@4,该符号在函数 _DllRegisterServer@0 中被引用

1>dllmain.obj : error LNK2019: 无法解析的外部符号 _DllEntryPoint@12,该符号在函数 _DllMain@12 中被引用

1>E:\Work\SourceCode\TestCode\FilterSample\Debug\FilterSample.dll : fatal error LNK1120: 2 个无法解析的外部命令

链接错误, 一般是库文件没有包含。所以,库输入中包含: strmbasd.lib

1>正在链接...

1>strmbasd.lib(wxdebug.obj) : error LNK2019: 无法解析的外部符号 __imp__timeGetTime@0,该符号在函数 "void __stdcall DbgInitialise(struct HINSTANCE__ *)" (?DbgInitialise@@YGXPAUHINSTANCE__@@@Z) 中被引用

1>strmbasd.lib(wxutil.obj) : error LNK2001: 无法解析的外部符号 __imp__timeGetTime@0

1>strmbasd.lib(wxutil.obj) : error LNK2019: 无法解析的外部符号 __imp__timeSetEvent@20,该符号在函数 "unsigned int __cdecl CompatibleTimeSetEvent(unsigned int,unsigned int,void (__stdcall*)(unsigned int,unsigned int,unsigned long,unsigned long,unsigned long),unsigned long,unsigned
int)" (?CompatibleTimeSetEvent@@YAIIIP6GXIIKKK@ZKI@Z) 中被引用

1>E:\Work\SourceCode\TestCode\FilterSample\Debug\FilterSample.dll : fatal error LNK1120: 4 个无法解析的外部命令

包含 winmm.lib, 可以解决 timeGetTime 链接错误的问题

增加头文件 FilterSample.h,其内容如下:

其中 GUID 的生成,需要用到下面的工具: Microsoft SDKs\Windows\v7.1\Bin\guidgen.exe

#ifndef _FILTER_SAMPLE_H_

#define _FILTER_SAMPLE_H_

// {33B57142-BD07-4a77-AE91-A8F6C24A8F40}

DEFINE_GUID(CLSID_FilterSample,

0x33b57142, 0xbd07, 0x4a77, 0xae, 0x91, 0xa8, 0xf6, 0xc2, 0x4a, 0x8f, 0x40);

class CFilterSample: public CCritSec, public CBaseFilter

{

public:

CFilterSample(TCHAR *pName,LPUNKNOWN pUnk,HRESULT *hr);

virtual ~CFilterSample();

static CUnknown * WINAPI CreateInstance(LPUNKNOWN pUnk, HRESULT *phr);

CBasePin *GetPin(int n);

int GetPinCount();

};

#endif

FilterSample.cpp 的内容如下:

// FilterSample.cpp : 定义 DLL 应用程序的导出函数。

//

#include "stdafx.h"

#include "streams.h"

#include "initguid.h"

#include "FilterSample.h"

// Using this pointer in constructor

#pragma warning(disable:4355 4127)

//////////////////////////////////////////////////////////////////////////

// AMOVIESETUP_FILTER 描述一个 Filter

// AMOVIESETUP_PIN 描述 pin

// AMOVIESETUP_MEDIATYPE 描述数据类型

const AMOVIESETUP_MEDIATYPE sudPinTypes =

{

&MEDIATYPE_NULL, // Major CLSID

&MEDIASUBTYPE_NULL // Minor type

};

const AMOVIESETUP_PIN psudPins[] =

{

{

L"Input", // Pin's string name

FALSE, // Is it rendered

FALSE, // Is it an output

FALSE, // Allowed none

FALSE, // Allowed many

&CLSID_NULL, // Connects to filter

L"Output", // Connects to pin

1, // Number of types

&sudPinTypes // Pin information

},

{

L"Output", // Pin's string name

FALSE, // Is it rendered

TRUE, // Is it an output

FALSE, // Allowed none

FALSE, // Allowed many

&CLSID_NULL, // Connects to filter

L"Input", // Connects to pin

1, // Number of types

&sudPinTypes // Pin information

}

};

const AMOVIESETUP_FILTER sudInfTee =

{

&CLSID_FilterSample, // CLSID of filter

L"Filter Sample Test Lib", // Filter's name

MERIT_DO_NOT_USE, // Filter merit

2, // Number of pins

psudPins // Pin information

};

//////////////////////////////////////////////////////////////////////////

CFactoryTemplate g_Templates[1] =

{

{

L"Filter Sample", // Name

&CLSID_FilterSample, // CLSID

CFilterSample::CreateInstance, // Method to create an instance of MyComponent

NULL, // Initialization function

&sudInfTee // Set-up information (for filters)

}

};

int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);

CFilterSample::CFilterSample(TCHAR *pName,LPUNKNOWN pUnk,HRESULT *hr)

:CBaseFilter(NAME("Filter Sample"), pUnk, this, CLSID_FilterSample)

{

}

CFilterSample::~CFilterSample()

{

}

CBasePin * CFilterSample::GetPin(int n)

{

return NULL;

}

int CFilterSample::GetPinCount()

{

return 0;

}

CUnknown * WINAPI CFilterSample::CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr)

{

CFilterSample *pFilter = new CFilterSample(NAME("Filter Sample"), pUnk, pHr);

if (pFilter== NULL)

{

*pHr = E_OUTOFMEMORY;

}

return pFilter;

}

编译时,可能遇到如下问题:

1>FilterSample.obj : error LNK2019: 无法解析的外部符号 "public: __thiscall CBaseFilter::CBaseFilter(wchar_t const *,struct IUnknown *,class CCritSec *,struct _GUID const &)" (??0CBaseFilter@@QAE@PB_WPAUIUnknown@@P***CCritSec@@ABU_GUID@@@Z),该符号在函数 "public: __thiscall
CFilterSample::CFilterSample(wchar_t *,struct IUnknown *,long *)" (??0CFilterSample@@QAE@PA_WPAUIUnknown@@PAJ@Z) 中被引用

1>E:\Work\SourceCode\TestCode\FilterSample\Debug\FilterSample.dll : fatal error LNK1120: 1 个无法解析的外部命令

解决方法: 属性页 常规->字符集 修改为“使用多字节字符集”

编译通过后,如何验证此 Filter 呢?

regsvr32 FilterSample.ax

regsvr32 提示错误:

模块“FilterSample.ax”已加载,但找不到入口点 DllRegisterServer。

请确保“FilterSample.ax”为有效的 DLL 或 OCX 文件,然后重试。

出现此错误的原因,是 FilterSample.def 未链接到工程中。在工程属性页,“链接器”/“输入”/“模块定义文件” 中输入: FilterSample.def 后,重新编译。

然后在命令行执行: regsvr32 FilterSample.ax,则提示成功。

如何确认成功了呢?可通过 Microsoft SDKs\Windows\v7.1\Bin\graphedt.exe 来查看。方法如下:

点击 graphedt.exe 的 Graph 菜单,选择 Insert Filters...。在弹出的对话框: Which filters do you want to insert? 中,选择 Directshow Filters/Filter Sample Test Lib。

这个名字看起来是不是很熟悉?看看上面的代码中是不是有这样的字符串,呵呵...。如果还不确认,请看 Filter Sample Test Lib 的 GUID 和 文件名分别是:

@device:sw:{083863F1-70DE-11D0-BD40-00A0C911CE86}\{33B57142-BD07-4A77-AE91-A8F6C24A8F40} 和 E:\Filters\FilterSample.ax(具体的目录与执行 regsvr32 时 FilterSample.ax 所在的路径相关)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: