Je suis en train de créer un site de chant où l'utilisateur peut capturer une vidéo de lui-même en train de chanter avec un mp3. J'en suis arrivé au point de pouvoir accéder à la caméra et d'afficher le flux en direct, mais comment puis-je enregistrer la vidéo afin que l'utilisateur puisse la télécharger et la conserver?
Mon code:
<!DOCTYPE html>
<head>
<link href="css/bootstrap.css" rel="stylesheet"">
<style>
#container {
margin: 0px auto;
width: 500px;
height: 375px;
border: 10px #333 solid;
}
#videoElement {
width: 500px;
height: 375px;
background-color: #666;
}
</style>
</head>
<body>
<button class="btn" onclick="show();">Record!</button>
<div id="record" style="display:none; text-align:center;">
<div id="container">
<video autoplay="false" id="videoElement">
</video>
</div>
<button id="play" class="btn" onclick="play()">Start Recording!</button>
<audio id="song" style="hidden">
<source src="love.mp3" type="audio/mpeg">
Your browser does not support the audio element.
</audio>
</div>
<script src="http://code.jquery.com/jquery.js"></script>
<script src="js/bootstrap.js"></script>
<script>
var video = document.querySelector("#videoElement");
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia || navigator.oGetUserMedia;
if (navigator.getUserMedia) {
navigator.getUserMedia({video: true, audio: true}, handleVideo, videoError);
}
function handleVideo(stream) {
video.src = window.URL.createObjectURL(stream);
document.getElementById("videoElement").pause();
}
function videoError(e) {
alert("There was an error with the video stream.\nCheck that your webcam is connected.");
}
function play()
{
var video = document.getElementById("videoElement");
var music = document.getElementById("song");
var button = document.getElementById("play");
if (video.paused) {
video.play();
music.play();
button.textContent = "Stop Recording";
} else {
video.pause();
music.pause();
button.textContent = "Continue Recording";
}
}
function show()
{
document.getElementById("record").style.display="block";
}
</script>
</body>
existe-t-il un moyen dans handleVideo je peux enregistrer le flux tel qu'il vient ou quelque chose?
MISE À JOUR 12/2014 Pour info, il y a une nouvelle API sur son chemin appelée MediaRecorder. Actuellement pris en charge uniquement dans Firefox, et à un stade précoce, mais quelque chose à avoir à l'esprit.
Dans un environnement local pur, vous ne pouvez pas et n'obtiendrez pas un très bon résultat. Vous pouvez enregistrer les images à l'aide de l'élément canvas en dessinant dessus et stocker des images jpeg dans un stockage local à partir du flux vidéo avec l'audio (qui doit être enregistré séparément), puis en post utiliser une bibliothèque pour créer par exemple un MJPEG fichier (AFAIK il n'y en a actuellement aucun qui prend en charge l'audio).
Cependant, vous rencontrerez plusieurs problèmes avec cette approche: il faudra beaucoup de temps pour utiliser JavaScript pour traiter toutes ces informations - il suffit d'enregistrer un cadre au format jpeg, de le convertir en blob et de l'enregistrer dans le système de fichiers ou la base de données indexée consommera le plus ( ou plus) du budget de temps dont vous disposez pour une seule image.
Vous ne pourrez pas synchroniser correctement les images vidéo avec l'audio - vous pouvez enregistrer un horodatage et l'utiliser pour "corriger" les images, mais votre FPS variera probablement en créant une vidéo saccadée. Et même si vous obtenez la synchronisation dans un certain ordre temporel, vous rencontrerez probablement des problèmes de décalage où l'audio et la vidéo ne correspondent pas, car il s'agit initialement de deux flux distincts.
Mais les vidéos dépassent très rarement 30 FPS (US) ou 25 FPS (Europe), vous n'aurez donc pas besoin du taux complet de 60 FPS fourni par le navigateur - mai. Cela vous donne un meilleur budget horaire d'environ 33 millisecondes par image pour le système américain (NTSC) et un peu plus si vous êtes dans un pays utilisant le système PAL. Il n'y a rien de mal à utiliser une fréquence d'images encore plus faible, mais à un certain point (<12-15 FPS), vous commencerez à remarquer un grave manque de fluidité.
Il existe cependant de nombreux facteurs qui influenceront cela, tels que le processeur, le système de disque, la dimension du cadre, etc. JavaScript est monothread et l'API Canvas est synchrone, donc un processeur 12 cœurs ne vous aidera pas beaucoup à cet égard et l'utilité de Web Workers est actuellement limitée à peu près à des tâches plus longues. Si vous avez beaucoup de mémoire disponible, vous pouvez mettre en cache les trames en mémoire ce qui est faisable et faire tout le traitement en post qui prendra encore un certain temps. Un flux enregistré à 720P @ 30 FPS consommera au moins 105 Mo par seconde (ce ne sont que des données brutes n'incluant pas la gestion interne des tampons par le navigateur qui peut doubler, voire tripler).
Une meilleure solution consiste probablement à utiliser WebRTC et à vous connecter à un serveur (externe ou local) et à y traiter le flux. Ce flux contiendra de l'audio et de la vidéo synchronisés et vous pouvez stocker le flux temporaire sur le disque sans les limitations d'une zone de stockage en bac à sable du navigateur. L'inconvénient ici sera (pour les connexions externes) la bande passante car cela peut réduire la qualité, ainsi que la capacité du serveur.
Cela ouvre la possibilité d'utiliser par exemple Node.js, .Net ou PHP pour effectuer le traitement proprement dit à l'aide de composants tiers (ou une approche de plus bas niveau telle que l'utilisation de C/C++ compilé et CGI/tuyauterie si vous êtes dedans).
Vous pouvez consulter ce projet open source qui prend en charge le recodage des flux WebRTC:
http://lynckia.com/licode/
Le projet Licode fournit une API client NodeJS pour WebRTC afin que vous puissiez l'utiliser côté serveur, voir la documentation
Et c'est essentiellement jusqu'où vous pouvez aller avec l'état actuel de HTML5.
Ensuite, il y a la possibilité d'installer Flash et de l'utiliser - vous aurez toujours besoin d'un serveur solution latérale (Red5, Wowza ou AMS).
Cela vous donnera probablement une expérience moins pénible, mais vous devez avoir Flash installé dans le navigateur (évidemment) et dans de nombreux cas, il y a un facteur de coût plus élevé en raison des licences (voir Red5 pour une source ouverte alternative).
Si vous êtes prêt à payer pour des solutions commerciales, il existe des solutions comme celle-ci:
http://nimbb.com/
le flux est créé ici.
function handleVideo(stream) {
video.src = window.URL.createObjectURL(stream);
document.getElementById("videoElement").pause();
}
vos données sont le sream .. ou window.URL.createObjectURL (stream).
mais vous ne pouvez pas simplement écrire stream ou window.URL.createObjectURL (stream) sur un stockage local (de 2 Mo à petit) ou sur webkitRequestFileSystem (qui vous permet de disposer de Go) ... vous devez lire les données sorties sur le tag vidéo et le convertir en canevas comme une seule image en l'enregistrant dans le webkitfilesystem.
comme le système de fichiers a changé récemment, j'ai recherché le nouveau code sur Google et j'ai trouvé cet exemple parfait pour vous. https://Gist.github.com/piatra/2549734
dans l'exemple qu'il utilise
setTimeout(function(){ draw(v, bc, w, h); }, 200);
qui écrit un cadre toutes les 200 ms
si vous voulez un framrate personnalisé, changez simplement les 200 ms en 1000/25 .. (25fps)
ou utilisez requestanimationframe et vous devriez obtenir environ 60 images par seconde si votre processeur le prend en charge.
maintenant vous n'avez pas un vrai flux dans un format sympa comme mp4 ... mais beaucoup d'images que vous pouvez afficher avec une autre fonction ... encore une fois vous avez besoin d'un processeur très rapide.
dans cet exemple, l'audio ne fonctionne pas.
pour enregistrer également l'audio sur WAV (vous ne pouvez pas enregistrer mp3 ou aac) ... j'ai trouvé cela.
http://typedarray.org/from-microphone-to-wav-with-getusermedia-and-web-audio/
donc à la fin, vous pouvez le faire ... mais cela prendrait beaucoup d'espace pendant quelques minutes et a besoin d'un processeur très rapide pour tout élaborer.
Voici le code pleinement fonctionnel pour capturer une vidéo et l'enregistrer sur le local:
Il a besoin d'une autorisation comme l'enregistrement de fichiers, d'un appareil photo et d'un micro:
<html>
<div class="left">
<div id="startButton" class="button">
Start
</div>
<h2>Preview</h2>
<video id="preview" width="160" height="120" autoplay muted></video>
</div>
<div class="right">
<div id="stopButton" class="button">
Stop
</div>
<h2>Recording</h2>
<video id="recording" width="160" height="120" controls></video>
<a id="downloadButton" class="button">
Download
</a>
</div>
<script>
let preview = document.getElementById("preview");
let recording = document.getElementById("recording");
let startButton = document.getElementById("startButton");
let stopButton = document.getElementById("stopButton");
let downloadButton = document.getElementById("downloadButton");
let logElement = document.getElementById("log");
let recordingTimeMS = 5000;
function log(msg) {
//logElement.innerHTML += msg + "\n";
}
function wait(delayInMS) {
return new Promise(resolve => setTimeout(resolve, delayInMS));
}
function startRecording(stream, lengthInMS) {
let recorder = new MediaRecorder(stream);
let data = [];
recorder.ondataavailable = event => data.Push(event.data);
recorder.start();
log(recorder.state + " for " + (lengthInMS/1000) + " seconds...");
let stopped = new Promise((resolve, reject) => {
recorder.onstop = resolve;
recorder.onerror = event => reject(event.name);
});
let recorded = wait(lengthInMS).then(
() => recorder.state == "recording" && recorder.stop()
);
return Promise.all([
stopped,
recorded
])
.then(() => data);
}
function stop(stream) {
stream.getTracks().forEach(track => track.stop());
}
startButton.addEventListener("click", function() {
navigator.mediaDevices.getUserMedia({
video: true,
audio: false
}).then(stream => {
preview.srcObject = stream;
downloadButton.href = stream;
preview.captureStream = preview.captureStream || preview.mozCaptureStream;
return new Promise(resolve => preview.onplaying = resolve);
}).then(() => startRecording(preview.captureStream(), recordingTimeMS))
.then (recordedChunks => {
let recordedBlob = new Blob(recordedChunks, { type: "video/webm" });
recording.src = URL.createObjectURL(recordedBlob);
downloadButton.href = recording.src;
downloadButton.download = "RecordedVideo.webm";
log("Successfully recorded " + recordedBlob.size + " bytes of " +
recordedBlob.type + " media.");
})
.catch(log);
}, false);
stopButton.addEventListener("click", function() {
stop(preview.srcObject);
}, false);
</script>
</html>
Référence: Enregistrement d'un élément multimédia