同步视频和音频(最好不使用 JavaScript)
Posted
技术标签:
【中文标题】同步视频和音频(最好不使用 JavaScript)【英文标题】:Synchronize video and audio (preferably without JavaScript) 【发布时间】:2016-08-19 19:45:29 【问题描述】:如果我有 html5 video
和 audio
元素,有没有一种干净的方法可以让它们保持同步?它们应该像包含音轨的视频文件一样,因此手动推进一个轨道应该将另一个轨道带上。假设这两个轨道的持续时间相同。
我想要一个可以跨浏览器运行的解决方案,但我并不特别关心它是否适用于旧版浏览器。如果可能,最好避免使用 javascript。否则,一个非常简单的 JavaScript 库将是最好的——它只要求同步哪些轨道并处理其余部分。
我已经查看了 mediagroup... 但它看起来只适用于 Safari。我查看了 audioTracks... 但用户必须在 Firefox 中启用该功能。
我查看了Popcorn.js,这是一个似乎为这项任务而设计的 JavaScript 框架……但看起来一年多来没有任何活动。除此之外,我能找到的唯一演示是将文本或幻灯片等内容同步到视频,而不是音频到视频。
【问题讨论】:
是否可以在外部程序中预先将音频添加到您的视频中?这将是同步两者的最可靠方式。 "without JavaScript",我会说这是不可能的,但你基本上是在两个元素上监听缓冲区事件,并停止它们。然后,当加载足够的数据时继续播放。重复。 @Glen Despaux 我也希望避免这种情况...... 您可能对 HTML 自身可以做什么提出了太多要求,那么...... @GlenDespaux 是对的,HTML 处理的是文档的结构而不是其行为。 【参考方案1】:您可以使用Promise.all()
、fetch()
检索媒体资源作为Blob
、URL.createObjectURL()
创建资源的Blob URL
; canplaythrough
event 和 Array.prototype.every()
检查每个资源是否可以播放;当两个资源都可以播放时,在每个资源上调用.play()
我没有在问题中说清楚。我的意思是这两条轨道 应该保持同步,就像播放带有音频的常规视频文件一样。
一种方法是创建一个时间戳变量,当设置变量大于最小延迟时,利用seeked
事件更新元素的.currentTime
,以防止递归调用.currentTime
。
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<button>load media</button>
<br>
<div id="loading" style="display:none;">loading media...</div>
<script>
var mediaBlobs = [];
var mediaTypes = [];
var mediaLoaded = [];
var button = document.querySelector("button");
var loading = document.getElementById("loading");
var curr = void 0;
var loadMedia = () =>
loading.style.display = "block";
button.setAttribute("disabled", "disabled");
return Promise.all([
// `RETURN` by smiling cynic are licensed under a Creative Commons Attribution 3.0 Unported License
fetch("https://ia600305.us.archive.org/30/items/return_201605/return.mp3")
, fetch("http://nickdesaulniers.github.io/netfix/demo/frag_bunny.mp4")
])
.then(responses => responses.map(media => (
[media.headers.get("Content-Type").split("/")[0]]: media.blob()
)))
.then(data =>
for (var currentMedia = 0; currentMedia < data.length; currentMedia++)
(function(i)
var type = Object.keys(data[i])[0];
mediaTypes.push(type);
console.log(data[i]);
var mediaElement = document.createElement(type);
mediaElement.id = type;
var label = document.createElement("label");
mediaElement.setAttribute("controls", "controls");
mediaElement.oncanplaythrough = () =>
mediaLoaded.push(true);
if (mediaLoaded.length === data.length
&& mediaLoaded.every(Boolean))
loading.style.display = "none";
for (var track = 0; track < mediaTypes.length; track++)
document.getElementById(mediaTypes[track]).play();
console.log(document.getElementById(mediaTypes[track]));
var seek = (e) =>
if (!curr || new Date().getTime() - curr > 20)
document.getElementById(
mediaTypes.filter(id => id !== e.target.id)[0]
).currentTime = e.target.currentTime;
curr = new Date().getTime();
mediaElement.onseeked = seek;
mediaElement.onended = () =>
for (var track = 0; track < mediaTypes.length; track++)
document.getElementById(mediaTypes[track]).pause()
mediaElement.ontimeupdate = (e) =>
e.target.previousElementSibling
.innerHTML = `$mediaTypes[i] currentTime: $Math.round(e.target.currentTime)<br>`;
data[i][type].then(blob =>
mediaBlobs.push(URL.createObjectURL(blob));
mediaElement.src = mediaBlobs[mediaBlobs.length - 1];
document.body.appendChild(mediaElement);
document.body.insertBefore(label, mediaElement);
)
(currentMedia));
)
;
button.addEventListener("click", loadMedia);
</script>
</body>
</html>
plnkrhttp://plnkr.co/edit/r51oh7KsZv8DEYhpRJlL?p=preview
【讨论】:
我认为这里缺少的部分是保持两条轨道同步。它们不应不同步,手动推进一首曲目应将另一首曲目与它同步。 @user1475412 "手动推进一个轨道应该把另一个轨道一起带上。"这个需求描述没有出现在实际问题中? 对不起,我没有在问题中说清楚。我的意思是这两个轨道应该保持同步,就像播放带有音频的普通视频文件一样。我会修改问题。【参考方案2】:据我所知,这对于纯 HTML 是不可能的。
您可以使用<video>
和<audio>
元素的currentTime
属性来同步时间。
var video = document.getElementById("your-video");
var audio = document.getElementByid("your-audio");
audio.currentTime = video.currentTime;
如有必要,您还可以使用timeupdate
事件来不断地重新同步视频和音频。
【讨论】:
我觉得这个方法效果不太好...见html5demos.com/two-videos 看那个demo的源码,好像时间只同步了一次。如果使用timeupdate
事件来不断地重新同步它们,它可能会更好。以上是关于同步视频和音频(最好不使用 JavaScript)的主要内容,如果未能解决你的问题,请参考以下文章
使用 AVPlayer 音频播放 AVMutableComposition 会不同步