Jump to content

How to Live Stream to Multiple Services with a RTMP Server

ionbasa

So you have OBS, FFSplit, Wirecast, or XSplit and you want to stream to: Twitch and YouTube at the same time, Twitch, Hitbox and Ustream, or any combination of sites. Currently there is no easy implementation into doing this from your streaming client other than running two instances of OBS, but that puts unnecessary strain on your CPU/GPU to encode a second stream. So how is this going to be feasibly possible?

 
Requirements:
 

First, you need an Linux Server preferably running under Debian or Ubuntu.
If you don't know how to setup a proper Linux server, I recommend reading @http://<your server ip>/ and you should get the "Welcome to nginx!" page.
Thats it, if you get no error code you now have installed nginx+rtmp-module. You can use the following command to open the nginx.conf in a text editor (in my example vim) with root privileges:

$ sudo vim /usr/local/nginx/conf/nginx.conf

Add the following at the very end of the file:

rtmp {        server {                listen 1935;                chunk_size 4096;                application live {                        live on;                        record off;                }        }}

And save the file.
Restart nginx with:

$ sudo /usr/local/nginx/sbin/nginx -s stop$ sudo /usr/local/nginx/sbin/nginx

Installation is complete!
 
 
Testing
 
Your server should now be ready to accept RTMP streams! Let's try it out.
Create a new profile in OBS/Xsplit/client of choice, and change your Broadcast Settings to the following:

  • Streaming Service: Custom
  • Server: rtmp://<your server ip>/live
  • Play Path/Stream Key: test

You may be wondering where that play path "test" came from. You can make up any play path and stream to it, and put that path into an RTMP player, and it will play back. For simple purposes, authentication isn't necessary. However, authentication is supported.
You should now be able to start streaming to your server. If you hit "Start Streaming" and don't get an error, then that's a good sign.
So how do you watch it?
 
To play back the stream that's being uploaded, you can do so with VLC:http://www.videolan.org/vlc/index.html
Just Open a Newtork Stream and enter in rtmp://<your server ip>/live/test as the URL. If it all worked right, then you should now be seeing your stream in VLC!
 
 
Starting nginx at system bootup
By default nginx requires a user to start it from the shell (if manually compiled). You can read instructions here: http://wiki.nginx.org/InitScripts on how to make the server auto-start when your server boots up. This is especially useful if you need to reboot the server do to an update or power outage. This way you don't have to remember to constantly start nginx manually.
 
 
Streaming to multiple locations or services
 
You can also use your RTMP server to forward to other streaming services and channels. Underneath the "record off;" line in your nginx.conf, add the following:

push rtmp://<other streaming service rtmp url>/<stream key>

And any stream streamed to that application will be forwarded on to the other service, as well as being served up from the server! You can add multiple "pushes" to forward the stream to multiple locations.
 
Example nginx.conf:

#user  nobody;worker_processes  1;error_log  logs/rtmp_error.log debug;pid        logs/nginx.pid;events {    worker_connections  1024;}rtmp {server {  listen 1935;  chunk_size 8192;  application stream {   live on;   meta copy;   push rtmp://live-ams.twitch.tv/app/live_XYZ_ZXY;   push rtmp://live.hitbox.tv/push/username?key=XYZ;  }}}

This very simple config just includes one application called stream which waits for you to send a stream to it.  The really important part are the two “push” directives I defined. As soon as the application receives your stream it will start sending it to both locations I set after the push. In this example to twitch.tv amsterdam server and to the hitbox.tv master. In OBS, XSplit or whatever program you use you would just setup a stream to a custom location (in xsplit custom rtmp) and choose rtmp://your.ip/stream as your server address and just enter anything for the streamkey/playpath.
 
The only downside of this whole setup, remember the big plus of less cpu usage compared to two or more encodings xsplit would do, is that you get less information about the connection to your services. In OBS or Xsplit you will only see how good your connection to the nginx server is. And especially on a local hosted one, this should be always fine. So you will have to ask your viewers sometimes if everything is fine and regularly check that both or all streams are still online.
Last but not least the nginx error logging capabilities can give you a lot of info of what went wrong, so always check them if you have problems
 
[spoiler=Advanced Configurations]
 
The nginx.conf file in detail:

  • Part 1:
#user  nobody;worker_processes  1;error_log  logs/error.log debug;events {worker_connections  1024;}

The first part of the configuration decides how many workers will be started by nginx, in most simple setups, one should be enough. You can also set the level of errors that will be saved to the log file here.
The worker_processes directive is the sturdy spine of life for Nginx. This directive is responsible for letting our virtual server know many workers to spawn once it has become bound to the proper IP and port(s). It is common practice to run 1 worker process per core.

  • Part 2:
http {include       mime.types;default_type  application/octet-stream;sendfile        on;keepalive_timeout  65;server {listen       8080;server_name  localhost;# rtmp statlocation /stat {rtmp_stat all;rtmp_stat_stylesheet stat.xsl;}location /stat.xsl {# you can move stat.xsl to a different locationroot /usr/local/nginx/html;}# rtmp controllocation /control {rtmp_control all;}error_page   500 502 503 504  /50x.html;location = /50x.html {root   html;}}}

The above parts are the http server settings. You can for example put a jwplayer with a properly configured index.html into the nginx/html folder and use the http server to test the streams you send to your rtmp server. Server is listening to port 8080 and is configured to produce a Statistics file which is accessible through "http://yourserver/stat". And you can check http://wiki.nginx.org/Configuration to find out more about nginx http configuration.
 
The keepalive_timeout assigns the timeout for keep-alive connections with the client. Simply put, Nginx will close connections with the client after this period of time.

  • Part 3:
rtmp {server {listen 1935;chunk_size 4096;application live1 {live on;record off;exec avconv -i rtmp://localhost/live1/StreamKEY -c:v libx264 -preset veryfast -b:v 2000k -bufsize 4000k -c:a copy -s 1280x720 -r 30 -f flv rtmp://localhost/live2/StreamKEY2}application live2 {live on;record off;push rtmp://ingest-ams1.hashd.tv/live/NAME?key=STREAM_KEY;push rtmp://live-fra.twitch.tv/app/YOUR_STREAM_KEY;}}} 

The above is a slightly more complex rtmp configuration using two applications. The first application is set to receive a stream and put it live if someone connects. Its also set to execute an avconv command line. This uses the live1 stream with the defined StreamKEY as input, re-encodes the video to a bitrate of roughly 2000k, a framerate of 30 and a resolution of 1280×720 and sends it to live2/StreamKEY2. Application live2 on the other hand is set to push the stream it receives to Hashd.tv – Amsterdam server and Twitch.tv – Frankfurt server. (It can also send the stream to a connecting user)
 
Now this very special setup waits for your stream to live1/StreamKEY. The avconv gets executed and forwards the stream to live2/StreamKEY2. It also gets resized and re-encoded according to the settings I mentioned. As soon as application live2 receives the avconv output it will start pushing this stream to both locations set with the push commands. Of course your Linux server or VM has to do the encoding in this case.

You could also just send a stream ready video to live2 without using the encoding options of avconv. But
I like this setup because I can send a high quality stream to live1 which just uses my local area network and not that much of my gaming pc, most cpu work is done on the linux machine by avconv.

[spoiler=Statistics]
When running a rtmp server, it can be very important to keep an eye on your statistics, such as uploaded or received amount of data, or currently running streams. The statistics module can also be used to setup a viewer count on your homepage:

rtmp_statistics.png

In this case, just configuring the stats page is not enough. You also have to move the "stat.xsl" which is located in the nginx-rtmp-module source folder to the nginx/html folder. I set nginx to look into this folder using these lines under the HTTP section of the nginx.conf configuration file:

location /stat.xsl {root /usr/local/nginx/html;}

After you set this up correctly, the stats should be accessible using http://localhost/stat or serverip/stat using a different PC.

In this example config I set two allow directives, so the whole http server can only be accessed from a lan ip in the 192.168.0.XXX range or from within the server using the localhost address 127.0.0.1. You can of course change this, but be aware, the stat page lists the application names and stream keys. So you do not want it to be accessible from anywhere and by everyone. But you can of course also change “location /stat” to something else.
 
Assuming you run nginx on a webserver that for example already is running an apache server for http stuff, you can simply change the listen port in the above config. Change “listen 80″ to “listen 8080″ for example and then restart the nginx server.



[spoiler=Real Life Use Senario:]
Now that we went through all the nginx setup and configuration stuff, its time to tell you about my experiences in using the software.
I set up a test scenario. The video footage of Grid2 and BF3 could come either off a console or a PC. I am capturing this in Box1 with a capture card and save it as a high quality file to disk. This uses a Intel Core2Quad 8400 up to 80-90% on 1080p30fps with the ultrafast preset. So I choose a higher crf value combined with zero buffer to reach a decent quality (similar to fraps/dxtory in most parts). Most I5′s should be able to produce a similar stream while playing on the same PC, but this is just a side note.

Now the nginx server can actually run on any of the PC’s/Boxes we use in this scenario. In my case I installed it on my laptop which I sometimes use to add Video footage to my streams. Running Linux and nginx only, it merely had any work to do by the way. Though if I used a better system for the nginx server, I could have setup an exec transcode to my final streaming settings. My laptop barely can handle encoding, so I have to do this on Box2.

Depending on your steps earlier, you can now again either use your Gaming PC, Box1 or a different Box2. You “just” need free computing power for the encoding on this box. With a simple avconv command line you can grab the high quality stream off the server, transcode it to your desired output resolution and send it back to nginx or directly to twitch or whatever. Assuming you never wanted to do a high quality recording, you can probably tweak my example for your needs. As you can see, nearly unlimited options are available.

2013-08-05-0037-48.mp4_snapshot_31.35_-2

The screenshot above shows the cpu usage used by the encoding in the upper part of the left window. In the lower right corner of the screen you can see the avconv.exe running under windows. This one could be replaced by an exec command on the nginx machine, assuming enough cpu power is available.

And in the upper right you can see the statistics of the nginx server. Live1 receives the high quality stream in 1920×1080 with a bitrate of roughly 15Mb at the time. Now this stream is being grabbed by the avconv.exe which explains why Live1 also puts out 15Mb at the time. Live2 receives the transcoded stream by avconv. Its resized to 1280×720 and a bitrate of roughly 2Mb. The nginx server is set to push any stream it receives on Live2 to my twitch.tv and hashd.tv channels. And as you can see, it outputs a near exact double of 4Mb which represents these two streams.

 
Resources Used
http://linustechtips.com/main/topic/6398-howto-create-your-own-linux-home-server-using-debian/
http://www.videolan.org/vlc/index.html
https://obsproject.com/forum/resources/how-to-set-up-your-own-private-rtmp-server-using-nginx.50/
http://www.helping-squad.com/nginx-rtmp-configuration-and-possible-solutions/
http://nginx.org/
https://www.digitalocean.com/community/tutorials/how-to-optimize-nginx-configuration
 
 
Final Thoughts

I may make a mini series on YouTube demonstrating all aspects of installation and configuration. Also this is hopefully going to be an up to date document. I will give incremental updates and some feature additions latter on down the line. I hope the comunity enjoys this writup I compiled. Most of the information has been gathered around the web by people who have done this setup already, the only draw back was that it wasn't made available in one easy to use location. I merely added in some commentary and modifications, and compiled the information into one neat page. I hope everyone finds this guide usefull.
 
PS: Linus, I now expect you to stream to both YouTube and Twitch simultaneously ;) .

http {    allow 192.168.0.0/24;    allow 127.0.0.1;    deny all;    access_log 		logs/rtmp_access.log;    include       	mime.types;    default_type  	application/octet-stream;    sendfile        	on;    keepalive_timeout  	65;		    server {        listen		80;        server_name	localhost;		        # rtmp statistics        location /stat {            rtmp_stat all;            rtmp_stat_stylesheet stat.xsl;        }		        location /stat.xsl {            # you can move stat.xsl to a different location            # under linux you could use /var/user/www for example            root html;			        }    }}

▶ Learn from yesterday, live for today, hope for tomorrow. The important thing is not to stop questioning. - Einstein◀

Please remember to mark a thread as solved if your issue has been fixed, it helps other who may stumble across the thread at a later point in time.

Link to comment
Share on other sites

Link to post
Share on other sites

Updated OP with some advanced configuration steps, how to add a stastistics page, and a real life use case senario.

 

Later this week I want to demonstrate how to do Picture in Picture streaming.

 

After that I want to focus on how to setup a page to stream with either flash HTML5 DASH / HLS.

After that will come some adminastrative stuff, such as securing your stream using keys, securing links.

Finally I plan to add a how to on transcoding on the fly, along with the options available for transcoding.

▶ Learn from yesterday, live for today, hope for tomorrow. The important thing is not to stop questioning. - Einstein◀

Please remember to mark a thread as solved if your issue has been fixed, it helps other who may stumble across the thread at a later point in time.

Link to comment
Share on other sites

Link to post
Share on other sites

HTML5 player would be awesome. It would be great if you could make a guide for it.

Link to comment
Share on other sites

Link to post
Share on other sites

HTML5 player would be awesome. It would be great if you could make a guide for it.

The HTML5 player is on my todo list. Hopefully I can set it up by next week.

▶ Learn from yesterday, live for today, hope for tomorrow. The important thing is not to stop questioning. - Einstein◀

Please remember to mark a thread as solved if your issue has been fixed, it helps other who may stumble across the thread at a later point in time.

Link to comment
Share on other sites

Link to post
Share on other sites

  • 3 years later...

Could you please display the actual conf file. So I can better understand. I'm still new at this and I need all the help I can get thanks

Link to comment
Share on other sites

Link to post
Share on other sites

Good tutorial but can you fix the formatting on the configs? 

 

rtmp {
	server { 
		listen 1935;              
		chunk_size 4096;
		application live {  
			live on;
			record off;             
		}
	}
}

 

import { signature } from "./signature";

signature.display({ cpu"Intel i9 9900k @ 3.56HZ",  gpu"ASUS GTX 1080",  ram"32GB CORSAIR DDR4", motherboard"ASUS Z390-E" });

 

Link to comment
Share on other sites

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×