| 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(); | |
| */ | |