WebRTC ve sunucu tabanlı Eş bağlantısı kullanılarak web kamerası ve ses nasıl kaydedilir


91

Kullanıcıların web kamerasını ve sesini kaydetmek ve sunucudaki bir dosyaya kaydetmek istiyorum. Bu dosyalar daha sonra diğer kullanıcılara sunulabilir.

Kayıttan yürütmeyle ilgili herhangi bir sorun yaşamıyorum, ancak içeriği kaydederken sorun yaşıyorum.

Anladığım kadarıyla getUserMedia .record()işlevi henüz yazılmadı - şimdiye kadar sadece bir öneri yapıldı.

PeerConnectionAPI kullanarak sunucumda bir eş bağlantı oluşturmak istiyorum. Bunun biraz zor olduğunu anlıyorum, ancak sunucuda bir eş oluşturmanın ve istemci eşinin gönderdiklerini kaydetmenin mümkün olması gerektiğini düşünüyorum.

Bu mümkünse, bu verileri flv veya başka bir video formatında kaydedebilmeliyim.

Tercihim, istemcinin yüklemeden önce ilk denemesini beğenmediyse videoları yeniden kaydetmesine izin vermek için web kamerası + ses istemci tarafını kaydetmek. Bu, ağ bağlantılarında kesintilere de izin verir. Verileri tuvale göndererek web kamerasından tek tek 'görüntülerin' kaydedilmesine izin veren bazı kodlar gördüm - bu harika, ancak sese de ihtiyacım var.

Şimdiye kadar sahip olduğum müşteri tarafı kodu:

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

Bende de aynı sorun var. GetRecordedData () yöntemi sizin için çalışıyor mu? Yeni güncellenen tarayıcılarımda değil.
Firas

Hayır - 'Google Canary'yi de denedim.
Dave Hilditch

Evet, onu yakından takip ediyorum - uygun bir çözüm olduğunda bu konuyu güncelleyeceğim.
Dave Hilditch

2
Yukarıdaki sorunun çözümüne sahipseniz lütfen benimle paylaşın, Teşekkürler
Muhammed

2
Herhangi bir sunucu tarafı RTC sihri aracılığıyla MediaStream baytlarına ulaşabilen oldu mu?
Vinay

Yanıtlar:


45

Kurento'ya mutlaka bir göz atmalısınız . Bir WebRTC beslemesinden kayıt yapmanızı ve daha fazlasını sağlayan bir WebRTC sunucu altyapısı sağlar. Ayrıca burada planladığınız uygulama için bazı örnekler bulabilirsiniz . Bu demoya kayıt yetenekleri eklemek ve medya dosyasını bir URI'de (yerel disk veya herhangi bir yerde) depolamak gerçekten çok kolay.

Proje, LGPL Apache 2.0 altında lisanslanmıştır.


DÜZENLE 1

Bu gönderiden bu yana, kayıt cihazının birkaç senaryoda nasıl ekleneceğini gösteren yeni bir eğitim ekledik.

Feragatname: Kurento'yu geliştiren ekibin bir parçasıyım.


2
@Redtopia Son zamanlarda yapılan bazı yük testlerinde, i5 / 16GB RAM üzerinde 150 one2one webrtc bağlantısı elde edebildik. Bu sayıların gelecekte daha iyi olmasını bekleyebilirsiniz, ancak mucizeler beklemeyin: SRTP için çok fazla şifreleme sürüyor ve bu zorlu. Biz donanım hızlandırmalı şifreleme / şifre çözme inceliyoruz ve sayılar daha yüksek gidecek ve seni temin edemez ama biz daha iyice test kadar olacak ne kadar daha iyi, biz bekliyoruz 3x iyileştirme
igracia

2
@ user344146 Muhtemelen cevap veren bendim. Bu gönderinin bağlantısını paylaşır mısın? Bu cevabı aldıysanız, muhtemelen zaten var olan veya listede olan bir şeyi sorduğunuz içindir. Görünüşe göre bir SNAPSHOT sürümünü derlemeye çalışıyorsunuz. Bu eserler merkezde yayınlanmıyor, bu yüzden ya eğitimlerin bir sürümünü kontrol edin ya da dahili geliştirme depomuzu kullanın. Bu listede birçok kez cevaplandı, dokümantasyonda geliştirme sürümleriyle çalışmakla ilgili bir girdi var ... Yazmak için zaman ayırdık, bu yüzden okumak için zaman ayırmanız iyi olur.
igracia

2
Böyle bir kayıt yapmak için sadece Kurento kullanıyorum. Karmaşık değil ama kavramı anlamak için biraz zamana ihtiyacım var - çünkü bazı dokümanlar gerçekten kaba - ve kurento'ya ne gönderebileceğimi veya olayların açıklamasını vb. Bulmak bazen gerçekten sinir bozucu olabilir. Ama yine de - bunun gibi açık bir proje gerçekten harika bir iş ve kullanmaya değer. Kurento yalnızca Linux'ta çalışıyor (Windows sürümü resmi değil ve tam işlevsellikle çalışmıyor).
Krystian

1
Yukarıdaki sorulara cevaplar bulundu (diğerleri için burada yayınlayın), Kurento şu anda JDK 7.0'ı destekliyor, Ubuntu 14.04'e bağlı olması gerekmiyor, sonraki sürümleri de desteklemesi gerekiyor, ancak Kurento resmi olarak Ubuntu'nun diğer sürümlerinde test edilmedi / diğer linux sürümü. Ayrıca Kurento, kuruluma hazır 64 bit sürümleri yayınlar, ancak sunucunun 32 bit sürümünü kurabilirsiniz, ancak önce onu oluşturmanız gerekir.
Bilbo Baggins

1
Maalesef cevabımda belirtildiği gibi, Twilio'nun satın alınmasından sonra Kurento'nun gelişimi ciddi şekilde yavaşladı. Bunun yerine Janus kullanmanızı tavsiye ederim.
jamix

18

Lütfen RecordRTC'yi kontrol edin

RecordRTC MİT üzerinde lisanslı github .


2
Bu oldukça harika - sorum: bu video ve sesi birlikte kaydedebilir mi (iki ayrı şey yerine gerçek bir video yaşayabilir mi?)
Brian Sevgili

Kabul edildi - harika, ancak verileri yalnızca ayrı olarak kaydettiği görülüyor.
Dave Hilditch

3
@BrianDear tane var RecordRTC-araya
Mifeng

3
Bu yaklaşım, Chrome'da Whammy.js aracılığıyla çalışır. Bu sorunludur çünkü kalite, Whammy'nin Chrome'un MediaStreamRecorder eksikliğini sağladığı öykünmeden çok daha düşük olma eğilimindedir. Esasen olan şey, WhammyRecorder'ın bir video etiketini MediaStream nesnesi URL'sine işaret etmesi ve ardından belirli bir kare hızında bir tuval öğesinin webp anlık görüntülerini almasıdır. Daha sonra tüm bu kareleri bir webm videosunda bir araya getirmek için Whammy kullanır.
Vinay

15

Sadece video kaydetmek için kurento veya diğer MCU'ları kullanmanın, özellikle Chrome'un v47 ve Firefox'tan v25'ten beri MediaRecorder API desteğine sahip olduğu gerçeğini göz önünde bulundurarak, biraz abartılı olacağına inanıyorum. Yani bu bağlantı noktasında, işi yapmak için harici bir js kitaplığına bile ihtiyacınız olmayabilir, MediaRecorder'ı kullanarak video / ses kaydetmek için yaptığım bu demoyu deneyin:

Demo - chrome ve firefox'ta çalışır (kasıtlı olarak blob'u sunucu koduna göndermeyi bıraktı)

Github Kod Kaynağı

Firefox çalıştırıyorsanız, burada kendi içinde test edebilirsiniz (Chrome ihtiyacı 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, MediaRecorder API'yi bayrak olmadan destekleyen ilk üründür.
Octavian Naicu

7

evet, anladığınız gibi, MediaStreamRecorder şu anda uygulanmıyor.

MediaStreamRecorder, getUserMedia () akışlarını kaydetmek için bir WebRTC API'sidir. Web uygulamalarının canlı bir ses / video oturumundan bir dosya oluşturmasına izin verir.

alternatif olarak bu http://ericbidelman.tumblr.com/post/31486670538/creating-webm-video-from-getusermedia'yı beğenebilirsiniz , ancak ses eksiktir.


1
Evet, ses dosyasını yakalayabilir, sunucuya gönderebilir ve sunucu tarafında gerçek bir video dosyası oluşturmak için bunları orada birleştirebilirsiniz. Ancak bu çözüm, bilgisayar yapılandırmasına bağlı olarak istemci tarafında çok yavaş olabilir, çünkü bir tuval kullanarak görüntü dosyaları oluşturmak VE sesi yakalamak zorundadır ve bunların tümü RAM'de ... Btw, firefox ekibi bunun üzerinde çalışıyor , umarım yakında yayınlarlar.
Firas

4

RecordRTC'yi temel alan RecordRTC'yi birlikte kullanabilirsiniz .

Video ve sesi ayrı dosyalarda birlikte kaydetmeyi destekler. ffmpegSunucuda iki dosyayı tek bir dosyada birleştirmek gibi bir araca ihtiyacınız olacak .


2
Bu bir tarayıcı çözümüdür, sunucu tarafı değil.
Brad

2

Web Çağrı Sunucusu 4 , WebRTC sesini ve videoyu WebM konteynerine kaydedebilir. Kayıt, ses için Vorbis kodeği ve video için VP8 kodeği kullanılarak yapılır. İlk WebRTC codec bileşenleri Opus veya G.711 ve VP8'dir. Bu nedenle, sunucu tarafında kayıt, başka bir konteyner, yani AVI kullanmak gerekirse, Opus / G.711'den Vorbis'e sunucu tarafı kod dönüştürmesini veya VP8-H.264 kod dönüştürmesini gerektirir.


bu ticari şeyler mi?
Stepan Yakovenko

0

Kayıt için bu konuda da yeterli bilgim yok.

Ama bunu Git hub'da buldum.

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

OnrecordComplete adlı vaka kodumda 89 numaralı satırda aslında kaydedici dosyasının bir bağlantısını ekliyor, bu bağlantıya tıklarsanız indirmeye başlayacak, bu yolu sunucunuza dosya olarak kaydedebilirsiniz.

Kayıt kodu şuna benzer

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 yolu tutar. Sorunumu bununla çözdüm, umarım birisi bunu faydalı bulacaktır


-4

Teknik olarak video ve sesi karıştırmak için arka uçta FFMPEG kullanabilirsiniz


7
evet ama onları oraya nasıl götüreceksin?
Eddie Monge Jr
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.