web-dev-qa-db-fra.com

Comment enregistrer une webcam et de l'audio à l'aide de webRTC et d'une connexion Peer basée sur un serveur

J'aimerais enregistrer la webcam et le son des utilisateurs et les enregistrer dans un fichier sur le serveur. Ces fichiers pourraient alors être servis à d’autres utilisateurs.

Je n'ai aucun problème avec la lecture, mais j'ai du mal à enregistrer le contenu.

D'après ce que j'ai compris, la fonction getUserMedia .record() n'a pas encore été écrite. Seule une proposition a été faite à ce jour.

Je souhaite créer une connexion homologue sur mon serveur à l'aide de PeerConnectionAPI. Je comprends que c'est un peu compliqué, mais je pense qu'il devrait être possible de créer un pair sur le serveur et d'enregistrer ce que le client-pair envoie.

Si cela est possible, je devrais alors pouvoir sauvegarder ces données au format flv ou n’importe quel autre format vidéo.

Ma préférence est en fait d'enregistrer la webcam + le côté client audio, afin de permettre au client de réenregistrer des vidéos s'il n'a pas aimé leur première tentative avant le téléchargement. Cela permettrait également des interruptions dans les connexions réseau. J'ai vu un code qui permet d'enregistrer des "images" individuelles à partir de la webcam en envoyant les données sur la toile - c'est cool, mais j'ai également besoin de l'audio.

Voici le code côté client que j'ai jusqu'à présent:

  <video autoplay></video>

<script language="javascript" type="text/javascript">
function onVideoFail(e) {
    console.log('webcam fail!', e);
  };

function hasGetUserMedia() {
  // Note: Opera is unprefixed.
  return !!(navigator.getUserMedia || navigator.webkitGetUserMedia ||
            navigator.mozGetUserMedia || navigator.msGetUserMedia);
}

if (hasGetUserMedia()) {
  // Good to go!
} else {
  alert('getUserMedia() is not supported in your browser');
}

window.URL = window.URL || window.webkitURL;
navigator.getUserMedia  = navigator.getUserMedia || navigator.webkitGetUserMedia ||
                          navigator.mozGetUserMedia || navigator.msGetUserMedia;

var video = document.querySelector('video');
var streamRecorder;
var webcamstream;

if (navigator.getUserMedia) {
  navigator.getUserMedia({audio: true, video: true}, function(stream) {
    video.src = window.URL.createObjectURL(stream);
    webcamstream = stream;
//  streamrecorder = webcamstream.record();
  }, onVideoFail);
} else {
    alert ('failed');
}

function startRecording() {
    streamRecorder = webcamstream.record();
    setTimeout(stopRecording, 10000);
}
function stopRecording() {
    streamRecorder.getRecordedData(postVideoToServer);
}
function postVideoToServer(videoblob) {
/*  var x = new XMLHttpRequest();
    x.open('POST', 'uploadMessage');
    x.send(videoblob);
*/
    var data = {};
    data.video = videoblob;
    data.metadata = 'test metadata';
    data.action = "upload_video";
    jQuery.post("http://www.foundthru.co.uk/uploadvideo.php", data, onUploadSuccess);
}
function onUploadSuccess() {
    alert ('video uploaded');
}

</script>

<div id="webcamcontrols">
    <a class="recordbutton" href="javascript:startRecording();">RECORD</a>
</div>
77
Dave Hilditch

Vous devriez certainement regarder Kurento . Il fournit une infrastructure de serveur WebRTC qui vous permet d’enregistrer à partir d’un flux WebRTC et bien plus encore. Vous pouvez également trouver quelques exemples pour l’application que vous envisagez ici . Il est très facile d'ajouter des fonctionnalités d'enregistrement à cette démo et de stocker le fichier multimédia dans un URI (disque local ou ailleurs).

Le projet est licencié sous LGPL Apache 2.0


EDIT 1

Depuis cet article, nous avons ajouté un nouveau tutoriel qui explique comment ajouter l'enregistreur dans quelques scénarios.

Disclaimer: Je fais partie de l'équipe qui développe Kurento.

44
igracia

Veuillez vérifier le RecordRTC

RecordRTC est MIT sous licence sur github .

15
Dmitry

Je pense que l’utilisation de kurento ou d’autres MCU uniquement pour l’enregistrement de vidéos serait un peu exagérée, en particulier si l’on tient compte du fait que Chrome bénéficie du support de MediaRecorder API de v47 et de Firefox depuis la v25. Donc, à cette jonction, vous n’auriez peut-être même pas besoin d’une bibliothèque js externe pour faire le travail. Essayez cette démo que j’ai faite pour enregistrer de la vidéo/de l’audio à l’aide de MediaRecorder:

Demo - fonctionnerait en chrome et Firefox (omis intentionnellement de pousser blob vers le code du serveur)

Code source Github

Si vous utilisez Firefox, vous pouvez le tester ici même (chrome doit https):

'use strict'

let log = console.log.bind(console),
  id = val => document.getElementById(val),
  ul = id('ul'),
  gUMbtn = id('gUMbtn'),
  start = id('start'),
  stop = id('stop'),
  stream,
  recorder,
  counter = 1,
  chunks,
  media;


gUMbtn.onclick = e => {
  let mv = id('mediaVideo'),
    mediaOptions = {
      video: {
        tag: 'video',
        type: 'video/webm',
        ext: '.mp4',
        gUM: {
          video: true,
          audio: true
        }
      },
      audio: {
        tag: 'audio',
        type: 'audio/ogg',
        ext: '.ogg',
        gUM: {
          audio: true
        }
      }
    };
  media = mv.checked ? mediaOptions.video : mediaOptions.audio;
  navigator.mediaDevices.getUserMedia(media.gUM).then(_stream => {
    stream = _stream;
    id('gUMArea').style.display = 'none';
    id('btns').style.display = 'inherit';
    start.removeAttribute('disabled');
    recorder = new MediaRecorder(stream);
    recorder.ondataavailable = e => {
      chunks.Push(e.data);
      if (recorder.state == 'inactive') makeLink();
    };
    log('got media successfully');
  }).catch(log);
}

start.onclick = e => {
  start.disabled = true;
  stop.removeAttribute('disabled');
  chunks = [];
  recorder.start();
}


stop.onclick = e => {
  stop.disabled = true;
  recorder.stop();
  start.removeAttribute('disabled');
}



function makeLink() {
  let blob = new Blob(chunks, {
      type: media.type
    }),
    url = URL.createObjectURL(blob),
    li = document.createElement('li'),
    mt = document.createElement(media.tag),
    hf = document.createElement('a');
  mt.controls = true;
  mt.src = url;
  hf.href = url;
  hf.download = `${counter++}${media.ext}`;
  hf.innerHTML = `donwload ${hf.download}`;
  li.appendChild(mt);
  li.appendChild(hf);
  ul.appendChild(li);
}
      button {
        margin: 10px 5px;
      }
      li {
        margin: 10px;
      }
      body {
        width: 90%;
        max-width: 960px;
        margin: 0px auto;
      }
      #btns {
        display: none;
      }
      h1 {
        margin-bottom: 100px;
      }
<link type="text/css" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<h1> MediaRecorder API example</h1>

<p>For now it is supported only in Firefox(v25+) and Chrome(v47+)</p>
<div id='gUMArea'>
  <div>
    Record:
    <input type="radio" name="media" value="video" checked id='mediaVideo'>Video
    <input type="radio" name="media" value="audio">audio
  </div>
  <button class="btn btn-default" id='gUMbtn'>Request Stream</button>
</div>
<div id='btns'>
  <button class="btn btn-default" id='start'>Start</button>
  <button class="btn btn-default" id='stop'>Stop</button>
</div>
<div>
  <ul class="list-unstyled" id='ul'></ul>
</div>
<script src="https://code.jquery.com/jquery-2.2.0.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>

9
mido

oui, comme vous l'avez compris, MediaStreamRecorder n'est actuellement pas implémenté.

MediaStreamRecorder est une API WebRTC permettant d'enregistrer des flux getUserMedia (). Il permet aux applications Web de créer un fichier à partir d’une session audio/vidéo en direct.

alternativement, vous pouvez faire comme ceci http://ericbidelman.tumblr.com/post/31486670538/creating-webm-video-from-getusermedia mais le fichier audio manque.

7
Konga Raju

Vous pouvez utiliser RecordRTC-together , basé sur RecordRTC.

Il prend en charge l'enregistrement vidéo et audio ensemble dans des fichiers séparés. Vous aurez besoin d’un outil tel que ffmpeg pour fusionner deux fichiers en un sur le serveur.

4
Mifeng

Web Call Server 4 peut enregistrer du contenu audio et vidéo WebRTC dans le conteneur WebM . L'enregistrement est effectué à l'aide d'un codec Vorbis pour l'audio et d'un codec VP8 pour la vidéo . Les codecs WebRTC initiaux sont Opus ou G.711 et VP8. . Ainsi, l’enregistrement côté serveur nécessite un transcodage côté serveur Opus/G.711 vers Vorbis ou un transcodage VP8-H.264 s’il est nécessaire d’utiliser un autre conteneur, c’est-à-dire AVI.

1
Bob42

Découvrez Janus. Voici une démo d'enregistrement:

https://janus.conf.meetecho.com/recordplaytest.html

Contrairement à Kurento, dont le développement a fortement ralenti après l’acquisition de Twilio, Janus continue d’être activement développé et soutenu.

1
jamix

Pour mémoire, je n'ai pas assez de connaissances à ce sujet, 

Mais j'ai trouvé ça sur Git hub- 

<!DOCTYPE html>
 <html>
<head>
  <title>XSockets.WebRTC Client example</title>
  <meta charset="utf-8" />


<style>
body {

  }
.localvideo {
position: absolute;
right: 10px;
top: 10px;
}

.localvideo video {
max-width: 240px;
width:100%;
margin-right:auto;
margin-left:auto;
border: 2px solid #333;

 }
 .remotevideos {
height:120px;
background:#dadada;
padding:10px; 
}

.remotevideos video{
max-height:120px;
float:left;
 }
</style>
</head>
<body>
<h1>XSockets.WebRTC Client example </h1>
<div class="localvideo">
    <video autoplay></video>
</div>

<h2>Remote videos</h2>
<div class="remotevideos">

</div>
<h2>Recordings  ( Click on your camera stream to start record)</h2>
<ul></ul>


<h2>Trace</h2>
<div id="immediate"></div>
<script src="XSockets.latest.js"></script>
<script src="adapter.js"></script>
<script src="bobBinder.js"></script>
<script src="xsocketWebRTC.js"></script>
<script>
    var $ = function (selector, el) {
        if (!el) el = document;
        return el.querySelector(selector);
    }
    var trace = function (what, obj) {
        var pre = document.createElement("pre");
        pre.textContent = JSON.stringify(what) + " - " + JSON.stringify(obj || "");
        $("#immediate").appendChild(pre);
    };
    var main = (function () {
        var broker;
        var rtc;
        trace("Ready");
        trace("Try connect the connectionBroker");
        var ws = new XSockets.WebSocket("wss://rtcplaygrouund.azurewebsites.net:443", ["connectionbroker"], {
            ctx: '23fbc61c-541a-4c0d-b46e-1a1f6473720a'
        });
        var onError = function (err) {
            trace("error", arguments);
        };
        var recordMediaStream = function (stream) {
            if ("MediaRecorder" in window === false) {
                trace("Recorder not started MediaRecorder not available in this browser. ");
                return;
            }
            var recorder = new XSockets.MediaRecorder(stream);
            recorder.start();
            trace("Recorder started.. ");
            recorder.oncompleted = function (blob, blobUrl) {
                trace("Recorder completed.. ");
                var li = document.createElement("li");
                var download = document.createElement("a");
                download.textContent = new Date();
                download.setAttribute("download", XSockets.Utils.randomString(8) + ".webm");
                download.setAttribute("href", blobUrl);
                li.appendChild(download);
                $("ul").appendChild(li);
            };
        };
        var addRemoteVideo = function (peerId, mediaStream) {
            var remoteVideo = document.createElement("video");
            remoteVideo.setAttribute("autoplay", "autoplay");
            remoteVideo.setAttribute("rel", peerId);
            attachMediaStream(remoteVideo, mediaStream);
            $(".remotevideos").appendChild(remoteVideo);
        };
        var onConnectionLost = function (remotePeer) {
            trace("onconnectionlost", arguments);
            var peerId = remotePeer.PeerId;
            var videoToRemove = $("video[rel='" + peerId + "']");
            $(".remotevideos").removeChild(videoToRemove);
        };
        var oncConnectionCreated = function () {
            console.log(arguments, rtc);
            trace("oncconnectioncreated", arguments);
        };
        var onGetUerMedia = function (stream) {
            trace("Successfully got some userMedia , hopefully a goat will appear..");
            rtc.connectToContext(); // connect to the current context?
        };
        var onRemoteStream = function (remotePeer) {
            addRemoteVideo(remotePeer.PeerId, remotePeer.stream);
            trace("Opps, we got a remote stream. lets see if its a goat..");
        };
        var onLocalStream = function (mediaStream) {
            trace("Got a localStream", mediaStream.id);
            attachMediaStream($(".localvideo video "), mediaStream);
            // if user click, video , call the recorder
            $(".localvideo video ").addEventListener("click", function () {
                recordMediaStream(rtc.getLocalStreams()[0]);
            });
        };
        var onContextCreated = function (ctx) {
            trace("RTC object created, and a context is created - ", ctx);
            rtc.getUserMedia(rtc.userMediaConstraints.hd(false), onGetUerMedia, onError);
        };
        var onOpen = function () {
            trace("Connected to the brokerController - 'connectionBroker'");
            rtc = new XSockets.WebRTC(this);
            rtc.onlocalstream = onLocalStream;
            rtc.oncontextcreated = onContextCreated;
            rtc.onconnectioncreated = oncConnectionCreated;
            rtc.onconnectionlost = onConnectionLost;
            rtc.onremotestream = onRemoteStream;
            rtc.onanswer = function (event) {
            };
            rtc.onoffer = function (event) {
            };
        };
        var onConnected = function () {
            trace("connection to the 'broker' server is established");
            trace("Try get the broker controller form server..");
            broker = ws.controller("connectionbroker");
            broker.onopen = onOpen;
        };
        ws.onconnected = onConnected;
    });
    document.addEventListener("DOMContentLoaded", main);
</script>

Le numéro de ligne 89 dans mon code de cas OnrecordComplete ajoute en fait un lien de fichier d’enregistreur. Si vous cliquez sur ce lien, le téléchargement commence, vous pouvez enregistrer ce chemin sur votre serveur en tant que fichier. 

Le code d'enregistrement ressemble à quelque chose comme ça

recorder.oncompleted = function (blob, blobUrl) {
                trace("Recorder completed.. ");
                var li = document.createElement("li");
                var download = document.createElement("a");
                download.textContent = new Date();
                download.setAttribute("download", XSockets.Utils.randomString(8) + ".webm");
                download.setAttribute("href", blobUrl);
                li.appendChild(download);
                $("ul").appendChild(li);
            };

Le blobUrl détient le chemin. J'ai résolu mon problème avec ça, j'espère que quelqu'un trouvera cela utile 

0
uniqueNt