簡體   English   中英

如何使用 webRTC 和基於服務器的對等連接來錄制網絡攝像頭和音頻

[英]How to record webcam and audio using webRTC and a server-based Peer connection

我想記錄用戶的網絡攝像頭和音頻並將其保存到服務器上的文件中。 然后,這些文件將能夠提供給其他用戶。

我在播放方面沒有問題,但是在獲取要錄制的內容時遇到了問題。

我的理解是 getUserMedia .record() function 尚未編寫 - 到目前為止只提出了一個建議。

我想使用 PeerConnectionAPI 在我的服務器上創建對等連接。 我知道這有點 hacky,但我認為應該可以在服務器上創建一個對等點並記錄客戶端對等點發送的內容。

如果可能的話,我應該能夠將這些數據保存為 flv 或任何其他視頻格式。

我的偏好實際上是在客戶端錄制網絡攝像頭 + 音頻,以允許客戶端在上傳前不喜歡他們的第一次嘗試時重新錄制視頻。 這也將允許中斷網絡連接。 我看到一些代碼允許通過將數據發送到 canvas 從網絡攝像頭記錄個人“圖像”——這很酷,但我也需要音頻。

這是我到目前為止的客戶端代碼:

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

你絕對應該看看Kurento 它提供了一個 WebRTC 服務器基礎設施,允許您從 WebRTC 提要等進行記錄。 您還可以在此處找到您正在規划的應用程序的一些示例。 向該演示添加錄制功能並將媒體文件存儲在 URI(本地磁盤或任何地方)中非常容易。

該項目在LGPL Apache 2.0 下獲得許可


編輯 1

自從這篇文章以來,我們添加了一個新教程,展示了如何在幾個場景中添加記錄器

免責聲明:我是開發 Kurento 團隊的一員。

我相信僅使用 kurento 或其他 MCU 來錄制視頻會有點矯枉過正,尤其是考慮到 Chrome 從 v47 和 Firefox 自 v25 開始就支持MediaRecorder API。 所以在這個路口,你甚至可能不需要外部 js 庫來完成這項工作,試試我制作的這個使用 MediaRecorder 錄制視頻/音頻的演示:

演示- 可以在 chrome 和 firefox 中工作(故意省略將 blob 推送到服務器代碼)

Github 代碼源

如果運行 firefox,你可以在這里測試它本身(chrome 需要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>

請檢查RecordRTC

RecordRTC 在github 上獲得了麻省理工學院的許可。

是的,正如您所理解的,MediaStreamRecorder 目前尚未實現。

MediaStreamRecorder 是一個用於記錄 getUserMedia() 流的 WebRTC API。 它允許網絡應用程序從實時音頻/視頻會話創建文件。

或者,您可以這樣做http://ericbidelman.tumblr.com/post/31486670538/creating-webm-video-from-getusermedia但缺少音頻部分。

您可以使用基於 RecordRTC 的 RecordRTC-together

它支持在單獨的文件中一起錄制視頻和音頻。 您將需要ffmpeg工具將服務器上的兩個文件合並為一個。

Web Call Server 4可以將 WebRTC 音頻和視頻錄制到 WebM 容器中。 錄制使用 Vorbis 編解碼器進行音頻和 VP8 編解碼器進行視頻。 最初的 WebRTC 編解碼器是 Opus 或 G.711 和 VP8。 因此,如果需要使用其他容器,即 AVI,服務器端錄制需要 Opus/G.711 到 Vorbis 服務器端轉碼或 VP8-H.264 轉碼。

看看Janus。 這是一個錄音演示:

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

與收購Twilio后發展速度嚴重放緩的Kurento不同,Janus繼續積極開發和支持。

作為記錄,我對此也沒有足夠的了解,

但是我在 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>

在我的案例代碼中,在第 89 行代碼 OnrecordComplete 實際上附加了一個記錄器文件的鏈接,如果您單擊該鏈接,它將開始下載,您可以將該路徑保存為您的服務器的文件。

錄音代碼看起來像這樣

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 保存路徑。 我用這個解決了我的問題,希望有人會覺得這很有用

目前瀏覽器支持客戶端錄制。

https://webrtc.github.io/samples/

可以在連接結束后通過一些 HTTP 請求上傳將錄制的文件推送到服務器。

https://webrtc.github.io/samples/src/content/getusermedia/record/ https://github.com/webrtc/samples/tree/gh-pages/src/content/getusermedia/record

這有一些缺點,如果用戶只是關閉選項卡而不在后端運行這些操作,則可能無法將文件完全上傳到服務器。

作為更穩定的解決方案Ant Media Server可以在服務器端錄制stream,錄制功能是Ant Media Server的基本功能之一。

antmedia.io

注意:我是 Ant 媒體團隊的成員。

從技術上講,您可以在后端使用 FFMPEG 來混合視頻和音頻

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM