How to check if my all promises are fulfilled - javascript

Currently I am writing a block of code.
I want to start webcamera when video will start play and stop camera when video is paused but before loading camera I want to check if my all models are loaded or not. I want to load the model once until page refresh.thats totaly a seprate case that if user page refersh it will load again. Now if I click on play button in video it starts my camera. How can i configure it in a way where if user pause the button it only disable the camera and press play button it only load the camera (not load my models again).
<html>
<head>
<title>Video detecting and emotion storing in database</title>
<script type="text/css" defer src="https://cdn.jsdelivr.net/npm/bootstrap#4.6.2/dist/css/bootstrap.min.css"></script>
<script type="text/css" src="style.css"></script>
<script defer type="text/javascript" src="script/face-api.min.js"></script>
<script defer type="text/javascript" src="script/script.js"></script>
<style>
#livecam{
height: 400px;
width: 600px;
float: right;
}
</style>
</head>
<body>
<div class="container">
<video id="myvideo" src="laravel.mp4" controls height="400" width="600" >
</video>
<video id="livecam" autoplay muted height="400" width="600" ></video>
</div>
</body>
</html>
..................................... Index.php
now my script.js
var video = document.getElementById('myvideo');
const liveview = document.getElementById('livecam');
const height = 400;
const width = 600;
Promise.all([
faceapi.nets.tinyFaceDetector.loadFromUri('/models'),
faceapi.nets.faceLandmark68Net.loadFromUri('/models'),
faceapi.nets.faceRecognitionNet.loadFromUri('/models'),
faceapi.nets.faceExpressionNet.loadFromUri('/models')
])
video.onplaying = function(){
enablewebcam();
alert("Video is playing");
};
video.onpause = function(){
disablecam();
}
function enablewebcam(){
navigator.mediaDevices.getUserMedia({video:{width:600, height:400},
audio:false}).then((stream) => {
liveview.srcObject = stream;
})
};
function disablecam(){
liveview.srcObject = null;
}

To check if your models have already been loaded before enabling the webcam, you can use a flag variable that is set to true after the models are loaded. Then, in your enablewebcam function, you can check the value of this flag before enabling the webcam:
let modelsLoaded = false;
Promise.all([
faceapi.nets.tinyFaceDetector.loadFromUri('/models'),
faceapi.nets.faceLandmark68Net.loadFromUri('/models'),
faceapi.nets.faceRecognitionNet.loadFromUri('/models'),
faceapi.nets.faceExpressionNet.loadFromUri('/models')
]).then(() => {
modelsLoaded = true;
});
function enablewebcam() {
if (modelsLoaded) {
navigator.mediaDevices.getUserMedia({ video: { width: 600, height: 400 }, audio: false }).then((stream) => {
liveview.srcObject = stream;
});
}
}
Alternatively, you can use the faceapi.nets.tinyFaceDetector.isLoaded() function to check if the tinyFaceDetector model has been loaded. If it has, you can assume that all the models have been loaded, since they are all being loaded in the same Promise.all block.
function enablewebcam() {
if (faceapi.nets.tinyFaceDetector.isLoaded()) {
navigator.mediaDevices.getUserMedia({ video: { width: 600, height: 400 }, audio: false }).then((stream) => {
liveview.srcObject = stream;
});
}
}
Either way, you can use the video.onpause event to stop the webcam when the video is paused, as you have already done in your code.

To make sure the models have loaded when the user clicks play, delay adding the controls attribute until after the models have been fetched.
If you do this in a then handler of the Promise.all call, you can add event listeners to the video element to start and stop the video in the same place - the user can then start and stop the video at will. You may want to get rid of the alert message` however.
The snippet has been cut down for testing but unfortunately does not work on Stack overflow:
"use strict";
var video = document.getElementById('myvideo');
const liveview = document.getElementById('livecam');
const height = 400;
const width = 600;
Promise.all([
// production
// faceapi.nets.tinyFaceDetector.loadFromUri('/models'),
// faceapi.nets.faceLandmark68Net.loadFromUri('/models'),
// faceapi.nets.faceRecognitionNet.loadFromUri('/models'),
// faceapi.nets.faceExpressionNet.loadFromUri('/models')
// testing
Promise.resolve(true),
Promise.resolve(true),
Promise.resolve(true),
Promise.resolve(true)
])
.then( ()=> {
video.onplaying = function(){
enablewebcam();
alert("Video is playing");
};
video.onpause = function(){
disablecam();
}
// show video controls:
video.setAttribute("controls", "");
function enablewebcam(){
navigator.mediaDevices.getUserMedia({video:{width:600, height:400},
audio:false})
.then((stream) => {
liveview.srcObject = stream;
})
.catch( err => {
console.log("no cam, ", err.message)
});
};
function disablecam(){
liveview.srcObject = null;
}
})
.catch(err => {
console.log(err);
alert("Something went wrong");
});
video { border: thin solid blue}
<div class="container">
<video id="myvideo"
src="https://i.imgur.com/LTc02xw_lq.mp4"
height="400" width="600">
</video>
<video id="livecam" autoplay muted height="400" width="600" ></video>
</div>

You can create an array of promises because the Promise class has an all method that receives an array of promises and returns the result once they are all fullfilled. If you think that one of the promises could fail, you should instead use allSettled because the all method returns Pending if one of the promises fails.
The allSettled method will return the promises data with a status and a value field. status giving you fullfilled or rejected and value giving you the promise data.
An example of this would be:
// Your array of promises
promises = [
...
]
// 'all' method
Promises.all(promises)
.then(data => console.log(data))
// 'allSettled' method
Promises.allSettled(promises)
.then(data => console.log(data))

So I found the answer as Hint by Ritik
Setting a variable true after successfull loading of model and everytime before enabling the camera will check that variable if it true or false.
Promise.all([
faceapi.nets.tinyFaceDetector.loadFromUri('/mmodels'),
faceapi.nets.faceLandmark68Net.loadFromUri('/models'),
faceapi.nets.faceRecognitionNet.loadFromUri('/models'),
faceapi.nets.faceExpressionNet.loadFromUri('/models')
]).then(function(){
modeloadedstatus = true;
})
checking modeloadedstatus before everytime enabling camera
video.onplaying = function(){
if(modeloadedstatus) {
enablewebcam();
console.log(modeloadedstatus)
alert("Video is playing");
} else{
alert("Error in model loading");
}
};

Related

react-player cant play local video

I'm trying to create a popup that will play a video and when it clicked while playing it will pause and hide the popup.
This is when the user clicks to show and play the video
<div className="mn sr" onClick={() => vidControl("PLAY")}>
Showreel
</div>
It will make this div visible and play the video
import Video from "../assets/videos/showreel/showreel.mov";
<div className="showreel" style={videoOpen ? { display: "block" } : { display: "none" }}>
<ReactPlayer
url={Video}
className="sr-video"
onClick={() => vidControl("PAUSE")}
/>
</div>
This function act as the video control or so-called
const vidControl = (params) => {
const video = document
.querySelector(".showreel")
.getElementsByTagName("video")[0];
if (params === "PLAY") {
video.play();
setVideoOpen(true);
} else {
video.pause();
setVideoOpen(false);
}
};
I have no problem when running it locally, but when I deployed and click to play it, there is an error says.
Uncaught (in promise) DOMException: The element has no supported sources.
I've searched for the same error and tried to fix it with this code since they say I gotta handle the promise but in the end, it doesn't fix my problem.
async function videoPromise() {
const video = document
.querySelector(".showreel")
.getElementsByTagName("video")[0];
try {
await video.play();
setVideoOpen(true);
console.log("play");
} catch (err) {
video.pause();
setVideoOpen(false);
console.log(err, "error");
}
}
Is there any problem with the code or the logic here? Appreciate any kinda responses, thanks before.

Is there a way to use PoseNet with live webcam feed?

I've already tried adding a video tag and then setting the source to the webcam, but this didn't work. It just produced 404s in the console. Here is the code I tried:
<html>
<head>
<!-- Load TensorFlow.js -->
<script src="https://cdn.jsdelivr.net/npm/#tensorflow/tfjs"></script>
<!-- Load Posenet -->
<script src="https://cdn.jsdelivr.net/npm/#tensorflow-models/posenet"></script>
</head>
<body>
<video autoplay="true" id="videoElement">
</video>
</body>
<script>
var video = document.querySelector("#videoElement");
if (navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices.getUserMedia({ video: true })
.then(function (stream) {
video.srcObject = stream;
})
}
var flipHorizontal = false;
var imageElement = document.getElementById('videoElement');
posenet.load().then(function(net) {
const pose = net.estimateSinglePose(imageElement, {
flipHorizontal: true
});
return pose;
}).then(function(pose){
var parts = pose["keypoints"];
console.log(parts[9]);
})
</script>
</html>
Please see our official example code here for using webcam with bodypix (which is very similar to posenet but gives you even more details). The webcam part of the code however would be the same:
CodePen:
https://codepen.io/jasonmayes/pen/QWbNeJd
Or Glitch: https://glitch.com/edit/#!/tensorflow-js-body-segmentation
Essentially the key parts here are:
const video = document.getElementById('webcam');
// Check if webcam access is supported.
function hasGetUserMedia() {
return !!(navigator.mediaDevices &&
navigator.mediaDevices.getUserMedia);
}
// Enable the live webcam view and start classification.
function enableCam(event) {
// getUsermedia parameters.
const constraints = {
video: true
};
// Activate the webcam stream.
navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
video.addEventListener('loadedmetadata', function() {
// do something once loaded metadata
});
video.srcObject = stream;
video.addEventListener('loadeddata', function(){
// Do something once loaded.
});
});
}
// If webcam supported, add event listener to button for when user
// wants to activate it.
if (hasGetUserMedia()) {
const enableWebcamButton = document.getElementById('webcamButton');
enableWebcamButton.addEventListener('click', enableCam);
} else {
console.warn('getUserMedia() is not supported by your browser');
}

rtcpeerconnection track event sometimes returning empty stream

What is the best approach for setting up an RTC connection that will success the first time ?
The following code sometimes works, sometimes doesn't. I think it's a problem with addIceCandidate being called either before or after createAnswer, and I don't know which is preferable, or if that is even the issue (for why its not working all the time, just paste it into a browser, and try it a few times, you should see that at least sometimes the "call" button doesn't work all the time):
<body>
<style>
video {
width: 300px
}
</style>
<button id="s">start</button>
<button id=c>Call</button><br>
<video id="L" autoplay muted></video>
<video id=R autoplay></video>
<video id=R2 autoplay></video>
<video id=R3 autoplay></video>
<script>
var ls, p, p2, bpl, bpr, con = {
// sdpSemantics: "default"
}, deets = {
offerToReceiveAudio: 1,
offerToReceiveVideo: 1
}
function g() {
navigator.
mediaDevices.getDisplayMedia().then(s => {
ls = L.srcObject = s;
})
}
s.onclick = e => {
g()
};
function wow(data={}) {
let local = new RTCPeerConnection(con),
remote = new RTCPeerConnection(con);
local .addEventListener("icecandidate", e => oic(remote, e));
remote.addEventListener("icecandidate", e => oic(local , e));
remote.addEventListener("track", e => grs(data.video, e));
data
.localStream
.getTracks()
.forEach(t => {
local.addTrack(t, data.localStream);
});
local.createOffer(deets).then(offer => {
local .setLocalDescription(offer);
remote.setRemoteDescription(offer);
remote.createAnswer().then(answer => {
remote.setLocalDescription(answer);
local .setRemoteDescription(answer);
})
});
}
c.onclick = e => {
let localStream = ls;
wow({
video: R,
localStream
});
wow({
video: R2,
localStream
});
wow({
video: R3,
localStream
});
};
function grs(vid,e) {
if(vid.srcObject !== e.streams[0]) {
vid.srcObject = e.streams[0];
}
}
function oic(pc, e) {
let other = pc;
if(e.candidate)
other
.addIceCandidate(e.candidate)
}
</script>
</video>
</body>
Notice how sometimes the video streams come in later and empty.
i run into the same problem when i use PeerConnection API before, the problem is Unified Plan SDP format, maybe it worth to read.
https://webrtc.org/getting-started/unified-plan-transition-guide
https://docs.google.com/document/d/1-ZfikoUtoJa9k-GZG1daN0BU3IjIanQ_JSscHxQesvU/edit#
Please look again at documentation. At first, you are using async functions, so it could not resolve at the time then you call it (for example user doesn't answer for prompt or browser decline it at all). At second, you're not handling errors, add catch() block to your code and browser will answer to your question itself

how to open html 5 video fullscreen if it was fullscreen before

I'm watching a series of videos on a website organised in a playlist. Each video is about 2 minutes long.
The website uses HTML 5 video player and it supports auto-play. That is each time a video ends, the next video is loaded and automatically played, which is great.
However, with Fullscreen, even if I fullscreened a video previously, when the next video loads in the playlist, the screen goes back to normal, and I have to click the fullscreen button again....
I've tried writing a simple javascript extension with Tampermonkey to load the video fullscreen automatically.
$(document).ready(function() {
function makefull() {
var vid = $('video')[0]
if (vid.requestFullscreen) {
vid.requestFullscreen();
} else if (vid.mozRequestFullScreen) {
vid.mozRequestFullScreen();
} else if (vid.webkitRequestFullscreen) {
vid.webkitRequestFullscreen();
}
//var vid = $('button.vjs-fullscreen-control').click();
}
makefull()
But I'm getting this error:
Failed to execute 'requestFullscreen' on 'Element': API can only be initiated by a user gesture.
It's extremely annoying to have to manually click fullscreen after each 2 min video. Is there a way I can achieve this in my own browser? I'm using Chrome.
If you can get the list of URL's then you can create your own playlist. The code cannot be accurately tested within a cross-origin <iframe>, for example at plnkr.co. The code can be tested at console at this very document. To test the code, you can use the variable urls at MediaFragmentRecorder and substitute "pause" event for "ended" event at .addEventListener().
If you have no control over the HTML or JavaScript used at the site not sure how to provide any code that will be able to solve the inquiry.
const video = document.createElement("video");
video.controls = true;
video.autoplay = true;
const urls = [
{
src: "/path/to/video/"
}, {
src: "/path/to/video/"
}
];
(async() => {
try {
video.requestFullscreen = video.requestFullscreen
|| video.mozRequestFullscreen
|| video.webkitRequestFullscreen;
let fullScreen = await video.requestFullscreen().catch(e => {throw e});
console.log(fullScreen);
} catch (e) {
console.error(e.message)
}
for (const {src} of urls) {
await new Promise(resolve => {
video.addEventListener("canplay", e => {
video.load();
video.play();
}, {
once: true
});
video.addEventListener("ended", resolve, {
once: true
});
video.src = src;
});
}
})();

Release webcam and microphone from getUserMedia after countdown [duplicate]

I opened a webcam by using the following JavaScript code:
const stream = await navigator.mediaDevices.getUserMedia({ /* ... */ });
Is there any JavaScript code to stop or close the webcam?
Since this answer has been originally posted the browser API has changed.
.stop() is no longer available on the stream that gets passed to the callback.
The developer will have to access the tracks that make up the stream (audio or video) and stop each of them individually.
More info here: https://developers.google.com/web/updates/2015/07/mediastream-deprecations?hl=en#stop-ended-and-active
Example (from the link above):
stream.getTracks().forEach(function(track) {
track.stop();
});
Browser support may differ.
Previously, navigator.getUserMedia provided you with a stream in the success callback, you could call .stop() on that stream to stop the recording (at least in Chrome, seems FF doesn't like it)
Use any of these functions:
// stop both mic and camera
function stopBothVideoAndAudio(stream) {
stream.getTracks().forEach(function(track) {
if (track.readyState == 'live') {
track.stop();
}
});
}
// stop only camera
function stopVideoOnly(stream) {
stream.getTracks().forEach(function(track) {
if (track.readyState == 'live' && track.kind === 'video') {
track.stop();
}
});
}
// stop only mic
function stopAudioOnly(stream) {
stream.getTracks().forEach(function(track) {
if (track.readyState == 'live' && track.kind === 'audio') {
track.stop();
}
});
}
Don't use stream.stop(), it's deprecated
MediaStream Deprecations
Use stream.getTracks().forEach(track => track.stop())
FF, Chrome and Opera has started exposing getUserMedia via navigator.mediaDevices as standard now (Might change :)
online demo
navigator.mediaDevices.getUserMedia({audio:true,video:true})
.then(stream => {
window.localStream = stream;
})
.catch( (err) =>{
console.log(err);
});
// later you can do below
// stop both video and audio
localStream.getTracks().forEach( (track) => {
track.stop();
});
// stop only audio
localStream.getAudioTracks()[0].stop();
// stop only video
localStream.getVideoTracks()[0].stop();
Suppose we have streaming in video tag and id is video - <video id="video"></video> then we should have following code -
var videoEl = document.getElementById('video');
// now get the steam
stream = videoEl.srcObject;
// now get all tracks
tracks = stream.getTracks();
// now close each track by having forEach loop
tracks.forEach(function(track) {
// stopping every track
track.stop();
});
// assign null to srcObject of video
videoEl.srcObject = null;
Starting Webcam Video with different browsers
For Opera 12
window.navigator.getUserMedia(param, function(stream) {
video.src =window.URL.createObjectURL(stream);
}, videoError );
For Firefox Nightly 18.0
window.navigator.mozGetUserMedia(param, function(stream) {
video.mozSrcObject = stream;
}, videoError );
For Chrome 22
window.navigator.webkitGetUserMedia(param, function(stream) {
video.src =window.webkitURL.createObjectURL(stream);
}, videoError );
Stopping Webcam Video with different browsers
For Opera 12
video.pause();
video.src=null;
For Firefox Nightly 18.0
video.pause();
video.mozSrcObject=null;
For Chrome 22
video.pause();
video.src="";
With this the Webcam light go down everytime...
Try method below:
var mediaStream = null;
navigator.getUserMedia(
{
audio: true,
video: true
},
function (stream) {
mediaStream = stream;
mediaStream.stop = function () {
this.getAudioTracks().forEach(function (track) {
track.stop();
});
this.getVideoTracks().forEach(function (track) { //in case... :)
track.stop();
});
};
/*
* Rest of your code.....
* */
});
/*
* somewhere insdie your code you call
* */
mediaStream.stop();
You can end the stream directly using the stream object returned in the success handler to getUserMedia. e.g.
localMediaStream.stop()
video.src="" or null would just remove the source from video tag. It wont release the hardware.
Since you need the tracks to close the streaming, and you need the stream boject to get to the tracks, the code I have used with the help of the Muaz Khan's answer above is as follows:
if (navigator.getUserMedia) {
navigator.getUserMedia(constraints, function (stream) {
videoEl.src = stream;
videoEl.play();
document.getElementById('close').addEventListener('click', function () {
stopStream(stream);
});
}, errBack);
function stopStream(stream) {
console.log('stop called');
stream.getVideoTracks().forEach(function (track) {
track.stop();
});
Of course this will close all the active video tracks. If you have multiple, you should select accordingly.
If the .stop() is deprecated then I don't think we should re-add it like #MuazKhan dose. It's a reason as to why things get deprecated and should not be used anymore. Just create a helper function instead... Here is a more es6 version
function stopStream (stream) {
for (let track of stream.getTracks()) {
track.stop()
}
}
You need to stop all tracks (from webcam, microphone):
localStream.getTracks().forEach(track => track.stop());
Start and Stop Web Camera,(Update 2020 React es6 )
Start Web Camera
stopWebCamera =()=>
//Start Web Came
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
//use WebCam
navigator.mediaDevices.getUserMedia({ video: true }).then(stream => {
this.localStream = stream;
this.video.srcObject = stream;
this.video.play();
});
}
}
Stop Web Camera or Video playback in general
stopVideo =()=>
{
this.video.pause();
this.video.src = "";
this.video.srcObject = null;
// As per new API stop all streams
if (this.localStream)
this.localStream.getTracks().forEach(track => track.stop());
}
Stop Web Camera function works even with video streams:
this.video.src = this.state.videoToTest;
this.video.play();
Using .stop() on the stream works on chrome when connected via http. It does not work when using ssl (https).
Please check this: https://jsfiddle.net/wazb1jks/3/
navigator.getUserMedia(mediaConstraints, function(stream) {
window.streamReference = stream;
}, onMediaError);
Stop Recording
function stopStream() {
if (!window.streamReference) return;
window.streamReference.getAudioTracks().forEach(function(track) {
track.stop();
});
window.streamReference.getVideoTracks().forEach(function(track) {
track.stop();
});
window.streamReference = null;
}
The following code worked for me:
public vidOff() {
let stream = this.video.nativeElement.srcObject;
let tracks = stream.getTracks();
tracks.forEach(function (track) {
track.stop();
});
this.video.nativeElement.srcObject = null;
this.video.nativeElement.stop();
}
Have a reference of stream form successHandle
var streamRef;
var handleVideo = function (stream) {
streamRef = stream;
}
//this will stop video and audio both track
streamRef.getTracks().map(function (val) {
val.stop();
});

Categories

Resources