最近在整理博客和浏览器收藏夹中的教程,把一些自己比较了解的基础知识进行了汇总,并且加入自己开发中遇到的问题和理解。由于参考来源太多,所以做了个详细列表在下面,感谢这些作者的无私和伟大,呵呵!
来源参考:w3、w3school、来源一、来源二、来源三、来源四、来源五、QA
一、标签解读
-
<audio> 标签属性
<audio id="media" src="http://www.abc.com/test.mp3" controls></audio>
src:音乐的URL (source标签在src属性不存在时使用)
preload:预加载(none、metadata、auto。如果不使用此属性,默认为auto。)
autoplay:自动播放
loop:循环播放
controls:浏览器自带的控制条
-
<video> 标签属性
<video id="media" src="http://www.abc.com/test.mp4" controls width="400px" height="400px"> </video>
src:视频的URL
poster:视频封面,没有播放时显示的图片
preload:预加载
autoplay:自动播放
loop:循环播放
controls:浏览器自带的控制条
width:视频宽度
height:视频高度
muted:是否输出视频的声音
二、Media对象方法和属性
-
获取HTMLVideoElement和HTMLAudioElement对象
-
//audio可以直接通过new创建对象
-
Media = new Audio("http://www.abc.com/test.mp3");
-
//audio和video都可以通过标签获取对象
-
Media = document.getElementById("media");
-
Media方法和属性——HTMLVideoElement 和 HTMLAudioElement 均继承自 HTMLMediaElement
-
//错误状态
-
Media.error; //null:正常
-
Media.error.code; //1.用户终止 2.网络错误 3.解码错误 4.URL无效
-
-
//网络状态
-
Media.currentSrc; //返回当前资源的URL
-
Media.src = value; //返回或设置当前资源的URL
-
Media.canPlayType(type); //是否能播放某种格式的资源
-
Media.networkState; //0.此元素未初始化 1.正常但没有使用网络 2.正在下载数据 3.没有找到资源
-
Media.load(); //重新加载src指定的资源
-
Media.buffered; //返回已缓冲区域,TimeRanges
-
Media.preload; //none:不预载 metadata:预载资源信息 auto:
-
-
//准备状态
-
Media.readyState; //1:HAVE_NOTHING 2:HAVE_METADATA 3.HAVE_CURRENT_DATA 4.HAVE_FUTURE_DATA 5.HAVE_ENOUGH_DATA
-
Media.seeking; //是否正在seeking
-
-
//回放状态
-
Media.currentTime = value; //当前播放的位置,赋值可改变位置
-
Media.startTime; //一般为0,如果为流媒体或者不从0开始的资源,则不为0
-
Media.duration; //当前资源长度 流返回无限
-
Media.paused; //是否暂停
-
Media.defaultPlaybackRate = value;//默认的回放速度,可以设置
-
Media.playbackRate = value;//当前播放速度,设置后马上改变
-
Media.played; //返回已经播放的区域,TimeRanges,关于此对象见下文
-
Media.seekable; //返回可以seek的区域 TimeRanges
-
Media.ended; //是否结束
-
Media.autoPlay; //是否自动播放
-
Media.loop; //是否循环播放
-
Media.play(); //播放
-
Media.pause(); //暂停//控制
-
Media.controls;//是否有默认控制条
-
Media.volume = value; //音量
-
Media.muted = value; //静音
-
-
//TimeRanges(区域)对象
-
TimeRanges.length; //区域段数
-
TimeRanges.start(index) //第index段区域的开始位置
-
TimeRanges.end(index) //第index段区域的结束位置
三、Media JS事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
eventTester =
function
(e){
Media.addEventListener(e,
function
(){
console.log((newDate()).getTime(),e);
});
}
eventTester(
"loadstart"
);
//客户端开始请求数据
eventTester(
"progress"
);
//客户端正在请求数据
eventTester(
"suspend"
);
//延迟下载
eventTester(
"abort"
);
//客户端主动终止下载(不是因为错误引起)
eventTester(
"error"
);
//请求数据时遇到错误
eventTester(
"stalled"
);
//网速失速
eventTester(
"play"
);
//play()和autoplay开始播放时触发
eventTester(
"pause"
);
//pause()触发
eventTester(
"loadedmetadata"
);
//成功获取资源长度
eventTester(
"loadeddata"
);
//
eventTester(
"waiting"
);
//等待数据,并非错误
eventTester(
"playing"
);
//开始回放
eventTester(
"canplay"
);
//可以播放,但中途可能因为加载而暂停
eventTester(
"canplaythrough"
);
//可以播放,歌曲全部加载完毕
eventTester(
"seeking"
);
//寻找中
eventTester(
"seeked"
);
//寻找完毕
eventTester(
"timeupdate"
);
//播放时间改变
eventTester(
"ended"
);
//播放结束
eventTester(
"ratechange"
);
//播放速率改变
eventTester(
"durationchange"
);
//资源长度改变
eventTester(
"volumechange"
);
//音量改变
|
事件详细说明:
四、浏览器对音视频格式支持说明
Audio
Firefox:支持 Ogg Vorbis和WAV
Opera :支持Ogg Vorbis和WAV
Safari :支持MP3,AAC格式 ,和MP4
Chrome :支持Ogg Vorbis,MP3,WAV,AAC和MP4
Internet Explorer 9+ :支持MP3,AAC格式 ,和MP4
IOS :支持MP3,AAC格式 ,和MP4
Android :支持AAC和MP3
为了最大程度支持所有上面提到的浏览器,建议开发者使用Ogg Vorbis和MP3这两种格式例如。
1
2
3
4
|
<
audio
controls>
<
source
src
=
"myAudio.ogg"
type
=
"audio/ogg"
>
<
source
src
=
"myAudio.mp3"
type
=
"audio/mp3"
>
</
audio
>
|
Video
Firefox :支持Ogg Theora格式和WEBM
Opera :支持Ogg Theora格式和WEBM
Safari :支持MP4
Chrome :支持Ogg Theora格式,MP4和WEBM
Internet Explorer 9 :支持MP4和WEBM(需要安装插件)
IOS :支持MP4
Android :支持MP4和WEBM(Android 2.3版本以上)
为了支持上述所有的浏览器,建议使用WebM和MP4视频文件作为source元素。例如。
1
2
3
4
|
<
video
controls>
<
source
src
=
"myVideo.mp4"
type
=
"video/mp4"
>
<
source
src
=
"myVideo.webm"
type
=
"video/webm"
>
</
video
>
|
再来张截图示意:(http://en.wikipedia.org/wiki/Html_video_tag)
五、疑难杂症
1、mp4格式视频无法在chrome中播放
Chrome浏览器支持HTML5,它支持原生播放部分的MP4格式(不用通过Flash等插件)。
为什么是部分MP4呢?MP4有非常复杂的含义(见http://en.wikipedia.org/wiki/Mp4),普通人对MP4的理解是后缀为.mp4的文件。但MP4本身不是一种简单的视频格式,它是一个包装了视频和音频格式的壳。至于里面的视频和音频使用什么编码格式是可变的。MP4的视频格式可以使用DivX也可使用H264,Chrome只支持H264。
然后,我猜测问题的原因是这样的:Chrome浏览器见到MP4后缀的文件,使用了原生HTML5视频播放起播放,但却发现视频格式无法解码。对于Firefox,它不支持原生播放MP4,于是使用了Flash,绝大部分的视频格式基本都可通过Flash播放。
这篇2011年1月的消息提到Google将放弃对H264的支持:http://www.infoq.com/cn/news/2011/01/chrome-h264。这篇是Google方面的描述:http://blog.chromium.org/2011/01/html-video-codec-support-in-chrome.html。如果Google不再支持在Chrome上原生播放MP4,那么会调用Flash播放器播放,这样反而不会出现有些MP4文件播放不了的问题。
为什么Chrome不支持所有的视频编码格式?绝大部份的视频编码格式都是要付版权费的,Google已经为H264买了单,Firefox没有Google那么有钱不愿意买。
最后,我录制了一段教学视频,指导大家怎样把各种视频转换成兼容性比较好的MP4文件。视频中使用的软件是“格式工厂”(http://www.formatoz.com/CN/index.html),这个软件基本上只是做了一个界面,其核心调用了开源软件FFMPEG。由于它违反了FFMPEG的LGPL许可协议,备受指责。使用Linux的朋友可以直接使用FFMPEG命令进行视频格式转换,命令如下:
ffmpeg -i infile.flv -vcodec libx264 o5.mp4
如果转换出的视频在某些设备还是无法播放,可以试试利用MediaCoder转换兼容性更好的MP4
2、让服务器能正确识别多媒体的MIME类型
即使对浏览器来说,已经设置了正确的媒体,但有可能是您的服务器并不能正确识别多媒体的MIME类型。MIME类型告诉服务器如何处理不同的文件类型。如果你使用Apache,则可以在.htaccess文件中添加下面的音频支持:
AddType audio/ogg ogg AddType audio/ogg oga AddType audio/wav wav AddType audio/mpeg mp3 AddType audio/mp4 mp4 AddType audio/mp4 mpa
类似地添加如下代码,以支持视频:
AddType video/webm webm AddType video/mp4 mp4 AddType video/ogg ogg AddType video/ogg ogv
如果不能访问服务器的.htaccess文件,则有可能在服务器的控制面板地方有一个选项,允许查看和添加MIME类型。
如果是Windows服务器,那么可能需要在IIS或者web.config中进行设置在web.config文件中 。
3、文件格式转换的问题
一种很常见的情况是,用户从客户端提交给服务端一个类型的媒体文件,并且尽管你已经从它的文件扩展名中确认了其MIME类型。但是,该文件没有被正确解码。例如,它可以是一个完全有效的MP4文件,但由于某种原因,在一些浏览器中无法播放。如果发生这种情况,最好把用户上传的文件进行编码,比如使用如Miro Video Coverter和Media Converter等编码器,可以确保正确的编码。
此外,一些文件,尤其是MP4文件,在测试时,不要总是在一个支持其格式的浏览器中进行测试,这是因为事实上,MP4存在不同的编码格式,可以根据不同格式对MP4(又称如H.264)进行编码(参考:http://en.wikipedia.org/wiki/H.264#Profiles)如果有的浏览器不支持其中的编码格式,那么它自然不会工作。如果遇到这种情况,尝试确保该文件是以最基本的MP4编码方式进行编码。最好建议使用工具,比如Miro转换工具,它能确保MP4文件能在最多的浏览器中得到支持。
如果需要支持Firefox 3.6和更低的版本,还需要转换对应的音频文件为Ogg格式},并将它们添加到中的元素中。
4、能否在MP4完整下载前进行播放?
一般情况下,HTML5的的音频和视频播放器将允许用户在完整下载文件前,就可以开始进行播放了,有时候,对于MP4文件来说却不能这样,要必须等待所有的视频下载完毕再播放,这主要是编码问题造成的
有时,MP4文件使用索引进行了编码(其中包含了比如文件长度等信息),往往这些信息是放在文件的尾部而不是头部。索引信息中,包含了文件的元信息,浏览器根据这些元信息去进行下载。如果索引放在后面的话,则必须等待到获得整个文件的索引后,才能知道文件的元信息,所以就必须等到整个文件下载完毕才能开始播放了。
如果您遇到这种情况,还有一个简单的修补程序,是由埃里克森Renaun提供的,下载地址为:http://renaun.com/blog/code/qtindexswapper/,下载到计算机上运行,则可以把文件的索引信息移动到文件头并保存。
5、避免用JS访问废除的属性
这个问题看上去好像有点多余,但每次在Stack Overflow中,都会看到很多开发者发问,比如为什么某个方法不能运行,原因在于他们使用了不存在的属性。比如,在
<audio>和<video>标签中都有的旧的属性autobuffer,在2010年10月已经被preload取代了。
人们似乎忘记了,HTML5是尚未敲定的标准(虽然它的大部分内容现在已经都相当稳定),所以作为开发者,必须多到W3C的官方网站去进行查阅相关资料。
6、Firefox 11 以上版本的音量控制的问题
最近相信不少开发者会发现音量控制的操作在Firefox 11及以上的版本中被取消了。是的,静音和音量控制仍然是可以使用的,但要通过键盘上的上和向下键进行控制,其原因主要是发现了两个bug(请参考:http://www.iandevlin.com/blog/2012/04/html5/html5-media-controls-and-firefox),这一点请开发者注意,估计firefox会很快修复这个问题。
7、音视频播放是否完全脱离插件?
HTML5的音频和视频点的最大卖点之一就是不需要安装第三方插件-例如Flash
不幸的是,这不完全正确,ie 9及以上版本的浏览器和Safari是需要使用Microsoft Media Player和Apple的QuickTime,才能播放HTML5音频和视频。
8、如何全屏视频?支持情况如何?
HTML5 视频的其中一大威力在于其全屏播放的特性但HTML5 规范中,对这个居然没有任何提及,相反,在另外一个关于全屏幕播放的API中有定义,但还是在草稿阶段,在一些浏览器中开始有试验性的支持。
以下浏览器去一些支持全屏API,但具体使用的api方法各自有不同:
Chrome 19 版本以上
Firefox的12 +
Safari浏览器5.1 +
注:iPhone上,video自动全屏播放!
也有一些其他方法,能在其他浏览器中支持使用全屏API,比如https://github.com/sindresorhus/screenfull.js
Internet Explorer9 以上版本忽略了video poster属性
如果在HTML 5的video标签中使用poster属性,其含义为在视频播放前提供一张静态的图片给用户,但ie 9以上的版本,除非设置了preload属性为none,否则将会忽略掉设置的poster属性。
这是由于Internet Explorer是最迟支持HTML 5的浏览器,我们都习惯了其他浏览器中,如果设置了poster属性,则会在播放视频前,先显示设置的这张图片。但IE 9并不这样做,如果要播放的视频的第一帧已经加载了,则不会显示有poster属性指定的图片了,而且在IE 10中,目前依然存在这个问题。
9、通过HTML5技术能否访问摄像头和麦克风?
HTML 5的起草者们,一直都希望HTML 5能访问摄像头和麦克风,因此早期是使用标签的,但现在是被getUserMedia API所取代了(详见: http://dev.w3.org/2011/webrtc/editor/getusermedia.html)。
API本身是容易使用的 ,但目前浏览器支持相当有限。Opera是目前唯一个实现这些功能的浏览器,但只支持视频Internet Explorer 10也将对其进行部分支持,Firefox也会跟随。
10、autoplay在iphone/ipad中不能实现的问题
-
通过iframe
12345678var
ifr=document.createElement(
"iframe"
);
ifr.setAttribute(
'src'
,
"song.mp3"
);
ifr.setAttribute(
'width'
,
'1px'
);
ifr.setAttribute(
'height'
,
'1px'
);
ifr.setAttribute(
'scrolling'
,
'no'
);
ifr.style.border=
"0px"
;
document.body.appendChild(ifr);
-
通过页面上的其他触摸或者点击事件来调用对应的play()方法
11、解决iPhone中,视频自动在新窗口打开问题
HTML
<video id="player" width="480" height="320" webkit-playsinline>
Obj-C
webview.allowsInlineMediaPlayback = YES;
六、参考范例:音乐播放器
在网上看到有人用JS写的播放器,木有仔细看,先贴过来。感觉让我自己写想不到这么周全,等后面要用再仔细寻更好方案。
原文地址:http://www.cnblogs.com/arby/archive/2012/04/07/2436352.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
|
function
Audio(song, playType, dom){
/*
* 播放器构造函数。
* dom:为audio元素,可以不传。
* song : 为歌曲列表,只支持数组形式,格式为[{}{}]
* playType 为播放方式: 1 顺序播放 2 随机播放 3 单曲循环 4 全部循环
*/
if
(!dom) {
this
.media = document.createElement(
'audio'
);
document.body.appendChild(
this
.media);
}
else
{
this
.media =
typeof
dom ==
'string'
? document.getElementById(dom) : dom;
}
this
.currentIndex = 0;
this
.songList = song;
this
.countTotal =
this
.songList.length;
this
.playType = playType || 1;
this
.MusicInfo = [];
this
.playing =
false
;
}
/*
* 播放器启动主函数
*/
Audio.prototype.startPlay =
function
(){
this
.media.src =
this
.songList[
this
.currentIndex].src;
this
._play();
}
/*
* 播放器播放核心函数.
*/
Audio.prototype._play =
function
(){
var
self =
this
;
this
.media.play();
this
.playing =
true
;
this
.mediaEvent(
'ended'
,callback);
function
callback(){
//单曲循环无需单独处理,只需直接调用startPlay()函数。
if
(self.media.currentTime == self.media.duration){
switch
(self.playType){
case
1:
if
(self.currentIndex == self.countTotal-1){
return
false
;
}
else
{
self.currentIndex++;
}
break
;
case
2:
self.currentIndex = Math.floor(Math.random()*self.countTotal);
break
;
case
4:
self.currentIndex++;
console.log(
"self.currentIndex=="
,self.currentIndex);
self.currentIndex = (self.currentIndex > self.countTotal-1) ? 0 : self.currentIndex;
break
;
}
self.startPlay();
}
}
}
/*
*播放下一首如果当前已经是最后一首则播放第一首
*/
Audio.prototype.playNext =
function
(){
this
.currentIndex++;
this
.currentIndex =
this
.currentIndex >
this
.countTotal-1 ? 0 :
this
.currentIndex;
this
.startPlay();
}
/*
*播放上一首如果当前已经是第一首则播放最后一首
*/
Audio.prototype.playPrevious =
function
(){
this
.currentIndex++;
this
.currentIndex =
this
.currentIndex < 0 ?
this
.countTotal-1 :
this
.currentIndex;
this
.startPlay();
}
/*
* 暂停当前播放,如果传回调函数,则暂停后执行回调。
*/
Audio.prototype.playPause =
function
(callback){
if
(
this
.playing){
this
.media.pause();
this
.playing =
false
;
}
else
{
this
.media.play();
this
.playing =
true
;
}
if
(!callbakc){callback();}
}
/*
* 获取当前播放位置
*/
Audio.prototype.getCurrentTime =
function
(){
return
this
.media.currentTime;
}
/*
* 播放器各种事件监听.
* tip 类型必须是正确的类型
*/
Audio.prototype.mediaEvent =
function
(eventType, callback){
Event.add(
this
.media,eventType,callback);
}
/*
* 播放用户自定义时间,即拖动进度条。
*/
Audio.prototype.playUserTime =
function
(time){
this
.media.currentTime = time;
}
/*
* 获取当前媒体信息
* src 当前媒体路径
* size 当前媒体总时长.
*/
Audio.prototype.getMusicInfo =
function
(){
this
.MusicInfo.src =
this
.media.currentSrc;
this
.MusicInfo.size =
this
.media.duration;
this
.MusicInfo.name =
this
.songList[
this
.currentIndex].name;
return
this
.MusicInfo;
}
/*
* 设置或者获取当前音量
* voluems的值需大于0 小于等于 1
*/
Audio.prototype.setVolume =
function
(volumes){
if
(volumes) {
this
.media.volume = volumes;
}
else
{
return
this
.media.volume;
}
}
/*
* 设置或者取消静音.
* flag的值为true是静音,false时正常
*/
Audio.prototype.muted =
function
(flag){
if
(flag){
this
.media.muted = 1;
}
else
{
this
.media.muted = 0;
}
}
/*
* 向播放列表添加新歌曲
* song为所需要添加的歌曲,可以多首,格式如构造函数中song.
*/
Audio.prototype.addSongToList =
function
(song){
this
.songList.push(song);
this
.countTotal =
this
.songList.length;
}
Audio.prototype.getBuffered =
function
(){
return
this
.media.buffered;
}
/*全局事件监听封装函数*/
var
Event = {
add :
function
(node, eventType, callback){
var
node =
typeof
node ==
'string'
? document.getElementById(node) : node;
if
(document.addEventListener){
node.addEventListener(eventType, callback,
false
);
}
else
{
node.attachEvent(
'on'
+ eventType, callback);
}
},
remove :
function
(node, eventType, callback){
var
node =
typeof
node ==
'string'
? document.getElementById(node) : node;
if
(document.removeEventListener){
node.removeEventListener(eventType, callback,
false
);
}
else
{
node.detachEvent(
'on'
+ eventType, callback);
}
}
}
var
core = {
formatPlayTime :
function
(tempTime){
var
temp = tempTime.toString().split(
"."
)[0];
if
(tempTime<=60){
temp = temp>=10? temp :
"0"
+temp;
return
"00 : "
+ temp;
}
else
{
var
minute =Math.floor(temp/60);
minute = (minute >= 10)? minute :
"0"
+ minute;
var
second = temp%60;
second = (second >= 10)? second :
"0"
+second;
return
minute +
" : "
+ second;
}
}
}
|