广播驱动体系(BDA) 系列讲座:三
2011-12-22 09:56
501 查看
三 BDA应用程序设计
微软在XP操作系统中提供了一个轻量级的ActiveX控件Video Control,该控件的使用将导致应用程序的开发极为方便。本文将讨论的是在没有这个控件的WIN2000操作系统下的DVB-S数字电视应用程序的设计。对于这种应用程序,必须手动的把需要的过滤器连接起来构成完整的过滤器图表。
在应用程序开发之前,应当确保数字电视接收卡及其BDA驱动程序被正确安装和成功加载。此时,在Graph Edit的BDA Source Filters目录和BDA Receiver Components目录下应当分别可以看到相应的Filter。以TwinhanDTV sat(双汉DVB-S)接收卡为例,在这两个目录下,分别可以看到TwinHan DVBS BDA Tuner Filter和TwinHan DVBS BDA Capture Filter两个设备过滤器。对于有些硬件提供商的接收卡,这两个控制节点在BDA中可能被一个Filter所实现,所以也只在某一目录下表现为一个Filter。
以下的讨论对涉及DirectShow应用程序设计的公共细节未做深入,讨论的重点放在有关数字电视应用程序设计的部分。为了简化起见,以下出现的代码都不含错误处理。
1. 初始化
和普通的DirectShow应用程序一样,程序首先应当对COM组件进行初始化,然后创建一个过滤器图表对象。代码如下:
CComPtr pGraph;
CoInitializeEx (NULL, COINIT_APARTMENTTHREADED);
pGraph.CoCreateInstance(CLSID_FilterGraph);
2. 取得调谐请求对象
前面的统一调谐模型已经详细讨论过调谐的细节。在应用程序中,可以使用系统枚举取得一个已有的调谐空间,也可以创建一个新的调谐空间以产生调谐请求并提交给Network Provider过滤器。以下代码以产生一个新的调谐空间为例(网络类型为DVB-S),说明了调谐请求对象的产生:
//Create DVBSTuningSpace Object and set its properties
CComPtr pIDVBSTuningSpace = NULL;
pIDVBSTuningSpace.CoCreateInstance(CLSID_DVBSTuningSpace);
pIDVBSTuningSpace->put_UniqueName( bstrName );//set a unique name for this object
pIDVBSTuningSpace->put_FriendlyName( bstrFriName );//set friendly name
pIDVBSTuningSpace->put__NetworkType(CLSID_DVBSNetworkProvider);
//Create DVBSLocator Object and set it as the default locator of the DVBSTuningSpace above
CComPtr pLocatorVal = NULL;
pLocatorVal.CoCreateInstance(CLSID_DVBSLocator);
pLocatorVal->put_SymbolRate(dwSymbolRate );//set symbol rate
pLocatorVal->put_CarrierFrequency(dwCarrFreq ) ;//set carrier frequency
pLocatorVal->put_SignalPolarisation(Polar );//set polarization
pIDVBSTuningSpace->put_DefaultLocator( pLocatorVal );
//the source code for adding the this TuningSpace to SystemTuningSpaces is omitted
//Create TuneRequest object and set its locator
CComPtr pITuneRequest = NULL;
pIDVBSTuningSpace->CreateTuneRequest(&pITuneRequest);
CComQIPtr pIDVBTuneRequest(pITuneRequest);
pIDVBTuneRequest->put_Locator(pLocatorVal);
上述代码将创建一个调谐请求对象(指针为pIDVBTuneRequest),以便提供给Network Provider 过滤器,代码中没有设置优先选择组件清单,所以MPEG-2 Demultiplexer过滤器的各输出PIN将输出默认基本流。
3. 创建Network Provider
如前所述,Network Provider Filter控制着调谐过程并且和Transport Information Filter协同工作以从传输流中取得节目信息。为了选择Network Provider的类型,应当询问调谐空间(Tuning Space)以取得网络类型信息,从而选择对应的Network Provider。
选择和创建过程代码如下:
CComPtr pNetworkProvider; // Network Provider filter
GUID CLSIDNetworkType; // GUID of the network type.
// Find the network type.
pIDVBSTuningSpace ->get__NetworkType(&CLSIDNetworkType);
if (CLSID_NetworkType == GUID_NULL)
{
// This tuning space is analog TV, AuxIn, or some other non-BDA type.
}
else
{
// Create the network provider filter for this network type.
pNetworkProvider.CoCreateInstance(CLSIDNetworkType);
// Add the network provider to the graph.
pGraph->AddFilter(pNetworkProvider, L"Network Provider");
}
上述代码中ITuneRequest::get_TuningSpace方法取得了一个特定的调谐请求的调谐空间,并且使用ITuningSpace::get__NetworkType方法获得了其网络类型GUID,这个GUID作为参数传递给CoCreateInstance以创建相应的Network Provider filter。
成功创建Network Provider并把其加入过滤器图表(Filter Graph)后,询问取得其ITuner接口,把调谐请求(Tune Request)发送给它。代码如下:
// Query for ITuner.
CComQIPtr pTuner(pNetworkProvider);
if (pTuner)
{ // Submit the tune request to the network provider.
pTuner->put_TuneRequest(pIDVBTuneRequest);
}
ITuner接口的put_TuneRequest方法把调谐请求发送给了network provider。
4. 增加并连接其他的过滤器
使用调谐请求(Tune Request)对Network Provider进行成功配置以后,就可以把其余的过滤器加入并连接到过滤器图中。
直接连接在Network Provider Filter后面的过滤器是位于BDA Source Filters(目录GUID为KSCATEGORY_BDA_NETWORK_TUNER)目录中的Tuner 过滤器;取决于硬件实现,Tuner过滤器后面连接的可能是位于BDA Receiver Components目录中的capture过滤器或demodulator过滤器(目录GUID为KSCATEGORY_BDA_RECEIVER_COMPONENT)。找出该接收卡对应的设备Filter需要在对应目录下进行系统枚举并试图建立连接,直至连接成功。
系统枚举的方法和DirectShow应用程序相同。
当BDA的设备Filter被连接完成以后,紧接着连接是MPEG-2 Demultiplexer过滤器,如前所述,这个过滤器默认输出五个PIN,可以选择使用智能连接技术Render每个PIN完成整个过滤器图表的建立。特别的,对于第四个PIN输出的IP数据,需要通过BDA MPE 过滤器再连接到BDA IP Sink过滤器上,这些数据的利用需要再做进一步开发。完整的过滤器图表如图3所示。
5. 应用程序控制及节目选取
和普通的DirectShow应用程序相同,应当从GraphBuilder取得IMediaControl和IMediaEvent等接口,以控制过滤器图的运行,暂停和停止以及对一些应用程序关心的事件的进行捕捉和处理。
Filter Graph成功建立并运行以后,就可以取得节目相关的信息。首先应当取得的是PAT表,获得PAT表的代码如下:
// Get the next section with PID 0, which is reserved for the PAT.
PID pid = 0x00; TID tid = 0x00;
DWORD dwTimeout = 500; // msec
MPEG2_FILTER mpeg2_filter = { 0 };
//The IMpeg2Data interface is exposed by the MPEG-2 Sections and Tables filter
CComPtr pSectionList = NULL;
pIMpeg2Data->GetSection(pid, tid, NULL , dwTimeout, &pSectionList);
通过pSectionList接口指针可以对PAT进行操作以获得本次调谐后可用的节目编号及其各自对应的PID。应用程序可以选择一路节目进行播出。该节目被选择以后,需要进一步取得该节目的PMT表以获得其基本流组件(音频,视频或者数据等子流)对应的ID,并将这些基本流ID映射到Demultiplexer过滤器的相应输出PIN上,就可以播出该节目了。PMT表的取得方法和PAT类似,只是GetSection方法中的PID应为所选择节目的ID,TID为2。
应用程序正常运行的时候,仍然可以提交一个新的调谐请求给Network Provider过滤器,从而引发一个新的调谐过程;也可以随时切换到另外一个节目频道;或者设置某个节目频道中的组件(音频,视频或者数据等子流)为可用或不可用。
四 结语
本文详细讨论了微软数字电视技术的广播驱动体系以及微软统一调谐模型,并在此基础上,实现了一个完整的数字电视应用程序。基于特定的数字电视接收卡,对该应用程序的进一步完善,可以实现在PC机上的数字电视的收看并可以在DirectShow框架下对收到的音频,视频和IP包等做进一步处理。
微软在XP操作系统中提供了一个轻量级的ActiveX控件Video Control,该控件的使用将导致应用程序的开发极为方便。本文将讨论的是在没有这个控件的WIN2000操作系统下的DVB-S数字电视应用程序的设计。对于这种应用程序,必须手动的把需要的过滤器连接起来构成完整的过滤器图表。
在应用程序开发之前,应当确保数字电视接收卡及其BDA驱动程序被正确安装和成功加载。此时,在Graph Edit的BDA Source Filters目录和BDA Receiver Components目录下应当分别可以看到相应的Filter。以TwinhanDTV sat(双汉DVB-S)接收卡为例,在这两个目录下,分别可以看到TwinHan DVBS BDA Tuner Filter和TwinHan DVBS BDA Capture Filter两个设备过滤器。对于有些硬件提供商的接收卡,这两个控制节点在BDA中可能被一个Filter所实现,所以也只在某一目录下表现为一个Filter。
以下的讨论对涉及DirectShow应用程序设计的公共细节未做深入,讨论的重点放在有关数字电视应用程序设计的部分。为了简化起见,以下出现的代码都不含错误处理。
1. 初始化
和普通的DirectShow应用程序一样,程序首先应当对COM组件进行初始化,然后创建一个过滤器图表对象。代码如下:
CComPtr pGraph;
CoInitializeEx (NULL, COINIT_APARTMENTTHREADED);
pGraph.CoCreateInstance(CLSID_FilterGraph);
2. 取得调谐请求对象
前面的统一调谐模型已经详细讨论过调谐的细节。在应用程序中,可以使用系统枚举取得一个已有的调谐空间,也可以创建一个新的调谐空间以产生调谐请求并提交给Network Provider过滤器。以下代码以产生一个新的调谐空间为例(网络类型为DVB-S),说明了调谐请求对象的产生:
//Create DVBSTuningSpace Object and set its properties
CComPtr pIDVBSTuningSpace = NULL;
pIDVBSTuningSpace.CoCreateInstance(CLSID_DVBSTuningSpace);
pIDVBSTuningSpace->put_UniqueName( bstrName );//set a unique name for this object
pIDVBSTuningSpace->put_FriendlyName( bstrFriName );//set friendly name
pIDVBSTuningSpace->put__NetworkType(CLSID_DVBSNetworkProvider);
//Create DVBSLocator Object and set it as the default locator of the DVBSTuningSpace above
CComPtr pLocatorVal = NULL;
pLocatorVal.CoCreateInstance(CLSID_DVBSLocator);
pLocatorVal->put_SymbolRate(dwSymbolRate );//set symbol rate
pLocatorVal->put_CarrierFrequency(dwCarrFreq ) ;//set carrier frequency
pLocatorVal->put_SignalPolarisation(Polar );//set polarization
pIDVBSTuningSpace->put_DefaultLocator( pLocatorVal );
//the source code for adding the this TuningSpace to SystemTuningSpaces is omitted
//Create TuneRequest object and set its locator
CComPtr pITuneRequest = NULL;
pIDVBSTuningSpace->CreateTuneRequest(&pITuneRequest);
CComQIPtr pIDVBTuneRequest(pITuneRequest);
pIDVBTuneRequest->put_Locator(pLocatorVal);
上述代码将创建一个调谐请求对象(指针为pIDVBTuneRequest),以便提供给Network Provider 过滤器,代码中没有设置优先选择组件清单,所以MPEG-2 Demultiplexer过滤器的各输出PIN将输出默认基本流。
3. 创建Network Provider
如前所述,Network Provider Filter控制着调谐过程并且和Transport Information Filter协同工作以从传输流中取得节目信息。为了选择Network Provider的类型,应当询问调谐空间(Tuning Space)以取得网络类型信息,从而选择对应的Network Provider。
选择和创建过程代码如下:
CComPtr pNetworkProvider; // Network Provider filter
GUID CLSIDNetworkType; // GUID of the network type.
// Find the network type.
pIDVBSTuningSpace ->get__NetworkType(&CLSIDNetworkType);
if (CLSID_NetworkType == GUID_NULL)
{
// This tuning space is analog TV, AuxIn, or some other non-BDA type.
}
else
{
// Create the network provider filter for this network type.
pNetworkProvider.CoCreateInstance(CLSIDNetworkType);
// Add the network provider to the graph.
pGraph->AddFilter(pNetworkProvider, L"Network Provider");
}
上述代码中ITuneRequest::get_TuningSpace方法取得了一个特定的调谐请求的调谐空间,并且使用ITuningSpace::get__NetworkType方法获得了其网络类型GUID,这个GUID作为参数传递给CoCreateInstance以创建相应的Network Provider filter。
成功创建Network Provider并把其加入过滤器图表(Filter Graph)后,询问取得其ITuner接口,把调谐请求(Tune Request)发送给它。代码如下:
// Query for ITuner.
CComQIPtr pTuner(pNetworkProvider);
if (pTuner)
{ // Submit the tune request to the network provider.
pTuner->put_TuneRequest(pIDVBTuneRequest);
}
ITuner接口的put_TuneRequest方法把调谐请求发送给了network provider。
4. 增加并连接其他的过滤器
使用调谐请求(Tune Request)对Network Provider进行成功配置以后,就可以把其余的过滤器加入并连接到过滤器图中。
直接连接在Network Provider Filter后面的过滤器是位于BDA Source Filters(目录GUID为KSCATEGORY_BDA_NETWORK_TUNER)目录中的Tuner 过滤器;取决于硬件实现,Tuner过滤器后面连接的可能是位于BDA Receiver Components目录中的capture过滤器或demodulator过滤器(目录GUID为KSCATEGORY_BDA_RECEIVER_COMPONENT)。找出该接收卡对应的设备Filter需要在对应目录下进行系统枚举并试图建立连接,直至连接成功。
系统枚举的方法和DirectShow应用程序相同。
当BDA的设备Filter被连接完成以后,紧接着连接是MPEG-2 Demultiplexer过滤器,如前所述,这个过滤器默认输出五个PIN,可以选择使用智能连接技术Render每个PIN完成整个过滤器图表的建立。特别的,对于第四个PIN输出的IP数据,需要通过BDA MPE 过滤器再连接到BDA IP Sink过滤器上,这些数据的利用需要再做进一步开发。完整的过滤器图表如图3所示。
5. 应用程序控制及节目选取
和普通的DirectShow应用程序相同,应当从GraphBuilder取得IMediaControl和IMediaEvent等接口,以控制过滤器图的运行,暂停和停止以及对一些应用程序关心的事件的进行捕捉和处理。
Filter Graph成功建立并运行以后,就可以取得节目相关的信息。首先应当取得的是PAT表,获得PAT表的代码如下:
// Get the next section with PID 0, which is reserved for the PAT.
PID pid = 0x00; TID tid = 0x00;
DWORD dwTimeout = 500; // msec
MPEG2_FILTER mpeg2_filter = { 0 };
//The IMpeg2Data interface is exposed by the MPEG-2 Sections and Tables filter
CComPtr pSectionList = NULL;
pIMpeg2Data->GetSection(pid, tid, NULL , dwTimeout, &pSectionList);
通过pSectionList接口指针可以对PAT进行操作以获得本次调谐后可用的节目编号及其各自对应的PID。应用程序可以选择一路节目进行播出。该节目被选择以后,需要进一步取得该节目的PMT表以获得其基本流组件(音频,视频或者数据等子流)对应的ID,并将这些基本流ID映射到Demultiplexer过滤器的相应输出PIN上,就可以播出该节目了。PMT表的取得方法和PAT类似,只是GetSection方法中的PID应为所选择节目的ID,TID为2。
应用程序正常运行的时候,仍然可以提交一个新的调谐请求给Network Provider过滤器,从而引发一个新的调谐过程;也可以随时切换到另外一个节目频道;或者设置某个节目频道中的组件(音频,视频或者数据等子流)为可用或不可用。
四 结语
本文详细讨论了微软数字电视技术的广播驱动体系以及微软统一调谐模型,并在此基础上,实现了一个完整的数字电视应用程序。基于特定的数字电视接收卡,对该应用程序的进一步完善,可以实现在PC机上的数字电视的收看并可以在DirectShow框架下对收到的音频,视频和IP包等做进一步处理。
相关文章推荐
- 广播驱动体系(BDA) 系列讲座:四
- 广播驱动体系(BDA) 系列讲座:五
- 广播驱动体系(BDA) 系列讲座:六
- 广播驱动体系(BDA) 系列讲座:一
- 广播驱动体系(BDA) 系列讲座:二
- 广播驱动体系(BDA) 系列讲座:七
- 基于微软广播驱动体系的数字电视技术及其应用程序
- BDA讲座系列,发表文章太慢,本人已经转移到百度空间中
- BDA(广播驱动架构)技术文章转载【和电视卡有关】
- [C# 网络编程系列]专题七:UDP编程补充——UDP广播程序的实现
- wince 驱动发送广播消息
- ARM的体系结构与编程系列博客——ARM体系版本
- “手把手教你学linux驱动开发”OK6410系列之02---虚拟字符设备
- Citrix Profile Management 和 VDI系列讲座之二:Profile漫游需要怎么配置存储和网络 (2)
- Compaq 511系列 显卡驱动 声卡驱动 网卡驱动
- Socket层实现系列 — 睡眠驱动的同步等待
- linux驱动基础系列--Linux I2c驱动分析
- 写在崩溃之前——Ubuntu下GMA3600系列/PowerVR/Atom (N/D)2000系列的驱动方法
- Linux字符设备驱动之cdev_init()系列
- 第一课 MC9S08DZ芯片驱动课程系列开场白