Live-streaming using a computer and a Ubuntu server to Twitch.tv

This article is outdated, please go to this link for an updated version: https://blog.maaudet.ca/2020/07/re-encoding-a-live-stream-using-nginx-rtmp-on-ubuntu-20-04/

Preface

I started live-streaming my gaming sessions a few months ago and have been using the NVENC encoding. I found that the quality wasn’t that great and I had a Ubuntu server around and I wanted to try to find out what I could do with it to help have better quality on my stream, and maybe record all my sessions with a higher quality.

I also didn’t want to buy a capture card or a Windows license for my server since I’m very comfortable with Ubuntu Server and didn’t have more usable hardware around.

The setup

Ubuntu server

Ubuntu Server 14.04 LTS.
On it is installed nginx-rtmp and FFmpeg.

Main computer

I use this computer for pretty much everything I do.
I use OBS with NVENC encoding.

Settings for the main computer

In OBS, I use NVENC encoding @ 50 Mbps bit rate and I use my monitor’s native resolution (1080p). I do not record on this computer, for some reasons OBS seems to slow down after a few hours while recording (When the recording file is about 100 GB).

Settings for the server

Installing FFmpeg

Notice: ffmpeg is back in Ubuntu 15.04. Therefore, if you have this version, you only need to run the “sudo apt-get install ffmpeg” part.

Ubuntu Server doesn’t come with FFmpeg by default in its repositories. So we need to add Jon Severinsson’s FFmpeg’s ppa.

[cc_bash]
sudo add-apt-repository ppa:jon-severinsson/ffmpeg
sudo apt-get update
sudo apt-get install ffmpeg
[/cc_bash]

Compiling and installing nginx with the rtmp module

You need to install the prerequisite libraries

[cc_bash]
sudo apt-get install build-essential libpcre3 libpcre3-dev libssl-dev
[/cc_bash]

After you need to download the latest nginx and the rtmp module and unpack them

[cc_bash]
wget http://nginx.org/download/nginx-1.7.9.tar.gz
wget https://github.com/arut/nginx-rtmp-module/archive/master.zip
tar -zxvf nginx-1.7.9.tar.gz
unzip master.zip
cd nginx-1.7.9
[/cc_bash]

Then you need to build nginx including the nginx-rtmp module

[cc_bash]
./configure –with-http_ssl_module –add-module=../nginx-rtmp-module-master
make
sudo make install
[/cc_bash]

Configuring nginx

The default location for the configuration file is:
/usr/local/nginx/conf/nginx.conf

At the end of the file, add the following:

[cc]
rtmp {
server {
listen 1935;
chunk_size 4096;

application livein {
live on;

exec ffmpeg -i “rtmp://127.0.0.1/livein/STREAM_KEY” -vb 1800k -minrate 1800k -maxrate 1800k -bufsize 1800k -s 1280×720 -c:v libx264 -preset faster -r 60 -g 120 -keyint_min 60 -x264opts “keyint=120:min-keyint=120:no-scenecut” -sws_flags lanczos -tune film -pix_fmt yuv420p -c:a copy -f flv -threads 8 -strict normal “rtmp://127.0.0.1/liveout/STREAM_KEY”;

record_path /your/path;

recorder allin {
record all;
record_suffix -allin-%F-%H-%M-%S.flv;
record_interval 15m;
}
}

application liveout {
live on;
record off;

push rtmp://TWITCH_ADDRESS;
}
}
}
[/cc]

Basically what will happen here is that you will stream to the livein application, it will execute the FFmpeg command (That we will see in details further down the page) that re-encodes the stream using libx264 with good quality, constant bit rate and the right key interval for Twitch. (Those settings gives an “Excellent” rating by Twitch)

The entry stream will also be recording everything with video files that lasts 15 minutes each (To get highlights it’s usually better to work with smaller files).

You can find a list of Twitch.tv’s ingest servers here.

Also, please note that this configuration is for 60 FPS streaming. If you want to lower it to 30 FPS you will need to keep all the key-frame settings in par.

General rtmp settings explained

All possible directives explained

  • record_path: Set this to the path at which you want to record everything.
  • recorder: This is a recorder set
  • record: This is set to all so we get both audio and video into the files.
  • record_suffix: I set it like that so I can easily identify the files using the hour of the day.
  • record_interval: This is set to 15 minutes, it will restart recording each times this interval is reached.

You may want to play with the Access settings (Allow/Deny) to only allow your local network to have access to your “In” stream. You can read more in the nginx-rtmp wiki here.

FFmpeg settings explained

  • -i: This is the input (Your stream, using the right STREAM_KEY)
  • -vb, -minrate, -maxrate, -bufsize: I found out that my stream was a lot more stable when all of those where the same size. -vb is the video bit rate, -minrate and -maxrate needs to be the same for Twitch (Constant bit rate).
  • -s: This is the output resolution you want. Here I transcode from 1080p to 720p.
  • -c:v libx264: The encoder you want to use (I strongly recommend to use libx264)
  • -preset: You can play around with this setting depending on your server. I use the faster preset and it works fine. You could try fastest (To use less CPU) or fast (To use more CPU).
  • -r, -g, -keyint_min 60, -x264opts: -r is your FPS. -g needs to be double your FPS (To have 2 seconds key-frame interval as requested by Twitch). -keyint_min is set to the same as my FPS. The content of -x264opts is to do the same thing about the key-frame interval.
  • -sws_flags: I use this to have a better down-scale quality.
  • -tune: I played around a few of this settings, and had the best experience with film you might need to play around this setting, but film is a safe choice.
  • -pix_fmt: This is the picture format, yuv420p seems to be the most supported/popular one.
  • -c:a: The audio codec is set as copy so it won’t re-encode the stream’s audio.
  • -threads: The number of CPU cores/threads you want to use. I have 8 on my server.

The output needs to be your liveout application with the right STREAM_KEY.

Running the server

You can start the nginx server by running the following command:

[cc_bash]
sudo /usr/local/nginx/sbin/nginx
[/cc_bash]

Or you can add it in your services.

[cc_bash]
sudo wget https://raw.github.com/JasonGiedymin/nginx-init-ubuntu/master/nginx -O /etc/init.d/nginx
sudo chmod +x /etc/init.d/nginx
sudo update-rc.d -f nginx defaults
sudo service nginx start
[/cc_bash]

Setting up the main computer

Using OBS, in your broadcast settings you need to use the “Custom” streaming service. The FMS URL will be something like rtmp://192.168.1.2/livein (Use your own server’s IP). Your Stream Key needs to be the same you used in your nginx configuration.

In the Encoding part I use Nvidia NVENC (Since it doesn’t use a lot of CPU). I do not have CBR checked and the quality balance is set to 10. My Max bit rate is set to 50000 Kb/s (Since it’s only going to communicate on my local network). You may need to adjust your max bit rate according to your needs and capabilities.

As for Audio encoding, I use the AAC codec, 160 bit rate and a Format of 48 Khz.

Additional read and resources

https://obsproject.com/forum/resources/how-to-set-up-your-own-private-rtmp-server-using-nginx.50/

https://obsproject.com/forum/threads/guide-two-pc-configuration-without-capturecard.6757/

http://www.maartenbaert.be/simplescreenrecorder/live-streaming/

Bonus script

I have written a script that converts all the flv videos from the recordings into mp4 file format for use in Adobe Premiere.

[cc_bash]
#!/bin/bash

FILES=/path/to/input/*.flv
OUTPUT_DIR=/path/to/output/
THREADS=8

echo;

echo “===================================”;
echo “FLV to MP4 mass converter by Manhim”;
echo “===================================”;

echo;
echo “Processing files…”;
echo;

for f in $FILES
do

b=basename "${f%.*}";
tf=”$b.mp4″;
t=”$OUTPUT_DIR$tf”;

if [ ! -e $t ]
then
echo -n “$b: Processing… “;
echo -e “$b: Processing… \n” >> convert_logs.log;
ffmpeg -i “$f” -c copy -threads “$THREADS” “$t” >> convert_logs.log 2>&1;
echo -e “\nDone.\n” >> convert_logs.log;
echo “Done.”;
else
echo “$b: Already processed.”;
fi

done

echo;
echo “Finished processing files.”;
echo;
[/cc_bash]

This script will not delete any files and it won’t reconvert files that where already converted (It’s only using file names to compare, but it should be enough). You may delete the flv files yourself after converting them. (I usually like to confirm that the mp4 files are working correctly before deleting the source files)

Conclusion

I hope that I covered everything that was required for this setup to work. If you feel like I forgot anything, please add a comment.

If you have any questions, feel free to add a comment on this blog post, I will be reading and answering them.