我在同一页面上嵌入了两个相同的YouTube视频。我希望他们两者同步,这是我的要求/说明:
我尝试使用YouTube JS API来监听播放器状态更改并尝试保持两个视频同步,但它并不像我希望的那样可靠。我将在下面发布部分代码。
有一点需要注意,一个视频看起来会比另一个视频大,所以YouTube可能会提供更高质量的视频。
因为我使用的是CSS3模糊,所以我只能使用最近的Webkit浏览器,所以单独使用这些(而不是FF / IE)的解决方案不是问题。
我的问题是,对于上述要求,有没有办法让这两个视频保持同步?我确实考虑过是否可以使用canvas API来“重绘”视频,但经过研究发现这是不可能的。
buffering = false;
var buffer_control = function(buffering_video, sibling_video, state) {
switch ( state ) {
case 1: // play
if ( buffering === true ) {
console.error('restarting after buffer');
// pause both videos, we want to make sure they are both at the same time
buffering_video.pauseVideo();
sibling_video.pauseVideo();
// get the current time of the video being buffered...
var current_time = buffering_video.getCurrentTime();
// ... and pull the sibling video back to that time
sibling_video.seekTo(current_time, true);
// finally, play both videos
buffering_video.playVideo();
sibling_video.playVideo();
// unset the buffering flag
buffering = false;
}
break;
case 3: // buffering
console.error('buffering');
// set the buffering flag
buffering = true;
// pause the sibling video
sibling_video.pauseVideo();
break;
}
}
答案 0 :(得分:31)
你的项目很有趣,这就是我决定尝试帮助你的原因。我从来没有使用过youtube API,但我尝试了一些编码,这可能是你的开始。
所以这里是我尝试的代码,它似乎工作得很好,它肯定需要一些改进(我没有尝试计算两个播放视频之间的偏移,但让他们取消静音显示不匹配,这听起来合法)
我们走了:
让我们从一些HTML基础知识开始
<!DOCTYPE html>
<html>
<head>
我们为前景播放器添加绝对定位,使其覆盖播放背景视频的那个(用于测试)
<style>
#player2{position:absolute;left:195px;top:100px;}
</style>
</head>
<body>
这里使用jQuery来淡入/淡出玩家(你会在下面看到原因)但你可以使用基本的JS
<script src="jquery-1.10.2.min.js"></script>
&lt;内部框架&GT; (和视频播放器)将取代这些&lt; DIV&GT;标签
<div id="player1"></div> <!-- Background video player -->
<div id="player2"></div> <!-- Foreground video player -->
<script>
此代码异步加载IFrame Player API代码。
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
此功能创建&lt;内部框架&GT; (以及YouTube播放器)下载API代码后。请注意回调函数:onPlayer1Ready和onPlayer1StateChange
var player1;
var player2;
function onYouTubeIframeAPIReady() {
player1 = new YT.Player('player1', {
height: '780',
width: '1280',
videoId: 'M7lc1UVf-VE',
playerVars: { 'autoplay': 0, 'controls': 0 },
events: {
'onReady': onPlayer1Ready,
'onStateChange': onPlayer1StateChange
}
});
player2 = new YT.Player('player2', {
height: '390',
width: '640',
videoId: 'M7lc1UVf-VE',
events: {
'onReady': onPlayer2Ready,
'onStateChange': onPlayer2StateChange
}
});
}
var player1Ready = false;
var player2Ready = false;
所以现在是代码中有趣的部分。同步项目中的主要问题与视频在启动之前需要缓冲的事实有关。实际上,API没有提供任何直观的功能来预加载视频(由于带宽问题(客户端和服务器端)。所以我们必须有点棘手。
预加载视频的步骤如下:
player.mute():Void
); player.seekTo(seconds:Number, allowSeekAhead:Boolean):Void
); YT.PlayerState.PLAYING
; player.pauseVideo():Void
); player.seekTo(seconds:Number, allowSeekAhead:Boolean):Void
; player.unMute():Void
); 您必须预先加载两个视频。
var preloading1 = false;
var preloading2 = false;
当视频播放器准备就绪时,API会调用这些功能。
function onPlayer1Ready(event)
{
player1Ready = true;
preloading1 = true; // Flag the player 1 preloading
player1.mute(); // Mute the player 1
$( "#player1" ).hide(); // Hide it
player1.seekTo(1); // Start the preloading and wait a state change event
}
function onPlayer2Ready(event) {
player2Ready = true; // The foreground video player is not preloaded here
}
当后台视频播放器的状态发生变化时,API会调用此函数。
function onPlayer1StateChange(event)
{
if (event.data == YT.PlayerState.PLAYING ) {
if(preloading1)
{
prompt("Background ready"); // For testing
player1.pauseVideo(); // Pause the video
player1.seekTo(0); // Rewind
player1.unMute(); // Comment this after test
$( "#player1" ).show(); // Show the player
preloading1 = false;
player2Ready = true;
preloading2 = true; // Flag for foreground video preloading
player2.mute();
//$( "#player2" ).hide();
player2.seekTo(1); // Start buffering and wait the event
}
else
player2.playVideo(); // If not preloading link the 2 players PLAY events
}
else if (event.data == YT.PlayerState.PAUSED ) {
if(!preloading1)
player2.pauseVideo(); // If not preloading link the 2 players PAUSE events
}
else if (event.data == YT.PlayerState.BUFFERING ) {
if(!preloading1)
{
player2.pauseVideo(); // If not preloading link the 2 players BUFFERING events
}
}
else if (event.data == YT.PlayerState.CUED ) {
if(!preloading1)
player2.pauseVideo(); // If not preloading link the 2 players CUEING events
}
else if (event.data == YT.PlayerState.ENDED ) {
player2.stopVideo(); // If not preloading link the 2 players ENDING events
}
}
当前景视频播放器的状态发生变化时,API会调用此函数。
function onPlayer2StateChange(event) {
if (event.data == YT.PlayerState.PLAYING ) {
if(preloading2)
{
//prompt("Foreground ready");
player2.pauseVideo(); // Pause the video
player2.seekTo(0); // Rewind
player2.unMute(); // Unmute
preloading2 = false;
$( "#player2" ).show(50, function() {
这是代码奇怪的一部分。取消注释下面的行将使同步非常糟糕,但如果您对其进行评论,则必须在PLAY按钮上单击两次 但是 同步看起来会更好。
//player2.playVideo();
});
}
else
player1.playVideo();
}
else if (event.data == YT.PlayerState.PAUSED ) {
if(/*!preloading1 &&*/ !preloading2)
player1.pauseVideo();
}
else if (event.data == YT.PlayerState.BUFFERING ) {
if(!preloading2)
{
player1.pauseVideo();
//player1.seekTo(... // Correct the offset here
}
}
else if (event.data == YT.PlayerState.CUED ) {
if(!preloading2)
player1.pauseVideo();
}
else if (event.data == YT.PlayerState.ENDED ) {
player1.stopVideo();
}
}
</script>
</body>
</html>
请注意,此代码可能无法计算视图。
如果您想要没有解释的代码,可以访问:http://jsfiddle.net/QtBlueWaffle/r8gvX/1/
2016年更新 Live Preview
希望这有帮助。