博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
DirectShow应用——支持DVD播放 (转)
阅读量:2497 次
发布时间:2019-05-11

本文共 5563 字,大约阅读时间需要 18 分钟。

DirectShow应用——支持DVD播放 (转)[@more@] 
一. 
基础知识:namespace prefix = o ns = "urn:schemas--com::office" />

 

首先,我们来增加一点感性认识,看一下DVD光盘的(采用MicroUDF标准)。我们可以看到,典型情况下光盘上有两个文件夹:VO_TS和AUDIO_TS(通常是空的,这里不作介绍)。VIDEO_TS下面一般包含三种类型的文件:.VOB文件、.IFO文件和.BUP文件。这些文件都是作什么用的呢?其实,.VOB文件是用来保存所有MPEG2格式的音视频数据的,这些数据包括影片内容、供菜单(Menu)和按钮(Button)以及多种语言字幕用的子图片(Sub-picture)流;.IFO文件则是控制.VOB文件用的,这个文件中可以找到有关何时以及如何播放.VOB文件数据的控制信息;而.BUP文件则是.IFO文件内容的一个(因为.IFO文件对于保证DVD光盘的正确播放起着至关重要的作用)。根据这三种文件的特性,我们也就可以理解它们在光盘介质上的排列顺序了:IFO-VOB-VOB...-BUP。

 

我们再来看一下各个具体的文件。VIDEO_TS.IFO文件,保存DVD光盘的视频管理器 (Video Manager,简称VMG)信息,主要是光盘的一些全局信息,比如光盘指定的播放区域、如何显示菜单等。VIDEO_TS.VOB文件,保存显示菜单的数据。类似VTS_xx_y.VOB的文件,保存各个视频节目。(注:这里"xx"是节目编号,从01到99,"y"是从0到9的编号;由于MicroUDF文件系统中一个文件最大只能1 GB,因此大多数影片不得不保存在多个VOB文件中。)VTS_xx_y.IFO文件,保存对应编号的VOB文件的音视频格式信息。

 

大致了解了文件系统,我们再来看一下DVD其他方面的基础知识。大家知道,一张DVD光盘主要包括三种数据:视频(Video)、(Audio)和子图片。视频一般采用MPEG2算法,视频流支持最多9个视角(Angle),支持Line 21 Closed Caption(模拟电视中的概念,主要是些文字信息);音频最多支持8条不同的流(即8种不同语言的配音),支持最多6声道的格式(具体格式可以是AC3、MPEG、LPCM、DTS、SDDS等),支持卡拉OK;子图片流最多可以支持32个(即提供多种语言的字幕)。DVD内容最主要的逻辑分类叫做“标题”(Title)(一个标题通常代表了一部电影,或者一段视频节目,一张DVD光盘最多可以有99个标题),每个标题又可以 最多分成999个“章节”(Chapter)(章节是便于随机访问的节点,每播放完一个章节的内容会自动播放下一个章节,或者跳回菜单)。

 

用户与DVD的交互,最主要是通过菜单来完成的。菜单有两种:视频管理器菜单(Video Manager Menu,简称VMGM,也叫做Top Menu或Title Menu)和视频标题集菜单(Video Title Set Menu,简称VTSM,也叫做 Menu,尽管它不是真正意义上的“根”菜单)。VMGM允许用户进入主要的标题或者标题集(包含有一组标题)。如果进入标题集,就显示VTSM子菜单。VTSM菜单可以包含进入当前标题集中各个标题的按钮,还有音频、视角、字幕、章节等选择子菜单。VTSM菜单是可选的,可以不实现;当用户开始播放一张DVD,一般首先看到的就是VMGM菜单,除非这张光盘在制作时被设置成了自动播放第一个标题(此时DVD也可以根本不制作VMGM菜单)。

 

DVD还有父母锁功能。DVD中的视频内容可以打上父母管理级别(Parental Management Level,简称PML);级别可以从1到8,其中1是无限制级别,8是最高限制级别。这样,可以禁止孩子在未经父母同意的情况下观看成人电影。注意:父母锁功能需要的支持。

 

DVD导航(Navigation)还有一个非常重要的抽象概念,就是域(ain)。通俗地说,也就是DVD在特定播放状态下的操作许可。比如“选择按钮”命令必须在菜单状态下才有效,“快进”命令在停止或者菜单状态下是无效的。播放器必须使用域的概念,阻止用户向DVD器发送无效的命令。下表列出了五个主要的域以及对应的操作说明:

Domain(域)

DVD导航器的工作内容

First Play(开始播放DVD时第一个播放的一段视频内容)

读取光盘上初始部分

Video Manager Menu(显示VMGM菜单时)

读取光盘的主菜单,菜单相关的指令都是有效的

Video Title Set Menu(显示VTSM菜单时)

读取VTSM菜单,或者设置音频、字幕、视角等的子菜单,菜单相关的指令都是有效的

Title(播放标题内容时)

菜单相关的指令都是无效的 

Stop(停止时)

导航器不在工作,此时可以播放指令

另外,DVD的制作者还可以利用“用户操作控制”功能(User Operation Controls,简称UOPs)来限制用户的操作。这需要在光盘上记录这些限制记号。比如,大多数光盘都不允许用户在DVD播放处于First Play域时执行快进或者显示菜单命令。

 

二.  DirectShow对DVD的支持

 

DirectShow对DVD播放提供了强力的支持。(DirectShow为支持DVD播放作了大量的工作,除了不提供MPEG2 Video Decoder Filter外。换句话说,必须提供第三方的MPEG2 Decoder,否则我们写的播放还是跑不起来的!)编写DVD播放程序,我们无须研究DVD的规格说明书;了解上面的这些基础知识就已经足够了。因为提供了一个叫DVD Navigator的Filter,帮我们完成了繁琐的DVD导航的任务;提供一个专门用于建立播放DVD的Filter Graph的COM(CLSID_DvdGraphBuilder)。我们所要做的,主要就是使用DVD Navigator的两个接口:IDvdInfo2,获得光盘的属性和导航状态;以及IDvdControl2,设置属性和执行播放操作。典型的播放DVD的Filter Graph如下:

ectratio="t">CSDN_Dev_Image_a%20href=2003-7-131013470.png" o:title="">

典型的Filter Graph创建过程如下:

// Create an instance of the DVD Graph Builder .

 

HRESULT hr;

 

hr = CoCreateInstance(CLSID_DvdGraphBuilder,

 

  NULL,

 

  CLSCTX_INPROC_SERVER,

 

   IID_IDvdGraphBuilder,

 

  reinterpret_cast(&m_pIDvdGB));

 

 

 

// Build the DVD filter graph.

 

AM_DVD_RENDERSTATUS buildStatus;

 

hr = m_pIDvdGB->RenderDvdVideoVolume(pszwDiscPath, m_dwRenderFlags, &buildStatus);

 

 

 

// Get the pointers to the DVD Navigator interfaces.

 

hr = m_pIDvdGB->GetDvdInterface(IID_IDvdInfo2, reinterpret_cast(&m_pIDvdI2));

 

hr = m_pIDvdGB->GetDvdInterface(IID_IDvdControl2, reinterpret_cast(&m_pIDvdC2));

 

  ... 

 

// Get a pointer to the filter graph manager.

 

hr = m_pDvdGB->GetFiltergraph(&m_pGraph);

 

... 

 

// Use the graph pointer to get a pointer to IMediaControl,

 

// for controlling the filter graph as a whole.

 

hr = m_pGraph->QueryInterface(IID_IMediaControl, reinterpret_cast(&m_pIMC));

 

... 

 

// Get a pointer to IMediaEventEx,

 

// used for handling DVD and other filter graph events.

 

hr = m_pGraph->QueryInterface(IID_IMediaEventEx, reinterpret_cast(&m_pME));

 

... 

 

// Use the graph builder pointer again to get the IVideoWindow interface,

 

// to set the window style and message-handling behavior of the video renderer filter.

 

hr = m_pIDvdGB->GetDvdInterface(IID_IVideoWindow, reinterpret_cast(&m_pIVW));

 

hr = m_pDvdGB->GetDvdInterface(IID_IAMLine21Decoder, reinterpret_cast(&pL21Dec));

 

 

关于IDvdInfo2和IDvdControl2的各个接口方法的详细说明和用法,请参见DirectShow SDK文档,以及SDK提供的例子代码DVDSample。下面,仅就编写DVD播放程序需要注意的地方,进行一些简单的罗列:

1.  为了得到DVD Navigator在创建时发出的事件,一般在RenderDvdVideoVolume 之前获得ImediaEventEx接口。

2.  菜单命令实际上有两种,一种是选中(),一种是激活(Activate)。前者如IDvdControl2::SelectAtPosition,IDvdControl2::SelectButton,IDvdControl2::SelectRelativeButton等,效果是高亮度显示被选中的菜单;后者如IDvdControl2::ActivateAtPosition,IDvdControl2::ActivateButton等,效果是产生相应的动作。也有选中加激活的命令,如IDvdControl2::SelectAndActivateButton。

3.  DVD最多支持8条音频流、32条子图片流,但在同一时刻,都只能各自选中某一条。

4.  DVD Navigator本身并不强调父母锁功能,而只是把光盘上的PML信息发送给应用程序。因此,父母锁功能需要在应用程序上完成。

5.  通过IDvdInfo2::GetState调用,可以得到IDvdState,用以实现“书签”的功能。具体实现参见DVDSample的CDvdCore::SaveBookmark和CDvdCore::RestoreBookmark两个。

6.  注意DVD播放时候的Filter Graph状态,需要同时考虑DVD Navigator的状态。

7.  支持卡拉OK的DVD,要求Audio Decoder实现AM_KSPROPSETID_DvdKaraoke属性集(即实现IKsPropertySet接口)。

8.  IDvdControl2关于播放的接口方法,一般都有异步和同步两种调用方式。如果是异步方式,调用这些接口方法后,会立即返回,而并不等到实际的操作完成。有时候,这样操作会引起DVD Navigator的状态混乱。对于这些接口方法,微软推荐了有5种调用方法,下面列出常用的3种:

(1)异步方式(以PlayTitle调用为例,下同)

  HRESULT hr = pDVDControl2->PlayTitle( uTitle,

 

 DVD_CMD_FLAG_None, // = 0

 

  NULL);

 

(2)阻塞方式

  HRESULT hr = pDVDControl2->PlayTitle( uTitle,

 

  EC_DVD_CMD_FLAG_Block, 

 

 NULL);

 

 

(3)使用同步对象

IDvdCmd* pObj;

 

HRESULT hr = pDVDControl2->PlayTitle(uTitle,  0, &pObj);

 

if(SUCCEEDED(hr))

 

{

 

  pObj->WaitToEnd();

 

  pObj->Release();

 

}

 

 

三.  总结

 

总之,DirectShow使我们从DVD的专业知识中解放出来;有了DirectShow的支持,编写一个DVD播放程序还是比较轻松的!再次提醒读者朋友们,必须要提供第三方的Video Decoder和Audio Decoder,否则,我们的DVD播放程序会陷入“万事具备,只欠东风”的窘境!

 

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/10748419/viewspace-959126/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/10748419/viewspace-959126/

你可能感兴趣的文章
Activiti工作流会签三 撤销,审批,驳回
查看>>
Oauth2方式实现单点登录
查看>>
CountDownLatch源码解析加流程图详解--AQS类注释翻译
查看>>
ES相关度评分
查看>>
我们一起做一个可以商用的springboot脚手架
查看>>
idea在搭建ssm框架时mybatis整合问题 无法找到mapper
查看>>
PHP empty、isset、innull的区别
查看>>
apache+nginx 实现动静分离
查看>>
通过Navicat远程连接MySQL配置
查看>>
phpstorm开发工具的设置用法
查看>>
Linux 系统挂载数据盘
查看>>
Git基础(三)--常见错误及解决方案
查看>>
Git(四) - 分支管理
查看>>
PHP Curl发送数据
查看>>
HTTP协议
查看>>
HTTPS
查看>>
git add . git add -u git add -A区别
查看>>
apache下虚拟域名配置
查看>>
session和cookie区别与联系
查看>>
PHP 实现笛卡尔积
查看>>