打印

[应用] [原创]Flash全站的技术应用(六)-Flash也能播放wmv,wma吗?可以!

前言
Flash能播放除flv,mp3以外的其它文件格式吗?结合Windows Media Player(以下简称WMP),答案是肯定的!不过有点可惜的是,这样的播放器不兼容FF浏览器。
记得一个月前,luzhugao把自己做的Flash+WMP音乐播放器拿到经典论坛里展示:
http://www.zhugao.cn/player/index.html
当时,他的作品可是备受青睐,同时也引起了笔者的关注。因为笔者前段时间也刚做了个类似的,正在打算要做个也可以播放视频的,所以想从他的作品中学习一下,然后再写个教程给大家分享下。可恰逢luzhugao正在做商业版的播放器,他的所有东西都加密了,不方便拿他的来研究。把教程写出来,也担心他的版权会受侵犯(加上笔者也曾经是受害者)。不过幸运的是,笔者在luzhugao的播放器里发现了有个显示波形的窗口,那个就是用来显示视频用的!当发现了这点以后,笔者就可以在自己播放器的基础上,研究怎么做视频播放了。
不过,笔者在做这个之前,也曾犹豫过。
因为我的网站之前是只是打算放flv的,所以就通过遮罩把播放器的外框做成圆角,但是笔者的视频都不是自己做的,直接用人家网站上的。目前flv如此不流行的情况下,笔者要用到自己的网站上,就非得先把人家的视频下到自己的机上,转成flv,再上传。或者好一点的,就是一边上传一边转格式。但是,很多时候,视频数量很多,而且时间也不短,要更新一次,恐怕需要几天时间,太慢了。
如果只复制视频的地址,就可以把视频更新到自己的网站上,那该多好啊。所以,结合WMP成为笔者的首选,可是,要把这样的播放器定制成别的形状就难得要命了,哪怕定得好,也不知道怎么样才能让播放器跟网页缝合起来。
然而,笔者还是尝试了,结果发现,好像那个尖角也没有太大影响,于是就做下去了。但是,现在进度条还没有做出来,然后,点里头的图片,光盘都暂时没有链接到视频里头。自己感觉,特别是后两者做起来会比较花时间,加上有人对我的教程期待已久,就先写教程好了。
PS:其实WMP的代码我也是在网上下一个来用的。

有个小尖角影响的播放器预览:
http://hbro.cincn.com/index.htm#contents=video
这里,双击视频窗口或者点十字按钮都可以实现全屏播放,全屏后双击就可以恢复原来的大小。

[ 本帖最后由 HBrO 于 2006-10-10 17:54 编辑 ]
本帖最近评分记录
为了让大家相信这一播放器确实可以播放除flv以外的WMP视频格式(注意,RM,RMVB那些不是WMP视频格式,不能在这里播放),笔者又做了一个演示文档,让读者可以自行在Flash的文本框里输入网址来播放。如果没有安全影响的话,估计本地的也是可以播放,不过路径最好使用file:///的那种格式。当然你也可以直接点选右侧播放列表里头的视频来测试。

演示播放器地址:
http://hbro.cincn.com/hbro/course/flashwebplayer/player.html

因为使用了WMP+Flash,所以基本上,整个播放器功能的实现都要通过JS,关于JS与AS的通讯,看下这帖子,笔者在这里就不再重复了。

http://bbs.blueidea.com/viewthre ... Dtype%26typeid%3D16

[ 本帖最后由 HBrO 于 2006-9-19 01:14 编辑 ]
现在,笔者先以一个简单的功能为例,说明Flash是怎么样控制视频,并且视频反过来如何改变Flash的当前状态。
点播放列表的任一项目后,通过名为setvideo的fscommand,把列表路径传到HTML里,此时,JS获取到路径,就可以设置视频的路径了。在演示文档里,WMP播放器的实例名设为video,那么,在接收到fscommand以后,就可以作如下设置:
switch(command){
  case "setvideo":
    video.URL=args;
    break;
}
此时,如果大家耐心等待(时间由网速决定),将能等到视频在WMP播放器里播放了。但是,要让用户等待很长时间,又没有任何提示的话,将让浏览者不耐烦,因此,有必要给用户一些提示,让用户看到希望。
如果大家都在线听过歌或者看过视频的话,相信都会看到一些提示如“正在连接”,“正在缓冲”等播放状态的消息,那么,我们自己能否获取呢?答案是肯定的。正在缓冲,正在播放,那些状态其实都能触发WMP控件的一些事件,并且能为我们所获得。
然而,这东西我其实一开始是不懂的,下了人家的纯WMP播放器研究了下,终于了解到了捕获事件的办法:
就是在HTML里插入这么一段JS:
<script language="JScript" for="video" event="playStateChange(ns)">video_evtPSChg(ns);</script>
这里的意思就是在播放状态改变事件响应之时,触发video_evtPSChg函数,ns则是表示状态的参数,类型为数字。至于哪个数表示什么,笔者将在后面举例说明一部分,有兴趣的可以继续研究。
此时,在video_evtPSChg函数里头,就可以写:
function video_evtPSChg(f){
// 6(缓冲处理中)
switch(f){
case 6:
player.setVariable("playstatus","正在缓冲,请稍候")
break;
}
}
如果你在Flash里创建了一个变量名为playstatus的动态文本框,那么,在点到播放列表项目,播放器缓冲数据的时候,就会在文本框里显示:“正在缓冲,请稍候”了。于是,就达到了WMP控制Flash的目的了。

播放器其它的功能,都是通过这样的原理实现的。下面将介绍这个演示播放器的制作教程。
问下这个的用途广泛么,是不是单纯的技术研究?
因为播放wmv wma基本上是个电脑,不装任何播放器都可以放吧,windows捆绑了media player
应该不会有人用FLASH了放这种文件的我想,即使是网页里播放
花大力气研究这个flash wmv player如果没有大用途,不是白费苦心么

以上纯属个人观点 / 不要被我误导哦 :)-

新站www.abingdesign.com / Windows vista FLASH体验版

TOP

还在为头像烦恼?还在为不能关注好友动态烦忧?快来蓝色理想家园吧!
1.1 新建一个Flash文档,保存为player.fla,大小为580*390(参考),然后,大家可以参考下面这一

图的布局,把播放器的一些基本元素排出来。

1.2 视频地址右边的输入文本框,实例名为addressBox,变量名为address。然后,右边的“确定”按钮

可以不定义实例名称。
1.3 地址下方的黑方块,就一个320*240的矩形就可以了,到时候,WMP控件将覆盖在这上面,因此这里

不用太讲究。
1.4 黑方块下面是一个显示播放状态的动态文本框,变量名为playstatus,然后在这下面做上进度条。

这里稍有讲究,先建一个实例名为progressBar的MC,然后,里头的小方块按钮则是一个实例名为ball的
MC,在这MC里头才是按钮。
1.5 下面的四个就是按钮了,可以不定义实例名称。动态文本框的变量名为time。
1.6 最后,右边播放列表下方的动态文本的变量名为listBox。
到此,Flash里基本的布局已经完成,下面就到程序控制了。

TOP

回复 #4 li6in9 的帖子

其实是用得上的,有了WMP结合,Flash网站可以用比较小的mid,wma文件,扩展了Flash的多媒体功能,弥补Flash在这方面的不足.

TOP

笔者的整个程序是从读入播放列表开始的,但是这个读取,分析播放列表,并不是本教程的重点,故只简单提供下代码:
2.2 先在player.fla所在目录下创建一个playList.xml文件,里头加入的内容使用如下格式:

<?xml version="1.0" encoding="GB2312"?><images page="0"><i a="images_abbr/3.jpg" d="超女决赛8进6-谭维维《如果我没有爱过》" id="10025" inList="True" s="mms://nv.sina.com.cn/ent/2006/09/08660827.wmv"/><i a="images_abbr/1.jpg" d="超级女声总决赛8进6-谭维维《离歌》" id="10024" inList="True" s="mms://nv.sina.com.cn/ent/2006/09/08327850.wmv"/><i a="images_abbr/22344543.jpg" d="超女总决赛8进6-厉娜《乐园》" id="10011" inList="True" s="mms://nv.sina.com.cn/ent/2006/09/08991394.wmv"/><i a="images_abbr/2.jpg" d="超女总决赛8进6-尚雯婕《如果没有你》" id="10010" inList="True" s="mms://nv.sina.com.cn/ent/2006/09/08987854.wmv"/></images>

该xml是笔者自己网站读后台之后生成的,有些信息可能与本播放器无关,不过,相信聪明的你们,在后面的xml分析结束后,就可以辨认出来了。

然后,可以加入读取,分析xml的as了:
Stage.showMenu=false;
Stage.scaleMode="noScale"
//上面两句是为了防止缩放影片用的,如果WMP控件放上去了,最好不要让用户可以控制你SWF的缩放。
System.useCodepage = true;
//防止中文乱码
var playlist:XML = new XML();
playlist.load("playlist.xml");
var urls:Array;
var descriptions:Array;
listBox.html = true;
listBox.multiline=true;//设置为多行文本,当然你也可以手动设置
listBox.wordWrap=true;//设置可自动换行,也能手动设置
playlist.onLoad = function(success:Boolean) {
       if (success) {
              urls = new Array();
              descriptions = new Array();
              listBox.htmlText = "";
              trace(playlist);
              for (var i in playlist.childNodes[0].childNodes) {
                     urls[i] = playlist.childNodes[0].childNodes[i].attributes.s;
                     descriptions[i] = playlist.childNodes[0].childNodes[i].attributes.d;
                     listBox.htmlText += "<a href='asfunction:setURL,"+urls[i]+"'>"+descriptions[i]+"</a><br>";//setURL函数将往HTML里传递视频地址参数,在点到了视频标题之后,setURL函数将被调用。
              }
       } else {
              trace("Loading Error!");
       }
};

TOP

2.3 定义setURL函数:
function setURL(url) {
       fscommand("setvideo", url); //这一命令将在HTML里接收
       address = url; //让视频地址那个动态文本把当前视频的路径显示出来
       playstatus="正在连接" //其实这一做法是不正确的,应该是在响应了WMP事件之后才设的。不过笔者在这里偷懒了。
}

TOP

走到这一步,为了比较清晰地说明每一个接口,在此先不添加Flash代码,把setvideo的fscommand完成。而在此之前,需要先把WMP播放器代码置入网页里头。
3.1 发布一下Flash,选择"文件"-"发布设置",在HTML选项卡里选择"带Fscommand跟踪的Flash",窗口模式则选择"不透明无窗口"(这个东西让笔者头痛了好久了,如果设置成窗口的话,好可怜,Flash始终都在WMP的上面,真不知道什么回事.)
3.2 点下发布按钮后,在格式选项卡里把HTML的勾去掉,然后点"确定"
3.3 此时生成了一个HTML文件,然后,建议用DreamWeaver或者Frontpage那些可视化的网页制作软件打开player.html。这回不用记事本,是考虑到调整视频WMP的位置比较方便。
3.4 如果你使用DreamWeaver,那就在里头拖一个层出来,并且设置位置。如果是用笔者当时设置的位置,那么,宽度将是320,高度将是240,top为58px,left为31px


3.5 在代码视图的<div></div>标签里头,插入播放器的代码。这段代码,笔者也是拷贝人家的,而且自己无论如何都不能在DW里通过插入命令,放入完全一致的内容,所以就只好屈就下了。

<object classid="CLSID:6BF52A52-394A-11d3-B153-00C04F79FAA6"
type="application/x-oleobject" name="video" width="320" height="240" id="video"
style="position:relative;left:0px;top:0px;width:320px;height:240px;">
    <param name="autoStart" value="true" />
    <param name="balance" value="0" />
    <param name="currentPosition" value="0" />
    <param name="currentMarker" value="0" />
    <param name="enableContextMenu" value="false" />
    <param name="enableErrorDialogs" value="false" />
    <param name="enabled" value="true" />
    <param name="fullScreen" value="false" />
    <param name="invokeURLs" value="false" />
    <param name="mute" value="false" />
    <param name="playCount" value="1" />
    <param name="rate" value="1" />
    <param name="uiMode" value="none" />
    <param name="volume" value="100" />
  </object>

其实,这段代码,大部分还是可以理解的。就是classid那个地方,笔者就是没有办法记下来。就像笔者虽然现在用Flash做网站,也还没记得Flash控件那段代码一样。
笔者是从一个音乐播放器里拷贝出来的,当时隐藏了视频框,不过它隐藏的办法个人感觉也不是很好,就是把width和height设成了0。这里,笔者把它改成320和240就看到视频框了,在DW的设计视图里,是一个ActiveX的图标:



对里头的参数,相信大家看到那些名称,都大概想到是什么意思了吧,比如说,param name="autoStart" value="true" />就是让WMP会自动播放,<param name="enableContextMenu" value="false" />就是屏蔽菜单,等等,倒是有两个,笔者没有看明白,暂时也没有查过相关资料,一个是uiMode,一个是invokeURLs。
另外,WMP控件的实例名为video。

然后,也插入关于播放器的事件响应代码:
<script language="JScript" for="video" event="playStateChange(ns)">video_evtPSChg(ns);</script>
      <script language="JScript" for="video" event="error()">video_evtWmpError();</script>
这里,笔者就只写了两个事件,一个是播放状态改变事件,另一个是播放错误事件。并且,在播放状态改变时,触发video_evtPSChg函数,播放错误时,触发video_evtWmpError函数。当然,你也可以根据需要,按这一格式添加事件。事件的具体名称,可以参考mirycat推荐的:
http://blog.guoshuang.com/guoshuangweb/books/wmpsdk.chm

这样,WMP播放器就已经插入到Flash里头了。

TOP

下面就可以写接收setvideo命令后的动作了。
4.1 在HTML文件里,找到place your code here一句,在这里添加代码:
switch(command){
  case "setvideo":
    initvideo(args);
    break;
}
同时定义一个initvideo函数:
function initvideo(args){
  video.URL=args;
}
笔者本来的代码其实是没有定义这一函数的,因为就一句话,但是后来功能多了以后,发现还是定义一个比较合适,就写成这样了。
此时保存HTML文件,在浏览器打开,如果文件路径正确无误的话,将会看到有视频播放了。
4.2 但是,加载的时候依然没有任何提示,网速慢的话,浏览者将没有耐心等下去,因此,事件处理函数成为当务之急。
定义video_evtPSChg函数:
function video_evtPSChg(f){
// 以下是状态值 (f) 的说明:
// 0(未定义) 1(已停止播放) 2(已暂停播放) 3(正在播放中) 4(向前搜索) 5(向后搜索)
// 6(缓冲处理中) 7(等待中) 8(已播放完毕) 9(转换曲目中) 10(就绪状态)
  switch(f){
    case 1:
      video_evtStop();
      break;
    case 2:
      video_evtPause();
      break;
    case 6:
      video_evtBuffer();
      break;
    case 3:
      video_evtPlay();
      break;
    case 8:
      break;
  }
}
因为代码本来也是拷贝人家的,注释也说得很清楚,笔者就把这些注释也拷出来,方便大家参考。在这里,笔者用了其中的几个事件,并且为每个事件都定义了函数。停止播放的时候,响应video_evtStop函数,暂停时,响应evtPause函数,缓冲时,响应video_evtBuffer函数(不过这里是不能获得缓冲百分比的,如要获得,就换一个事件:Buffering(bf)),播放中,响应video_evtPlay函数。
4.3 下面,定义这几个函数
function video_evtStop(){
  player.setVariable("playstatus","已停止")
}
function video_evtPause(){
  player.setVariable("playstatus","已暂停")
}
function video_evtBuffer(){
  player.setVariable("playstatus","正在缓冲,请稍侯")
}
function video_evtPlay(){
  player.setVariable("playstatus","正在播放")
}
这几个函数都设置了Flash里头的一个变量值,将显示在视频区域下方的动态文本里。那么,WMP在触发这四个事件的时候,Flash里就可以显示出来了。

TOP

那么,setvideo这一接口算是基本完成了,不过,别忘了还有点尾巴没有收好,就是让用户输入视频路径,按“确定”也同样可以播放视频。于是,
5.1 回到player.fla文件,给“确定”按钮添加动作:
on (release) {
       if (addressBox.text != "") {//通过检查是否没有输入路径以降低出错的机率。
              fscommand("setvideo", addressBox.text);
       }
}
5.2 当然,这也不能避免用户输入的地址有误或者不能播放而导致的加载错误,因此,现在要在HTML里处理错误了。
之前已经加了这么句代码:
<script language="JScript" for="video" event="error()">video_evtWmpError();</script>
因此,下面应该定义video_evtWmpError函数:
function evtWmpError(){
  video.Error.clearErrorQueue();//先清空错误
  player.setVariable("playstatus","加载失败")//让Flash的动态文本显示出错消息
  Retry()//进入重试状态
}
var tryTime=0
function Retry(){
  tryTime++;
  if(tryTime>5){//重试次数超过5次的时候
    tryTime=0;//重置tryTime
    clearTimeout(RetryID)//放弃重试
  }else{//在重试次数还没超过5次的时候,
    RetryID=setTimeout(initvideo,1000,video.URL)//每隔一秒重试一次。
  }
}
以上只是笔者的一个错误处理方案,你们完全可以根据自己的需要,在evtWmpError函数里头写出适合于你自己具体情况的错误处理代码。笔者的这一代码,是在加载错误以后,周期性调用重试函数,再在重试函数里头让播放视频的动作重新执行,以达到重试的目的。如果再一次播放失败的话,WMP会自动调用evtWmpError事件,此时tryTime会加一,说明已经重试了一遍。如此反复,如果第五次调用initvideo函数还出错的话,那么就会执行clearTimeout(RetryID),放弃重试。

TOP

当这些事件处理已经比较完善的时候,我们接下来的一些控制就不需要考虑播放时究竟发生了什么,然后要提示用户些什么,我们只管去控制视频的播放,播放状态的提示就会自动给你跑出来。不信,你们试试看。
6.1 分别给播放,暂停,停止,全屏按钮加入以下的四段代码:
播放按钮:
on(release){
  fscommand("playvideo")
}
暂停按钮:
on(release){
  fscommand("pausevideo")
}
停止按钮:
on(release){
  fscommand("stopvideo")
}
全屏按钮:
on(release){
  fscommand("fullscreen",true)//注意,这里的控制不是让播放器全屏,这是用在网页上的,跟之前几个是同等的。
}
然后,在HTML的fscommand函数的switch里追加代码:
case "playvideo":
  video.controls.play();//controls是WMP的一个对象,里头包含很多控制WMP播放的方法。这是让WMP的视频播放。
  break;
case "pausevideo":
  video.controls.pause();//这是WMP的暂停方法;
  break;
case "stopvideo":
  video.controls.stop();//这是WMP的停止方法;
  break;
case "fullscreen":
  video.fullscreen=args;//设置WMP是否全屏显示,Flash当时传过去的参数为true,故会全屏显示。这个属性,在下载的音乐播放器里没有,笔者在别的地方找了好久,好不容易在新浪视频里头找到了这一句。
6.2 现在生成一个swf,在网页里测试,你将看到视频区下方的状态栏会随着播放状态的变化而改变了。比如说,你在播放时按了暂停按钮,状态文本会提示已暂停。在整个代码里,就只有video_evtPause函数里头有这一设置。但是点暂停按钮都没有调用这一函数喔。那么,为什么还是会出现“已暂停”这几个字呢?答案很简单,就是你点了按钮后,通过fscommand调用了video.controls.pause,而暂停事件是在WMP暂停时自动触发的,于是便调起了video_evtPause了。
哈哈,是不是觉得这样很好用呢?你不需要再在任何控制暂停的地方设置一下状态文本,你只管控制你的视频就行了,其它东西,事件处理函数会及时为你处理,不需要你再为此而操劳了。
最后,就剩下进度条的制作了,其实原理也跟上面的一样,不过这里涉及一些数学问题和逻辑思维,需要AS和JS很好地配合,而且难度相对上面的功能来说,稍高了点,加上很多人都很关注进度条的做法,笔者打算先好好睡一觉,再比较详细地讲讲进度条的做法。

TOP

终于出来了,斑竹辛苦了,我觉得这篇文章应该给四个大拇指:)
收藏,继续关注中……

TOP

看了.顶了.不错.

原来想和一个教育类的视频网站的.唉,现在网站的带宽还是不够啊.好的又买不起了.只好作罢了.

将来能搞个像PPLive那样的p2p流媒体服务器也好职..

加紧赚钱买服务器啦

TOP

引用:
原帖由 HBrO 于 2006-9-19 02:30 发表
... 笔者打算先好好睡一觉,再比较详细地讲讲进度条的做法 ...
终于现身了
好好睡一觉吧,期待你的进度条
停止签名

TOP

好羡慕版主的东西,也好想学,但我对JS一窍不通,不知能不能把用flash播放wma格式的音乐方法学会。这样也可以扩展一下我做的那个音乐播放器。
不知您做的能不能脱离游览器运行?

TOP

脱离浏览器?不行,
不过,如果你想通过扩展格式来扩展你那个播放器的话,可以,不过不是现在这个.我本地就有这么一个程序.但是BUG还有特别多,而且现在也没有弄它了.

TOP

突然想起来,做这个之前,可以先把时间那个动态文本的显示做出来:
7.1 在AS里追加代码:
//format是一个处理时间显示的小函数,因为时间的显示方式是00:00/00:00,如果不进行处理,在对时间数值进行运算之后,显示出来的将是0:0/0:0,不符合要求。
function format(str) {
       str = "00"+str;//这样一处理,就可以保证分和秒的单元的长度大于2;
       //str = str.substr(str.length-2, 2);//此时再截取两个,就可以让显示出来的分和秒的单元的长度等于2,但是这样会有一个Bug,就是如果时间长于100分钟的时候,将不能正确显示。所以如果不能保证视频长度小于100分钟的话,最好再处理一下:
        len=Math.max(2,str.length-2);//让分钟的单元在长度不到2的时候,补充到2,否则就等于本身的长度
        str=str.substr(str.length-len,len);//这一次截取就有保证了。
       return str;
}
function showTime() {
       video_pos = videopos;
       video_dur = videodur;//videopos,videodur通过JS传到AS里,单位为秒,跟AS的sound对象不同,那是毫秒
       if (isNaN(video_pos)) {
              video_pos = 0;//时间如果是非数字的话,设为0
       }
       video_posmin = format(Math.floor(video_pos/60));
       video_possec = format(Math.floor(video_pos%60));//这两个是获取分和秒数值的代码,相信小学生也明白算法,然后,用刚才定义的format函数把字符单元长度处理成最少两个
       if (isNaN(video_dur)) {
              video_dur = 0;
       }
       video_durmin = format(Math.floor(video_dur/60));
       video_dursec = format(Math.floor(video_dur%60));
       time = video_posmin+":"+video_possec+"/"+video_durmin+":"+video_dursec;//把位置时间和总时间连在一起,显示在time动态文本里
}
timeId=setInterval(showTime,200)//周期性更新时间显示

7.2 在JS里给Flash设置变量:
function video_showTime(){
  player.setVariable("videopos",video.controls.currentPosition)
  player.setVariable("videodur",video.currentMedia.duration)
  id=setTimeout(video_showTime,200)
}
该函数在点到视频的时候再调用也不晚,故该周期性函数的调用语句追加到initvideo函数里头。

TOP

进度条的制作:
8.1 原理简介
虽然进度条对于大多数中高级水平的AS制作者来说,是再简单不过的事情,不过,考虑到经常有初学者问到播放器进度条的制作问题,在此,笔者还是花上一些笔墨写写吧。
一个最常规的横向进度条,就是一个滑块在一定长度L的区域做横向移动,当用户不拖动滑块的时候,滑块在进度条的位置将会随着视频位置的变化而改变。而这里说的视频位置,是指视频当前时间与总时间的比值。一个两分钟的视频刚开始播放时,其位置时间为0,那么,进度条滑块的位置也就是0。播到一分钟的时候,位置时间将是60s/120s*100%=50%,也就是让滑块位于0.5L的位置,两分钟的时候,位置时间将是120s/120s*100%=100%,就是让滑块位于L的位置,也就是进度条的最右端。
不过,位置时间和总时间并不是常量,必须要根据这两个变量,动态算出进度条滑块的位置:
ball._x=pos/dur*L
从上面的计算过程,可以看出,该表达式中,pos就是视频的位置时间,dur就是视频的总时间,L则是进度条的长度。假如最左端不是0而是某一数值initx的话,那上面的表达式就要改成:
ball._x=initx+pos/dur*L

8.2 时间刚才已经获取了,所以,现在就只需要获得initx和L了。
这个,只要在进度条progressBar元件里头第一帧读一次就可以了。
var initx:Number = ball._x;
var inity:Number = ball._y;
var maxLength:Number = 301;
在这里,获取进度条滑块(滑块实例名为ball)的x和y的位置(之所以要获得y位置,是控制拖动滑块的时候,纵坐标的位置保持不变),然后,maxLength就是8.1表达式中的L,这个大家可以动态获取,不过笔者比较懒,直接写个常量上去了事了。

8.3 让滑块的位置周期性地改变:
this.onEnterFrame = function() {
       ball._x = initx+_parent.video_pos/_parent.video_dur*maxLength;
};
此时,生成一个SWF,在网页里测试,就可以看到进度条的滑块随视频位置时间的变化而改变了。

TOP

8.4 接下来就做拖动了。
拖动滑块,首先需要限制滑块只能横向在initx到initx+maxLength这一范围内移动,纵向不能改变。
然后,当释放滑块的时候,我们要让视频移动到相应的位置pos,根据进度条的原理,此时的pos依然满足:
ball._x=initx+pos/dur*L
于是,可以解得pos=(ball._x-initx)/L*dur
然后,再把这一数值以fscommand传给HTML,但是,由于dur其实是视频的总时间,属于WMP的信息,直接在Flash里传出去似乎不是很好(这纯粹是个人的想法),于是,笔者把上面的式子改了一下:
pos/dur=(ball._x-initx)/L
然后,pos/dur用一变量percent代替,传给HTML,再让JS处理。
于是,现在可以在ball里头的按钮添加代码:
on (press) {
       startDrag(this, false, _parent.initx, _parent.inity, _parent.initx+_parent.maxLength, _parent.inity);
}
on (release, releaseOutside) {
       fscommand("setvideopercent", (_x-_parent.initx)/_parent.maxLength);//这里需要让HTML接收位置时间,然后通过JS控制视频播放
       stopDrag();
}
此时在网页里测试影片,你会发现,视频播放的时候,滑块根本不听你的话,它老是跟着播放进度走。

......怎么办呢?

此时,我们必须想办法,在按下按钮的时候,禁用
ball._x = initx+_parent.video_pos/_parent.video_dur*maxLength;
这么一句。这里,最好的办法,个人觉得是去掉onEnterFrame事件,然后在释放滑块以后,重新声明。
不过,笔者已经形成了不太好的习惯,喜欢通过一个布尔变量来判断是否执行。定义一个dragging变量,如果为true,则不允许滑块跟着视频走。
那么,progressBar第一帧的代码就改成:
var initx:Number = ball._x;
var inity:Number = ball._y;
var maxLength:Number = 301;
dragging = false;
this.onEnterFrame = function() {
       if (!dragging) {
              ball._x = initx+_parent.video_pos/_parent.video_dur*maxLength;
       }
};
ball里头的按钮代码则改为:
on (press) {
       _parent.dragging = true;//按下后,滑块将不跟视频走了,任你在进度条长度范围内拖动
       startDrag(this, false, _parent.initx, _parent.inity, _parent.initx+_parent.maxLength, _parent.inity);
}
on (release, releaseOutside) {        
       fscommand("setvideopercent", (_x-_parent.initx)/_parent.maxLength);
       stopDrag();
       _parent.dragging=false;//释放滑块后,滑块可以跟视频走了
}
生成SWF文件。

TOP

8.5 然后,要为setvideopercent这一命令写响应的JS代码:
在JS的fscommand函数中的switch里追加:
case "setvideopercent":
            video.controls.currentPosition=args*video.currentMedia.duration
            break;
保存HTML,然后测试下,发现进度条可以拖了,并且释放的时候也能定位视频,不过就可能有个Bug,滑块会弹回去原位置一刹那,才跳回你释放的位置
......
头痛了大约30秒,发现,在on(release, releaseOutside)事件中设置了dragging以后,fscommand接收到的命令后向Flash传变量这一操作因为时间延迟,还没来得及完成呢!这样的话,笔者只好在JS里确保向Flash传变量这一操作完成才设dragging吧。于是,笔者把这一设置写在了JS里头,把AS的那句
_parent.dragging=false;
去掉,然后把JS改成:
case "setvideopercent":
            video.controls.currentPosition=args*video.currentMedia.duration
            player.setVariable("progressBar.dragging",false)
            break;
这么运行,Bug就已经修复了。然而,......,这么一改,本来很工整的代码,就在这里变乱了。唉!代码变乱的根源往往就在于此,笔者无论在制作之前构思多久,把代码结构想得多么完善,总得在这么一些地方作些小修补,然后,代码就变得越来越不工整了。
当然,这也部分归因于fscommand的不完善,因此,在这里,强烈支持火山,把这播放器的ExternalInterface版本做出来!

TOP

最后,笔者发现忘了做一个音量控制了,不过,相信大家在看了进度条的制作以后,应该知道如何制作音量控制了。这里,笔者给大家一点提示,设置音量的办法,是改变video.settings.volume的数值。

TOP

hbr真牛.呵呵.as看起来好乱.用oop写更好了. 有空再仔细看.

TOP

牛,这些天,也在找这方面的东西,前两天以为在FLASH上真的无法实现WMV的播放了,只好去找一些在线转换程序,这下好了,又可以一步到位了.

不过我到是想把FLASH做在层里面,这样可以很好的实现视频边框美化.

有没有人知道这个层怎么样才能控制好位置,公司首页为居中对齐,这样800*600与1024*768位置会发生不一样.
是不是得用一个判断:如果是JS检测到是800*600,位层位置定为XXX,XXX然后,再定1024,然后再定1280,呵呵,不知道有没有更好的办法.

TOP

你想知道居中对齐怎么做?看看我这里,查看源文件,把setPos函数找出来看看
http://hbro.cincn.com/cindex.htm#contents=video

TOP

还有一个办法,也许可行,不过我觉得不太可取的就是.把FLASH做成透明的,然后在视频那里挖个空

TOP