I am trying to get the first frame of a video in order to put it in a canvas, using this code but the canvas remains empty.
video.addEventListener("canplay",function () {
var $this = this;
console.log("canplay");
console.log(video.readyState);
canvas.getContext('2d').drawImage($this, 0, 0, canvas.width, canvas.height);
});
I also use this code to mirror the video in a canvas and it works.
video.addEventListener('play', function() {
var $this = this;
(function loop() {
if (!$this.paused && !$this.ended) {
context.save();
context.scale(-1, 1);
context.drawImage($this, 0, 0, mCanvas.width*-1, mCanvas.height);
context.restore();
setTimeout(loop, 1000 / 30); // drawing at 30fps
}
})();
}, 0);
How can I get the first frame of the video? Morevoer I have the possibility to change the URL dynamically: what should I do to get the first frame of the new video?
Related
It's my first post on Stackoverflow! I hope this is clear, and thanks in advance for your help.
I am drawing two videos to canvas, and recording the canvas for a single video for playback and review.
video1 is a video from our server.
video2 is the user's webcam feed.
The issue:
The two videos are not entirely synced due to some delay in the webcam capture.
I am trying to figure out how to delay the ctx.DrawImage of video1 by a "x" milliseconds so that I can get the two videos to appear on the canvas more synchronized, making the final recording look more synchronized.
Here is my code for drawing to the canvas.
// Draw two videos to one canvas
$(function() {
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var video1 = document.getElementById('teachervid');
var video2 = document.getElementById('studentvideo');
video1.addEventListener('play', function() {
var $this = this; //cache
(function loop() {
if (!$this.paused && !$this.ended) {
ctx.drawImage($this, 0, 0, 960, 540);
setTimeout(loop, 1000 / 30); // drawing at 30fps
}
})();
}, 0);
video2.addEventListener('play', function() {
var $this = this; //cache
(function loop() {
if (!$this.paused && !$this.ended) {
ctx.drawImage($this, 960, 0, 960, 540);
setTimeout(loop, 1000 / 30); // drawing at 30fps
}
})();
}, 0);
});
To be clear, I am not trying to change the frame rate, simply offset the start points of the two videos so that video 1 is drawn X milliseconds after video2 is drawn. I assume I will need to tweak and test what X should be once I figure out how.
Note, Keep in mind that I am new to JS and programming when responding.
Cheers!
I've made a simple setup, getting the webcam / phone camera stream and the passing it on , drawing on a html 2d canvas.
But ive been having trouble figuring out how to show the stream with a delay of few seconds. Kinda like a delay mirror.
I tried playing with ctx.globalAlpha = 0.005; but this gives me a ghosting effect rather than 'delaying' the stream.
Any idea how this can be achieved?
The snippet below doesnt work here probably because of security issues apparently but here's a pen:
https://codepen.io/farisk/pen/LvmGGQ
var width = 0, height = 0;
var canvas = document.createElement('canvas'),
ctx = canvas.getContext('2d');
document.body.appendChild(canvas);
var video = document.createElement('video'),
track;
video.setAttribute('autoplay',true);
window.vid = video;
function getWebcam(){
navigator.mediaDevices.getUserMedia({ video: true }).then(function(stream) {
var videoTracks = stream.getVideoTracks();
var newStream = new MediaStream(stream.getVideoTracks());
video.srcObject = newStream;
video.play();
track = stream.getTracks()[0];
}, function(e) {
console.error('Rejected!', e);
});
}
getWebcam();
var rotation = 0,
loopFrame,
centerX,
centerY,
twoPI = Math.PI * 2;
function loop(){
loopFrame = requestAnimationFrame(loop);
// ctx.globalAlpha = 0.005;
ctx.drawImage(video, 0, 0, width, height);
ctx.restore();
}
function startLoop(){
loopFrame = requestAnimationFrame(loop);
}
video.addEventListener('loadedmetadata',function(){
width = canvas.width = video.videoWidth;
height = canvas.height = video.videoHeight;
centerX = width / 2;
centerY = height / 2;
startLoop();
});
canvas.addEventListener('click',function(){
if ( track ) {
if ( track.stop ) { track.stop(); }
track = null;
} else {
getWebcam();
}
});
video,
canvas {
max-width: 100%;
height: auto;
}
The snippet below doesnt work here probably because of security issues apparently but here's a pen:
https://codepen.io/farisk/pen/LvmGGQ
You might want to consider storing the video data you get in an array of sorts. It might mean delaying the playback for n seconds at first.
Basically on frame 1, you store the video feed into an array, and draw nothing. This happened until frame 1000 (1 second). At that point start drawing based on the first element of the array.
Once you draw that frame, remove it from the array and add the new frame.
I have an audio visualizer to which I'm attempting to add controls. Unfortunately, the problem cannot be easily replicated in a snippet because a special server must be setup to allow frequency access to the audio. However, I'll describe the problem the best I can.
All JavaScript for the project is below. I haven't tried skip functions yet but play/pause doesn't work.
This block handles all the play/pause.
function updatePlayState(){
//console.log(paused)
console.log(audio.paused)
//audio.play();
audio.pause();
console.log(audio.paused)
/*if(!paused){
paused = true;
audio.pause();
console.log(audio.src)
}else{
audio.play();
}*/
}
When I click the button, the console logs false and then true. However, it continues the same behavior after additional clicks. The audio also doesn't pause. The audio object I'm using is global so scope must not be the issue. I'm just wanting to get the audio to pause and then I'll move on to additional functionality.
//initialize global variables...
var audio, canvas, ctx, audioCtx, source, analyser, playlist_index = 0, full_screen = false, paused = false;
var playlist = [
//'http://localhost/audio-visualizer/audio/audio.mp3',
'http://localhost/audio-visualizer/audio/HaxPigMeow.mp3',
'http://localhost/audio-visualizer/audio/4ware.mp3',
'http://localhost/audio-visualizer/audio/Narwhals_song.mp3'
];
//when the page loads...
window.addEventListener('load', function() {
//initialize the canvas...
initializeCanvas();
//initialize audio...
initializeAudio();
//initialize audio analyzer (get frequency information)...
initializeAudioAnalyser();
//initialize audio controls...
initializeAudioControls();
});
//when the window is resized...
window.addEventListener('resize', function() {
resizeCanvas();
});
function initializeCanvas() {
//get the canvas...
canvas = document.getElementById('canvas');
//create a canvas context to draw graphics...
ctx = canvas.getContext('2d');
//resize the canvas to fit the window...
resizeCanvas();
}
function resizeCanvas() {
//set height of canvas...
canvas.width = window.innerWidth;
//set width of canvas...
canvas.height = window.innerHeight;
//set width of context...
ctx.width = window.innerWidth;
//set height of context...
ctx.height = window.innerHeight;
//reset drawing properties...
setCanvasDrawingProperties();
}
function initializeAudio() {
//load the audio...
audio = new Audio(playlist[playlist_index]);
//bypass CORS (Cross Origin Resource Sharing) restrictions...
audio.crossOrigin = 'anonymous';
//when the audio finishes playing; replay...
//audio.loop = true;
//play automatically...
//audio.autoplay = true;
//wait until audio fully loads before playing...
audio.oncanplaythrough = function() {
setTimeout(function() {
window.addEventListener('click',function(e){
audio.play();
//request full screen access...
if(e.target.tagName != 'INPUT'){
var root_element = document.documentElement;
rfs = root_element.requestFullscreen
|| root_element.webkitRequestFullScreen
|| root_element.mozRequestFullScreen
|| root_element.msRequestFullscreen
;
rfs.call(root_element);
}
//show audio controls....
document.getElementById('controlContainer').style.display = 'block';
setTimeout(function(){
document.getElementById('controlContainer').style.opacity = '1';
},500);
//hide the loading message...
document.getElementById('overlayLoadingMessage').style.opacity = '0';
window.setTimeout(function() {
document.getElementById('overlayLoadingMessage').style.display = 'none';
}, 500);
});
}, 1000);
};
audio.addEventListener('ended',function(){
skipForward();
playlist_index++;
if(playlist_index == playlist.length){
playlist_index = 0;
}
audio.src = playlist[playlist_index];
audio.crossOrigin = 'anonymous';
audio.play();
})
}
function initializeAudioControls(){
document.getElementById('skipBack').addEventListener('click',skipTrackBackward);
document.getElementById('skipForward').addEventListener('click',skipTrackForward);
document.getElementById('pause').addEventListener('click',updatePlayState);
function skipTrackForward(){
console.log('skip forward')
}
function skipTrackBackward(){
console.log('skip backward')
}
function updatePlayState(){
//console.log(paused)
console.log(audio.paused)
//audio.play();
audio.pause();
console.log(audio.paused)
/*if(!paused){
paused = true;
audio.pause();
console.log(audio.src)
}else{
audio.play();
}*/
}
}
function initializeAudioAnalyser() {
//create an audio context for browsers (including older webkit)...
if(window.webkitAudioContext){
//an older browser which needs to use the webkit audio constructor...
audioCtx = new window.webkitAudioContext;
}else{
//a newer browser which has full support for the audio context...
audioCtx = new window.AudioContext;
}
//create a new analyser...
analyser = audioCtx.createAnalyser();
//create new media source for the audio context...
source = audioCtx.createMediaElementSource(audio);
//connect the analyser to the source...
source.connect(analyser);
//connect audio output device information to the analyser to gather audio frequencies...
analyser.connect(audioCtx.destination);
//set drawing properties...
setCanvasDrawingProperties();
//let's do this thing (time to animate)...
animate();
}
function setCanvasDrawingProperties() {
//set background color of future drawing...
ctx.fillStyle = '#fff';
//blur radius (50px)...
ctx.shadowBlur = 50;
//shadow color...
ctx.shadowColor = "#ddd";
}
function animate() {
//clear canvas...
ctx.clearRect(0, 0, window.innerWidth, window.innerHeight);
//create new frequency array map...
frequencyBinaryCountArray = new Uint8Array(analyser.frequencyBinCount);
//input frequency data into the array map...
analyser.getByteFrequencyData(frequencyBinaryCountArray);
//calculate radius based on frequency information (uses channel 50 right now)..
var r = frequencyBinaryCountArray[50];
//set x of circle...
var x = (window.innerWidth / 2);
//set y of circle...
var y = (window.innerHeight / 2);
//set start angle (the circumference of the circle)...
var startAngle = 2 * Math.PI;
//set end angle (the end circumference of the circle)...
var endAngle = 0 * Math.PI;
//draw a circle; radius is based on frequency...
//begin the drawing...
ctx.beginPath();
//draw the circle...
ctx.arc(x, y, r, startAngle, endAngle);
//fill the circle with a color...
ctx.fill();
//close the path...
ctx.closePath();
//do it again (appx 60 times per second)...
requestAnimationFrame(animate);
}
Tested in Chrome 67.x (latest version as of this post) on macOS High Sierra.
I was stuck on it a while but, immediately after posting the question, I discovered the global click listener that starts playing the audio was also firing when I clicked the pause button. It was overriding the pause function. To fix it, I moved the audio play inside the e.target tagname exception. However, to prevent future confusion, I added a button to start the visualization rather than a global click event.
Thanks for looking.
I'm trying to draw a video into the canvas in javascript and HTML5 (like an intro video for a game) which is working fine on the web browser but is not working on android, so I'm not sure if I making a mistake somewhere or this is not supported on mobile devices.
Here is the code:
//create canvas and get 2d context
var canvas = document.getElementById('introVid');
var ctx = canvas.getContext('2d');
// allow fullscreen
function fullscreen() {
var el = canvas;
if (el.webkitRequestFullScreen) {
el.webkitRequestFullScreen(); //chrome
} else {
el.mozRequestFullScreen(); //firefox
}
}
canvas.addEventListener("click", fullscreen); //enable fullscreen onClick
//draw the video into canvas
var video = document.getElementById("video");
video.addEventListener('loadeddata', function() {
video.play(); // start playing
update(); //start rendering
});
function update() {
ctx.drawImage(video, 0, 0, 300, 150);
requestAnimationFrame(update); //wait the browser be ready for next frame
};
Here a working demo on fiddle:
http://jsfiddle.net/h1hjp0Lp/122/
I loop over a part of a HTML video and simultaneously draw a Canvas with the current frame of the video.
When the Videos starts over, there is always 1 gray frame at the canvas.
If the loop region is long, its not a big problem, but for my needs these regions are maybe 0.5 seconds and then the canvas starts to flicker if you loop over and over again.
When drawing the canvas, I also tried different video properties (ended, loop, networkState, readyState) - doesnt help
I provided a jsfiddle to show you my problem. (just press play at the video)
https://jsfiddle.net/Lz17fnf3/2/
$('#v').on('timeupdate', function () {
if ($('#v')[0].currentTime > 2) {//Loop for one second
$('#v')[0].currentTime = 1;
}
var $this = $('#v')[0]; //cache
(function loop() {
if (!$this.paused && !$this.ended) {
drawCanvas();
setTimeout(loop, 1000 / 25); // drawing at 25fps
}
})();
});
function drawCanvas() {
var elem = document.getElementById('c');
var c = elem.getContext('2d');
var v = $('#v')[0];
$('#c').attr('width', v.videoWidth);
$('#c').attr('height', v.videoHeight);
if (v.readyState == 4) {
c.drawImage(v, 0, 0, v.videoWidth, v.videoHeight, 0, 0, v.videoWidth, v.videoHeight);
}
}
The reason it flickers is because when you assign the width or height to a canvas element, this action resets the entire context of the canvas, most likely that is causing the blank frame. Try moving all the canvas/context definitions outside the drawCanvas.
Something like:
var elem = document.getElementById('c');
var c = elem.getContext('2d');
var v = $('#v')[0];
// In order to set the canvas width & height, we need to wait for the video to load.
function init() {
if (v.readyState == 4) {
$('#c').attr('width', v.videoWidth);
$('#c').attr('height', v.videoHeight);
} else {
requestAnimationFrame(init);
}
}
init();
$('#v').on('timeupdate', function () {
if ($('#v')[0].currentTime > 2) { //Loop for one second
$('#v')[0].currentTime = 1;
}
var $this = $('#v')[0]; //cache
(function loop() {
if (!$this.paused && !$this.ended) {
drawCanvas();
setTimeout(loop, 1000 / 25); // drawing at 25fps
}
})();
});
function drawCanvas() {
c.drawImage(v, 0, 0, v.videoWidth, v.videoHeight, 0, 0, v.videoWidth, v.videoHeight);
}