第三章 音频和视频API - HTML5 程序设计

返回介绍

第三章 音频和视频API

发布于 2017-06-08 字数 33067 浏览 753 评论 0

本章,我们将探索HTML5的两个重要元素–audio和video,并演示如何利用它们创建引人注目的应用。audio 和video 元素的出现让HTML5 的媒体应用多了新选择,开发人员不必使用插件就能播放音频和视频。对于这两个元素. HTML5 规范提供了通用、完整、可脚本化控制的API。

首先,我们会讨论音频(audio) 和视频(video) 的容器文件和编解码器,以及为什么支持

这些编解码器。接着将分析没有支持哪些常用的编解码器,这种缺陷也是使用这两个蝶体元素的最大弊端。不过,我们也会讨论将来有可能怎样解决这个问题。此外,我们还会演示HTML5Audio和Video?的一种切换机制,通过该机制,可以让浏览器在所列媒体文档中挑选最合适的文件类型进行播放。

然后,我们会演示如何通过API 编程的方式来控制页面中的音频和视频.最后,我们会探讨HTML5Audio 和Video 在实际中的应用。

3.1 HTML5 Audio 和Video 概述

本节,我们要讨论与HTML5audio 元素和video 元素相关的两个关键概念:容器(container)和编解码器codec)。

3.1.1 视频容器

不论是音频文件还是视频文件,实际上都只是一个容器文件。这点类似于压缩了一组文件的ZIP 文件。从图3-1 可以看出来,视频文件(视频容器)包含了音频轨道、视频轨道和其他一些元数据。视频播放的时候,音频轨道和视频轨道是绑定在一起的.元数据部分包含了该视频的封面、标题、子标题、字幕等相关信息.

主流视频容器支持如下视频格式:

  • Audio Video Interleave (.avi)
  • Flash Video (.flv)
  • MPEG 4 (.mp4)
  • Matroska (.mkv)
  • Ogg(.ogv)

第三章 音频和视频API

图3-1 视频容器

3.1.2 音频和视频编解码器

音频和视频的编码/解码器是一组算法,用来对一段特定音频或视频流进行解码和编码,以便音频和视频能够播放.原始的媒体文件体积非常大,假如不对其编码,那么构成一段视频和音频的数据可能会非常庞大,以至于在因特网上传播需耗费无法忍受的时间。若没有解码器的话,接收方就不能把编码过的数据重组为原始的媒体数据.编解码器可以读懂特定的容器格式,并且对其中的音频轨道和视频轨道解码。

下面是一些音频解码器:

  • AAC
  • MPEG-3
  • OggVorbis

下面是一些视编解码器:

  • H.264
  • VP8
  • Ogg Theora

编解码榻的战争和暂时停战

有一些编解码器受专利保护,有一些则是免费的.例如Vorbis 音频编解码器和Theora视频编解码器可以免费使用,而要想使用MPEG-4 和H.264 的话就需要支付相关费用了。

最初. HTML5 规范本来打算指定编解码器,但实施起来困难重重.比如Ogg Theora,有的厂商考虑到他们已有的硬件或软件不支持,所以不希望HTML5规范中包含Ogg Theora。例如Apple 的iPhone 使用的硬件解码器就是H.264 而不是Theora. 另一方面,免费系统若采用要支付专利费用的编解码器将不可避免地影响其下游分销业务。而专有编解码器的性能指标又是采用免费编解码器的浏览器厂商需要考虑的一个重要因素.这种情况导致了现在的僵局,没有任何一种编解码器可以被所有浏览器厂商接受并在其产品中提供支持。

目前, HTML5 规范放弃了对编解码器的要求,不过未来很有可能重新考虑。现在,开发人员能做的只能是熟悉各种浏览器的支持情况,针对不同的浏览器环境对媒体文件进行重编码(你可能已经这么做了)。

我们非常希望随着时间的推移,不同编解码器的支持程度越来越高并最终汇集成统一版本,这样可以简化将来对通用媒体类型的选择.当然,也有可能某个编解码器逐渐强大起来并最终成为领墙内的事实标准。此外,HTML5 的媒体标签内建了一套机制来挑选最适合在浏览器中播放的内容类型,进而实现不同的环墙下媒体类型的简单切换。

WebM来了

“2010 年5 月.,Google 发布了WebM 视频格式。现在主流的Web 视频都比较模糊,作为新的音烦和视频格式, WebM 旨在改善这种现状,让Web 视频清晰化。WebM 的后缀名是webm ,是基于Matroska 修改的纣簇格式,视须使用VP8 编码,音频使用OggVorbis 编码。Google 以不受限许可的方式发布了WebM 的规范和软件,包括源码和专利权。WebM 是一种高清视频格式,对二次开发者和发布者均免费,它代表了编’解码器的重大选步。

随着浏览嚣的不断发展,至少Firefox、Opera 和Chrorne宣称会支持WebM. 其中Operal0.60已经实现了对宫它的支持。Mozilla 和Google 已经宣布在他们的下一个浏览器版本中提供对WebM的支持。”

—-Frank

3.1.3 HTML5 Audio和Video 的限制

有些功能是HTML5 规范所不支持的,如下所示。

  • 流式音频和视频.因为目前HTML5 视频规范中还没有比特率切换标准,所以对视频的支持只限于加载的全部媒体文件,但是将来一旦流媒体格式被HTML5 支持,则肯定会有相关的设计规范。
  • HTML5 的媒体受到HTTP跨源(cross-origin) 资源共享的限制.关于跨源资源共享的更多信息,请参考第5 章。
  • 全屏视频无法通过脚本控制.从安全性角度来看,让脚本元素控制全屏操作是不合适的。不过,如果要让用户在全屏方式下播放视频,浏览器可以提供其他控制手段。
  • 对audio 元素和video 元素的访问尚未完全加入规范中。.基子流行的字幕格式SRT 的字幕支持规范(WebSRT) 仍在编写中。

3.1.4 audio 元素和 video 元素的浏览器支持情况

从表3-1 中可以看到,在写这本书的时候,很多浏览器已经实现了对HTML5 中audio 元素和video 元素的支持。表中还显示了对编解码器的支持情况。

表3-1 audio元素和video元素的浏览器支持情
浏览器 支持情况 编解码器、容器
Chromc 3.0及以上版本支持 Theora和Vorbis、Ogg容器
H.264和AAC. MPEG 4容器
Firefox 3.5及以上版本支持 Theora和Vorbis. Ogg容器
Internet Explorer 不支持
Opera 10.5及以上版本支持 Theora和Vorbis、Ogg容器(10.5及以上版本支持)
VP8和Vorbis、WebM格式(10.5及以上版本支持)
Safari 3.2及以上版本支持 H.264和AAC 、MPEG4容器

按照惯例,在使用audio 元素和video 元素之前,第一件事还是检测浏览器是否支持。在3.2.1节我们会演示如何通过代码的方式检测浏览器支持情况。

3.2 使用HTML5Audio 和Video API

本节,我们会探讨如何在Web 应用中使用HTML5 Audio 和Video。 在页面中播放视频的典型方式是使用Flash、QuickTime 或者Windows Media 插件向HTML 中嵌入视频,相对这种方式,使用HTML5的媒体标签有两大好处,可以极大地方便用户和开发人员。

  • 作为浏览器原生支持的功能,新的audio 元素和video元素无需安装。尽管有的插件安装率很高,但是在控制比较严格的公司环境下往往被屏蔽。因为有的插件绑定广告,所以很多用户选择了禁用此类插件,于是在摆脱广告干扰的同时也丢弃了其媒体播放的能力。插件也是安全问题的一个来源。此外,插件很难与页面其他内容集成,往往在设计好的页面中导致剪裁、透明度等问题。由于插件使用的是独立的渲躲模型,与基本的Web 页面使用的不同,所以在开发的过程中,如果遇到弹出式菜单或者其他需要跨越插件边界显示重叠元素的时候,开发人员就会面临很大的困难。
  • 媒体元素向Web 页面提供了通用、集成和可脚本化控制的API。 对于开发人员来说,使用新的媒体元素之后,可以轻易地使用脚本来控制和播放内容,本章后面会有很多相关的示例。

使用媒体标签最大的缺点在于缺少通用编解码器支持,这个我们已经在前面讨论过了,但是我们希望编解码器的支持情况越来越好,随着时间的推移能够最终统一起来,到时候通用媒体类型就能轻松实现并且流行起来了。此外,媒体标签内建了一套机制来挑选最适合在浏览器中播放的内容类型,关于这点,我们将在本意随后的部分进行详细讨论。

3.2.1 浏览器支持性检测

检测浏览器是否支持audio 元素或video 元素最简单的方式是用脚本动态创建它,然后检测特定函数是否存在:

var hasVideo = !!(document.createElement('video').canPlayType);

这段脚本会动态创建一个vi deo 元素,然后检查canPlayType() 函数是否存在。通过”!!”

运算符将结果转换成布尔值,就可以反映出视频对象是否已创建成功。

如果检测结果是浏览器不支持audio 或video 元素的话,则需要针对这些老的浏览器触发另外一套脚本来向页面中引入媒体标签,虽然同样可以用脚本控制媒体,但使用的是诸如Flash 等其他播放技术了。

另外,可以在audio 元素或video 元素中放入备选内容,如果浏览器不支持该元素,这些备选内容就会显示在元素对应的位置。可以把以Flash 插件方式播放同样视频的代码作为备选内容。如果仅仅只想显示一条文本形式提示信息替代本应显示的内容,那就简单了,在audio 元素或video 元素中按下面这样插入信息即可:

<video src="video.ogg" controls>
Your browser does not support HTML5 video.
</video>

如果是要为不支持HTML5 媒体的浏览器提供可选方式来显示视频,可以使用相同的方法,将以插件方式播放视频的代码作为备选内容,放在相同的位置即可:

<video src="video.ogg">
<object data="videoplayer.swf" type="application/x-shockwave-flash">
<param name="movie" value="video.swf"/>
</object>
</video>

在video 元素中嵌入显示Flash 视频的object元素之后,如果浏览器支持HTML5视频,那么HTML5 视频会优先显示,Flash视频作后备。不过在HTML5 披广泛支持之前,可能需要供多种视频格式。

所有人都使用的媒体

“让Web 应用做到所有人都能访问不仅仅是一件正确的事,这更是业务上的需求. 有时还是一种法律约束!针对视觉和听觉有障碍的用户, Web 应用应该提供他们需要的备选内容。

对于貌’簧和音频可访问性方面,设计HTML5 标准的组织敏锐地注意到了规范固有支持性的缺乏,例如未启用字摹筝, 并且相应的方案也在计划制定中。在此期间, 开发人员应该至少提供视频字幕全文的链接,并且考虑使用VideoAPl脚本来同步文本显示,或者显示在视频旁边。

需要注意的是,位于audio 元素和video 元素中的备选内容只有在浏览器不支持HTML5audio 元素和video 元素的时候才会起作用,囚此无障碍显示的内容不能放在这儿, 否则当浏览器支持HTML5媒体的时候,用户就看不到了。”

———Brian

3.2.2 理解媒体元素

得益于出色的设计思路, HTML5 中audio 元素和video元素有很多相同之处. 两者都支持的操作有播放、暂停、静音/消除静音、加载等,因此通用的动作被从video和audio 元素中剥离出来并放到了媒体(media) 元素部分。接下来我们就从这些共同点出发,来了解媒体元素。

1、基本操作:声明媒体元素

为了举例说明,我们会用audio 元素来演示HTML5 媒体元素的通用动作。本章的示例涉及大量的媒体文件,这些素材会在随书的示倒支持文件中找到。

在下面的示例中(示例文件是audio.btml) ,我们创建了一个音频播放页面,播放的是舒缓、安详。可让公众自由播放的巴赫的《空气)):

 <!DOCTYPE html>
<html>
<title>HTML5 Audio </title>
<audio controls src="johann_sebastian_bach_air.ogg">
An audio clip from Johann Sebastian Bach.
</audio>
</html>

这段代码假定HTML文档和音频文件(johann_ sebastian _ bach_air.ogg)的位置是在同一路径下。图3-2 是在支持audio元素的浏览器中的页面显示效果。从图中可以看到一个带有播放按钮的播放控制条。点击播放按钮,就可以播放音频文件。

代码中的controls特性告诉浏览器显示通用的用户控件,包括开始、停止、跳播以及音量控制。如果不指定controls 特性,用户将无法播放页面上的音频。

audio 元素之间的内容,是为不支持audio 元素的浏览器准备的替换内容,如果用户用的是老版本浏览器,页面上就会显示这些文本信息。替换内容不局限于文本信息,还可以换成Flash播放器等视频播放插件。或者直接给出媒体文件的链接地址。

第三章 音频和视频API

图3.2 简单的音频控制

2. 使用source元素

最后,介绍最重要的特性: src。最简单的情况下,src 特性直接指向媒体文件就可以了。但是,万一浏览器不支持相笑容器或者编解码器呢(比如Ogg和Vorbis) ?这就需要用到备用声明了。备用声明中可以包含多种来源,浏览器可以从这么多的来源中进行选择(见示例audio_multisource.html) :

<audio controls>
<source src="johann_sebastian_bach_air.ogg">
<source src="johann_sebastian_bach_air.mp3">
An audio clip from Johann Sebastian Bach.
</audio>

从上面的代码可以看到,在audio元素中,我们使用两个新的source元素替换了先前的src特性。这样可以让浏览器根据自身播放能力自动选择,挑选最佳的来源进行播放.对于来源,浏览器会按照声明顺序判断。如果支持的不止一种,那么浏览器会选择支持的第一个来源。

提示:注意来源列表的排放顺序,要按照用户体验由高到低或者服务器消耗由低刽高列出。

在支持audio 元素的浏览器中运行上述代码,页面的显示结果与添加可选来源列表之前没有任何变化。但是如果浏览器不支持。Ogg vorbis格式。而是支持MP3格式,那上面的代码就起作用了,这种声明模型的妙处在于当开发人员在与媒体文件进行交互操作的时候,不需要考虑实际上调用的是哪个容器和编解码器.。浏览器给开发人员提供操作媒体文件的统一接口,这与所选择播放的文件来源无关。

此外.还有一种暗示浏览器应该使用哪个媒体来源的方式,我们知道一个媒体容器可能会支持多种类型的编解码器,因而就不难理解声明的源文件的扩展名可能会让浏览器误以为自己支持或不支持某种类型了。如果type特性中指定的类型与源文件不匹配,浏览器可能就会拒绝播放。指定类型的方式就是为source元素添加type特性。如果我们明确知道浏览器支持某种类型,将它写明显然更明智。否则,最好是省略type特性,让浏览器自己检测编码方式。此外还需要注意的是, WebM格式只支持一种音频编解码器和一种视频编解码器。也就是说只要看到.webm扩展名或者video/webm的内容类型,就可以知道来源的全部情况了。如果浏览器支持WebM,那么就可以播放所有Webm文件,代码如下(示例代码文件为audio_ type.html) :

<audio controls>
<source src="johann_sebastian_bach_air.ogg" type="audio/ogg; codecs=vorbis">
<source src="johann_sebastian_bach_air.mp3" type="audio/mpeg">
An audio clip from Johann Sebastian Bach.
</audio>

从上面的代码中可以看到,容器和编解码器都可以在type特性中声明。代码中的值分别代表Ogg Vorbis和MP3 。所有的支持列表见RFC 4218, RFC4218 是由IETF(Internet Engineering Task Force, Internet工程任务组}维护的一套文档。表3.2 中列出了一些常用组合。

表3-2 媒体类型和特性值
类型 特性值
在Ogg容器中的Theora视频和Vorbis音频 Type=’video/ogg;codecs=”theora,vorbis””
在Ogg容器中的Vorbis音频 Type=’audio/ogg;codecs=”vorbis”
在MP4容器中的simple baseline H.264视频和lowcomplexity AAC音频 Type=’audio/mp4;codecs=”avcl,42E01E,MP4A.40.2””
在MP4容器中的MPEG-4简单视频和简单AAC音频 Type=’audio/MP4;codecs=”MP4v.20.8,MAPa.40.2””

3. 媒体的控制

从前面的示例中我们看到,在audio 元素或video 元素中指定controls特性即可在页面上以默认方式进行播放控制。正像你想的那样,如果不加这个特性,那么在播放的时候就不会显示控制界面。假如播放的是音频,那么页面上任何信息都不会出现,因为音频元素的唯一可视化信息就是它对应的控制界面。假如播放的是视频,那么视频内容会照常显示。即使不添加controls特性也不能影响页面正常显示。有一种方法可以让没有controls特性的音频或视频正常播放。那就是在audio元素或video元素中设置另一个特性: autoplay (见audio_no_control.html 示例文件) :

<audio autoplay>
<source src="johann_sebastian_bach_air.ogg" type="audio/ogg; codecs=vorbis">
<source src="johann_sebastian_bach_air.mp3" type="audio/mpeg">
An audio clip from Johann Sebastian Bach.
</audio>

通过设置autoplay特性,不需要任何用户交互,音频或视频文件就会在加载完成后自动播放。.不过大部分用户对这种方式会比较民畴反感,所以应慎用autoplay特性。在无任何提示的情况下,播放一段音频通常有两种用途,第一种是用来制造背景氛围,第二种是强制用户接收广告,这种方式的问题在于会干扰用户本机播放的其他音频,尤其会给依赣屏幕阅读功能进行Web内容导航的用户带来不便。

如果内置的控件不适应用户界面的布局,或者希望使用默认控件中没有的条件或者动作来控制音频或视频文件,那么可以借助一些内置的JavaScript函数和特性.。表3-3 列出了一些常用的函数。

表3-3 常用的控制函数
函数 动作
Load() 加载音频/视频文件,为播放做准备。通常情况下不必调用,除非是动态生成的元素。用来在播放前预加载
Play() 加载(有必要的话)并播放音频/视频文件,除非音频/视频已经暂停在其他位置了,否则默认从开头播放
Pause() 暂停处于播放状态的音频/视频文件
Canplaytype(type) 测试cideo元素是否支持给定MIME类型的文件

canPlayType(type)函数有一个特殊的用途; 向动态创建的video元素中传入某段视频的MlME类型后,仅仅通过一行脚本语句即可获得当前浏览器对相关视频类型的支持情况。例如,下面的代码可以快速判断当前浏览器是否支持播放fooType 类型的视频,而无需在浏览器窗口中显示任何内容:

var supportsFooVideo = !!(document.createElement('video').canPlayType(‘fooType’));
表3-4 只读的媒体特性
只读特性
duration 整个媒体文件的播放时长,以s为单位,如果无法获取时长,则返回NAN
paused 如果媒体文件当前别暂停,则返回true。如果还未开始播放,默认返回true
ended 如果媒体文件已经播放完毕,则返回true
starttmie 返回最早的播放起始时间,一般是0.0,除非是缓冲过的媒体文件,并且一部分内容已经不再缓冲区
error 在发生了错误的情况下返回的错误代码
currentsrc 以字符串形成返回当前正在播放或已加载的文件,对应于浏览器在source元素中选择的文件

表3-5 列出了可被脚本修改并直接影响播放的部分媒体元素特性。它们的作用类似于函数。

表3-5 可脚本控制的特性值
特性
autoplay 将媒体文件设置为创建后自动播放,或者查询是否已设置为autoplay
loop 如果媒体文件播放完毕后能重新播放则返回true,或者将媒体文件设置为循环播放(或者不循环播放)
currentTime 以s为单位返回从开始播放到现在所用的时间。在播放过程中,设置currenttime来进行搜索,并定位到媒体文件的特定位置
controls 显示或隐藏用户控制界面,或者查询用户控制界面当前是否可见
volume 在0.0到1.0之间设置音频音量的相对值,或者查询当前量相对值
Muted 为音频文件设置静音或者消除静音,或者检测当前是否静音
autobuffer 通知播放器在媒体文件开始播放前,是否进行缓冲加载。如果媒体文件已设置为autoplay,则忽略此特性

开发人员可以基于上述功能和特性自行开发媒体播放用户界面,进而实现对浏览器支持的音频和视频的控制。

3.2.3 使用audio 元素

如果你已经了解audio元素和video元素的共享特性,那就基本认识了audio元素所能提供的功能,我们直接着一个简单的示例,它演示了如何通过脚本来控制audio元素。

激活audio元素

如果需要在用户交互界面上播放一段音频,同时不想被时间轴和控制界面影响页面显示效果,则可创建一个隐藏的audio元素一一不设置controls特性,或将其设置为false一一然后用自行开发的控制界面控制音频的播放。参考下面这段代码,代码文件为audioCue.html:

<!DOCTYPE html>
<html>
<link rel="stylesheet" href="styles.css">
<title>Audio cue</title>
<audio id="clickSound">
<source src="johann_sebastian_bach_air.ogg">
<source src="johann_sebastian_bach_air.mp3">
</audio>
<button id="toggle" onclick="toggleSound()">Play</button>
<script type="text/javascript">
function toggleSound() {
var music = document.getElementById("clickSound");
var toggle = document.getElementById("toggle");
if (music.paused) {
music.play();
toggle.innerHTML = "Pause";
}
else {
music.pause();
toggle.innerHTML ="Play";
}
}
</script>
</html>

我们再次用audio元素播放了巴赫的那首曲子。不过在示例中. 我们隐藏了用户控制界面,也没有将其设置为加载后自动播放,而是创建了一个具有切换功能的按钮,以脚本的方式控制音频的播放:

<button id="toggle" onclick="toggleSound()">Play</button>

按钮在初始化时会提示用户单击它以播放音频。每次单击时,都会触发togg1eSound ()函数。在toggleSound() 函数中,我们首次访问了DOM中的audio元素和button元素:

if (music.paused) {
music.play();
toggle.innerHTML = "Pause";
}

通过访问audio元素的paused特性,可以检测到用户是否已经暂停播放。如果音频还没开始播放,那么paused特性默认为true,这种情况会在用户第一次单击按钮的时候遇到。此时,需要调用play()函数来播放音频,同时修改按钮上的文字,告际用户再次单击就会暂停:

else {
music.pause();
toggle.innerHTML ="Play";
}

相反,如果音频没有暂停(仍在播放),我们会使用pause( )函数将它暂停,然后变换按钮上的文字,让用户知道下次单击的时候音频将继续播放。挺容易,不是吗?这是HTML5媒体元素的关键:建立简单的显示和控制机制支持多种媒体类型,以淘汰媒体播放插件。简单是HTML5媒体元素最大的优点。

3.2.4 使用video 元素

我们已经讨论了很多简单的应用。后面的示例中。我们将尝试提高一些复杂度。HTML5 video元素同audio元素非常类似,只是比audio元素多了一些特性,详见表3-6。

表3-6 video元素的额外特性
特性
poster 在视频加载完成之前,代表视频内容的图片的RUL地址,可以想象一下“电影海报”。噶特性不仅可读,而且可以修改,以便跟换图片
Width、hetight 读取或设置显示尺寸。如果设置的宽度与视频本身大小不匹配,可能导致居中显示,上下或左右可能出现黑色条状区域
Videowidth、videoheight 返回视频的固有或自适应的宽度和高度。只读

video元素还有一个audio元素不支持的关键特性:可被HTML5 Canvas的函数调用(更多关于HTML5 Canvas的内容见第2 章)。

创建视频时序查看器

在下面这个稍显复杂的示例中,我们将演示如果抓取video元素中的帧并显示在动态canvas上.为了演示这个功能,我们将创建一个简单的视频时序查看器。当视频播放时,定期从视频中抓取图像帧并绘制到旁边的canvas上,当用户单击canvas上显示的任何一帧时,所播放的视频会跳转到相应的时间点。只需寥寥几行代码即可创建时序查看器,它支持用户在较长的视频中随意跳转。

示例中选用的视频是20世纪中期电影院的优惠广告,一起来感受一下吧(见图3-3) 。

第三章 音频和视频API

图3-3 视频时序查看器

添加video元素和canvas元素

先用一段简单的代码来显示视频:

<video id="movies" autoplay oncanplay="startVideo()" onended="stopTimeline()"
autobuffer="true" width="400px" height="300px">
<source src="Intermission-Walk-in.ogv" type='video/ogg; codecs="theora, vorbis"'>
<source src="Intermission-Walk-in_512kb.mp4"
type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"'>
</video>

video 元素声明了autoplay特性,这样一来,页面加载完成后,视频马上会被自动播放。此外还增加了两个事件处理函数。当视频加载完毕,准备开始播放的时候,会触发oncanpl ay 函数来执行我们预设的动作。类似地,当视频播放完后,会触发onended函数以停止帧的创建。

接下来我们将创建id为timeline 的canvas,之后会以固定的时间间隔在上面给制视频帧。

<canvas id="timeline" width="400px" height="300px">

添加变量

接下来我们要为示例编写脚本代码,在脚本中声明一些有助于调整示例的变量,同时增强代码可读性。

// # of milliseconds between timeline frame updates
var updateInterval = 5000;
// size of the timeline frames
var frameWidth = 100;
var frameHeight = 75;
// number of timeline frames
var frameRows = 4;
var frameColumns = 4;
var frameGrid = frameRows * frameColumns;

Updateinterval用来控制抓取帧的频率——代码中是每5s一次。Framewidth和frameheight两个参数用来指定在canvas中展示的视频帧的大小。类似地,framerows、framecolumns以及framegrid三个参数决定了在时序中总共显示多少帧。

// current frame
var frameCount = 0;
// to cancel the timer at end of play
var intervalId;
var videoStarted = false;

为了跟踪当前播放的是哪一帧,我们引入了frameCount变量。frameCount变量可被示例中的所有函数调用.。(出于演示目的,示例视频每隔5s会取出一帧。) intervalId 用来停止控制抓取帧的计时器。最后,我们还添加了videoStarted标志以确保每个示倒只创建一个计时器。

添加updateFrame函数

整个示例的核心功能是抓取视频帧并绘制到canvas上,它是视频与canvas相结合的部分,其代码如下:

// paint a representation of the video frame into our canvas
function updateFrame() {
var video = document.getElementById("movies");
var timeline = document.getElementById("timeline");
var ctx = timeline.getContext("2d");
// calculate out the current position based on frame
// count, then draw the image there using the video
// as a source
var framePosition = frameCount % frameGrid;
var frameX = (framePosition % frameColumns) * frameWidth;
var frameY = (Math.floor(framePosition / frameRows)) * frameHeight;
ctx.drawImage(video, 0, 0, 400, 300, frameX, frameY, frameWidth, frameHeight);
frameCount++;
}

在第2章我们已经了解到,在操作canvas前,首先需要做的就是在获取canvas的二维上下文对象:

var ctx = timeline.getContext("2d");

因为我们希望按从左到右、从上到下的顺序镇充canvas网格,所以需要精确计算从视频中截取的每帧应该对应到哪个canvas网格中。根据每帧的宽度和高度,可以计算出它们的起始绘制坐标(X,Y):

var framePosition = frameCount % frameGrid;
var frameX = (framePosition % frameColumns) * frameWidth;
var frameY = (Math.floor(framePosition / frameRows)) * frameHeight;

最后是将图像绘制到canvas上的关键函数调用,在第2章的示例中,我们已经使用过位置和缩放参散,但这里我们向drawImage()函数中传人的不是图像,而是视频对象:

ctx.drawImage(video, 0, 0, 400, 300, frameX, frameY, frameWidth, frameHeight);

canvas的绘图程序可以将视频源当做图像或者图案进行处理,这样开发人员就可以方便地修改视频并将其重新显示在其他位置。

提示:当canvas使用视须作为绘制来源时,画出来的只是当前播放的帧,canvas的显示图像不会随着视烦的播放而动态更新, 如果希望更新显示内容.。需要在视频播放期间重新绘制图像。

添加startVideo函数

最后,更新frameCount.。这表示我们开始在时序查看器上绘制新的视频截图。现在示例只剩下一个功能要实现,那就是定时更新时序查看器上的帧:

function startVideo() {
// only set up the timer the first time the
// video is started
if (videoStarted)
return;
videoStarted = true;
// calculate an initial frame, then create
// additional frames on a regular timer
updateFrame();
intervalId = setInterval(updateFrame, updateInterval);

别忘了, 一旦视频加载并可以播放就会触发start Video()函数。因此,我们首先要保证每次页面加载都仅触发一次startVideo(), 除非视频重新播放。

// only set up the timer the first time the
// video is started
if (videoStarted)
return;
videoStarted = true;

视频开始播放后,我们将抓取第一帧,接着会启用间隔计时器来定期调用updateFrame() 函数。所谓间隔计时器是以指定时间间隔不断重复的计时器。示例中的结果是每5s 抓取一个新截图:

// calculate an initial frame, then create
// additional frames on a regular timer
updateFrame();
intervalId = setInterval(updateFrame, updateInterval);

处理用户输入

用户单击时序查看器上的某一帧肘,系统该怎么处理?下面我们就来回答这个问题:
// set up a handler to seek the video when a frame
// is clicked
var timeline = document.getElementById("timeline");
timeline.onclick = function(evt) {
var offX = evt.layerX - timeline.offsetLeft;
var offY = evt.layerY - timeline.offsetTop;
// calculate which frame in the grid was clicked
// from a zero-based index
var clickedFrame = Math.floor(offY / frameHeight) * frameRows;
clickedFrame += Math.floor(offX / frameWidth);
// find the actual frame since the video started
var seekedFrame = (((Math.floor(frameCount / frameGrid)) *
frameGrid) + clickedFrame);
// if the user clicked ahead of the current frame
// then assume it was the last round of frames
if (clickedFrame > (frameCount % 16))
seekedFrame -= frameGrid;
// can't seek before the video
if (seekedFrame < 0)
return;

代码稍显复杂。我们族取了id为tímeline的canvas,并对其设置了用于处理用户单击的函数.。该函数通过单击事件来确定用户单击位置的X和Y坐标:

var timeline = document.getElementById("timeline");
timeline.onclick = function(evt) {
var offX = evt.layerX - timeline.offsetLeft;
var offY = evt.layerY - timeline.offsetTop;

然后,我们利用帧的尺寸计算出用户单击的是16 个帧中的哪一个:

// calculate which frame in the grid was clicked
// from a zero-based index
var clickedFrame = Math.floor(offY / frameHeight) * frameRows;
clickedFrame += Math.floor(offX / frameWidth);

用户单击的帧一定是刚刚播放的视频帧中的一个,所以通过对应的网格索引能够计算出最近播放的帧:

// find the actual frame since the video started
var seekedFrame = (((Math.floor(frameCount / frameGrid)) * frameGrid) + clickedFrame);

如果用户单击的帧在当前帧之前.需要向前跳跃一个完整的网格周期,以确定实际播放时间;

// if the user clicked ahead of the current frame
// then assume it was the last round of frames
if (clickedFrame > (frameCount % 16))
seekedFrame -= frameGrid;

最后,我们必须添加安全控制代码,以免用户单击的帧由于某种原因比视频初始帧还早:

// can't seek before the video
if (seekedFrame < 0)
return;

现在我们已经知道了用户想要跳转到的时间点,接下来是实现跳转播放,虽然这是示例的核心函数,但是代码却很简单:

// seek the video to that frame (in seconds)
var video = document.getElementById("movies");
video.currentTime = seekedFrame * updateInterval / 1000;
// then set the frame count to our destination
frameCount = seekedFrame;

通过设置video元素的currenttime特性,可以让视频自动跳转到指定时闹,并将当前帧数( frameCount) 设置为新选择的帧。

提示 与JavaScript计时器以ms为单位不同, video中的currentTime以秒为单位。

添加stopTien函数

整个视频时序查看器示例中,最后要做的工作是在视频播放完毕肘,停止帧的抓取。虽然不是必须的,但是如果不这么做,示例会在现有代码基础上不停地抓取帧,过段时间就会让时序查看器变成一片空白:

// stop gathering the timeline frames
function stopTimeline() {
clearInterval(intervalId);
}

视频播放完华时会触发onended( ) 函数..stopTimeline 函数会在此时被调用。

我们的视频时序查看嚣的功能可能还不够强大,无法满足高;端用户的要求,不过别忘了它仅用了很少的代码啊。好,继续吧。

3.2.5 进阶功能

尽管有些技巧我们在示例中用不上,但这并不妨碍它们在多种类型的HTML5 Web应用中发挥作用。本节,我们就来介绍一些简单实用的进阶功能。

页面中的背景噪音

很多网站为所有访问者自动播放音乐,希望以这种方式来”款待”用户。虽然有时候我们不大喜欢这样的方式,不过用HTML5 的audio元素实现起来倒是非常便捷:

<!DOCTYPE html>
<html>
<link rel="stylesheet" href="styles.css">
<title>Background Music</title>
<audio autoplay loop>
<source src="johann_sebastian_bach_air.ogg">
<source src="johann_sebastian_bach_air.mp3">
</audio
<h1>You're hooked on Bach!</h1>
</html>

从上面的代码中可以看到,实现循环播放一首背景音乐非常简单, 只需在audio元素中设置autoplay 和loop特性即可(见图3-4)。

第三章 音频和视频API

图3-4 设置autoplay特性以便在页面加载时播放音乐

一眨眼(<blink>) 用户就会流失

“所谓能力越强责任越大,但有些事情可以做,并不代表着应该做。 <blink>元素就是一个活生生的例子?!

Audio元素和video元素可以通过简单的方式实现强大的播放功能,但不要仅仅因为这个便利性就在不恰当的地方肆意使用它们。如果开发人员有足够的理由对页面的音频或视频使用autoplay (可能是媒体浏览嚣,用户期望一打开页画画就播放内容) .,一定要确保明确关闭自动播放的功能。当用户发现页面上有烦人的内容尚无法轻易关闭时,会断然离开。让用户流失?没有比这种方式更快的了。”

—-Brian

鼠标悬停播放视频

video元素中,另一种简单高效的用法是通过在视频上移动鼠标来触发play和pause功能。页面包含多个视频,且由用户来选择播放某个视频时,这个功能就非常适用了。比如在用户鼠标移到某个视频上时,播放简短的视频预览片段,用户单击后,播放完整的视频。上述效果可以通过下面的代码轻松实现(示例文挡为mouseoverVideo.html) :

<!DOCTYPE html>
<html>
<link rel="stylesheet" href="styles.css">
<title>Mouseover Video</title>
<video id="movies" onmouseover="this.play()" onmouseout="this.pause()"
autobuffer="true"
width="400px" height="300px">
<source src="Intermission-Walk-in.ogv" type='video/ogg; codecs="theora, vorbis"'>
<source src="Intermission-Walk-in_512kb.mp4" type='video/mp4; codecs="avc1.42E01E,
mp4a.40.2"'>
</video>
</html>

只需额外设置几个特性,即可实现鼠标悬停预览视频的效果,如图3-5所示。

第三章 音频和视频API

图3-5 鼠标悬停播放视频

3.3 小结

本章我们介绍了HTML5 audio元素和video元素的用饭,演示了如何使用它们建引人注目的Web 应用。audio元素和video元素的引入,让HTML5应用在对媒体的使用上多了一种选择:不用插件即可播放音频和视频。此外,audio元素和video元素还提供了通用的、集成化的、可用脚本控制的API。

我们首先了解了audio和video的容器文件和编解码器,以及为什么HTML5支持这些编解码器,然后演示了一种让浏览器自动选择最合适媒体类型进行播放的机制。

接下来,我们演示了如何通过编程方式使用API 控制audìo元素和video元素。 最后,我们探讨了HTML5Audio和video的实际应用。

下一章,我们将演示如何在Web 应用中基于地理定位倍息来更新用户所在的位置。

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

支持 Markdown 语法,需要帮助?

目前还没有任何评论,快来抢沙发吧!