Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multistreams with Green Screen Effect #310

Open
wants to merge 25 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e5f5fb0
In the instructions, you forgot to copy the dist file
jimver04 Nov 22, 2021
dcde012
In the instructions, you forgot to copy the dist file
jimver04 Jan 24, 2022
c671683
Merge branch 'networked-aframe:master' into master
jimver04 Jan 24, 2022
dfd0258
Video Multistream with shaders.v1.
jimver04 Jan 25, 2022
4a31658
Video Multistream with shaders.v2. Success !!!
jimver04 Jan 25, 2022
69e15c4
Video Multistream with shaders.v3. Improvements.
jimver04 Jan 25, 2022
c14f2ce
Green Screen Video Stream with shaders.v4. Final.
jimver04 Jan 25, 2022
79b4ed1
Green Screen Video Stream with shaders. Final.
jimver04 Jan 25, 2022
cff676f
Some of Vincent's comments addressed, but the main comment about the …
jimver04 Feb 4, 2022
97465a0
Ship is almost ready
jimver04 Feb 4, 2022
037dee5
Merge branch 'networked-aframe:master' into master
jimver04 Feb 6, 2022
a2a4853
Add to networked-video-source.js component the ability to do the gree…
jimver04 Feb 6, 2022
9d8e234
Add to networked-video-source.js component the ability to do the gree…
jimver04 Feb 6, 2022
e4e7fe2
Merge remote-tracking branch 'origin/master'
jimver04 Feb 6, 2022
9534e7d
Add to networked-video-source.js component the ability to do the gree…
jimver04 Feb 6, 2022
3be52f4
Add to networked-video-source.js component the ability to do the gree…
jimver04 Feb 18, 2022
08cad64
Todo:
jimver04 Feb 23, 2022
a99cdb2
Todo:
jimver04 Feb 26, 2022
dec412b
Todo:
jimver04 Feb 26, 2022
fce4925
Green screen and size ok. Todo: Crop and move panel
jimver04 Feb 28, 2022
7f97564
Move unecessary examples to a folder
jimver04 Jun 23, 2022
5ad1b98
Latest tide up
jimver04 Jun 27, 2022
5e6cc38
Latest tide up
jimver04 Jun 28, 2022
319e7f7
Tide up Client
jimver04 Aug 5, 2022
57f1707
Simple Client Prototype finalized
jimver04 Aug 5, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
24 changes: 18 additions & 6 deletions dist/networked-aframe.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/networked-aframe.min.js

Large diffs are not rendered by default.

30 changes: 30 additions & 0 deletions docs/getting-started-local.md
Original file line number Diff line number Diff line change
Expand Up @@ -371,3 +371,33 @@ I would love love love you to send me cool examples you've made, and I'm looking

[@HaydenLee37](https://twitter.com/haydenlee37)

--------

#Stopping NAF

How to stop NAF ?

As you have observed there is no stop command. If you are in a Linux based server, e.g. Ubuntu, try the following commands to Find and Kill (the process that you have initiated for NAF).

**1. Find**

`sudo lsof -i:8080`

With this command you find where node server listens (change 8080 to whatever port you use)

Then you will get a big report that has also a line beginning with **node**

`COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME

node 3766 JohnSmith 20u IPv4 27606 0t0 TCP *:8080 (LISTEN)`


You want the second field namely ProcessID which happens for me to be 3766 but for you will be another number


**2. Kill**

**sudo kill -9 3766**



Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On Linux, a process that runs in a terminal in foreground can be stopped with Ctrl+C.
Is this not working for you?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The process might be initialized with a cron job or some other way. We usually put an automatic way in case for some reason the server restarts. So , in order to kill it you must search it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. Generally pm2 is used to deploy a nodejs app, to start it as a service. Last time I deployed easyrtc-server.js on a test server I read https://www.digitalocean.com/community/tutorials/how-to-set-up-a-node-js-application-for-production-on-ubuntu-16-04 and used this:

$ sudo npm install -g pm2
$ pm2 start easyrtc-server.js
                          Runtime Edition

        PM2 is a Production Process Manager for Node.js applications
                     with a built-in Load Balancer.

                Start and Daemonize any application:
                $ pm2 start app.js

                Load Balance 4 instances of api.js:
                $ pm2 start api.js -i 4

                Monitor in production:
                $ pm2 monitor

                Make pm2 auto-boot at server restart:
                $ pm2 startup

                To go further checkout:
                http://pm2.io/


                        -------------

[PM2] Spawning PM2 daemon with pm2_home=/home/vincentfretin/.pm2
[PM2] PM2 Successfully daemonized
[PM2] Starting /home/vincentfretin/vr/easyrtc-server.js in fork_mode (1 instance)
[PM2] Done.
┌────────────────┬────┬──────┬────────┬───┬─────┬───────────┐
│ Name           │ id │ mode │ status │ ↺ │ cpu │ memory    │
├────────────────┼────┼──────┼────────┼───┼─────┼───────────┤
│ easyrtc-server │ 0  │ fork │ online │ 0 │ 0%  │ 29.6 MB   │
└────────────────┴────┴──────┴────────┴───┴─────┴───────────┘
 Use `pm2 show <id|name>` to get more details about an app


vincentfretin@server1:~/vr$ pm2 startup
[PM2] Init System found: systemd
[PM2] To setup the Startup Script, copy/paste the following command:
sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u vincentfretin --hp /home/vincentfretin

[PM2] Freeze a process list on reboot via:
$ pm2 save

[PM2] Remove init script via:
$ pm2 unstartup systemd

Show info about the app:

    pm2 show easyrtc-server

Show logs:

    tail -f /home/vincentfretin/.pm2/logs/easyrtc-server-out.log

Feel free to modify your doc to include that.

227 changes: 227 additions & 0 deletions examples/advanced-video-green-screen.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
<html>
<head>
<!-- Dimitrios Ververidis for CERTH/ITI, 25/1/2022 -->
<meta charset="utf-8">
<title>Multi Streams Example — Networked-Aframe</title>

<meta name="description" content="Dev Example — Networked-Aframe with Green Screen effect">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />


<script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.slim.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.7/dat.gui.min.js"></script>
<script src="/easyrtc/easyrtc.js"></script>
<script src="/dist/networked-aframe.js"></script>

<script src="https://unpkg.com/aframe-randomizer-components@^3.0.1/dist/aframe-randomizer-components.min.js"></script>
<!--<script src="https://unpkg.com/aframe-particle-system-component@1.0.5/dist/aframe-particle-system-component.min.js"></script>-->
<script src="https://cdn.jsdelivr.net/gh/IdeaSpaceVR/aframe-particle-system-component@master/dist/aframe-particle-system-component.min.js"></script>
<script src="/js/spawn-in-circle.component.js"></script>
<link rel="stylesheet" type="text/css" href="/css/style.css" />
<link rel="stylesheet" type="text/css" href="/css/adv-screen.css" />

</head>
<body>
<a-scene networked-scene="
room: basic-multi-stream-green-screen;
debug: true;
adapter: easyrtc;
audio: true;
video: true;
">

<a-assets>
<img id="grid" src="https://img.gs/bbdkhfbzkk/stretch/https://i.imgur.com/25P1geh.png" crossorigin="anonymous">
<img id="sky" src="https://i.imgur.com/WqlqEkq.jpg" crossorigin="anonymous" />

<!-- Avatar -->
<template id="avatar-template">
<a-entity class="avatar" networked-audio-source>

<a-plane id="screenPlane" color="#FFF" width="2" height="1.5" position="0 0.6 -0.15" material="side: back"
networked-video-source-green-screen="streamName: screen; GreenThresholdIn:0.02"></a-plane>
</a-entity>
</template>
</a-assets>

<!-- Pawn -->
<a-entity id="player"
networked="template:#avatar-template;attachTemplateToLocal:false;"
camera
position="0 1.6 0"
spawn-in-circle="radius:3"
wasd-controls look-controls
>

<a-sphere class="head"
visible="false"
random-color
></a-sphere>
</a-entity>

<!-- Grid -->
<a-entity position="0 0 0"
geometry="primitive: plane; width: 10000; height: 10000;" rotation="-90 0 0"
material="src: #grid; repeat: 10000 10000; transparent: true; metalness:0.6; roughness: 0.4; sphericalEnvMap: #sky;"></a-entity>

<!-- Lights -->
<a-entity light="color: #ccccff; intensity: 1; type: ambient;" visible=""></a-entity>
<a-entity light="color: #ffaaff; intensity: 1.5" position="5 5 5"></a-entity>

<!-- Sky -->
<a-sky src="#sky" rotation="0 -90 0"></a-sky>

</a-scene>

<!-- GitHub Corner. -->
<a href="https://github.com/networked-aframe/networked-aframe" class="github-corner">
<svg width="80" height="80" viewBox="0 0 250 250" style="fill:#222; color:#fff; position: absolute; top: 0; border: 0; right: 0;">
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path>
</svg>
</a>
<style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}
</style>

<div class="actions">
<button id="screen-btn" type="button" class="button" style="height:80px">Send Video</button>
</div>

<!-- Preview what stream you send -->
<div class="videoUI" style="text-align:center; color:white">
<span style="font-size: small">This is what you send (Before, After processing)</span>

<div class="video-canvas-container">
<!-- Here we first put the data to process them -->
<canvas id="canvas_secret" class="output_canvas" width="800px" height="600px" style="width:160px; height:120px"></canvas>
</div>

<div class="video-canvas-container" style="left:200px">
<!-- Here are the processed data -->
<canvas id="video_output_canvas" class="output_canvas" width="800px" height="600px" style="width:160px; height:120px"></canvas>
</div>
</div>

<script>
// --------- here I capture my own stream in order to transmit it as I want ----
const constraints = {
video: true,
};

// Get my camera stream (to do some processing before capturing to canvas
const myvideo = document.createElement('video');
navigator.mediaDevices.getUserMedia(constraints).then((stream) => {
myvideo.srcObject = stream;
myvideo.play();
});

// ---------- The gui for configuring other clients inputs -----------------
const API = {
GreenThresholdIn: 0.02,
GreenThresholdOut: 5,
};

// GUI for changing thresshold for green screen
const gui = new dat.GUI( { width: 400 });

const videoInbound = gui.addFolder("Video Inbound");
videoInbound.open();

videoInbound.add( API, 'GreenThresholdIn', 0, 0.7 ).onChange( function () {
document.getElementById("screenPlane").setAttribute("networked-video-source-green-screen","GreenThresholdIn",
API.GreenThresholdIn);

} );

const videoOutbound = gui.addFolder("Video outbound");
videoOutbound.open();

videoOutbound.add(API, "GreenThresholdOut", 0, 255, 1).onChange((val) => {
API.GreenThresholdOut = val;
});

gui.open();

// Process my stream
var canvasElement = document.getElementById('video_output_canvas');
var canvasElementSecret = document.getElementById('canvas_secret');

const w = canvasElement.width;

console.log("w -----> ", w);
const h = canvasElement.height;
var canvasCtx = canvasElement.getContext('2d');
var canvasCtxSecret = canvasElementSecret.getContext('2d');

var canvasStream;
let r,g,b;

(function loop() {
canvasCtxSecret.drawImage(myvideo, 0, 0, w, h);
let imageData = canvasCtxSecret.getImageData(0, 0, w, h);

for (var i = 0; i < imageData.data.length; i += 4) {
r = imageData.data[i]; g = imageData.data[i+1]; b = imageData.data[i+2];
if (g-r> API.GreenThresholdOut){
imageData.data[i] =0;
imageData.data[i+1]=255;
imageData.data[i+2]=0;
}
}
canvasCtx.putImageData(imageData, 0, 0);
setTimeout(loop, 1000 / 30); // drawing at 30fps
}
)();

// final processed stream to send
canvasStream = canvasElement.captureStream(30);

// Screen share status
let screenEnabled = false;

// Screen share button element
const screenBtnEle = document.getElementById('screen-btn');

// Define custom schema for syncing avatar color, set by random-color
NAF.schemas.add({
template: '#avatar-template',
components: [
'position',
'rotation'
]
});

// Called by Networked-Aframe when connected to server
function onConnect () {
console.log("onConnect", new Date());
setTimeout(function(){
// This is the processed stream that we want to send
// We do not want the default stream camera (takes bandwidth)
NAF.connection.adapter.enableCamera(false);
},5000);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you try setting video:false on networked-scene like I said in #296 (comment) ?
As far I understand, having video:true implies negotiating a video track with the other participants, and setting enableCamera(false) afterwards will just make the track inactive. Setting video:false will not add the default camera video track from the RTCPeerConnection at all.
I don't have two PC to test that on my local machine. I usually test with both my PC and iPad, but on the iPad the page freeze.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will try that also. I totally forgot it as it has been a long time ago.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes you are right, it works with video:false


// Handle screen button click (Off and On)
screenBtnEle.addEventListener('click', function() {
if (screenEnabled) {
NAF.connection.adapter.removeLocalMediaStream("screen");
screenEnabled = false;
screenBtnEle.textContent = 'Send Video';
} else {
NAF.connection.adapter.addLocalMediaStream(canvasStream, "screen"); // stream
screenEnabled = true;
screenBtnEle.textContent = 'Stop sending Video';
}
});
}

</script>
<!--
Known issues with this demo, some cases are not handled:
- If participant A shares their screen, the partipant B sees the other participant's screen.
When participant A stops their screen share, the other participant will see a frozen screen, the last image received.
- If participant A starts screen share, stops, and restarts the screen share, the other participant won't see it.
-->
</body>
</html>