Skip to main content

Adding an OBS Stream to your Website

Koh Rong, Cambodia

This tutorial starts where the last ended. I setup OBS to re-stream my INSTAR IP cameras RTSP stream to the NGINX RTMP module and tested that I was able to access this RTMP stream with a VLC player. I now want to embed this video stream into a website (Reference).

Update the NGINX Configuration File​

RTMP Module Config​

Our current RTMP setup looks like this:

rtmp {
server {
listen 1935;
chunk_size 4096;

application live {
live on;
record off;
}
}
}

We will be using stream as our stream name so our endpoint will be: rtmp://localhost/show/stream . Which will later be available as http://localhost:8080/hls/stream.m3u8. For good HLS experience we recommend using 3 seconds fragments with 60 seconds playlist:

rtmp {
server {
listen 1935; # Listen on standard RTMP port
chunk_size 4096;

application show {
live on;
# Turn on HLS
hls on;
hls_path /mnt/hls/;
hls_fragment 3;
hls_playlist_length 60;
# disable consuming the stream from nginx as rtmp
deny play all;
}
}
}

Note that the example points /mnt/hls/ as the target path for the hls playlist and video files. You can change this to a different directory but make sure that nginx have write permissions:

mkdir /mnt/hls/
chown -R <nginx user>:<nginx user> /mnt/hls/
chmod 777 /mnt/hls

HTTP Server Config​

Since HLS consists of static files, a simple http server can be set up with two additions, correct MIME types and CORS headers.

server {
listen 8080;

location /hls {
# Disable cache
add_header Cache-Control no-cache;

# CORS setup
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Expose-Headers' 'Content-Length';

# allow CORS preflight requests
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}

types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}

root /mnt/;
}
}

Complete nginx.conf​

The default location for nginx conf is /usr/local/nginx/conf/nginx.conf or /etc/nginx/nginx.conf:

worker_processes auto;
events {
worker_connections 1024;
}

# RTMP configuration
rtmp {
server {
listen 1935; # Listen on standard RTMP port
chunk_size 4096;

application show {
live on;
# Turn on HLS
hls on;
hls_path /mnt/hls/;
hls_fragment 3;
hls_playlist_length 60;
# disable consuming the stream from nginx as rtmp
deny play all;
}
}
}

http {
sendfile off;
tcp_nopush on;
directio 512;
default_type application/octet-stream;

server {
listen 8080;

location / {
# Disable cache
add_header 'Cache-Control' 'no-cache';

# CORS setup
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Expose-Headers' 'Content-Length';

# allow CORS preflight requests
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}

types {
application/dash+xml mpd;
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}

root /mnt/;
}
}
}

Restart nginx with:

/usr/local/nginx/sbin/nginx -s stop
/usr/local/nginx/sbin/nginx -t
/usr/local/nginx/sbin/nginx

Test your Stream​

NGINX RTMP Streaming Server

NGINX RTMP Streaming Server

From existing rtmp stream already in h264​

if you have an existing rtmp stream in the correct codec, you can skip ffmpeg and tell nginx to pull the stream directly. In order to do so add a pull directive under application section in nginx.conf like so:

application show {
live on;
pull rtmp://example.com:4567/sports/channel3 live=1;
# to change the local stream name use this syntax: ... live=1 name=ch3;

# other directives...
# hls_...
}

From local webcam​

To achieve the stream encoding and muxing we will use the almighty ffmpeg.

To install ffmpeg using PPA run these commands

add-apt-repository ppa:mc3man/bionic-prop
apt-get update
apt-get install ffmpeg
ffmpeg -i rtsp://192.168.2.117/12 -vcodec libx264 -vprofile baseline -acodec aac -strict -2 -f flv rtmp://localhost:1935/show/stream
  • -re - consume stream on media's native bitrate (and not as fast as possible)
  • -f - use video4linux2 plugin
  • -i - select physical device to capture from
  • -vcodec - specify video codec to output
  • -vprofile - use x264 baseline profile
  • -acodec - use aac audio codec
  • -strict - allow using the experimental aac codec
  • -f - specify format to output
  • rtmp://localhost/show/stream - rtmp endpoint to stream to. if the target port is not 1935 is should be included in the uri.

The last path component is the stream name - that means that multiple channels can be pushed using different names

rtmp {
server {
listen 1935; # Listen on standard RTMP port
chunk_size 4096;

application show {

# Once receive stream, transcode for adaptive streaming
# This single ffmpeg command takes the input and transforms
# the source into 4 different streams with different bitrate
# and quality. P.S. The scaling done here respects the aspect
# ratio of the input.

exec ffmpeg -i rtmp://192.168.2.111/appname/streamname -vcodec libx264 -vprofile baseline -acodec aac -strict -2 -f flv rtmp://localhost/show/stream

live on;
# Turn on HLS
hls on;
hls_path /mnt/hls/;
hls_fragment 3;
hls_playlist_length 60;
# disable consuming the stream from nginx as rtmp
deny play all;
}
}
}

Restart nginx with:

/usr/local/nginx/sbin/nginx -s stop
/usr/local/nginx/sbin/nginx -t
/usr/local/nginx/sbin/nginx

Embed within website​

Now that we are pushing our stream into nginx, a manifest file in the format stream-name.m3u8 is created in the target folder along with the video fragments.

For our example, the manifest is available at: http://localhost:8080/hls/stream.m3u8.

For testing our new HLS live stream we will use videojs5.

<video
id="autoplay"
width="720"
height="360"
class="video-js vjs-default-skin vjs-big-play-centered"
controls
>
<source
src="http://192.168.2.111:8080/hls/stream.m3u8"
type="application/x-mpegURL"
/>
</video>

<link href="//vjs.zencdn.net/5.7.1/video-js.css" rel="stylesheet" />
<script src="//vjs.zencdn.net/5.7.1/video.js"></script>
<script src="//videojs.github.io/videojs-contrib-hls/node_modules/videojs-contrib-hls/dist/videojs.hls.min.js"></script>

<script>
var player = videojs('autoplay')
player.play()
</script>

HTML5 Boilerplate