2015-03-17 03:13:51 +03:00
|
|
|
<html><head>
|
|
|
|
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
|
|
|
|
<title>Canvas RTCPeerConnection Filter Demo</title>
|
|
|
|
<style>
|
|
|
|
#video-container {
|
|
|
|
padding: 15px;
|
|
|
|
-moz-column-count: 3;
|
|
|
|
}
|
|
|
|
#preview {
|
|
|
|
position:relative;
|
|
|
|
height:400px;
|
|
|
|
}
|
|
|
|
#canvas {
|
|
|
|
height:400px;
|
|
|
|
}
|
|
|
|
#video {
|
|
|
|
height:400px;
|
|
|
|
}
|
|
|
|
#localvideo1 {
|
|
|
|
height:120px;
|
|
|
|
width:160px;
|
|
|
|
}
|
|
|
|
#mycanvas1 {
|
|
|
|
height:120px;
|
|
|
|
width:auto;
|
|
|
|
}
|
|
|
|
#pc2video {
|
|
|
|
height:auto;
|
|
|
|
width:100%;
|
|
|
|
max-height:380px;
|
|
|
|
}
|
|
|
|
#thebutton {
|
|
|
|
}
|
|
|
|
#buttons {
|
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
.hidden
|
|
|
|
{
|
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
</style>
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
|
|
|
|
<center>
|
|
|
|
<a href="index.html">Main webrtc demo page</a><br>
|
|
|
|
<h2>Canvas as a Filter for PeerConnection Demo</h2>
|
|
|
|
<b>NOTE: You need Firefox 41, and set canvas.capturestream.enabled to true in about:config!</b><br>
|
|
|
|
</center>
|
|
|
|
<div id="startstopbutton">
|
|
|
|
<button id="thebutton" onclick="xstart();">Start!</button>
|
|
|
|
</div>
|
|
|
|
<div id="video-container">
|
|
|
|
<div id="preview">
|
|
|
|
<h3>Local Preview</h3>
|
|
|
|
<video id="localvideo1" controls="controls" muted autoplay></video>
|
|
|
|
</div>
|
|
|
|
<div id="canvas">
|
|
|
|
<h3>Canvas</h3>
|
|
|
|
<div id="buttons"></div>
|
|
|
|
<canvas id="mycanvas1" width="640" height="480"></canvas>
|
|
|
|
</div>
|
|
|
|
<div id="video">
|
|
|
|
<h3>Remote Video</h3>
|
|
|
|
<video id="pc2video" controls="controls" muted autoplay></video>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div id="log"></div>
|
|
|
|
|
|
|
|
<script type="text/javascript" src="jquery.js"></script>
|
|
|
|
<script type="text/javascript" src="seriously.js"></script>
|
|
|
|
<script type="text/javascript" src="effects/seriously.invert.js"></script>
|
|
|
|
<script type="text/javascript" src="effects/seriously.ascii.js"></script>
|
|
|
|
<script type="text/javascript" src="effects/seriously.tvglitch.js"></script>
|
|
|
|
<script type="text/javascript" src="effects/seriously.hue-saturation.js"></script>
|
|
|
|
<script type="text/javascript" src="effects/seriously.select.js"></script>
|
|
|
|
|
2018-01-11 08:34:58 +03:00
|
|
|
<script type="application/javascript">
|
2015-03-17 03:13:51 +03:00
|
|
|
let pc2video = document.getElementById("pc2video");
|
|
|
|
|
|
|
|
let localvideo1 = document.getElementById("localvideo1");
|
|
|
|
|
|
|
|
let canvas = document.getElementById("canvas");
|
|
|
|
let canvas1 = document.getElementById("mycanvas1");
|
|
|
|
|
|
|
|
let thebutton = document.getElementById("thebutton");
|
|
|
|
let buttons = document.getElementById("buttons");
|
|
|
|
|
|
|
|
let logarea = document.getElementById("log");
|
|
|
|
|
|
|
|
let pc1;
|
|
|
|
let pc2;
|
|
|
|
|
|
|
|
let pc1_offer;
|
|
|
|
let pc2_answer;
|
|
|
|
|
|
|
|
let offer_constraints = { offerToReceiveVideo: false,
|
|
|
|
offerToReceiveAudio: false };
|
|
|
|
let answer_constraints = { offerToReceiveVideo: true,
|
|
|
|
offerToReceiveAudio: true };
|
|
|
|
|
|
|
|
let real_stream;
|
|
|
|
let canvas_stream;
|
|
|
|
|
|
|
|
var senders1 = [ ];
|
|
|
|
|
|
|
|
var seriously = new Seriously();
|
|
|
|
var source = seriously.source('#localvideo1');
|
|
|
|
var target = seriously.target('#mycanvas1');
|
|
|
|
var effects = {
|
|
|
|
invert: {},
|
|
|
|
tvglitch: {
|
|
|
|
distortion: 0.02,
|
|
|
|
verticalSync: 0,
|
|
|
|
scanlines: 0.22,
|
|
|
|
lineSync: 0.03,
|
|
|
|
frameSharpness: 10.67,
|
|
|
|
frameLimit: 0.3644,
|
|
|
|
bars: 0.55},
|
|
|
|
ascii: {},
|
|
|
|
'hue-saturation': {}
|
|
|
|
};
|
|
|
|
var select = seriously.effect('select', {
|
|
|
|
count: Object.keys(effects).length
|
|
|
|
});
|
|
|
|
source.on('ready', function() {
|
|
|
|
target.width = source.width;
|
|
|
|
target.height = target.height;
|
|
|
|
});
|
|
|
|
target.source = select;
|
|
|
|
Object.keys(effects).forEach(function (key, index) {
|
|
|
|
var effect = seriously.effect(key);
|
|
|
|
var opts = effects[key];
|
|
|
|
|
|
|
|
effect.source = '#localvideo1';
|
|
|
|
select['source' + index] = effect;
|
|
|
|
effects[key] = effect;
|
|
|
|
|
|
|
|
for (var k in opts) {
|
|
|
|
if (opts.hasOwnProperty(k)) {
|
|
|
|
effect[k] = opts[k];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var button = $('<button/>', {
|
|
|
|
text: key,
|
|
|
|
click: function() {
|
|
|
|
select.active = index;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
$('#buttons').append(button);
|
|
|
|
});
|
|
|
|
|
|
|
|
function log(msg) {
|
|
|
|
logarea.innerHTML = "<p>" + msg + "</p>" + logarea.innerHTML;
|
|
|
|
}
|
|
|
|
|
|
|
|
function failed(code) {
|
|
|
|
log("Failure callback: " + JSON.stringify(code));
|
|
|
|
}
|
|
|
|
|
|
|
|
function logReset() {
|
|
|
|
logarea.innerHTML = "";
|
|
|
|
}
|
|
|
|
|
|
|
|
// pc1.createOffer finished, call pc1.setLocal
|
|
|
|
function step1(offer) {
|
|
|
|
log("Offer: " + sdpPrettyPrint(offer.sdp));
|
|
|
|
pc1_offer = offer;
|
|
|
|
|
|
|
|
pc1.setLocalDescription(offer, step2, failed);
|
|
|
|
}
|
|
|
|
|
|
|
|
// replace CR NL with HTML breaks
|
|
|
|
function sdpPrettyPrint(sdp) {
|
|
|
|
return sdp.replace(/[\r\n]+/g, '<br>');
|
|
|
|
}
|
|
|
|
|
|
|
|
// pc1.setLocal finished, call pc2.setRemote
|
|
|
|
function step2() {
|
|
|
|
pc1.onicecandidate = function(obj) {
|
|
|
|
if (obj.candidate) {
|
|
|
|
log("pc1 found ICE candidate: " + JSON.stringify(obj.candidate));
|
|
|
|
pc2.addIceCandidate(obj.candidate);
|
|
|
|
} else {
|
|
|
|
log("pc1 got end-of-candidates signal");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pc2.setRemoteDescription(pc1_offer, step3, failed);
|
|
|
|
};
|
|
|
|
|
|
|
|
// pc2.setRemote finished, call pc2.createAnswer
|
|
|
|
function step3() {
|
|
|
|
pc2.didSetRemote = true;
|
|
|
|
while (pc2.ice_queued.length > 0) {
|
|
|
|
pc2.addIceCandidate(pc2.ice_queued.shift());
|
|
|
|
}
|
|
|
|
pc2.createAnswer(step4, failed, answer_constraints);
|
|
|
|
}
|
|
|
|
|
|
|
|
// pc2.createAnswer finished, call pc2.setLocal
|
|
|
|
function step4(answer) {
|
|
|
|
log("Answer: " + sdpPrettyPrint(answer.sdp));
|
|
|
|
pc2_answer = answer;
|
|
|
|
|
|
|
|
pc2.setLocalDescription(answer, step5, failed);
|
|
|
|
}
|
|
|
|
|
|
|
|
// pc2.setLocal finished, call pc1.setRemote
|
|
|
|
function step5() {
|
|
|
|
pc2.onicecandidate = function(obj) {
|
|
|
|
if (obj.candidate) {
|
|
|
|
log("pc2 found ICE candidate: " + JSON.stringify(obj.candidate));
|
|
|
|
pc1.addIceCandidate(obj.candidate);
|
|
|
|
} else {
|
|
|
|
log("pc2 got end-of-candidates signal");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pc1.setRemoteDescription(pc2_answer, step6, failed);
|
|
|
|
}
|
|
|
|
|
|
|
|
// pc1.setRemote finished, media should be running!
|
|
|
|
function step6() {
|
|
|
|
pc1.didSetRemote = true;
|
|
|
|
while (pc1.ice_queued.length > 0) {
|
|
|
|
pc1.addIceCandidate(pc1.ice_queued.shift());
|
|
|
|
}
|
|
|
|
log("Offer/Answer finished");
|
|
|
|
}
|
|
|
|
|
|
|
|
function xstart() {
|
|
|
|
thebutton.innerHTML = "Stop!";
|
|
|
|
thebutton.onclick = stop;
|
|
|
|
|
2023-02-04 00:28:16 +03:00
|
|
|
pc1 = new RTCPeerConnection();
|
|
|
|
pc2 = new RTCPeerConnection();
|
2015-03-17 03:13:51 +03:00
|
|
|
pc1.didSetRemote = false;
|
|
|
|
pc2.didSetRemote = false;
|
|
|
|
pc1.ice_queued = [];
|
|
|
|
pc2.ice_queued = [];
|
|
|
|
|
|
|
|
pc2.onicecandidate = function(obj) {
|
|
|
|
if (obj.candidate) {
|
|
|
|
log("pc2 found ICE candidate: " + JSON.stringify(obj.candidate));
|
|
|
|
if (pc1.didSetRemote) {
|
|
|
|
pc1.addIceCandidate(obj.candidate);
|
|
|
|
} else {
|
|
|
|
pc1.ice_queued.push(obj.candidate);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
log("pc2 got end-of-candidates signal");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pc1.onicecandidate = function(obj) {
|
|
|
|
if (obj.candidate) {
|
|
|
|
log("pc1 found ICE candidate: " + JSON.stringify(obj.candidate));
|
|
|
|
if (pc2.didSetRemote) {
|
|
|
|
pc2.addIceCandidate(obj.candidate);
|
|
|
|
} else {
|
|
|
|
pc2.ice_queued.push(obj.candidate);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
log("pc1 got end-of-candidates signal");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pc2.onaddstream = function(obj) {
|
|
|
|
log("pc2 got remote stream from pc1 " + obj.type);
|
2017-11-02 08:50:18 +03:00
|
|
|
pc2video.srcObject = obj.stream;
|
2015-03-17 03:13:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
var myrequest = { video: true };
|
|
|
|
|
|
|
|
navigator.mediaDevices.getUserMedia(myrequest).then(function(stream1) {
|
|
|
|
real_stream = stream1;
|
|
|
|
var local_stream = stream1;
|
|
|
|
|
2017-11-02 08:50:18 +03:00
|
|
|
localvideo1.srcObject = real_stream;
|
2015-03-17 03:13:51 +03:00
|
|
|
|
|
|
|
if (canvas1.captureStream) {
|
|
|
|
seriously.go(function () {
|
|
|
|
effects.tvglitch.time = Date.now();
|
|
|
|
});
|
|
|
|
|
|
|
|
canvas_stream = canvas1.captureStream(15);
|
|
|
|
local_stream = canvas_stream;
|
|
|
|
$('#mycanvas1').show();
|
|
|
|
$('#buttons').show();
|
|
|
|
} else {
|
|
|
|
canvas.innerHTML = canvas.innerHTML + "<p></p><h2>Missing canvas.captureStream() support</h2>";
|
|
|
|
}
|
|
|
|
|
|
|
|
local_stream.getTracks().forEach(function(track) {
|
|
|
|
senders1[track.kind] = pc1.addTrack(track, local_stream);
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
pc1.createOffer(step1, failed, offer_constraints);
|
|
|
|
}, failed);
|
|
|
|
}
|
|
|
|
|
|
|
|
function stop() {
|
|
|
|
$('#mycanvas1').hide();
|
|
|
|
$('#buttons').hide();
|
|
|
|
localvideo1.pause();
|
2017-11-02 08:50:18 +03:00
|
|
|
localvideo1.srcObject = null;
|
2015-03-17 03:13:51 +03:00
|
|
|
pc2video.pause();
|
2017-11-02 08:50:18 +03:00
|
|
|
pc2video.srcObject = null;
|
2015-03-17 03:13:51 +03:00
|
|
|
real_stream.getTracks().forEach(function(track) {
|
|
|
|
track.stop();
|
|
|
|
});
|
|
|
|
real_stream = null;
|
|
|
|
if (canvas_stream) {
|
|
|
|
canvas_stream.getTracks().forEach(function(track) {
|
|
|
|
track.stop();
|
|
|
|
});
|
|
|
|
canvas_stream = null;
|
|
|
|
}
|
|
|
|
pc1.close();
|
|
|
|
pc2.close();
|
|
|
|
pc1 = null;
|
|
|
|
pc2 = null;
|
|
|
|
|
|
|
|
senders1 = [];
|
|
|
|
|
|
|
|
thebutton.innerHTML = "Start!";
|
|
|
|
thebutton.onclick = xstart;
|
|
|
|
|
|
|
|
logReset();
|
|
|
|
}
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
</body></html>
|