canvas捕获的第一帧输出到img后全黑

The first frame captured by the canvas becomes completely black after outputting to the img

试了很多文章和方法还是无法解决,希望得到一点提示

那英语不是我的母语,抱歉

  var video = document.getElementById('video');
  var canvas = document.createElement('canvas');
  var videobg = document.getElementById('bgc');

  video.addEventListener('loadeddata', function() {
    canvas.width = video.videoWidth;
    canvas.height = video.videoHeight;
    canvas.getContext('2d');
    var img = new Image;
    img.onload = function() {
      ctx.drawImage(video, 0, 0, video.videoWidth, video.videoHeight);
    }
    var imgURL = canvas.toDataURL('image/jpeg');
    img.setAttribute('src', imgURL);
    videobg.appendChild(img);
  })
}
  <div class="flexbord">
    <div id="bgc" class="bgc">
      <video id="video" src="https://kwibao-video.s3.ap-northeast-1.amazonaws.com/h7C886i3HFJs98SVUQG5_video_1626853820000.mp4" type="mp4" autoplay muted loop></video>
    </div>
    <div class="qwe"></div>
  </div>

您在这里混合了几段代码...

当您想在 canvas 上绘制 img 时,img.onload 部分适用。在这种情况下你不是,你想绘制 video,然后(可能)用从 canvas.

中提取的图像填充 img

所以在这种情况下,你不需要等待图像加载,你可以直接将视频绘制到canvas。 但是,loadeddata 并不意味着帧已呈现给视频元素,因此您可能更愿意等待 playing 等其他事件。

var video = document.getElementById('video');
var canvas = document.createElement('canvas');
var videobg = document.getElementById('bgc');
var ctx = canvas.getContext("2d");
video.addEventListener('playing', function() {
  canvas.width = video.videoWidth;
  canvas.height = video.videoHeight;
  canvas.getContext('2d');
  // draw the video directly
  ctx.drawImage(video, 0, 0, video.videoWidth, video.videoHeight);
  var img = new Image;
  // now this represents the canvas, when the video has been drawn on it
  var imgURL = canvas.toDataURL('image/jpeg');
  img.setAttribute('src', imgURL);
  videobg.appendChild(img);
}, {
  once: true
});
.bgc { display: flex; }
<div class="flexbord">
  <div id="bgc" class="bgc">
    <!-- don't forget to set the crossorigin attribute -->
    <video id="video" src="https://kwibao-video.s3.ap-northeast-1.amazonaws.com/h7C886i3HFJs98SVUQG5_video_1626853820000.mp4" crossorigin type="mp4" autoplay muted loop></video>
  </div>
  <div class="qwe"></div>
</div>

不过,您最好避免使用 toDataURL,而更喜欢使用 toBlob,这样会占用更少的内存

var video = document.getElementById('video');
var canvas = document.createElement('canvas');
var videobg = document.getElementById('bgc');
var ctx = canvas.getContext("2d");
video.addEventListener('playing', function() {
  canvas.width = video.videoWidth;
  canvas.height = video.videoHeight;
  canvas.getContext('2d');
  // draw the video directly
  ctx.drawImage(video, 0, 0, video.videoWidth, video.videoHeight);
  var img = new Image;
  canvas.toBlob(async(blob) => {
    img.src = URL.createObjectURL(blob);
    await img.decode(); // wait for the image is loaded
    URL.revokeObjectURL(img.src);
    videobg.appendChild(img);
  }, 'image/jpeg');
}, {
  once: true
});
.bgc { display: flex; }
<div class="flexbord">
  <div id="bgc" class="bgc">
    <!-- don't forget to set the crossorigin attribute -->
    <video id="video" src="https://kwibao-video.s3.ap-northeast-1.amazonaws.com/h7C886i3HFJs98SVUQG5_video_1626853820000.mp4" crossorigin type="mp4" autoplay muted loop></video>
  </div>
  <div class="qwe"></div>
</div>

或者,因为你显然只是在“展示”这个框架,所以直接附加 <canvas>,这在记忆方面更好:

var video = document.getElementById('video');
var canvas = document.createElement('canvas');
var videobg = document.getElementById('bgc');
var ctx = canvas.getContext("2d");
video.addEventListener('playing', function() {
  canvas.width = video.videoWidth;
  canvas.height = video.videoHeight;
  canvas.getContext('2d');
  // draw the video directly
  ctx.drawImage(video, 0, 0, video.videoWidth, video.videoHeight);
  // show the canvas
  videobg.appendChild(canvas);
}, {
  once: true
});
.bgc { display: flex; }
<div class="flexbord">
  <div id="bgc" class="bgc">
    <!-- don't forget to set the crossorigin attribute -->
    <video id="video" src="https://kwibao-video.s3.ap-northeast-1.amazonaws.com/h7C886i3HFJs98SVUQG5_video_1626853820000.mp4" crossorigin type="mp4" autoplay muted loop></video>
  </div>
  <div class="qwe"></div>
</div>