html - Synchronize video and audio (preferably without JavaScript) - Stack Overflow

If I have HTML5 video and audio elements, is there a clean way to keep them in sync? They should act li

If I have HTML5 video and audio elements, is there a clean way to keep them in sync? They should act like a video file that contains an audio track, so advancing one track manually should bring the other one along with it. Let's say the two tracks have the same duration.

I'd like a solution that works across browsers, but I don't particularly care if it works on older browsers. It would also be nice to avoid the use of JavaScript if possible. Otherwise, a dead-simple JavaScript library would be best -- something that only asks for which tracks to synchronize and takes care of the rest.

I've looked into mediagroup... but it looks like it only works in Safari. I've looked into audioTracks... but the user has to enable the feature in Firefox.

I've looked into Popcorn.js, which is a JavaScript framework that seems designed for this task... but it looks like there hasn't been any activity in over a year. Besides that, the only demonstrations I can find are of synchronizing things like text or slides to video, not audio to video.

If I have HTML5 video and audio elements, is there a clean way to keep them in sync? They should act like a video file that contains an audio track, so advancing one track manually should bring the other one along with it. Let's say the two tracks have the same duration.

I'd like a solution that works across browsers, but I don't particularly care if it works on older browsers. It would also be nice to avoid the use of JavaScript if possible. Otherwise, a dead-simple JavaScript library would be best -- something that only asks for which tracks to synchronize and takes care of the rest.

I've looked into mediagroup... but it looks like it only works in Safari. I've looked into audioTracks... but the user has to enable the feature in Firefox.

I've looked into Popcorn.js, which is a JavaScript framework that seems designed for this task... but it looks like there hasn't been any activity in over a year. Besides that, the only demonstrations I can find are of synchronizing things like text or slides to video, not audio to video.

Share Improve this question edited Aug 30, 2016 at 1:20 user1475412 asked Aug 19, 2016 at 19:45 user1475412user1475412 1,8193 gold badges27 silver badges30 bronze badges 10
  • Is it at all possible to add the audio to your video beforehand in an external program? It would be the most reliable way of syncing the two. – Glen Despaux Jr Commented Aug 19, 2016 at 19:48
  • "without JavaScript", I would say this is out of the question, but you basically to listen for buffer event on both elements, and stop them both. Then, continue playing when enough data is loaded. Repeat. – Adam Azad Commented Aug 19, 2016 at 19:50
  • @Glen Despaux I'm looking to avoid that, too... – user1475412 Commented Aug 19, 2016 at 19:50
  • 1 You may be asking too much of what HTML can do on its own, then... – Glen Despaux Jr Commented Aug 19, 2016 at 19:52
  • @GlenDespaux is right, HTML deals with the structure of the document not its behaviour. – n0m4d Commented Aug 24, 2016 at 12:26
 |  Show 5 more ments

2 Answers 2

Reset to default 3 +150

You can use Promise.all(), fetch() to retrieve media resource as a Blob, URL.createObjectURL() to create a Blob URL of resource; canplaythrough event and Array.prototype.every() to check if each resource can play; call .play() on each resource when both resources can play

I didn't make it clear in the question. I meant that the two tracks should stay in sync as though playing a regular video file with audio.

One approach could be to create a timestamp variable, utilize seeked event to update .currentTime of elements when set variable is greater than a minimum delay to prevent .currentTime being called recursively.

<!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/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>

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

To my knowledge, this is impossible with pure HTML.

You can use the currentTime property of both <video> and <audio> elements to synchronize the time.

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

If necessary, you could also use the timeupdate event to continuously re-sync the video and audio.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745446505a4628070.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信