Title : Stream live video using nginx
Author: Solène
Date  : 26 August 2019
Tags  : openbsd68 openbsd gaming nginx

This blog post is about a nginx rtmp module for turning your nginx
server into a video streaming server.

The official website of the project is located on github at:
https://github.com/arut/nginx-rtmp-module/

I use it to stream video from my computer to my nginx server, then
viewers can use `mpv rtmp://perso.pw/gaming` in order to view the
video stream. But the nginx server will also relay to twitch for
more scalability (and some people prefer viewing there for some
reasons).

The module will already be installed with nginx package since OpenBSD
6.6 (not already out at this time).

There is no package for install the rtmp module before 6.6.
On others operating systems, check for something like "nginx-rtmp" or
"rtmp" in an nginx context.

Install nginx on OpenBSD:

    pkg_add nginx

Then, add the following to the file /etc/nginx/nginx.conf

    load_module modules/ngx_rtmp_module.so;
    rtmp {
        server {
            listen 1935;
            buflen 10s;
    
            application gaming {
                live on;
                allow publish 176.32.212.34;
                allow publish 175.3.194.6;
                deny publish all;
                allow play all;
    
                record all;
                record_path /htdocs/videos/;
                record_suffix %d-%b-%y_%Hh%M.flv;
    
            }
        }
    }

The previous configuration sample is a simple example allowing
172.32.212.34 and 175.3.194.6 to stream through nginx, and that will
record the videos under /htdocs/videos/ (nginx is chrooted in
/var/www).

You can add the following line in the "application" block to relay the
stream to your Twitch broadcasting server, using your API key.

    push rtmp://live-ams.twitch.tv/app/YOUR_API_KEY;

I made a simple scripts generating thumbnails of the videos and
generating a html index file.

Every 10 minutes, a cron check if files have to be generated,
make thumbnails for videos (tries at 05:30 of the video and then
00:03 if it doesn't work, to handle very small videos) and then
create the html.

The script checking for new stuff and starting html generation:

    #!/bin/sh
    
    cd /var/www/htdocs/videos
    
    for file in $(find . -mmin +1 -name '*.flv')
    do
            echo $file
            PIC=$(echo $file | sed 's/flv$/jpg/')
            if [ ! -f "$PIC" ]
            then
                    ffmpeg -ss 00:05:30 -i "$file" -vframes 1 -q:v 2 "$PIC"
                    if [ ! -f "$PIC" ]
                    then
                            ffmpeg -ss 00:00:03 -i "$file" -vframes 1 -q:v 2 "$PIC"
                            if [ ! -f "$PIC" ]
                            then
                                    echo "problem with $file" | mail user@my-tld.com
                            fi
                    fi
            fi
    done
    cd ~/dev/videos/ && sh html.sh

This one makes the html:

    #!/bin/sh
    
    cd /var/www/htdocs/videos
    
    PER_ROW=3
    COUNT=0
    
    cat << EOF > index.html
    <html>
      <body>
    <h1>Replays</h1>
    <table>
    EOF
    
    for file in $(find . -mmin +3 -name '*.flv')
    do
            if [ $COUNT -eq 0 ]
            then
                    echo "<tr>" >> index.html
                    INROW=1
            fi
            COUNT=$(( COUNT + 1 ))
            SIZE=$(ls -lh $file  | awk '{ print $5 }')
            PIC=$(echo $file | sed 's/flv$/jpg/')
    
            echo $file
            echo "<td><a href=\"$file\"><img src=\"$PIC\" width=320 height=240 /><br />$file ($SIZE)</a></td>" >> index.html
            if [ $COUNT -eq $PER_ROW ]
            then
                    echo "</tr>" >> index.html
                    COUNT=0
                    INROW=0
            fi
    done
    
    if [ $INROW -eq 1 ]
    then
            echo "</tr>" >> index.html
    fi
    
    cat << EOF >> index.html
        </table>
      </body>
    </html>
    EOF