您可以使用HTMLVideoElement 和HTMLCanvasElement 进行后备。
首先通过检查窗口对象中是否存在构造函数来检查您的浏览器是否支持MediaStream Image Capture API。
if ('ImageCapture' in window) {
// Has support for API.
} else {
// No support, use fallback.
}
然后基于此使用 API 或使用您的后备。
在后备中创建一个视频元素、画布元素和一个画布上下文。将MediaStreamTrack 设置为视频元素的srcObject。视频能够解码数据并制作真实图片。
使用视频图像通过CanvasRenderingContext2D.drawImage() 方法将图像绘制到画布元素。这样,canvas 元素将绘制视频中当前帧的图像。
现在您可以提取画布上绘制的数据,并使用HTMLCanvasElement.toBlob() 方法将其转换为Blob。
将函数调用包装在 Promise 中,原因有两个:
- 您需要从回调中提取 blob,Promise 包装器可以帮助您做到这一点。
-
ImageCapture.takePhoto() 方法也返回一个 Promise。因此,您将获得与支持 API 时相同的行为。
所有放在一起看起来像这样。
function getBlobFromMediaStream(stream) {
if ('ImageCapture' in window) {
const videoTrack = stream.getVideoTracks()[0];
const imageCapture = new ImageCapture(videoTrack);
return imageCapture.takePhoto();
} else {
const video = document.createElement('video');
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
video.srcObject = stream;
return new Promise((resolve, reject) => {
video.addEventListener('loadeddata', async () => {
const { videoWidth, videoHeight } = video;
canvas.width = videoWidth;
canvas.height = videoHeight;
try {
await video.play();
context.drawImage(video, 0, 0, videoWidth, videoHeight);
canvas.toBlob(resolve, 'image/png');
} catch (error) {
reject(error);
}
});
});
}
}
如下例所示调用您的函数。我已经放弃了throw 语句,这样当您调用getBlobFromMediaStream 函数时,所有rejected 状态都会在同一点被捕获。
根据ImageCapture.takePhoto() 的文档,当promise 实现时你会得到一个Blob,当它被拒绝时你会得到一个错误。
后备也是如此。唯一的区别是HTMLCanvasElement.toBlob() 函数会在画布的位图不是原点干净时抛出SecurityError。
getBlobFromMediaStream(mediaStream).then(blob => {
// Work with your blob.
}).catch(error => {
console.log(`Photo could not be taken. ${error}`);
})