THE SITUATION:
I need to do the following:
Get the video from a
<video>
and play inside a<canvas>
Record the stream from the canvas as a Blob
That's it. First part is okay. For the second part I managed to record a Blob, the problem is that the Blob is empty.
THE VIEW:
<video id="video" controls="true" src="http://upload.wikimedia.org/wikipedia/commons/7/79/Big_Buck_Bunny_small.ogv"></video>
<canvas id="myCanvas" width="532" height="300"></canvas>
THE CODE:
// Init
console.log(MediaRecorder.isTypeSupported('video/webm')) // true
const canvas = document.querySelector("canvas")
const ctx = canvas.getContext("2d")
const video = document.querySelector("video")
// Start the video in the player
video.play()
// On play event - draw the video in the canvas
video.addEventListener('play', () => {
function step() {
ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
requestAnimationFrame(step)
}
requestAnimationFrame(step);
// Init stream and recorder
const stream = canvas.captureStream()
const recorder = new MediaRecorder(stream, {
mimeType: 'video/webm',
});
// Get the blob data when is available
let allChunks = [];
recorder.ondataavailable = function(e) {
console.log({e}) // img1
allChunks.push(e.data);
}
// Start to record
recorder.start()
// Stop the recorder after 5s and check the result
setTimeout(() => {
recorder.stop()
const fullBlob = new Blob(allChunks, { 'type' : 'video/webm' });
const downloadUrl = window.URL.createObjectURL(fullBlob)
console.log({fullBlob}) // img2
}, 5000);
})
THE RESULT:
This the console.log
of the ondataavailable
event:
This is the console.log
of the Blob:
THE FIDDLE:
Here is the JsFiddle. You can check the results in the console:
https://jsfiddle.net/1b7v2pen/
BROWSERS BEHAVIOR:
This behavior (Blob data size: 0) it happens on Chrome and Opera.
On firefox it behaves slightly different.
It records a very small video Blob (725 bytes). The video length is 5 seconds as it should be, but it's just a black screen.
THE QUESTION:
What is the proper way to the record a stream from a canvas?
Is there something wrong in the code?
Do you know why the Blob came out empty?
Thanks!
MediaRecorder.stop()
is kind of an asynchronous method.In the stop algorithm, there is a call to requestData, which itself will queue a task to fire an event dataavailable with the currently available data since the last such event.
This means that synchronously after you called MediaRecorder#stop() the last data grabbed will not be part of your
allChunks
Array yet. They will become not so long after (normally in the same event loop).So, when you are about to save recordings made from a MediaRecorder, be sure to always build the final Blob from the MediaRecorder's
onstop
event, which will signal that the MediaRecorder is actually ended, did fire its last dataavailable event, and that everything is all good.And one thing I missed at first, is that you are requesting a cross-domain video. Doing so, without the correct cross-origin request, will make your canvas (and MediaElement) tainted, so your MediaStream will be muted.
Since the video you are trying to request is from wikimedia, you can simply request it as a cross-origin resource, but for other resources, you'll have to be sure the server is configured to allow these requests.
Also, I can't refrain to note that if you don't do any special drawings from your canvas, you might want to save the video source directly, or at least, record the <video>'s captureStream MediaStream directly.