11521 sujets

JavaScript, DOM et API Web HTML5

Bonjour
J'essaie de récupérer un flux de webcam, qui va aller sur un canevas et être manupilé dans tous les sens. Avec le code suivant, je récupère mon flux - peut-être même aussi avec iOS, qui est un autre gros problème, mais pas ici -, tout va bien. Comme ça doit pouvoir être vu surtout sur un smartphone, aussi sur une tablette, je veux récupérer les dimensions de l'image pour l'adapter au mieux à celles du device.

Et c'est là que je tombe sur un problème tès bête. J'ai aucun souci à récupérer les dimensions dans l'évènement, mais j'arrive pas à les sortir du bloc. Avec n'importe quel autre bloc, il suffit de faire une variable globales, mais là, elle sont ignorées.

Que faire ?

Merci d'avance.

<!DOCTYPE html>

<body>
    <video id='webcam' autoplay playsinline></video>
    <script>
        var webcam = document.getElementById('webcam');
        var width, height ;

        webcam.addEventListener("loadedmetadata", function(){
            width = this.videoWidth ;
            height = this.videoHeight
            console.log("loadedMetaData: ", this.videoWidth, this.videoHeight)  ;
        });
        
        console.log("hors fonction: ", width, height)  ;


        window.onload=function(){
            console.log("Onload: ", width, height);

            if (navigator.mediaDevices.getUserMedia) {
                navigator.mediaDevices.getUserMedia({
                    audio: false,
                    video: {
                        facingMode: 'environment'
                    }
                })
                .then(function(stream) {
                    webcam.srcObject = stream;
                })
            }
        }
    </script>
</body>
Modérateur
Bonjour,

Si je comprends la question (j'ai un doute), lorsque tu exécutes la ligne console.log("hors fonction: ", width, height) ; width et height ne contiennent rien.

Si c'est bien ça la question, c'est normal vu que les instructions qui sont dans webcam.addEventListener() sont exécutées en différé (lorsque l'évènement 'loadedmetadata' pour la webcam survient).

De même pour ce qui est des instructions qui sont dans window.onload=function(){...}, qui ne seront exécutées qu'une fois la page chargée.

Alors que console.log("hors fonction: ", width, height); est exécutée immédiatement.

Il faut que la suite de ton code soit lancée à l'intérieur des webcam.addEventListener() et window.onload=function(){...}. Il n'y a pas d'autres choix.

Au passage, il faudrait remplacer
window.onload=function(){...}
par
window.addEventListener("load", function() {...}, false);

C'est plus propre, et cohérent avec
webcam.addEventListener("loadedmetadata", function(){...}, false);

Amicalement,
Merci beaucoup pour ta réponse.

Oui, après avoir posté le message j'ai noté que console.log("hors fonction: ", width, height) et console.log("Onload: ", width, height); s'exécutaient avant console.log("loadedMetaData: ", this.videoWidth, this.videoHeight) et que donc ils ne pouvaient pas avoir width et height. Le problème est que si je mets le bloc navigator.mediaDevices.getUserMedia() dans le listener de la webcam, ça ne marche plus, je n'a pas du tout d'image.

Le sujet de la question est en fait de pouvoir récupérer les dimensions de la vidéo pour en adapter la talle de l'écran. Peut-être qu'il y a une façon élémentaire de faire ça que je ne connais pas.

Amicalement

Alex
Modérateur
Bonjour,

En utilisant exactement ton code, la video va prendre toute la largeur de l'écran (ou plutôt de la fenêtre) si j'ajoute dans le css :
video {width:100%;}


Evidemment, tu peux aussi utiliser plein d'autres propriétés css (genre fit-object ou autre) à appliquer sur la balise video qui devraient à mon avis suffire pour faire ce dont tu as besoin.

Amicalement,
Modifié par parsimonhi (21 Dec 2018 - 20:55)
Modérateur
Bonjour,

Après, si tu tiens à utiliser javascript pour redimensionner ta video, je ne vois pas ce qui ne pourrait pas marcher.

Par exemple, pour diviser par 2 la largeur de la vidéo :

<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="initial-scale=1.0,user-scalable=yes">
<title>Webcam</title>
</head>
<body>
    <video id='webcam' autoplay playsinline></video>
    <script>
        var webcam = document.getElementById('webcam');
        
        function mySuperGenialCode()
        {
                	// faire ici tout traitement super génial sur la video
        	       webcam.width = webcam.videoWidth/2;
        }

        webcam.addEventListener("loadedmetadata", function(){
        	        mySuperGenialCode();
        });
        
        window.onload=function(){
            if (navigator.mediaDevices.getUserMedia) {
                navigator.mediaDevices.getUserMedia({
                    audio: false,
                    video: {
                        facingMode: 'environment'
                    }
                })
                .then(function(stream) {
                    webcam.srcObject = stream;
                })
            }
        }
    </script>
</body>
</html>


Note que webcam.videoWidth est "read only" : on ne peut pas la modifier. C'est webcam.width que l'on peut modifier.

Amicalement,
Utiliser du css m’irait très bien, au contraire ; ça me simplifierait bien des choses. Fit-object m’a l’air fort prometteur.
Le problème que je rencontre c’est que cette vidéo n’est pas toute seule sur la page. Il y a aussi un canevas sur lequel il se passe plein de choses mais qui doit être masqué. A quoi vient s’ajouter deux fenêtres modales superposées. Overflow:hide (display:none a l’air de marcher aussi) marche très bien sur l’écran d’ordinateur. Mais je crois me rendre compte que mon problème sur le smartphone vient de ce que le canevas masqué prend de la place ; le problème est doublé du fait qu’il faut prévoir les deux orientations paysage et portrait.
Ce qui n’aide pas non plus c’est qu’afficher la webcam s’affiche beaucoup plus difficilement sur iPhone et même si j’ai du code qui fonctionne, je ne parviens pas à comprendre ce qui fait que ça fonctionne ou pas. Ne pas avoir d’iPhone et de faire des tests en différé n’aide pas non plus …
Merci pour toutes tes réponses
Amicalement
Alex
Voici le code sur lequel je travaille en modèle réduit. Pour le tester, il y a juste besoin d’une image ‘images/image.jpg’ et d’une webcam.
La div canvasContainer est en l’état affichée, ce qui est prévu pour le masquer c’est qu’elle prenne la classe ‘masquer’.

<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Webcam base intervalle</title>
    <style>
        .masquer {
            /* A ajouter à div#canvasContainer pour masquer le canevas webcam+image */
            max-height: 0px;
            overflow: hidden;
        }
    </style>
</head>
<body>
    <!-- Conteneur de la webcam affichée et du canevas normalement masqué. -->
    <div id='container' style="text-align:center;margin-top:25px">
        <video id='webcam' width='640' height='480' autoplay playsinline></video>
        <div id="canvasContainer" class="">
            <canvas id='canvas'></canvas>
        </div>
    </div>
    <script>
        var image = new Image();
        image.src="images/image.jpg";
        window.onload = function () {
            var webcam = document.getElementById('webcam');
            var videoWidth = Number(webcam.width);
            var videoHeight = Number(webcam.height);

            var canvas = document.getElementById('canvas');
            var context = canvas.getContext('2d');

            // Récupération du flux de la webcam et affichage dans la balise video#webcam.
            if (navigator.mediaDevices.getUserMedia) {
                navigator.mediaDevices.getUserMedia({
                    audio: false,
                    video: {
                        facingMode: 'environment'
                    }
                })
                    .then(function (stream) {
                        webcam.srcObject = stream;
                    })
            }

            // Gestion du flux d'images, le dessin du flux et des images sur le canevas.
            intervall = window.setInterval(function () {

                image.width = image.width * videoHeight / image.height;
                image.height = videoHeight;

                canvas.width = videoWidth + image.width;
                canvas.height = videoHeight;

                context.drawImage(webcam, 0, 0, videoWidth, videoHeight);
                context.drawImage(image, videoWidth, 0, image.width, image.height);

            }, 20);
        }
    </script>
</body>
</html>



Sur l’ordinateur ça se passe très bien. Mais sur le smartphone on voit bien que même si le canevas est masqué, il persiste à occuper de l’espace, ce qui empêche la vidéo de remplir l’écran.
J’ai mis le test en ligne pour pouvoir le visionner avec un smartphone :
https://alexreflexive.github.io/testing/
https://alexreflexive.github.io/testing/test_a.html (canevas non masqué)
https://alexreflexive.github.io/testing/test_b.html (canevas masqué)
Modifié par Reflexive (26 Dec 2018 - 13:06)
Modérateur
Bonjour,

Je pense que si tu rajoutes un max-width:0 en plus du max-height:0 qu'il y a déjà, ça pourrait le faire.

Amicalement,