经过一些对JW和FLOW播放器的研究,最后还是用OSMF写了一个简单的播放器,估计最好还是用FLASH自身的控件写更好控制一些,毕竟程序员最好能对底层比较了解,这样对播放器的修改时非常有好处的。
下面有些凌乱的注意点:
1:跨域问题
比如我在本地要播放一个网站 www.test.com下面的FLV流文件,那么FALSH9.0之前系统会以http方式去请求是否有这样一个文件
crossdomain.xml文件存在,这个文件是把钥匙,你要访问我服务器上的东西,就得有这个钥匙,钥匙的一般写法是
<script type='text/javascript'>
var so = new SWFObject('OsmfPlayer.swf','ply','480','400','9','#000000');
so.addParam('allowfullscreen','true');
so.addParam('allowscriptaccess','always');
so.addVariable('PlayUrl', 'http://www.test.com?a=1&b=2);
so.write('flashcontent');
</script>
注意啊,上面的addParam和addVariable很容易混淆,实际上我个人认为吧,前者是flash自带的参数名,如allowfullscreen是不能更改的,后者是自定义的变量,名字可以更改。
这边就涉及到一个新的问题。PlayUrl这个参数后面的值是一个带?和&的字符串,如何在AS3里完整获得这个字符串值也是一个麻烦事,目前个人写法是进行拼接。写成这样:
so.addVariable('PlayUrl', 'http://www.test.com');
so.addVariable('a', '1');
so.addVariable('b', '2');
然后在AS3里用this.loaderInfo.parameters.PlayUrl,this.loaderInfo.parameters.a,this.loaderInfo.parameters.b获得各自的值进行拼接赋给播放器。
挺麻烦,不知道有没有更好的办法?
3:元数据的获得
element.client.addHandler("onMetaData", onMetaData); //添加侦听
private function onMetaData(info:Object):void
{
metadata_ = info;
print("获取元数据");
print("metadata: duration=" + info.duration + " width=" + info.width + " height=" + info.height + " framerate=" + info.framerate);
/*var m:Number;
//print(info.seekpoints); //只对mp4有效
for (m=0; m<info.seekpoints.length; m++) {
print(info.seekpoints[m]["time"]); //枚举最重要
}
var n:Number; //keyframes 只对flv有效
for (n=0; n<info.keyframes.filepositions.length; n++) {
print(' fileposition: '+info.keyframes.filepositions[n]+' time: '+info.keyframes.times[n]); //枚举最重要
} */
}
元数据获得分为FLV和MP4,FLV和MP4的拉动都是通过关键帧来实现的,但是差别还是挺大的:
mp4文件的SEEK点叫做metadata.seekpoints,flv的叫做keyframes,这个差别是很大的。
private function onMetaData(info:Object):void
{
true_duration = player.duration;
(controlbarlayout.getChildByName('totalshowtext') as TextField).setTextFormat(format1);
(controlbarlayout.getChildByName('totalshowtext') as TextField).text = timeFormat(player.duration);
metadata_ = info;
var m:Number;
//print(info.seekpoints); //只对mp4有效
for (m=0; m<info.seekpoints.length; m++) {
print(info.seekpoints[m]["time"]); //枚举最重要
}
print("metadata: duration=" + info.duration + " width=" + info.width + " height=" + info.height + " framerate=" + info.framerate);
var n:Number; //keyframes 只对flv有效
for (n=0; n<info.keyframes.filepositions.length; n++) {
print(' fileposition: '+info.keyframes.filepositions[n]+' time: '+info.keyframes.times[n]); //枚举最重要
}
}
mp4寻找SEEK点方法
private function get_nearest_seekpoint(second:Number, seekpoints)
{
var index1 = 0;
var index2 = 0;
// Iterate through array to find keyframes before and after scrubber second
for(var i = 0; i != seekpoints.length; i++)
{
if(seekpoints[i]["time"] < second)
{
index1 = i;
}
else
{
index2 = i;
break;
}
}
// Calculate nearest keyframe
if(second - seekpoints[index1]["time"] < seekpoints[index2]["time"] - second)
{
return index1;
}
else
{
return index2;
}
}
调用
var keyframe = get_nearest_seekpoint(dragsecond, metadata_.seekpoints); //元数据应该是第一次所取得的元数据,而且metadata_.seekpoints矩阵值应该保持不变
print("seek: nearest keyframe=" + keyframe);
var playsecond:Number; //附近关键帧的有效开始时间点
playsecond = metadata_.seekpoints[keyframe]["time"];
print("seek second" + playsecond);
print("seek操作后播放地址是:"+videoUrl+"?start="+playsecond);
element.resource = new URLResource(videoUrl+"?start="+playsecond);
player.media = element;
一个播放器如果不能正确播放给定的FLV或MP4文件,需要几个方面检查:
1:Fiddler抓到的播放实际路径是不是和给定路径一模一样,有时候参数有一点错误也是不能播放的。
2: 搞清楚是否有跨域问题存在。
3:播放器SWF帧率是不是和视频帧率一致,据说这个有影响。