如果m+1/2的二次方加上n+5/7的绝对值等于零则m与n的大小关系是?

第一节、 HTML基本语法(文末有对该文视频讲解)

  HTML的官方介绍什么的我就不说了,打字也挺累的,只简单介绍一下吧,其他的懂不懂都没关系。   HTML全称为Hypertext Markup Language,中文解释为超文本标记语言。   在HTML语言中,所有的标记都必须用尖括号(即大于号“<”和小于号“>”)括起来,一般情况下,每个标记单独占一行,

代码很简单,我就不解释了,看一下执行效果吧,这是网页初打开时的状态:

下面这个是我点击这个链接后出现的画面:

这样就达到了创建邮件链接的目的,好了,我们今天的任务结束,下节课开始讲表单,朋友们再见。 第23节、使用表单

今天继续,开始说表单的实现,先说一下什么是表单,来看个图吧:

我这个图是截的free258的注册页面的图,这就是一个表单,我们在表单里输入相关的信息,然后点击最下面的“注册”按钮,这样我们所填写的信息就通过post或get方式传送给了网站的数据库,这样网站的管理人员就有了我们的注册资料。 那么,表单就是一种用来收集站点访问者信息的一种手段,当我们填完表单后,我们点击“注册”或“提交”按钮,这样我们所填的信息就被送出了,这时候,网站管理人员事先设定好的处理我们提交的信息的程序就会启动,以各种不同的方式处理这些数据。 那么,在HTML中,表单标记为form,基本语法格式如下:

我们来介绍一下form标记的属性:

1. name属性:我们使用这个属性指定表单的名字,以便在后面使用脚本的时候调用该表单,不然没有名字的话,脚本不认识它。
2. method属性:指定传送数据的方式,该属性可以有两个值,get和post,其中get的意思是直接将表单数据附加到请求该页的URL后,从而传送到服务器上,post的意思是在HTTP请求中嵌入表单数据,再传送。
需要注意的是,使用get方式时应保证表单的数据不超过8192个字节,若超过了8192个字节,那么表单中的数据将被截断,从而造成数据处理失败,另外,如果表单中传送的是用户名和密码等重要信息的话,不要使用get方法,而应该使用更安全的post方法,所以,当我们指定表单数据的传送方式时,最好用post方法。
3. action属性:指定将要接收表单数据的服务器端程序或该程序的URL地址。
4. onsubmit属性:指定提交表单时要调用的事件处理程序
5. onreset属性:指定重置表单时要调用的事件处理程序
6. target属性:指定一个目标窗口,其取值如下:
☆ _blank:在未命名的窗口中打开目标文档
☆ _parent:在显示当前文档的窗口的父窗口中打开目标文档
☆ _self:在提交表单所使用的窗口中打开目标文档
☆ _top:在当前窗口中打开目标文档,并确保目标文档占用整个窗口

在一个网页中可以包含多个表单,在每个表单里都可以包含各种控件、文本框、复选框、下拉选单、按钮等内容,但,需要记住的是,表单是不能嵌套的。 OK,下面我们先来说如何使用输入型表单控件: 在HTML中,我们使用input标记来创建各种输入型表单控件,通过将input标记的type属性设置为不同的值,可以创建不同类型的输入型表单控件,包括单行文本框、密码框、复选框、单选按钮、文件域、按钮等。 下面我们来说一下使用单行文本框的方法。 将input的type属性设为text,即在网页中插入了一个单行文本输入框。 基本语法为:

其中,name属性指定该单行文本框的名字,指定名字是为了我们以后使用脚本处理表单中的数据的时候用,value属性指定单行文本框的初始值,即在用户未输入任何内容时文本框里显示的内容,size属性指定单行文本框的宽度,maclength属性指定单行文本框内可输入的最大字符数。 OK,这东西不难的,那么下面我们就再来说一个,使用密码输入框。 朋友们应该有过体会,就是我们在注册账户或登录账户的时候,我们输进去的密码显示的是星号(*)或者实心圆点(●),我们现在就来讨论一下这些技术的实现方法: 使用密码输入框的方法跟使用单行文本框的方法差不多,只是input的type值由text变成了password,即基本语法为:

这里name属性与单行文本框的名字的作用一样,value和size、maxlength都一样。 好,密码输入框我们也说过了,不要着急,上面两个输入框使用的方法大致上是一样的,那么,我们就再来说一个不同的,不过这个不同也只是一点点的不同罢了,那就是----使用按钮。 我们在注册或者登录的时候经常会用到各种各样的按钮,比如确定、重写、提交、注册等等按钮,这些按钮的实现方法就是将input的type属性设置为不同值来实现的。 在HTML里,我们可以使用input的type值设为submit(提交按钮),reset(重置按钮)和button(自定义按钮)。 创建按钮的基本语法为:

其中type可取的值有: 1. submit:创建一个提交按钮,当用户将表单中的需要填的东西填完了之后,点击此按钮提交填写好的数据,当我们点击了提交按钮之后,表单中的(包括提交按钮的名字和值)以ASCII文本格式传送给由表单中指定的表单处理程序来处理。 一般情况下,每个表单都是有提交按钮的。 2. reset:创建一个重置按钮,在输入表单时如果我们输入错误的地方有很多或者填完以后发现没有表达自己的意思的话,我们可以使用重置按钮,这个按钮的作用就是清空表单中已被填写或选择的项目,将表单还原到初始状态。 3. button:创建一个自定义按钮,这样的按钮被创建以后,我们必须为其指定一个专门的按钮处理程序,也就是必须为其指定一个处理脚本。 4. name:指定按钮的名称,注意,这个是按钮的名字,不是在按钮上显示的文字。 5. value:指定在按钮上显示的文字,比如设为“提交”。 另外,值得一提的是,除了上述属性之外,按钮控件还支持onclick事件,onclick事件就是鼠标单击事件,就是当我们单击了这个按钮的时候按钮可以作出相应的反应。 OK,下面我们来写一段代码,使用我们上边学习的内容来创建一个简单的表单。

  我们来看一下执行效果吧:   这是网页刚打开的时候:

  这是我填写了一些内容之后:

  可以看到,在密码的输入栏里显示的是星号,这样安全系数就进一步增强了。   点击重写按钮则清空所有已填写的内容,恢复表单的初始状态,当然,在这里我点击确定也是没有用的,因为我没有对<form>标记指定处理它提交的内容的程序,我们会在接下来的课程中一步一步讲到。   好了,今天就说这么多吧,我们明天见! 第24节、在表单中使用图形化按钮、单选按钮和复选按钮

  上节课我们说的是,在表单中使用单行文本框以及密码框、提交按钮、重置按钮等,今天我们来学习一下使用图形化按钮和单选按钮和复选按钮。   先说使用图形化按钮,意思就是使用一张图片作为一个按钮来使用,这样看起来更美观,它的基本语法是这样的:

其中,type的值为image,这意思就是说,我现在使用的是一个图形按钮,而后面的src属性则指定了我们使用的图像按钮的位置,再后面,是name属性和value属性,我们在写代码的时候,这两个属性随便用一个就好,不必两个都用,因为它们在这里的作用是一样的-----都是指定的图像的替换文字,也就是当图像显示不出来时的替换文字。 使用图形化的按钮就说完了,下面是使用单选按钮,首先,我们来了解一下什么是单选按钮,所谓单选按钮,顾名思义,就是在一组选项中,我们一次只能选择一个,实现方法是将type的属性设置为radio,基本语法是这样的:

其中,name属性指定单选按钮的名称,若干个名称相同的单选按钮构成一个单选选项组,我们一次在这个组中只能选择一个选项。 Value属性指定提交时的值,就是每个单选选项对应的编号。 还有一个checked属性,这个属性是可选属性,它是用来指定单选框的默认选择的,就是如果使用了这个属性,则这个选框在初始状态时是被默认选中的。 单选也说完了,还有一个复选,这个也不难,使用复选框 下面我们来写一段代码, 例28(23.html):

  OK,我们来看一下代码的执行效果:

  好了,这个表单里用到了单元格的合并,单行文本框,单选框,复选框,提交按钮和重置按钮,可以看到在单选框里,“男”是默认被选中的,这就是我们使用了checked属性的效果。   今天就说到这里吧,关键还是要多多练习,那样才会有效果。   下节课再见,我是不是嫖客,再见。

第25节、在表单中插入文件域

  上节课我们说了使用单选按钮和复选按钮还有图形化的按钮,我们举的例子有单选按钮和复选按钮,但没有举图形化的按钮的例子,那么这节课我们就来演示一下,在演示之前呢,我们还需要学习一点知识,那就是学学在表单中插入文件域。   首先,说明一下什么是文件域,我们来看个图吧:

  这里是红吧上传页面的一部分,这里就是一个文件域,可以看出,一个文件域由一个文本框和一个“浏览”按钮组成,我们可以直接在文本框中输入文件的路径,也可以点击浏览,然后选择需要上传的文件。   我们将input标记的type属性设为file,即可在网页中插入文件域。   语法格式为:

其中,name属性指定文件域的名字标识,value属性指定初始文件名,size属性指定文件名输入框的宽度。 下面我们来写一段实例,对着实例看看你就明白怎么用了。 例29(24.html):

来看一下代码的执行效果吧: 虚拟机坏了,只好在本地打开了,呵呵:

OK,这节课就说这么多吧。

第26节、使用其他类型的表单控件

这节课,应该是HTML课程的最后一节课了,呵呵,苦难的日子终于要结束了,把这事做完我就得给吧里再规划一下了。 废话不多说了,今天的内容可能有些多,但都不难,我们一个一个的来看。 一、 在表单中使用滚动文本框 我们在前面讲过使用单行文本框,即将input的type属性值设为text,这里的多行文本框的实现方法可不一样了,我们直接在<form>和</form>标记对之间使用textarea标记来创建多行文本框(即滚动文本框),其基本语法为:

其中的name属性指定滚动文本框控件的名称,rows属性指定该控件的高度(以行为单位),cols属性指定该控件的宽度(以字符为单位),readonly属性是可选的,这个单词朋友们应该可以看懂吧,是只读的意思,即指定该属性后该控件内的内容不可被浏览者修改。 而<textarea>和</textarea>之间的内容将作为这个滚动文本框的初始值。

二、 在表单中使用下拉菜单控件

我想朋友们应该知道什么是下拉菜单吧,我们可以从列表或选单中选择一项或多项。 我们在<form>和</form>标记之间使用select标记来创建下拉菜单,并使用option标记将每个选项列出来,其基本语法为:

同样的,name属性指定该控件的名称,size属性指定在列表中一次可以看到的选项数目,multiple属性是一个布尔属性,它指定该控件是否允许选择多项,即加上该属性时,允许多选,不加则不允许多选,selected属性指定该项的初始状态为选中状态。

我们前面介绍的都是使用单个控件的例子,但如果我们需要在一个页面里使用多个表单控件的话,给他们分组是一个不错的选择。 在HTML里,使用fieldset标记对表单控件进行分组,该标记必须以legend标记开头,以指定控件组的标题,在legend之后是该组内的控件,也可以使用嵌套的fieldset。 其基本语法格式为:

  好了,我们上面把今天的内容大致说了一下,下面又到写代码的环节了,最后一节课,我们尽量多用前面学习的知识吧,下面来一起创建一个表单: 例30(25.html):

  OK,我们来看代码的执行效果:

  这就是控件分组的效果,还是不错的。   那么到这里为止,我们的表单就已经基本结束了,最后再介绍一点,即我们创建了表单以后设计到的表单的提交和处理问题,当用户填写完表单后,点击提交按钮即可将表单数据提交给服务器上指定的表单处理程序。   提交信息表单处理程序的方法由form标记的method属性来确定,

  提交表单的方法有两种:

1 get方法将表单的名称/值对进行程序编码,并将该信息赋予给一个叫QUERY_STRING的服务器变量;
3 post方法则直接将名称/值对传送至表单处理程序作为该程序的输入

  表单处理程序的URL地址由form标记的action属性来决定,当然,如果要处理我们自己创建的表单数据的话,我们需要在服务器端为其编写脚本(asp、php等)作为该表单的处理程序,说到这里可能有的朋友已经想到注入了,呵呵,这个貌似跟注入还是有那么一点点关系的,呵呵   好了,我们表单的学习正式结束,到这里,我们的HTML课程也就结束了,历时26节课,我写了有一个多月,每天坚持着写一篇,虽然很简单,但也算是为吧里做了点贡献吧,呵呵   其实编程这东西还是需要很大毅力的,我看书的时候,第一遍看不懂,我觉得很正常,那我会继续看第二遍,还不懂,继续第三遍,呵呵,最终我学会了。

本文介绍如何为增强的视频呈现器编写自定义演示器 (EVR) 。 自定义演示者可以同时与 DirectShow 和 Media Foundation 一起使用;接口和对象模型对于这两种技术都是相同的,尽管确切的操作顺序可能会有所不同。

本主题中的示例代码改编自 Windows SDK 中提供的 。

在编写自定义演示者之前,应熟悉以下技术:

  • 增强的视频呈现器。 请参阅 。
  • 。 EVR 混音器是媒体基础转换,演示者直接在混音器上调用方法。
  • 实现 COM 对象。 演示者是进程内自由线程 COM 对象。

本部分包含演示者对象模型和接口的概述。

EVR 使用两个插件组件来呈现视频:混音器和演示者。 混音器混合视频流,并根据需要取消交错视频。 演示者绘制 (或 演示 视频) 显示,并在绘制每个帧时安排。 应用程序可以将其中任一对象替换为自定义实现。

EVR 有一个或多个输入流,混音器具有相应的输入流数。 流 0 始终是 引用流。 其他 流是子流,混合器 alpha 混合到引用流中。 参考流确定复合视频的主帧速率。 对于每个参考帧,混音器从每个子流获取最新的帧,alpha 将它们混合到参考帧上,并输出单个复合帧。 如果需要,混音器还执行从 YUV 到 RGB 的反交错和颜色转换。 无论输入流数或视频格式如何,EVR 始终将混音器插入视频管道。 下图演示了此过程。

  • 在混音器上设置输出格式。 在流式处理开始之前,演示者在混音器的输出流上设置媒体类型。 此媒体类型定义复合图像的格式。
  • 分配 Direct3D 图面。 混音器将复合帧点到这些表面。
  • 显示帧的时间安排。 EVR 提供演示时钟,演示者会根据此时钟计划帧。
  • 执行帧单步执行和清理。

在任何时候,演示者处于以下状态之一:

  • 已启动。 EVR 的演示文稿时钟正在运行。 演示者在到达时计划演示的视频帧。
  • 已暂停。 演示文稿时钟挂起。 演示者不显示任何新样本,而是维护其计划的样本队列。 如果收到新样本,演示者会将它们添加到队列。
  • 已停止。 演示文稿时钟已停止。 演示者放弃计划的任何样本。
  • 关闭。 演示者释放与流式处理相关的任何资源,例如 Direct3D 图面。 这是演示者的初始状态,演示者销毁演示者之前的最后状态。

在本主题中的示例代码中,演示者状态由枚举表示:

演示者处于关闭状态时,某些操作无效。 示例代码通过调用帮助程序方法检查此状态:

实现以下接口需要演示者:

还可以为应用程序提供与演示者通信的接口。 标准演示者为此实现了 接口。 可以实现此接口或定义自己的接口。 应用程序通过调用

接口包含一个返回设备 GUID 的方法 。 设备 GUID 可确保演示者和混音器使用兼容的技术。 如果设备 GUID 不匹配,则 EVR 无法初始化。

标准混音器和演示者都使用 Direct3D 9,设备 GUID 等于 IID_IDirect3DDevice9。 如果打算将自定义演示者与标准混音器一起使用,则必须 IID_IDirect3DDevice9演示者的设备 GUID。 如果替换这两个组件,则可以定义新的设备 GUID。 本文的其余部分假定演示者使用

即使演示者关闭,该方法也应成功。

接口使演示者能够从 EVR 和混音器获取接口指针,如下所示:

  1. 当 EVR 初始化演示者时,它会调用演示者的 方法。 该参数是指向 EVR 的
  2. 演示者调用 从 EVR 或混音器获取接口指针。

方法类似于 方法。 这两种方法都采用服务 GUID 和接口标识符 (IID) 作为输入,但 LookupService 返回接口指针数组,而 GetService 返回单个指针。 但是,在实践中,始终可以将数组大小设置为 1。 查询的对象取决于服务 GUID:

在 的实现中,从 EVR 获取以下接口:

从混音器中获取以下接口:

当从 获取的接口指针不再有效时,EVR 调用 。 在此方法中,释放所有接口指针,并将演示者状态设置为关闭:

EVR 出于各种原因调用 ,包括:

在演示者的生存期内,EVR 可能会多次调用 和

接口继承 ,并添加两种方法:

方法返回演示者的媒体类型。 (有关设置媒体类型的详细信息,请参阅 ”。) 媒体类型作为 接口指针返回。 以下示例假定演示者将媒体类型存储为 指针。 若要从媒体类型获取 IMFVideoMediaType 接口,请调用 QueryInterface

方法是 EVR 与演示者通信的主要机制。 定义了以下消息。 本主题的其余部分提供了实现每个消息的详细信息。

混音器的输出媒体类型无效。 演示者应与混音器协商新的媒体类型。 请参阅 。
流式处理已开始。 此消息不需要执行任何特定操作,但你可以使用它来分配资源。
混音器已收到新的输入样本,并可能能够生成新的输出帧。 演示者应在混音器上调用 。 请参阅 。
演示文稿已结束。 请参阅 。
EVR 正在刷新其呈现管道中的数据。 演示者应放弃计划用于演示的任何视频帧。
请求演示者向前推进 N 帧。 演示者应放弃下一个 N-1 帧并显示第 N 帧。 请参阅 。

演示者必须实施 接口,作为 实现的一部分,该接口继承 了 IMFClockStateSink。 每当 EVR 的时钟更改状态时,EVR 都使用此接口通知演示者。 有关时钟状态的详细信息,请参阅 。

下面是实现此接口中方法的一些准则。 如果演示者关闭,所有方法都应失败。

为了支持除 1× 速度以外的播放速率,演示者必须实现 接口。 下面是实现此接口中方法的一些准则。 关闭演示者后,所有方法都应失败。 有关此接口的详细信息,请参阅 。

返回零,指示没有最小播放速率。
对于非精简播放,播放速率不应超过监视器的刷新速率: 最大速率 = ( Hz) / 视频帧速率 (fps) 。 视频帧速率在演示者的媒体类型中指定。
对于精简播放,播放速率不受限制;返回 值FLT_MAX。 实际上,源和解码器将是精简播放期间的限制因素。
对于反向播放,返回最大速率的负值。
如果 flRate 的绝对值超过演示者的最大播放速率,则返回MF_E_UNSUPPORTED_RATE。 计算 描述的最大播放速率。

以下示例演示如何实现 方法:

前面的示例调用帮助程序方法 GetMaxRate 来计算最大转发播放速率:

以下示例演示如何实现 方法:

演示者必须通知 EVR 各种事件。 为此,它使用 EVR 的 接口,当 EVR 调用演示者的

下表列出了演示者发送的事件以及事件参数。

有关详细信息,请参阅 。
有关详细信息,请参阅 。
发生需要流式处理才能停止的错误。
指定演示者呈现每个帧所花费的时间量。 (可选。)
  • Param1:指向一个常量 LONGLONG 值的指针,该值包含处理帧的时间量(以 100 纳米秒为单位)。
有关详细信息,请参阅 。
指定呈现示例中的当前滞后时间。 如果值为正值,则样本会落后于计划。 如果值为负值,则样本提前。 (可选。)
  • Param1:指向包含延迟时间的常量 LONGLONG 值的指针,以 100 纳秒为单位。
如果播放速率为零 ,则立即在EC_STEP_COMPLETE 后发送。 此事件包含显示的帧的时间戳。
有关详细信息,请参阅 。
演示者已完成或取消帧步骤。
有关详细信息,请参阅 。
文档的早期版本错误地描述了 Param1 。 此参数不用于此事件。

  1. 在混音器上调用 以获取可能的输出类型。 此类型描述混音器可以生成的格式,给定图形设备的输入流和视频处理功能。

  2. 检查演示者是否可以将此媒体类型用作其呈现格式。 以下是要检查的一些事项,尽管实现可能有自己的要求:

    如果类型不可接受,请返回到步骤 1 并获取混音器的下一个建议类型。

  3. 创建一个新的媒体类型,该类型是原始类型的克隆,然后更改以下属性:

    • 将 属性设置为要分配给 Direct3D 图面的宽度和高度。
  4. 将 属性设置为通常为 1:1) 的显示 (PAR。
  5. 设置几何光圈 ( 属性) 等于 Direct3D 图面中的矩形。 当混音器生成输出帧时,它会将源图像点入此矩形。 几何光圈可以像表面一样大,也可以是表面中的子孔径。 有关详细信息,请参阅 。
  6. 若要测试混音器是否接受修改后的输出类型,请使用MFT_SET_TYPE_TEST_ONLY标志调用 。 如果混音器拒绝该类型,请返回到步骤 1 并获取下一个类型。

  7. 分配 Direct3D 图面池,如 中所述。 当混合器绘制复合视频帧时,混音器将使用这些图面。

  8. 通过调用不带标志的 在混音器上设置输出类型。 如果对 SetOutputType 的第一次调用在步骤 4 中成功,则该方法应再次成功。

如果混音器类型耗尽, 方法将返回 MF_E_NO_MORE_TYPES。 如果演示者找不到适合混音器的输出类型,则无法呈现流。 在这种情况下,DirectShow或媒体基础可能会尝试其他流格式。 因此,演示者可能会连续接收多个 MFVP_MESSAGE_INVALIDATEMEDIATYPE 消息,直到找到有效的类型。

混音器自动将视频装箱,考虑到源和目标的 PAR (像素纵横比) 。 为了获得最佳效果,表面宽度和高度和几何光圈应等于你希望视频在显示器上显示的实际大小。 下图演示了此过程。

以下代码显示了该过程的大纲。 某些步骤放置在帮助程序函数中,具体细节将取决于演示者的要求。

有关视频媒体类型的详细信息,请参阅 。

演示者创建 Direct3D 设备并在流式处理过程中处理任何设备丢失。 演示者还托管 Direct3D 设备管理器,它为其他组件使用相同的设备提供了一种方法。 例如,混音器使用 Direct3D 设备混合子流、取消交错和执行颜色调整。 解码器可以使用 Direct3D 设备进行视频加速解码。 (有关视频加速的详细信息,请参阅 .)

若要设置 Direct3D 设备,请执行以下步骤:

  1. 通过调用 创建设备管理器。在设备管理器上设置设备。

如果另一个管道组件需要设备管理器,它会在 EVR 上调用 ,为服务 GUID 指定 MR_VIDEO_ACCELERATION_SERVICE 。 EVR 将请求传递给演示者。 对象获取 指针后,可以通过调用 来获取设备的句柄。 当对象需要使用设备时,它将设备句柄传递给

创建设备后,如果演示者销毁设备并创建一个新设备,则演示者必须再次调用 。 ResetDevice 方法使任何现有设备句柄失效,这会导致 返回DXVA2_E_NEW_VIDEO_DEVICE。 此错误代码使用设备向其他对象发出信号,指出它们应打开新的设备句柄。 有关使用设备管理器的详细信息,请参阅 。

演示者可以在窗口模式或全屏独占模式下创建设备。 对于窗口模式,应为应用程序提供指定视频窗口的方法。 标准演示者为此实现了 方法。 首次创建演示者时,必须创建设备。 通常,目前你不知道所有设备参数,例如窗口或后退缓冲区格式。 可以创建临时设备,稍后将其替换&#;只需记住在设备管理器上调用

演示者设置媒体类型后,可以分配 Direct3D 图面,混音器将使用该图面来写入视频帧。 图面必须与演示者的媒体类型匹配:

  • 图面格式必须与媒体子类型匹配。 例如,如果子类型 MFVideoFormat_RGB24,则必须 D3DFMT_X8R8G8B8图面格式。 有关子类型和 Direct3D 格式的详细信息,请参阅 。
  • 图面宽度和高度必须与媒体类型的 属性中给定的尺寸匹配。

分配图面的建议方式取决于演示者是窗口运行还是全屏运行。

如果为 Direct3D 设备开窗,则可以创建多个交换链,每个交换链都有一个后退缓冲区。 使用此方法可以独立呈现每个图面,因为呈现一个交换链不会干扰其他交换链。 混音器可以将数据写入图面,同时计划另一个图面进行演示。

首先,确定要创建的交换链数。 建议至少使用三个。 对于每个交换链,请执行以下操作:

  1. 调用 并传入指向图面的指针。 此函数返回指向视频示例对象的指针。 当演示者调用混音器的 方法时,视频示例对象实现 接口,演示者使用此接口将表面传递到混音器。 有关视频示例对象的详细信息,请参阅 。
  2. 将 指针存储在队列中。 演示者将在处理过程中从此队列中提取示例,如 中所述。

在全屏独占模式下,设备不能有多个交换链。 创建全屏设备时,将隐式创建此交换链。 交换链可以有多个后退缓冲区。 但是,遗憾的是,如果在写入同一交换链中的另一个后退缓冲区时存在一个后退缓冲区,则无法轻松协调这两个操作。 这是因为 Direct3D 实现图面翻转的方式。 调用 Present 时,图形驱动程序会更新图形内存中的图面指针。 如果在调用

最简单的选项是为交换链创建一个视频示例。 如果选择此选项,请按照为窗口模式指定的相同步骤操作。 唯一的区别是示例队列包含单个视频示例。 另一种方法是创建屏幕外图面,然后将它们点亮到后缓冲区。 你创建的图面必须支持 方法,混音器用于复合输出帧。

演示者首先分配视频示例时,它会将它们置于队列中。 演示者每当需要从混音器中获取新帧时,都从此队列中绘制。 混音器输出帧后,演示者会将样本移到第二个队列中。 第二个队列用于等待其计划的演示时间的示例。

为了更轻松地跟踪每个示例的状态,视频示例对象实现 接口。 可按如下所示使用此接口:

  1. 在演示者中实现 接口。

  2. 在将示例置于计划队列之前,请查询 接口的视频示例对象。

  3. 使用指向回调接口的指针调用 。

  4. 当示例准备好演示时,请将其从计划队列中删除、演示该示例并释放对该示例的所有引用。

  5. 该示例调用回调。 (在这种情况下,示例对象不会被删除,因为它在调用回调之前本身保留引用计数。)

  6. 在回调中,将示例返回到可用队列。

使用 跟踪样本不需要演示者;可以实现最适合设计的任何技术。 IMFTrackedSample 的一个优点是,可以将演示者的计划和呈现函数移到帮助程序对象中,并且这些对象在发布视频示例时不需要任何特殊的机制来回叫演示者,因为示例对象提供了该机制。

以下代码演示如何设置回调:

在回调中,对异步结果对象调用 以检索指向示例的指针:

每当混音器收到新的输入样本时,EVR 就会向演示者发送 MFVP_MESSAGE_PROCESSINPUTNOTIFY 消息。 此消息指示混音器可能具有要传送的新视频帧。 对此,演示者在混音器上调用 。 如果方法成功,演示者将计划演示示例。

若要从混音器获取输出,请执行以下步骤:

  1. 检查时钟状态。 如果时钟暂停,请忽略 MFVP_MESSAGE_PROCESSINPUTNOTIFY 消息,除非这是第一个视频帧。 如果时钟正在运行,或者这是第一个视频帧,请继续。

  2. 从可用示例队列中获取示例。 如果队列为空,则表示当前计划演示所有已分配的样本。 在这种情况下,暂时忽略 MFVP_MESSAGE_PROCESSINPUTNOTIFY 消息。 当下一个示例可用时,请重复此处列出的步骤。

  3. (Optional.) 如果时钟可用,请通过调用 获取当前时钟时间

  4. 在混音器上调用 。 如果 ProcessOutput 成功,示例包含视频帧。 如果该方法失败,请检查返回代码。 ProcessOutput 中的以下错误代码不是关键故障:

    混音器需要更多输入,然后才能生成新的输出帧。
    如果收到此错误代码,请检查 EVR 是否已到达流的末尾并相应地做出响应,如 中所述。 否则,请忽略此 MF_E_TRANSFORM_NEED_MORE_INPUT 消息。 当混音器获得更多输入时,EVR
    混音器的输出类型可能由于上游格式更改而失效。
    如果收到此错误代码,请将演示者的媒体类型设置为 NULL。 EVR 将请求新格式。
    混音器需要新的媒体类型。
    如果收到此错误代码,请重新谈判混音器的输出类型,如 中所述。
  5. (Optional.) 如果时钟可用,请获取当前时钟时间 (T2) 。 混音器引入的延迟量 (T2T1 - ) 。 将具有此值 的EC_PROCESSING_LATENCY 事件发送到 EVR。 EVR 使用此值进行质量控制。 如果没有可用的时钟,则无法发送

在演示者从混音器获取任何输出之前,此步骤序列可以终止。 为了确保不会删除任何请求,应在发生以下情况时重复相同的步骤:

  • 回调。 这会处理混音器接收输入但演示者的所有视频样本都正在使用 (步骤 2) 的情况。

此方法 ProcessInputNotify 设置一个布尔标志来记录混音器具有新输入的事实。 然后,它会调用 ProcessOutputLoop 下一个示例中所示的方法。 此方法尝试从混音器中提取尽可能多的样本:

有关此示例的一些备注:

  • 设置 TrackSample 回调的方法显示在 ”部分中。

有时演示者可能需要重新绘制最新的视频帧。 例如,标准演示者在以下情况下重新绘制帧:

  • 在窗口模式下,响应应用程序窗口收到的 WM_PAINT 消息。 请参阅 。

使用以下步骤请求混音器重新创建最新的帧:

  1. 调用 。 指定最新视频帧的时间戳。 (需要缓存此值并为每个 frame

重新绘制帧时,可以忽略演示文稿时钟并立即显示帧。

视频帧可以随时到达 EVR。 演示者负责根据帧的时间戳在正确的时间呈现每个帧。 当演示者从混音器中获取新样本时,它将样本置于计划队列中。 在单独的线程上,演示者会不断从队列的头获取第一个示例,并确定是否:

  • 将示例保留在队列中,因为它很早。
  • 放弃示例,因为它已晚。 尽管如果可能,应避免删除帧,但如果演示者不断落后,则可能需要删除帧。

若要获取视频帧的时间戳,请调用视频示例中的 。 时间戳相对于 EVR 的表示时钟。 若要获取当前时钟时间,请调用 。 如果 EVR 没有演示文稿时钟,或者示例没有时间戳,可以在获取示例后立即显示该示例。

若要获取每个示例的持续时间,请调用 。 如果示例没有持续时间,可以使用 函数从帧速率计算持续时间。

安排示例时,请记住以下事项:

  • 如果播放速率比正常速度快或慢,则时钟以更快的速度或较慢的速度运行。 这意味着示例上的时间戳始终提供相对于演示文稿时钟的正确目标时间。 但是,如果将演示文稿时间转换为其他一些时钟时间 (例如,高分辨率性能计数器) ,则必须根据时钟速度缩放时间。 如果时钟速度发生变化,EVR 将调用演示者的 方法。
  • 对于反向播放,播放速率可以为负数。 播放速率为负时,演示文稿时钟向后运行。 换句话说, N + 1 发生在 N 时间之前。

以下示例计算示例相对于演示文稿时钟的早期或迟到时间:

演示文稿时钟通常由系统时钟或音频呈现器驱动。 (音频呈现器从声卡使用 audio.) 的速率派生时间,通常演示文稿时钟不会与监视器的刷新速率同步。

如果 Direct3D 演示文稿参数为演示文稿间隔指定 D3DPRESENT_INTERVAL_DEFAULTD3DPRESENT_INTERVAL_ONE ,则 “演示 ”操作将等待监视器的垂直回溯。 这是防止撕裂的简单方法,但降低了计划算法的准确性。 相反,如果呈现间隔

以下函数可帮助你获取准确的计时信息:

  • IDirect3DDevice9::GetRasterStatus 返回有关光栅的信息,包括当前扫描线以及光栅是否位于垂直空白期。
  • DwmGetCompositionTimingInfo 返回桌面窗口管理器的计时信息。 如果启用了桌面组合,则此信息非常有用。

本部分假定你为每个图面创建了单独的交换链,如 中所述。 若要演示示例,请从视频示例获取交换链,如下所示:

  1. 在视频示例中调用 以获取缓冲区。

以下代码演示了这些步骤:

源矩形是要显示的视频帧部分。 它相对于规范化坐标系进行定义,其中整个视频帧占用了坐标 {0, 0, 1, 1} 的矩形。 目标矩形是绘制视频帧的目标图面中的区域。 标准演示者允许应用程序通过调用 来设置这些矩形。

有多种选项可用于应用源矩形和目标矩形。 第一个选项是让混音器应用它们:

  • 使用 属性设置源矩形。 将视频点燃到目标图面时,混音器将应用源矩形。 混音器的默认源矩形是整个框架。
  • 将目标矩形设置为混音器输出类型的几何光圈。 有关详细信息,请参阅 。

Present 方法中应用目标矩形。

如果应用程序更改目标矩形或调整窗口大小,则可能需要分配新图面。 如果是这样,则必须小心地将此操作与计划线程同步。 刷新计划队列,并在分配新图面之前放弃旧示例。

EVR 上的每个输入流都已结束时,EVR 会将 MFVP_MESSAGE_ENDOFSTREAM 消息发送到演示者。 但是,在收到消息时,可能还有一些待处理的视频帧。 在响应流结束消息之前,必须从混音器中清空所有输出,并显示所有剩余帧。 显示最后一帧后,将 EC_COMPLETE 事件发送到 EVR。

下一个示例演示了满足各种条件时发送 EC_COMPLETE 事件的方法。 否则,它会返回S_OK而不发送事件:

  • 如果 m_fSampleNotify 变量为 TRUE,则表示混音器具有尚未处理的一个或多个帧。 (有关详细信息,请参阅 .)
  • 只要一个或多个帧在计划队列中等待,该方法 AreSamplesPending 就假定返回 TRUE

EVR 旨在支持媒体基金会中的帧单步执行DirectShow和清理。 框架单步执行和清理在概念上相似。 在这两种情况下,应用程序一次请求一个视频帧。 在内部,演示者使用相同的机制来实现这两个功能。

DirectShow中的帧单步执行,如下所示:

  • 应用程序调用 。 dwSteps 参数中提供了步骤数。 EVR 将
  • 如果应用程序调用 或更改图形状态, (正在运行、暂停或停止)

媒体基础中的清理工作如下所示:

  • 应用程序通过调用 将播放速率设置为零。

收到 MFVP_MESSAGE_STEP 消息后,演示者等待目标帧到达。 如果步骤数为 N,演示者将丢弃下一个 (N - 1 个) 样本,并显示第 N 个样本。 演示者完成帧步骤后,它会将 事件发送到 EVR, lParam1 设置为 FALSE。 此外,如果播放速率为零,则演示者会发送 事件。 如果 EVR 在帧步骤操作仍挂起时取消帧单步执行,则演示者会发送一个设置为 TRUE的 EC_STEP_COMPLETE 事件。

应用程序可以多次帧步骤或清理,因此演示者可能会在收到MFVP_MESSAGE_CANCELSTEP消息之前接收多个MFVP_MESSAGE_STEP消息。 此外,演示者可以在时钟开始或时钟运行时接收 MFVP_MESSAGE_STEP 消息。

本部分介绍实现帧步进的算法。 帧单步执行算法使用以下变量:

  • step_count。 一个无符号整数,指定当前帧单步执行操作中的步骤数。

  • step_state。 在任何时间,演示者都可以在帧单步执行方面处于以下状态之一:

    演示者已收到 MFVP_MESSAGE_STEP 消息,并且时钟已启动,但演示者正在等待接收目标帧。
    演示者已收到目标帧,并已安排它进行演示,但尚未显示该帧。
    演示者已呈现目标帧并发送 事件,并正在等待下一个 MFVP_MESSAGE_STEP

    这些状态独立于 状态。

为帧单步算法定义了以下过程:

  1. 如果时钟速率为零,请使用采样时间发送 EC_SCRUB_TIME 事件。
  1. 如果时钟速率为零且 采样时间 + 采样持续时间<锁时间,则放弃样本。 退出。

按如下所示调用这些过程:

以下流程图显示了帧单步执行过程。

在 EVR 上设置演示者

实现演示者后,下一步是将 EVR 配置为使用它。

在DirectShow应用程序中,按如下所示在 EVR 上设置演示者:

  1. 将 EVR 添加到筛选器图。
  2. 创建演示者的实例。 演示者可以通过 IClassFactory 支持标准 COM 对象创建,但这不是必需的。
  3. 查询 接口的 EVR 筛选器。

在 Media Foundation 中,有多个选项,具体取决于是创建 EVR 媒体接收器还是 EVR 激活对象。 有关激活对象的详细信息,请参阅 。

对于 EVR 媒体接收器,请执行以下操作:

  1. 调用 创建媒体接收器。
  2. 查询 接口的 EVR 媒体接收器。

对于 EVR 激活对象,请执行以下操作:

  1. 调用 以创建激活对象。

  2. 在激活对象上设置以下属性之一:

  3. (可选)在激活对象上设置 属性。



我要回帖

更多关于 若(m+n+1)(m+n-2)=18,求m+n的值 的文章

 

随机推荐