Search code examples
javascriptfirefoxhtml5-canvashtml5-videochromium

Video is not drawn on canvas when autoplay is false on Chromium


The following code works fine on Firefox whether autoplay is true or false but not on Chromium. How can I fix it?

EDIT 1: I found out that I can begin with autoplay = true and then in onloadeddata pause the video with video.pause().

EDIT 2: Another interesting thing was found. You can set video.currentTime to, for example 5, to capture the 5th second and if the duration of your video is less than, again for example 5s, the last frame will be drawn on the canvas. And then you can set it back to zero inonloadeddata event. It is good because in most cases the first seconds are black.

let inputFile = document.getElementById("files");
let container = document.getElementById("container");
inputFile.addEventListener("change", inputFileEventHandler);

function inputFileEventHandler() {
  for (const file of inputFile.files) {
    let canvas = document.createElement("canvas");
    canvas.style.border = "1px solid gray";
    canvas.style.padding = "16px";

    let video = document.createElement("video");
    video.style.width = "250px";
    video.style.height = "auto";
    video.style.border = "1px solid gray";
    video.style.padding = "16px";
    video.autoplay = false;
    video.src = URL.createObjectURL(file);

    container.append(video);
    container.append(canvas);

    video.onloadeddata = () => {
      canvas.getContext("2d").drawImage(video, 0, 0, video.videoWidth, video.videoHeight);
    }
  }
}
<!DOCTYPE html>
<html>
  <body>
    <input type="file" id="files" name="files" multiple>
    <div id="container"></div>    
  </body>
</html>


Solution

  • I have no idea what is the problem

    Seems like preload: auto helps, but I'm not sure

    Handling multiple events at once makes it work, but not always

    let inputFile = document.getElementById("files");
    let container = document.getElementById("container");
    inputFile.addEventListener("change", inputFileEventHandler);
    
    const events = `abort
    canplay
    canplaythrough
    durationchange
    loadeddata
    suspend`.split('\n')
    
    function inputFileEventHandler() {
    
      for (const file of inputFile.files) {
        const video = document.createElement("video");
        video.style.width = "250px";
        video.style.height = "auto";
        video.style.border = "1px solid gray";
        video.style.padding = "16px";
        video.autoplay = false;
        video.preload = 'auto';
        video.src = URL.createObjectURL(file);
        container.append(video);
    
        for (const event of events) {
          const canvas = document.createElement("canvas");
          canvas.style.border = "1px solid gray";
          canvas.style.padding = "16px";
          container.append(canvas);
    
    
          video.addEventListener(event, () => {
            console.log(event)
            const ctx = canvas.getContext("2d")
            ctx.drawImage(video, 0, 0, video.videoWidth, video.videoHeight);
            ctx.font = "24px serif";
            ctx.fillText(event, 10, 50);
          })
        }
      }
    }
    <!DOCTYPE html>
    <html>
    
    <body>
      <input type="file" id="files" name="files" multiple>
      <div id="container"></div>
    </body>
    
    </html>