Aufzeichnen von Webcam und Audio mit webRTC und einer serverbasierten Peer-Verbindung

88

Ich möchte die Webcam und das Audio des Benutzers aufzeichnen und in einer Datei auf dem Server speichern. Diese Dateien könnten dann anderen Benutzern zur Verfügung gestellt werden.

Ich habe keine Probleme mit der Wiedergabe, aber ich habe Probleme, den Inhalt aufzunehmen.

Ich verstehe, dass die .record()Funktion getUserMedia noch nicht geschrieben wurde - bisher wurde nur ein Vorschlag dafür gemacht.

Ich möchte mithilfe der PeerConnectionAPI eine Peer-Verbindung auf meinem Server herstellen. Ich verstehe, dass dies ein bisschen hackig ist, aber ich denke, es sollte möglich sein, einen Peer auf dem Server zu erstellen und aufzuzeichnen, was der Client-Peer sendet.

Wenn dies möglich ist, sollte ich diese Daten in flv oder einem anderen Videoformat speichern können.

Eigentlich bevorzuge ich die clientseitige Aufnahme von Webcam + Audio, damit der Client Videos erneut aufnehmen kann, wenn ihm der erste Versuch vor dem Hochladen nicht gefallen hat. Dies würde auch Unterbrechungen bei Netzwerkverbindungen ermöglichen. Ich habe einen Code gesehen, mit dem einzelne "Bilder" von der Webcam aufgezeichnet werden können, indem die Daten auf die Leinwand gesendet werden - das ist cool, aber ich brauche auch Audio.

Hier ist der clientseitige Code, den ich bisher habe:

  <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>
Dave Hilditch
quelle
Ich habe das gleiche Problem. Funktioniert die Methode getRecordedData () für Sie? Es ist nicht in meinen frisch aktualisierten Browsern.
Firas
Nein - ich habe auch "Google Canary" ausprobiert.
Dave Hilditch
Ja, ich behalte es im Auge - ich werde diesen Thread aktualisieren, wenn es eine richtige Lösung gibt.
Dave Hilditch
2
Wenn Sie die Lösung der obigen Frage haben, teilen Sie mir bitte mit, Danke
Muhammad
2
Hat es jemand geschafft, über serverseitige RTC-Magie auf die MediaStream-Bytes zuzugreifen?
Vinay

Antworten:

44

Sie sollten sich unbedingt Kurento ansehen . Es bietet eine WebRTC-Serverinfrastruktur, mit der Sie aus einem WebRTC-Feed und vielem mehr aufnehmen können. Sie können auch einige Beispiele für die Anwendung finden Sie planen , hier . Es ist wirklich einfach, dieser Demo Aufnahmefunktionen hinzuzufügen und die Mediendatei in einer URI (lokale Festplatte oder wo auch immer) zu speichern.

Das Projekt ist unter LGPL Apache 2.0 lizenziert


BEARBEITEN 1

Seit diesem Beitrag haben wir ein neues Tutorial hinzugefügt, das zeigt, wie der Rekorder in einigen Szenarien hinzugefügt wird

Haftungsausschluss: Ich bin Teil des Teams, das Kurento entwickelt.

igracia
quelle
2
@ Redtopia In einigen kürzlich durchgeführten Lasttests konnten wir 150 one2one-Verbindungen von webrtc auf einem i5 / 16 GB RAM erhalten. Sie können davon ausgehen, dass diese Zahlen in Zukunft besser sein werden, aber erwarten Sie keine Wunder: Für SRTP wird viel verschlüsselt, und das ist anspruchsvoll. Wir beschäftigen uns mit hardwarebeschleunigter Verschlüsselung / Entschlüsselung, und die Zahlen werden steigen, und obwohl ich Ihnen nicht versichern kann, wie viel besser es sein wird, bis wir es gründlicher testen, erwarten wir eine
dreifache
2
@ user344146 Das habe ich wohl beantwortet. Würde es Ihnen etwas ausmachen, einen Link zu diesem Beitrag zu teilen? Wenn Sie diese Antwort erhalten haben, liegt dies wahrscheinlich daran, dass Sie etwas gefragt haben, das bereits vorhanden oder in der Liste enthalten war. Anscheinend haben Sie versucht, eine SNAPSHOT-Version zu kompilieren. Diese Artefakte werden nicht zentral veröffentlicht. Sie können also entweder eine Version der Tutorials auschecken oder unser internes Entwickler-Repo verwenden. Dies wurde in der Liste schon oft beantwortet, es gibt einen Eintrag in der Dokumentation über die Arbeit mit Entwicklungsversionen ... Wir haben uns die Zeit genommen, es zu schreiben, also wäre es nett von Ihnen, sich die Zeit zu nehmen, es zu lesen.
igracia
2
Ich benutze nur Kurento, um solche Aufnahmen zu machen. Ich bin nicht kompliziert, brauche aber ein wenig Zeit, um das Konzept zu verstehen - da einige der Dokumente wirklich gemein sind - und zu finden, was ich an kurento senden kann, oder eine Beschreibung von Ereignissen usw. kann manchmal sehr frustrierend sein. Aber trotzdem - ein offenes Projekt wie dieses ist wirklich ein großartiger Job und es lohnt sich, ihn zu nutzen. Kurento funktioniert nur unter Linux (die Windows-Version ist nicht offiziell und funktioniert nicht mit voller Funktionalität).
Krystian
1
Kurento hat derzeit JDK 7.0 unterstützt. Es ist nicht so, dass es von Ubuntu 14.04 abhängig sein muss, es sollte auch spätere Versionen unterstützen, aber Kurento wird nicht offiziell auf anderen Versionen von Ubuntu getestet / andere Linux-Version. Kurento veröffentlicht auch 64-Bit-Versionen, die für die Installation verfügbar sind. Sie können jedoch eine 32-Bit-Version des Servers installieren, müssen diese jedoch zuerst erstellen.
Bilbo Beutlin
1
Wie in meiner Antwort erwähnt, hat sich die Entwicklung von Kurento nach der Übernahme von Twilio leider stark verlangsamt. Ich empfehle stattdessen Janus zu verwenden.
Jamix
17

Bitte überprüfen Sie die RecordRTC

RecordRTC ist MIT-lizenziert auf Github .

Dmitry
quelle
2
Das ist ziemlich großartig - meine Frage: Kann das Video und Audio zusammen aufnehmen (Live ein echtes Video statt zwei getrennte Dinge?)
Brian Dear
Einverstanden - großartig, aber es sieht so aus, als würden die Daten nur separat aufgezeichnet.
Dave Hilditch
3
@ BrianDear gibt es eine RecordRTC-zusammen
Mifeng
2
Dieser Ansatz funktioniert über Whammy.js in Chrome. Dies ist problematisch, da die Qualität der Emulation, die Whammy für das Fehlen eines MediaStreamRecorders in Chrome bereitstellt, tendenziell viel geringer ist. Im Wesentlichen zeigt WhammyRecorder ein Video-Tag auf die MediaStream-Objekt-URL und erstellt dann Webp-Snapshots eines Canvas-Elements mit einer bestimmten Bildrate. Anschließend werden Whammy verwendet, um alle diese Frames zu einem Webm-Video zusammenzufügen.
Vinay
13

Ich glaube, die Verwendung von Kurento oder anderen MCUs nur zum Aufzeichnen von Videos wäre etwas übertrieben, insbesondere angesichts der Tatsache, dass Chrome seit Version 25 MediaRecorder API-Unterstützung von Version 47 und Firefox bietet. An dieser Kreuzung benötigen Sie möglicherweise nicht einmal eine externe JS-Bibliothek, um die Aufgabe zu erledigen. Probieren Sie diese Demo aus, die ich zum Aufnehmen von Video / Audio mit MediaRecorder erstellt habe:

Demo - würde in Chrome und Firefox funktionieren (absichtlich weggelassen, Blob auf Servercode zu schieben)

Github-Codequelle

Wenn Sie Firefox ausführen, können Sie es hier selbst testen (Chrome-Anforderungen 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>

mido
quelle
Chrome 49 ist das erste Unternehmen, das die MediaRecorder-API ohne Flag unterstützt.
Octavian Naicu
7

Ja, wie Sie verstanden haben, ist MediaStreamRecorder derzeit nicht implementiert.

MediaStreamRecorder ist eine WebRTC-API zum Aufzeichnen von getUserMedia () - Streams. Damit können Web-Apps eine Datei aus einer Live-Audio- / Videositzung erstellen.

Alternativ können Sie diese http://ericbidelman.tumblr.com/post/31486670538/creating-webm-video-from-getusermedia mögen, aber Audio fehlt Teil.

Konga Raju
quelle
1
Ja, und Sie können die Audiodatei erfassen, an den Server senden und dort kombinieren, um eine echte Videodatei auf der Serverseite zu erstellen. Diese Lösung kann jedoch auf der Clientseite je nach Computerkonfiguration sehr langsam sein, da Bilddateien mithilfe einer Zeichenfläche erstellt UND das Audio erfasst werden müssen, und dies alles im RAM ... Übrigens arbeitet das Firefox-Team daran , also hoffentlich werden sie es bald veröffentlichen.
Firas
4

Sie können RecordRTC-together verwenden , das auf RecordRTC basiert.

Es unterstützt die gemeinsame Aufnahme von Video und Audio in separaten Dateien. Sie benötigen ein Tool ffmpeg, um zwei Dateien auf dem Server zu einer zusammenzuführen.

Mifeng
quelle
2
Dies ist eine Browser-Lösung, nicht serverseitig.
Brad
2

Web Call Server 4 kann WebRTC-Audio und -Video in einen WebM-Container aufnehmen. Die Aufnahme erfolgt mit dem Vorbis-Codec für Audio und dem VP8-Codec für Video. Anfängliche WebRTC-Codecs sind Opus oder G.711 und VP8. Für die serverseitige Aufzeichnung ist daher entweder die serverseitige Transcodierung von Opus / G.711 nach Vorbis oder die Transcodierung nach VP8-H.264 erforderlich, wenn ein anderer Container, z. B. AVI, verwendet werden muss.

Bob42
quelle
ist das kommerzielles Zeug?
Stepan
0

Für die Aufzeichnung habe ich auch nicht genug Wissen darüber,

Aber ich fand das auf 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>

In Zeile 89 in meinem Fallcode OnrecordComplete wird tatsächlich ein Link der Rekorderdatei angehängt. Wenn Sie auf diesen Link klicken, wird der Download gestartet, und Sie können diesen Pfad als Datei auf Ihrem Server speichern.

Der Aufzeichnungscode sieht ungefähr so ​​aus

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

Das blobUrl hält den Pfad. Ich habe mein Problem damit gelöst und hoffe, dass jemand dies nützlich findet

uniqueNt
quelle
-4

Technisch gesehen können Sie FFMPEG im Backend verwenden, um Video und Audio zu mischen

EugeneB
quelle
7
Ja, aber wie bringt man sie dorthin?
Eddie Monge Jr