const FPS = 30; let frame = 0; var chunks = []; var stream; var rec; var track; function timeout(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } function initRecorder() { stream = document.getElementById('canvasrecord').captureStream(0); track = stream.getVideoTracks()[0]; if (!track.requestFrame) { track.requestFrame = () => stream.requestFrame(); } rec = new MediaRecorder(stream, { bitsPerSecond: 3200000, }); rec.ondataavailable = function (evt) { console.log('chunky'); chunks.push(evt.data); }; rec.start(); console.log('Recorder has been started'); rec.onstart = function () { rec.pause(); console.log('start!'); }; } async function recordFrame() { console.log(frame); waitForEvent(rec, 'pause'); //rec.onpause = async function(e) { // wake up the recorder rec.resume(); recordAnimate(false, (frame / FPS) * 1000); //animate(false, (frame/FPS)*1000) // force write the frame track.requestFrame(); // wait until our frame-time elapsed await timeout(1000 / FPS); // sleep recorder rec.pause(); //} } async function exportRecording() { rec.stop(); stream.getTracks().forEach((track) => track.stop()); await waitForEvent(rec, 'stop'); return new Blob(chunks); } // Record canvas async function record() { updateRecordCanvas(); if ($('input[name=radio]:checked').val() == 'image') { recording = true; paused = true; animate(false, currenttime); const dataURL = canvasrecord.toDataURL({ format: 'png', }); const link = document.createElement('a'); link.download = 'image.png'; link.href = dataURL; document.body.appendChild(link); link.click(); document.body.removeChild(link); recording = false; } else { if (!recording) { recording = true; paused = true; recordAnimate(false, (frame / FPS) * 1000); recording = true; $('#download-real').html('Rendering...'); $('#download-real').addClass('downloading'); var fps = 60; var aCtx = new AudioContext(); function audioTimerLoop(callback, frequency) { var freq = frequency / 1000; var silence = aCtx.createGain(); silence.gain.value = 0; silence.connect(aCtx.destination); onOSCend(); var stopped = false; function onOSCend() { osc = aCtx.createOscillator(); osc.onended = onOSCend; osc.connect(silence); osc.start(0); osc.stop(aCtx.currentTime + freq); callback(aCtx.currentTime); if (stopped) { osc.onended = function () { return; }; } } return function () { stopped = true; }; } var stopAnim = audioTimerLoop(renderAnim, 1000 / fps); var stream = document .getElementById('canvasrecord') .captureStream(fps); objects.forEach(function (object) { if ( canvasrecord.getItemById(object.id).get('assetType') && canvasrecord.getItemById(object.id).get('assetType') == 'video' ) { var audio = $( canvasrecord.getItemById(object.id).getElement() )[0]; var audioContext = new AudioContext(); var audioSource = audioContext.createMediaElementSource(audio); var audioDestination = audioContext.createMediaStreamDestination(); audioSource.connect(audioDestination); stream.addTrack( audioDestination.stream.getAudioTracks()[0] ); } }); if (background_audio != false) { var audioContext = new AudioContext(); var audioSource = audioContext.createMediaElementSource(background_audio); var audioDestination = audioContext.createMediaStreamDestination(); audioSource.connect(audioDestination); stream.addTrack(audioDestination.stream.getAudioTracks()[0]); background_audio.currentTime = 0; background_audio.play(); } let chunks = []; var recorder = new MediaRecorder(stream, { bitsPerSecond: 3200000, }); recorder.ondataavailable = (e) => chunks.push(e.data); recorder.onstop = (e) => { stopAnim(); downloadRecording(chunks); animate(false, 0); $('#seekbar').offset({ left: offset_left + $('#inner-timeline').offset().left + currenttime / timelinetime, }); canvas.renderAll(); console.log('Finished rendering'); }; recorder.start(); setTimeout(function () { recorder.stop(); }, duration); async function renderAnim(time) { await recordAnimate(time * 1000); } } } } /* initRecorder(); //await timeout(2000) // draw one frame at a time while (frame++ < FPS * (duration/1000)) { await longDraw(); // do the long drawing await recordFrame(); // record at constant FPS } // now all the frames have been drawn const recorded = await exportRecording(); // we can get our final video file const a = document.createElement('a'); a.style.display = 'none'; a.href = URL.createObjectURL(recorded); a.download = "test.webm"; document.body.appendChild(a); a.click(); recording = false; currenttime = 0; animate(false, 0); $("#seekbar").offset({left:offset_left+$("#inner-timeline").offset().left+(currenttime/timelinetime)}); canvas.renderAll(); resizeCanvas(); if (background_audio != false) { background_audio.pause(); background_audio = new Audio(background_audio.src) } $("#download-real").html("Download"); $("#download-real").removeClass("downloading"); updateRecordCanvas(); // Fake long drawing operations that make real-time recording impossible function longDraw() { recordAnimate((frame/FPS)*1000) return wait(Math.random() * 300) .then(recordAnimate((frame/FPS)*1000)); }*/ /* paused = true; recording = true; $("#download-real").html("Rendering..."); $("#download-real").addClass("downloading"); var fps = 60; var aCtx = new AudioContext(); function audioTimerLoop(callback, frequency) { var freq = frequency / 1000; var silence = aCtx.createGain(); silence.gain.value = 0; silence.connect(aCtx.destination); onOSCend(); var stopped = false; function onOSCend() { osc = aCtx.createOscillator(); osc.onended = onOSCend; osc.connect(silence); osc.start(0); osc.stop(aCtx.currentTime + freq); callback(aCtx.currentTime); if (stopped) { osc.onended = function() { return; }; } }; return function() { stopped = true; }; } var stopAnim = audioTimerLoop(renderAnim, 1000/(fps)); var stream = document.getElementById("canvasrecord").captureStream(fps); objects.forEach(function(object){ if (canvasrecord.getItemById(object.id).get("assetType") && canvasrecord.getItemById(object.id).get("assetType") == "video") { var audio = $(canvasrecord.getItemById(object.id).getElement())[0]; var audioContext = new AudioContext(); var audioSource = audioContext.createMediaElementSource(audio); var audioDestination = audioContext.createMediaStreamDestination(); audioSource.connect(audioDestination); stream.addTrack(audioDestination.stream.getAudioTracks()[0]); } }) if (background_audio != false) { var audioContext = new AudioContext(); var audioSource = audioContext.createMediaElementSource(background_audio); var audioDestination = audioContext.createMediaStreamDestination(); audioSource.connect(audioDestination); stream.addTrack(audioDestination.stream.getAudioTracks()[0]); background_audio.currentTime = 0; background_audio.play(); } let chunks = []; var recorder = new MediaRecorder(stream, { bitsPerSecond : 3200000, }); recorder.ondataavailable = e => chunks.push(e.data); recorder.onstop = e => { stopAnim(); downloadRecording(chunks); animate(false, 0); $("#seekbar").offset({left:offset_left+$("#inner-timeline").offset().left+(currenttime/timelinetime)}); canvas.renderAll(); console.log("Finished rendering") } recorder.start(); setTimeout(function() { recorder.stop(); }, duration) async function renderAnim(time) { await animate(false, time*1000); } */ /* $("#download-real").html("Rendering..."); $("#download-real").addClass("downloading"); // browser check if (typeof MediaStreamTrackGenerator === undefined || typeof MediaStream === undefined || typeof VideoFrame === undefined) { console.log('Your browser does not support the web APIs used in this demo'); return; } // recording setup const fps = 60; const generator = new MediaStreamTrackGenerator({ kind: "video" }); const writer = generator.writable.getWriter(); const stream = new MediaStream(); stream.addTrack(generator); const recorder = new MediaRecorder(stream, { mimeType: "video/webm" }); recorder.start(); function timeout(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } // animate stuff console.log('rendering...') console.log(duration); for (let i = 0; i < (duration/1000)*fps; i++) { animate(false, (i/fps)*1000); const frame = new VideoFrame(document.getElementById("canvasrecord"), { timestamp: (i / fps)*1000 }); await writer.write(frame); await timeout(100) console.log("frame "+(i/fps)*1000); } console.log('rendering done'); // stop recording and recorder.addEventListener("dataavailable", (evt) => { const a = document.createElement('a'); a.style.display = 'none'; a.href = URL.createObjectURL(evt.data); a.download = "test.webm"; document.body.appendChild(a); a.click(); recording = false; currenttime = 0; animate(false, 0); $("#seekbar").offset({left:offset_left+$("#inner-timeline").offset().left+(currenttime/timelinetime)}); canvas.renderAll(); resizeCanvas(); if (background_audio != false) { background_audio.pause(); background_audio = new Audio(background_audio.src) } $("#download-real").html("Download"); $("#download-real").removeClass("downloading"); updateRecordCanvas(); }); recorder.stop(); */