首先多播放器窗口,除了一个以外display:none,一般需求中两个就足够了。然后监听是否结束(关于监听,稍后再发一篇讲讲Javascript的监听问题),监听本P播放结束之后将下一个的链接赋值到隐藏的那个,交替display,进度条当然需要重做,这里就需要统计总时长了。
当然理论上很好想,实际在用的时候还是遇到了一些问题:
最近由于工作需要在研究HTML5的播放器,HTML5其实自带的已经很全了,但是当我们需要把切割的视频整合播放的时候就遇到了麻烦,这里我想到了一个思路,正好发现网上也提到了很多这种思路:
首先多播放器窗口,除了一个以外display:none,一般需求中两个就足够了。然后监听是否结束(关于监听,稍后再发一篇讲讲Javascript的监听问题),监听本P播放结束之后将下一个的链接赋值到隐藏的那个,交替display,进度条当然需要重做,这里就需要统计总时长了。
当然理论上很好想,实际在用的时候还是遇到了一些问题:
首先我们来看一下,在加载过程中,依次会发生什么:
当音频/视频处于加载过程中时,会依次发生以下事件:
loadstart
durationchange
loadedmetadata
loadeddata
progress
canplay
canplaythrough
并且这些步骤全部都不是瞬时发生的,试网速而定,正因为如此所以当时我测试替换URL-获取时间-替换URL时才因此失败了。结果得到了一串 NULL,正确的做法是需要监听并执行以上操作。
如果你需要提前缓冲,需要监听timeupdate并且返回值,然后与总时长相减,根据条件判断并加载就行了^ ^
此外的一些,自取函数,之所以打上jQuery标签,是因为懒……:
url使用飞驴获取,时效性很短需要测试请替换数组内容
代码如下 | 复制代码 |
var videos = new Array('视频1', '视频2', '视频3'); var timeline = new Array(0); // 记录各点时间 var nowVideoLocation = 0; // 目前所在的位置 var playerNum = 0; // 目前使用的video标签位置 var str; // 输出信息 var totalTime = 0; // 视频总时长 var currentVideoTime = 0; var i = 0; // 初始化计数器 var targetTime = 0; // 目标时间 var targetPlayer = 0; // 记录目标播放器 var loadNextSource = false; // 是否已经将下一个url写入src $('document').ready(function() { initTimeline(); // 运行初始化函数 // $('.video:eq(' + playerNum + ')').attr('src', videos[i]); /* setInterval(function(){ str = $('#video-meta').html(); $('#video-meta').html(str + '目前时间') }, 100) */ /* $('.video')[playerNum].addEventListener(''); */ $('#btn-play').click(function() { if ($('.video')[playerNum].paused) $('.video')[playerNum].play(); else $('.video')[playerNum].pause(); }); $('#set-time').click(function() { setToTime($('#time').val()); }) }); function initHandler() { timeline[i] = $('.video') [1].duration; totalTime += timeline[i]; if (i < videos.length - 1) { $('.video')[1].src = videos[++i] } else { $('.video')[1].src = ''; $('.video')[1].removeEventListener('loadedmetadata', initHandler, true); } } function currentTimeHandler() { currentVideoTime = $('.video')[playerNum].currentTime; if (timeline[nowVideoLocation] - currentVideoTime < 20 && !loadNextSource) { loadNextVideo(nowVideoLocation + 1); loadNextSource = true; } console.log(currentVideoTime); // 定期返回监控时间 } function initTimeline () { $('.video')[1].preload = 'auto'; $('.video')[1].src = videos[i]; $('.video')[0].src = videos[i]; $('.video')[1].addEventListener('loadedmetadata', initHandler, true); $('.video')[0].addEventListener('timeupdate', currentTimeHandler, true); $('.video')[0].addEventListener('ended', switchNextVideo, true); } function loadNextVideo(nextLocation) { var nextPlayer = Number(!playerNum); if (nextLocation < videos.length) { $('.video')[nextPlayer].preload = 'auto'; $('.video')[nextPlayer].src = videos[nextLocation]; } } function setToTime(time) { var videoChapter; var nextPlayer = Number(!playerNum); if (time >= totalTime) { videoChapter = videos.length - 1; time = totalTime; } else { for (videoChapter = 0; videoChapter < videos.length - 1; videoChapter++) { if (time - timeline[videoChapter] < 0) { break; } else { console.log('videoTime:' + time); time -= timeline[videoChapter]; } } } console.log('videoChapter: '+videoChapter); if (videoChapter == nowVideoLocation) { $('.video')[playerNum].currentTime = time; } else { loadNextVideo(videoChapter); console.log(time); targetTime = time; /*$('.video')[nextPlayer].currentTime = time;*/ targetPlayer = nextPlayer; $('.video')[targetPlayer].addEventListener('durationchange', jumpToTime, true); switchToVideo(); nowVideoLocation = videoChapter; console.log('nowVideoLocation: '+nowVideoLocation); } } function jumpToTime() { $('.video')[targetPlayer].currentTime = targetTime; console.log('hello'); $('.video')[targetPlayer].removeEventListener('durationchange', jumpToTime, true); } function switchNextVideo() { var nextPlayer = Number(!playerNum); loadNextSource = false; console.log('SwitchNow!'); if (nowVideoLocation < videos.length - 1) { $('.video:eq(' + nextPlayer + ')').css('display', ''); $('.video:eq(' + playerNum + ')').css('display', 'none'); $('.video')[playerNum].pause(); $('.video')[playerNum].removeEventListener('timeupdate', currentTimeHandler, true); $('.video')[playerNum].removeEventListener('ended', switchNextVideo, true); $('.video')[playerNum].src = ''; $('.video')[nextPlayer].addEventListener('timeupdate', currentTimeHandler, true); $('.video')[nextPlayer].addEventListener('ended', switchNextVideo, true); $('.video')[nextPlayer].play(); nowVideoLocation++; playerNum = nextPlayer; } else { $('.video')[playerNum].removeEventListener('ended', switchNextVideo, true); } } function switchToVideo() { var nextPlayer = Number(!playerNum); console.log('SwitchNow!'); loadNextSource = false; $('.video:eq(' + nextPlayer + ')').css('display', ''); $('.video:eq(' + playerNum + ')').css('display', 'none'); $('.video')[playerNum].pause(); $('.video')[playerNum].removeEventListener('timeupdate', currentTimeHandler, true); $('.video')[playerNum].removeEventListener('ended', switchToVideo, true); $('.video')[playerNum].src = ''; $('.video')[nextPlayer].addEventListener('timeupdate', currentTimeHandler, true); $('.video')[nextPlayer].addEventListener('ended', switchToVideo, true); $('.video')[nextPlayer].play(); } |
后记:后来在这里看到类似思路,加载点略不同,测试了一下似乎在提前在网速不佳的情况下表现效果会so bad,还是这样就好了,进度条需要诸君利用setToTime函数自行重写,请自便
ps:可以使用jPlayer,jPlayer对HTML5中的<audio>和<video>标签做了很好的封装。在浏览器支持HTML5的情况下用HTML5标签,在浏览器不支持HTML5的情况下用flash代替。更重要的是jPlayer提供对播放器界面的完全定制,保证无论是在何种浏览器下播放器外观都能够一致。由于可以定制播放器界面,你提出来的要求便可以满足。
下面是我自己一个项目的代码片段,我精简了一下。你找一下timeupdate: function(event) {这一行代码,里面有更新进度条的代码