同步视频和音频(最好不使用JavaScript)

时间:2016-08-19 19:45:29

标签: javascript html5 audio video

如果我有HTML5 videoaudio元素,是否有一种干净的方法可以让它们保持同步?它们应该像包含音轨的视频文件一样,因此手动前进一个轨道应该带来另一个轨道。假设这两首曲目的持续时间相同。

我想要一个适用于浏览器的解决方案,但我并不特别关心它是否适用于旧浏览器。如果可能的话,避免使用JavaScript也会很好。否则,一个死的简单的JavaScript库将是最好的 - 只需要询问哪些轨道要同步并处理其余的。

我调查了mediagroup ...但看起来它只适用于Safari。我查看了audioTracks ...但是用户必须在Firefox中启用此功能。

我查看了Popcorn.js,这是一个似乎专为此任务设计的JavaScript框架......但看起来一年多来没有任何活动。除此之外,我能找到的唯一演示是将文本或幻灯片等内容同步到视频,而不是音频到视频。

2 个答案:

答案 0 :(得分:2)

您可以使用Promise.all()fetch()将媒体资源检索为BlobURL.createObjectURL()以创建Blob URL资源; canplaythrough事件和Array.prototype.every()检查每个资源是否可以播放;当两个资源都可以播放时,在每个资源上调用.play()

  

我没有在问题中说清楚。我的意思是两条轨道   应保持同步,就好像播放带有音频的常规视频文件一样。

一种方法可能是创建一个时间戳变量,当set变量大于最小延迟时,利用seeked事件来更新元素的.currentTime,以防止递归调用.currentTime。 / p>



<!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>
&#13;
&#13;
&#13;

plnkr http://plnkr.co/edit/r51oh7KsZv8DEYhpRJlL?p=preview

答案 1 :(得分:0)

据我所知,使用纯HTML时这是不可能的。

您可以使用currentTime<video>元素的<audio>属性来同步时间。

var video = document.getElementById("your-video");
var audio = document.getElementByid("your-audio");
audio.currentTime = video.currentTime;

如有必要,您还可以使用timeupdate事件不断重新同步视频和音频。