How to Render Webcam/Live video in WebGL without Library - webgl

I have been following this tutorial and it succesfully renders video on to a cube using webGL.
Is it possible for instead of using a video I would like to use a live feed from a webcam without using frameworks like Three.js?
The code below reads from the webcam into HTMLVideoElement how to convert it into texture so I can map it to my vertices in raw WebGL?
function setupVideo(url) {
const video = document.createElement('video');
var playing = false;
var timeupdate = false;
video.autoplay = true;
video.muted = true;
video.loop = true;
// Waiting for these 2 events ensures
// there is data in the video
video.addEventListener('playing', function() {
playing = true;
checkReady();
}, true);
video.addEventListener('timeupdate', function() {
timeupdate = true;
checkReady();
}, true);
navigator.getUserMedia = ( navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia);
var hasUserMedia = navigator.getUserMedia ? true : false;
console.log(hasUserMedia);
// Prefer camera resolution nearest to 1280x720.
var constraints = { audio: true, video: { width: 640, height: 360 } };
navigator.mediaDevices.getUserMedia(constraints)
.then(function(mediaStream) {
video.srcObject = mediaStream;
video.onloadedmetadata = function(e) {
};
})
.catch(function(err) { console.log(err.name + ": " + err.message); }); // always check for errors at the end.
video.play();
function checkReady() {
if (playing && timeupdate) {
copyVideo = true;
}
}
return video;
}

Related

I'm using the serverless Twilio Voice JavaScript quickstart. Can I set two audio output devices at the same time here?

I've got a project that is built on the serverless Twilio Voice JavaScript quickstart. Here's a link to the quickstart.
https://www.twilio.com/docs/voice/sdks/javascript/get-started#information
Below is the chunk of code where it allows the user to select an audio output device. Is it possible to select more than one audio output device, so my users can hear their phones ring through their speakers AND their headsets at the same time?
function updateDevices(selectEl, selectedDevices) {
selectEl.innerHTML = '';
device.audio.availableOutputDevices.forEach(function (device, id) {
let isActive = selectedDevices.size === 0 && id === 'default';
selectedDevices.forEach(function (device) {
if (device.deviceId === id) {
isActive = true;
}
});
const option = document.createElement('option');
option.label = device.label;
option.setAttribute('data-id', id);
if (isActive) {
option.setAttribute('selected', 'selected');
}
selectEl.appendChild(option);
});
}
function updateAllAudioDevices() {
if (device) {
updateDevices(speakerDevices, device.audio.speakerDevices.get());
updateDevices(ringtoneDevices, device.audio.ringtoneDevices.get());
}
}
async function getAudioDevices() {
await navigator.mediaDevices.getUserMedia({ audio: true });
updateAllAudioDevices.bind(device);
}
function updateOutputDevice() {
const selectedDevices = Array.from(speakerDevices.children)
.filter((node) => node.selected)
.map((node) => node.getAttribute('data-id'));
device.audio.speakerDevices.set(selectedDevices);
}
function updateRingtoneDevice() {
const selectedDevices = Array.from(ringtoneDevices.children)
.filter((node) => node.selected)
.map((node) => node.getAttribute('data-id'));
device.audio.ringtoneDevices.set(selectedDevices);
}
function bindVolumeIndicators(call) {
call.on('volume', function (inputVolume, outputVolume) {
let inputColor = 'red';
if (inputVolume < 0.5) {
inputColor = 'green';
} else if (inputVolume < 0.75) {
inputColor = 'yellow';
}
inputVolumeBar.style.width = `${Math.floor(inputVolume * 300)}px`;
inputVolumeBar.style.background = inputColor;
let outputColor = 'red';
if (outputVolume < 0.5) {
outputColor = 'green';
} else if (outputVolume < 0.75) {
outputColor = 'yellow';
}
outputVolumeBar.style.width = `${Math.floor(outputVolume * 300)}px`;
outputVolumeBar.style.background = outputColor;
});
}

How do I stream my desktop to a webpage via webRTC?

I've done a tutorial that does this exact thing but streams my webcam, and I'd like to stream my desktop instead - more specifically, a certain window. This is to stream a simulation via the local network, but it has to be done on WebRTC. What should I change?
(function(){
var video = document.getElementById('video'),
vendorUrl = window.URL || window.webkitURL;
navigator.getMedia = navigator.getDisplayMedia ||
navigator.webkitURLGetDisplayMedia ||
navigator.mozGetDisplayMedia ||
navigator.msGetDisplayMedia;
//capture video
navigator.getMedia({
video: true,
Audio: false
}, function(stream){
video.src = vendorUrl.createObjectURL(stream);
video.play();
}, function(error) {
//an error occured
//error.code
});
})();
Use navigator.mediaDevices.getDisplayMedia and no need vendorUrl here.
navigator.mediaDevices.getDisplayMedia({
video: true;
audio: false;
}, function(stream) {
video.srcObject = stream;
video.onloadedmetadata = function(e){
video.play();
}
});

iOS: Animated scroll position jumps on long touch gestures

Based on TweenMax, the ScrollTo Plugin and ScrollMagic (this is probably not where the problem came from):
I wanna have a hero section on top of a page, only tweening downwards if the user is scrolling from the very beginning. Everything works as expected on my laptop (MBP). Following problem: If I use a touch-device (iPhone SE, iOS 12.4.1) and use a short touch gesture, the window is tweening to the destination withouth any issue. But if I keep my finger on the screen, the page starts to flicker and jumps back to the top after the tween finished.
Codepen
Since it's not working with Codepen on my mobile device:
Reduced test
Is there any way to fix this behaviour? Already tried to toggle preventDefault with eventListeners on Callbacks as well as setting the position again onComplete.
var vh = window.innerHeight * 0.01;
document.documentElement.style.setProperty('--vh', `${vh}px`);
// assume the feature isn't supported
var supportsPassive = false;
// create options object with a getter to see if its passive property is accessed
var opts = Object.defineProperty && Object.defineProperty({}, 'passive', { get: function(){ supportsPassive = true }});
// create a throwaway element & event and (synchronously) test out our options
document.addEventListener('test', function() {}, opts);
// var allowScroll = true;
function preventDefault(e) {
e = e || window.event;
if (e.preventDefault) {
e.preventDefault();
}
// if (e.stopImmediatePropagation) {
// e.stopImmediatePropagation();
// }
if (e.stopPropagation) {
e.stopPropagation();
}
e.returnValue = false;
}
function getBodyScrollTop() {
var el = document.scrollingElement || document.documentElement;
return el.scrollTop;
// return window.pageYOffset
}
function setBodyScrollTop(scrollTop) {
var el = document.scrollingElement || document.documentElement;
el.scrollTop = scrollTop;
// window.pageYOffset = scrollTop;
}
function addMousewheelListener() {
if (e.addEventListener)
{
// IE9, Chrome, Safari, Opera
e.addEventListener("mousewheel", preventScroll, supportsPassive ? { passive: false } : false);
// Firefox
e.addEventListener("DOMMouseScroll", preventScroll, supportsPassive ? { passive: false } : false);
}
// IE 6/7/8
else
{
e.attachEvent("onmousewheel", preventScroll);
}
}
function removeMousewheelListener() {
if (e.removeEventListener)
{
// IE9, Chrome, Safari, Opera
e.removeEventListener("mousewheel", preventScroll, supportsPassive ? { passive: false } : false);
// Firefox
e.removeEventListener("DOMMouseScroll", preventScroll, supportsPassive ? { passive: false } : false);
}
// IE 6/7/8
else
{
e.detachEvent("onmousewheel", preventScroll);
}
}
function removeTouchListeners(e) {
window.removeEventListener("touchmove", preventScroll);
window.removeEventListener("touchstart", removeTouchListeners);
window.removeEventListener("touchend", removeTouchListeners);
}
function preventScroll(e) {
// if(TweenMax.isTweening(window) || !allowScroll) {
// e.preventDefault();
// e.stopImmediatePropagation();
preventDefault(e)
// }
}
function deactivateScroll() {
// allowScroll = false;
console.log('fired 1');
// window.addEventListener("touchstart", preventScroll, { passive: false });
window.addEventListener("touchmove", preventScroll, { passive: false });
addMousewheelListener();
}
function activateScroll() {
// allowScroll = true;
removeMousewheelListener();
// var scrollTop = y;
// var scrollTop = getBodyScrollTop;
// setBodyScrollTop(scrollTop);
window.addEventListener("touchstart", removeTouchListeners, { passive: false });
window.addEventListener("touchend", removeTouchListeners, { passive: false });
// var event1 = new Event('touchstart');
// var event2 = new Event('touchmove');
// var event3 = new Event('touchend');
// window.dispatchEvent(event1);
// window.dispatchEvent(event2);
// window.dispatchEvent(event3);
}
var ctrl = new ScrollMagic.Controller();
var sceneLeave = new ScrollMagic.Scene({
triggerElement: "#content",
triggerHook: "onEnter",
offset: 1
})
.addTo(ctrl)
.on("enter", function(event) {
TweenMax.to(window, 1, {
scrollTo: {
y: "#content",
autoKill: false
},
onStart: deactivateScroll,
onComplete: activateScroll
});
});

MediaRecorder Blob to file in an electron app

I have an electron app that has very simple desktop capturing functionality:
const {desktopCapturer} = require('electron')
const fs = require('fs');
var recorder;
var chunks = [];
var WINDOW_TITLE = "App Title";
function startRecording() {
desktopCapturer.getSources({ types: ['window', 'screen'] }, function(error, sources) {
if (error) throw error;
for (let i = 0; i < sources.length; i++) {
let src = sources[i];
if (src.name === WINDOW_TITLE) {
navigator.webkitGetUserMedia({
audio: false,
video: {
mandatory: {
chromeMediaSource: 'desktop',
chromeMediaSourceId: src.id,
minWidth: 800,
maxWidth: 1280,
minHeight: 600,
maxHeight: 720
}
}
}, handleStream, handleUserMediaError);
return;
}
}
});
}
function handleStream(stream) {
recorder = new MediaRecorder(stream);
chunks = [];
recorder.ondataavailable = function(event) {
chunks.push(event.data);
};
recorder.start();
}
function stopRecording() {
recorder.stop();
toArrayBuffer(new Blob(chunks, {type: 'video/webm'}), function(ab) {
var buffer = toBuffer(ab);
var file = `./test.webm`;
fs.writeFile(file, buffer, function(err) {
if (err) {
console.error('Failed to save video ' + err);
} else {
console.log('Saved video: ' + file);
}
});
});
}
function handleUserMediaError(e) {
console.error('handleUserMediaError', e);
}
function toArrayBuffer(blob, cb) {
let fileReader = new FileReader();
fileReader.onload = function() {
let arrayBuffer = this.result;
cb(arrayBuffer);
};
fileReader.readAsArrayBuffer(blob);
}
function toBuffer(ab) {
let buffer = new Buffer(ab.byteLength);
let arr = new Uint8Array(ab);
for (let i = 0; i < arr.byteLength; i++) {
buffer[i] = arr[i];
}
return buffer;
}
// Record for 3.5 seconds and save to disk
startRecording();
setTimeout(function() { stopRecording() }, 3500);
I know that to save the MediaRecorder blob sources, I need to read it into an ArrayBuffer, then copy that into a normal Buffer for the file to be saved.
However, where this seems to be failing for me is combining the chunk of blobs into blobs. When the chunks are added into a single Blob - it's like they just disappear. The new Blob is empty, and every other data structure they are copied into afterwards also is completely empty.
Before creating the Blob, I know I have valid Blob's in the chunks array.
Here's what the debug info of chunks is, before executing the new Blob(chunks, {.. part.
console.log(chunks)
Then here's the debug info of the new Blob(chunks, {type: 'video/webm'}) object.
console.log(ab)
I'm completely stumped. All the reference tutorials or other SO answers I can find basically follow this flow. What am I missing?
Electron version: 1.6.2
That's not possible to be working. You didn't wait for value to come in stopReocoring. You need to change your stopRecording function to following:
function stopRecording() {
var save = function() {
console.log(blobs);
toArrayBuffer(new Blob(blobs, {type: 'video/webm'}), function(ab) {
console.log(ab);
var buffer = toBuffer(ab);
var file = `./videos/example.webm`;
fs.writeFile(file, buffer, function(err) {
if (err) {
console.error('Failed to save video ' + err);
} else {
console.log('Saved video: ' + file);
}
});
});
};
recorder.onstop = save;
recorder.stop();
}
This problem literally just fixed itself today without me changing anything. I'm not sure what about my system changed (other than a reboot) but it's now working exactly as it should.

Pinch and zoom not working on ipad

I am unable to do pinch and zoom on ipad, I guess that the below given code may be effecting the code,
Please give any perfect solution.
Is there any issue with the binding of body child events or need to calculate the touches in different variables, and do manual calculation.
///I-Pad evenet Binding
$(document).ready(function () {
$("body").children().bind('touchstart touchmove touchend touchcancel', function () {
var touches = event.changedTouches, first = touches[0], type = "";
switch (event.type) {
case "touchstart": type = "mousedown";
break;
case "touchmove": type = "mousemove";
break;
case "touchend": type = "mouseup";
break;
default: return;
}
var simulatedEvent = document.createEvent("MouseEvent");
simulatedEvent.initMouseEvent(type, true, true, window, 1,
first.screenX, first.screenY,
first.clientX, first.clientY, false,
false, false, false, 0/*left*/, null);
if (touches.length < 2) {
first.target.dispatchEvent(simulatedEvent);
event.preventDefault();
}
});
(function () {
var last_x = null, last_y = null, w_area = workarea[0],
panning = false, keypan = false, dopanning = false;
$("#svgroot").bind('mousemove mouseup', function (evt) {
if (dopanning === false) return;
var clientxnew = +$("#svgcontent")[0].getAttribute("x"),
clientynew = +$("#svgcontent")[0].getAttribute("y");
clientxnew += (evt.clientX - last_x);
clientynew += (evt.clientY - last_y);
last_x = evt.clientX;
last_y = evt.clientY;
//this.setAttribute("viewBox", vb.join(' '));
// updateCanvas(true);
$("#svgcontent").show();
$("#svgcontent")[0].setAttribute("x", clientxnew);
$("#svgcontent")[0].setAttribute("y", clientynew);
svgedit.select.getSelectorManager().selectorParentGroup.setAttribute("transform", "translate(" + clientxnew + "," + clientynew + ")");
if (evt.type === 'mouseup') { dopanning = false; }
return false;
}).mousedown(function (evt) {
var mouse_target = svgCanvas.getMouseTarget(evt);
if (svgCanvas.getMode() == "text" || svgCanvas.getMode() == "textedit") {
dopanning = false; return;
}
if ((mouse_target.id.indexOf("grouplayerdragged") > -1 || mouse_target.id.indexOf("hotspot") > -1 ||
mouse_target.id.indexOf("clonediv") > -1 || mouse_target.tagName === "text")) { dopanning = false; return; }
if (selectedElement != null) {
dopanning = false; return;
}
if (evt.button === 0) {
dopanning = true;
last_x = evt.clientX;
last_y = evt.clientY;
svgCanvas.clearSelection(true);
return false;
}
});
$(window).mouseup(function () {
panning = false;
dopanning = false;
});
you should use gesturechange. try this way (this is not your exact solution but you can hack it)
var angle = 0;
var newAngle;
var scale = 1;
var newScale;
function saveChanges() {
angle = newAngle;
scale = newScale;
}
function getAngleAndScale(e) {
// Don't zoom or rotate the whole screen
e.preventDefault();
// Rotation and scale are event properties
newAngle = angle + e.rotation;
newScale = scale * e.scale;
// Combine scale and rotation into a single transform
var tString = "scale(" + newScale + ")";
document.getElementById("theDiv").style.webkitTransform = tString;
}
function init() {
// Set scale and rotation during gestures
document.getElementById("theDiv").addEventListener("gesturechange", getAngleAndScale, false);
// Preserve scale and rotation when gesture ends
document.getElementById("theDiv").addEventListener("gestureend", saveChanges, false);
}
<body>
<div style="width:300px;height:300px;overflow:scrool;-webkit-overflow-scrolling: touch;">
<img id="theDiv" style="width:100%;" src="http://animal.discovery.com/guides/wild-birds/gallery/mallard_duck.jpg" />
</div>
Try this on your ipad

Resources