MediaStream 录制 API 对 canvas 元素的视频捕获无法正常工作
Video capture of canvas element by MediaStream Recording API is not working
我正在尝试使用官方 MediaStream Recording API
录制和下载 canvas
元素的视频
<!DOCTYPE html>
<html>
<body>
<h1>Lets test mediaRecorder</h1>
<canvas id="myCanvas" width="200" height="100" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML canvas tag.
</canvas>
<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.font = "30px Arial";
ctx.fillText("Hello World", 10, 50);
const stream = c.captureStream(25);
var recordedChunks = [];
console.log(stream);
var options = { mimeType: "video/webm; codecs=vp9" };
mediaRecorder = new MediaRecorder(stream, options);
mediaRecorder.ondataavailable = handleDataAvailable;
mediaRecorder.start();
function handleDataAvailable(event) {
console.log("data-available");
if (event.data.size > 0) {
recordedChunks.push(event.data);
console.log(recordedChunks);
download();
} else {
// ...
}
}
function download() {
var blob = new Blob(recordedChunks, {
type: "video/webm"
});
var url = URL.createObjectURL(blob);
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
a.href = url;
a.download = "test.webm";
a.click();
window.URL.revokeObjectURL(url);
}
// demo: to download after 10 sec
setTimeout(event => {
console.log("stopping");
mediaRecorder.stop();
}, 10000);
</script>
</body>
</html>
代码正在运行,我可以下载 test.webm
但我猜它没有任何数据,因为我在 VLC 媒体播放器中播放此文件时没有看到任何内容
我缺少什么让它工作?
您遇到了一些错误。
第一个有点情有可原,Chrome doesn't generate seekable webm files. 这是因为媒体文件的构建方式以及 MediaRecorder API 的工作方式。为了让他们能够添加此信息,他们必须保留元数据所在的块,以便在录制完成时添加此信息。
我不太确定 Firefox 在这里有什么不同,但 VLC 更喜欢他们的文件。
另一个 Chrome 更不可原谅的错误是,在我们再次绘制源 canvas 之前,它们不会将新帧传递给 MediaRecorder。
因此,在您的情况下,您在启动 MediaRecorder 后没有绘制任何内容,因此您在输出中什么也得不到...
要解决这个问题,只需在我们停止记录器之前绘制一个帧就足够了,除了没有任何内容可以让我们确切知道浏览器何时将该帧推送到记录器...
所以这里唯一可行的解决方法是在我们记录它的同时连续绘制 canvas。好处是它不需要绘制任何新东西:我们可以通过绘制透明矩形来欺骗浏览器认为绘制了新东西。
最后一点,虽然 Chrome 确实支持以透明方式导出 canvas,但并非所有浏览器都可以,即使支持大多数播放器也有默认的黑色背景。所以录制的时候一定要给自己画一个其他颜色的背景。
综上所述,这是一个固定的演示:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
// draw a white background
ctx.fillStyle = "white";
ctx.fillRect(0, 0, c.width, c.height);
ctx.fillStyle = "black";
ctx.font = "30px Arial";
ctx.fillText("Hello World", 10, 50);
const stream = c.captureStream(25);
var recordedChunks = [];
var options = {};
mediaRecorder = new MediaRecorder(stream, options);
mediaRecorder.ondataavailable = handleDataAvailable;
mediaRecorder.start();
// Chrome requires we draw on the canvas while recording
mediaRecorder.onstart = animationLoop;
function animationLoop() {
// draw nothing, but still draw
ctx.globalAlpha = 0;
ctx.fillRect(0, 0, 1, 1);
// while we're recording
if (mediaRecorder.state !== "inactive") {
requestAnimationFrame(animationLoop);
}
}
// wait for the stop event to export the final video
// the dataavailable can fire before
mediaRecorder.onstop = (evt) => download();
function handleDataAvailable(event) {
recordedChunks.push(event.data);
}
function download() {
var blob = new Blob(recordedChunks, {
type: "video/webm"
});
var url = URL.createObjectURL(blob);
// exporting to a video element for that demo
// the downloaded video will still not work in some programs
// For this one would need to fix the markers using something like ffmpeg.
var video = document.getElementById('video');
video.src = url;
// hack to make the video seekable in the browser
// see
video.onloadedmetadata = (evt) => {
video.currentTime = 10e6;
video.addEventListener("seeked", () => video.currentTime = 0, {
once: true
})
}
}
setTimeout(() => {
console.clear();
mediaRecorder.stop();
}, 10000);
console.log("please wait while recording (10s)");
<h1>Lets test mediaRecorder</h1>
<canvas id="myCanvas" width="200" height="100" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML canvas tag.
</canvas>
<video controls id="video"></video>
我正在尝试使用官方 MediaStream Recording API
录制和下载canvas
元素的视频
<!DOCTYPE html>
<html>
<body>
<h1>Lets test mediaRecorder</h1>
<canvas id="myCanvas" width="200" height="100" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML canvas tag.
</canvas>
<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.font = "30px Arial";
ctx.fillText("Hello World", 10, 50);
const stream = c.captureStream(25);
var recordedChunks = [];
console.log(stream);
var options = { mimeType: "video/webm; codecs=vp9" };
mediaRecorder = new MediaRecorder(stream, options);
mediaRecorder.ondataavailable = handleDataAvailable;
mediaRecorder.start();
function handleDataAvailable(event) {
console.log("data-available");
if (event.data.size > 0) {
recordedChunks.push(event.data);
console.log(recordedChunks);
download();
} else {
// ...
}
}
function download() {
var blob = new Blob(recordedChunks, {
type: "video/webm"
});
var url = URL.createObjectURL(blob);
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
a.href = url;
a.download = "test.webm";
a.click();
window.URL.revokeObjectURL(url);
}
// demo: to download after 10 sec
setTimeout(event => {
console.log("stopping");
mediaRecorder.stop();
}, 10000);
</script>
</body>
</html>
代码正在运行,我可以下载 test.webm
但我猜它没有任何数据,因为我在 VLC 媒体播放器中播放此文件时没有看到任何内容
我缺少什么让它工作?
您遇到了一些错误。
第一个有点情有可原,Chrome doesn't generate seekable webm files. 这是因为媒体文件的构建方式以及 MediaRecorder API 的工作方式。为了让他们能够添加此信息,他们必须保留元数据所在的块,以便在录制完成时添加此信息。
我不太确定 Firefox 在这里有什么不同,但 VLC 更喜欢他们的文件。
另一个 Chrome 更不可原谅的错误是,在我们再次绘制源 canvas 之前,它们不会将新帧传递给 MediaRecorder。
因此,在您的情况下,您在启动 MediaRecorder 后没有绘制任何内容,因此您在输出中什么也得不到...
要解决这个问题,只需在我们停止记录器之前绘制一个帧就足够了,除了没有任何内容可以让我们确切知道浏览器何时将该帧推送到记录器...
所以这里唯一可行的解决方法是在我们记录它的同时连续绘制 canvas。好处是它不需要绘制任何新东西:我们可以通过绘制透明矩形来欺骗浏览器认为绘制了新东西。
最后一点,虽然 Chrome 确实支持以透明方式导出 canvas,但并非所有浏览器都可以,即使支持大多数播放器也有默认的黑色背景。所以录制的时候一定要给自己画一个其他颜色的背景。
综上所述,这是一个固定的演示:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
// draw a white background
ctx.fillStyle = "white";
ctx.fillRect(0, 0, c.width, c.height);
ctx.fillStyle = "black";
ctx.font = "30px Arial";
ctx.fillText("Hello World", 10, 50);
const stream = c.captureStream(25);
var recordedChunks = [];
var options = {};
mediaRecorder = new MediaRecorder(stream, options);
mediaRecorder.ondataavailable = handleDataAvailable;
mediaRecorder.start();
// Chrome requires we draw on the canvas while recording
mediaRecorder.onstart = animationLoop;
function animationLoop() {
// draw nothing, but still draw
ctx.globalAlpha = 0;
ctx.fillRect(0, 0, 1, 1);
// while we're recording
if (mediaRecorder.state !== "inactive") {
requestAnimationFrame(animationLoop);
}
}
// wait for the stop event to export the final video
// the dataavailable can fire before
mediaRecorder.onstop = (evt) => download();
function handleDataAvailable(event) {
recordedChunks.push(event.data);
}
function download() {
var blob = new Blob(recordedChunks, {
type: "video/webm"
});
var url = URL.createObjectURL(blob);
// exporting to a video element for that demo
// the downloaded video will still not work in some programs
// For this one would need to fix the markers using something like ffmpeg.
var video = document.getElementById('video');
video.src = url;
// hack to make the video seekable in the browser
// see
video.onloadedmetadata = (evt) => {
video.currentTime = 10e6;
video.addEventListener("seeked", () => video.currentTime = 0, {
once: true
})
}
}
setTimeout(() => {
console.clear();
mediaRecorder.stop();
}, 10000);
console.log("please wait while recording (10s)");
<h1>Lets test mediaRecorder</h1>
<canvas id="myCanvas" width="200" height="100" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML canvas tag.
</canvas>
<video controls id="video"></video>