Come registrare la webcam e l'audio utilizzando webRTC e una connessione peer basata su server


90

Vorrei registrare la webcam e l'audio degli utenti e salvarli in un file sul server. Questi file potrebbero quindi essere forniti ad altri utenti.

Non ho problemi con la riproduzione, tuttavia ho problemi a registrare il contenuto.

La mia comprensione è che la .record()funzione getUserMedia non è stata ancora scritta - finora è stata fatta solo una proposta.

Vorrei creare una connessione peer sul mio server utilizzando PeerConnectionAPI. Capisco che sia un po 'complicato, ma penso che dovrebbe essere possibile creare un peer sul server e registrare ciò che il client-peer invia.

Se questo è possibile, dovrei essere in grado di salvare questi dati in flv o in qualsiasi altro formato video.

La mia preferenza è in realtà quella di registrare la webcam + audio lato client, per consentire al client di registrare nuovamente i video se non gli è piaciuto il primo tentativo prima del caricamento. Ciò consentirebbe anche interruzioni nelle connessioni di rete. Ho visto un codice che consente la registrazione di singole "immagini" dalla webcam inviando i dati alla tela: è fantastico, ma ho bisogno anche dell'audio.

Ecco il codice lato client che ho finora:

  <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>

Ho lo stesso problema. Il metodo getRecordedData () funziona per te? Non è sui miei browser appena aggiornati.
Firas

No, ho provato anche "Google Canary".
Dave Hilditch,

Sì, lo tengo d'occhio: aggiornerò questo thread quando ci sarà una soluzione adeguata.
Dave Hilditch

2
se hai la soluzione della domanda sopra, condividila con me, grazie
Muhammad

2
Qualcuno è riuscito a ottenere i byte MediaStream tramite qualche magia RTC lato server?
Vinay

Risposte:


44

Dovresti assolutamente dare un'occhiata a Kurento . Fornisce un'infrastruttura server WebRTC che consente di registrare da un feed WebRTC e molto altro ancora. Puoi anche trovare alcuni esempi per l'applicazione che stai pianificando qui . È davvero facile aggiungere funzionalità di registrazione a quella demo e memorizzare il file multimediale in un URI (disco locale o dovunque).

Il progetto è concesso in licenza con LGPL Apache 2.0


MODIFICA 1

Da questo post, abbiamo aggiunto un nuovo tutorial che mostra come aggiungere il registratore in un paio di scenari

Disclaimer: faccio parte del team che sviluppa Kurento.


2
@Redtopia In alcuni recenti test di carico siamo stati in grado di ottenere 150 connessioni one2one di webrtc su una RAM i5 / 16GB. Puoi aspettarti che questi numeri saranno migliori in futuro, ma non aspettarti miracoli: c'è molta crittografia in corso per SRTP, e questo è impegnativo. Stiamo esaminando la crittografia / decrittografia con accelerazione hardware e i numeri aumenteranno, e anche se non posso assicurarti quanto sarà migliore finché non lo
testeremo

2
@ user344146 Probabilmente stavo rispondendo io. Ti dispiacerebbe condividere un link a quel post? Se hai ottenuto quella risposta, probabilmente è perché hai chiesto qualcosa che era già lì o nell'elenco. Sembra che tu stia cercando di compilare una versione SNAPSHOT. Questi artefatti non vengono pubblicati centralmente, quindi puoi controllare una versione dei tutorial o utilizzare il nostro repository di sviluppo interno. Questo ha avuto risposta nella lista molte volte, c'è una voce nella documentazione su come lavorare con le versioni di sviluppo ... Ci siamo presi il tempo per scriverlo, quindi sarebbe carino da parte tua dedicare del tempo a leggerlo.
igracia

2
Sto solo usando Kurento per fare tale registrazione. Non è complicato, ma serve un po 'di tempo per capire il concetto - perché alcuni documenti sono davvero meschini - e trovare quello che posso inviare a Kurento, o la descrizione di eventi e così via a volte può essere davvero frustrante. Ma comunque, un progetto aperto come questo è davvero un ottimo lavoro e vale la pena usarlo. Kurento funziona solo in Linux (la versione per Windows non è ufficiale e non funziona con tutte le funzionalità).
Krystian

1
Trovate le risposte alle domande di cui sopra (postando qui per altri), Kurento attualmente supporta JDK 7.0, non è che debba dipendere da Ubuntu 14.04, dovrebbe supportare anche le versioni successive, ma Kurento non è testato ufficialmente su altre versioni di Ubuntu / altra versione di Linux. Anche Kurento rilascia versioni a 64 bit prontamente disponibili per l'installazione, tuttavia puoi installare la versione a 32 bit del server ma devi prima crearla.
Bilbo Baggins

1
Sfortunatamente, come affermato nella mia risposta, lo sviluppo di Kurento ha subito un forte rallentamento dopo l'acquisizione di Twilio. Consiglio invece di usare Janus.
Jamix

17

Per favore, controlla RecordRTC

RecordRTC ha una licenza MIT su GitHub .


2
È davvero fantastico - la mia domanda: può registrare video e audio insieme (vivere un vero video piuttosto che due cose separate?)
Brian Dear,

D'accordo: fantastico, ma sembra che registri solo i dati separatamente.
Dave Hilditch

3
@BrianDear c'è un RecordRTC-together
Mifeng

2
Questo approccio funziona tramite Whammy.js in Chrome. Questo è problematico poiché la qualità tende ad essere molto inferiore rispetto all'emulazione che Whammy fornisce per la mancanza di un MediaStreamRecorder in Chrome. Ciò che accade essenzialmente è che WhammyRecorder punta un tag video all'URL dell'oggetto MediaStream e quindi scatta istantanee webp di un elemento canvas a una determinata frequenza di fotogrammi. Quindi utilizza Whammy per mettere insieme tutti quei fotogrammi in un video webm.
Vinay

15

Credo utilizzando kurento o altro MCU solo per la registrazione di video sarebbe po 'eccessivo, soprattutto se si considera il fatto che Chrome ha MediaRecorder il supporto API da v47 e Firefox dal V25. Quindi a questo incrocio, potresti non aver nemmeno bisogno di una libreria js esterna per fare il lavoro, prova questa demo che ho fatto per registrare video / audio usando MediaRecorder:

Demo : funzionerebbe in Chrome e Firefox (intenzionalmente omesso di spingere BLOB al codice del server)

Sorgente del codice GitHub

Se esegui Firefox, puoi testarlo qui stesso (Chrome ha bisogno 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>


Chrome 49 è il primo a supportare l'API MediaRecorder senza flag.
Ottaviano Naicu

7

sì, come hai capito, MediaStreamRecorder non è attualmente implementato.

MediaStreamRecorder è un'API WebRTC per la registrazione di flussi getUserMedia (). Consente alle app Web di creare un file da una sessione audio / video live.

in alternativa potresti fare questo http://ericbidelman.tumblr.com/post/31486670538/creating-webm-video-from-getusermedia ma la parte audio manca.


1
Sì, e puoi catturare il file audio, inviarlo al server e combinarli lì per creare un vero file video sul lato server. Ma questa soluzione potrebbe essere molto lenta sul lato client a seconda della configurazione del computer, in quanto deve creare file di immagine utilizzando una tela E catturare l'audio, e tutto questo nella RAM ... A proposito, il team di Firefox ci sta lavorando , quindi si spera che lo pubblicheranno presto.
Firas

4

È possibile utilizzare RecordRTC-together , che si basa su RecordRTC.

Supporta la registrazione di video e audio insieme in file separati. Avrai bisogno di uno strumento come ffmpegunire due file in uno sul server.


2
Questa è una soluzione browser, non lato server.
Brad

2

Web Call Server 4 può registrare audio e video WebRTC nel contenitore WebM. La registrazione viene eseguita utilizzando il codec Vorbis per l'audio e il codec VP8 per il video. I codec WebRTC iniziali sono Opus o G.711 e VP8. Quindi, la registrazione lato server richiede la transcodifica lato server da Opus / G.711 a Vorbis o la transcodifica VP8-H.264 se è necessario utilizzare un altro contenitore, ad esempio AVI.


è roba commerciale?
Stepan Yakovenko

0

Per la cronaca, inoltre, non ne ho abbastanza conoscenza,

Ma l'ho trovato su 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>

Sulla linea numero 89 nel mio caso il codice OnrecordComplete aggiunge effettivamente un collegamento al file del registratore, se clicchi su quel collegamento inizierà il download, puoi salvare quel percorso sul tuo server come file.

Il codice di registrazione ha un aspetto simile a questo

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);
            };

BlobUrl contiene il percorso. Ho risolto il mio problema con questo, spero che qualcuno lo trovi utile


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.