Publish IP camera videos on web pages

16 minute read

Publish a video of an IP camera installed at home on a web page.

Thanks to ahonomics, I am now a country of poor people without hiding, and I try to achieve this on the lowest possible budget. At this time, I rely on (1) cheap and high-quality IP cameras made in China, (2) free and high-quality free software (open source software), and (3) useful life. It is a used laptop computer that has passed.

As prerequisites, (A) a home LAN with an optical line and (B) a web server installed on the Internet are assumed. (A) is mandatory. It would be possible without (B), but the intended readers of this article will not complain even if we proceed as if it were.

1: IP camera

The IP camera used is a model called SV-801W-1080P-HX of the SV3C brand, and the main specifications are as follows.

–Aluminum die-cast housing, IP66 waterproof / dustproof
–Fixed angle of view 2 million pixels (1920 x 1080)
–Both wired / WiFi compatible
–Power supply by AC adapter
–Infrared night vision photography
–Motion detection
–Supports micro SD card (up to 64 GB)
–RTSP compatible
–ONVIF compatible

  • send e-mail
    –FTP upload

The price is 4,899 yen (as of October 2020) on Amazon.co.jp, which is one of the cheapest, but at first glance it is robust and equipped with all the functions expected of this kind of surveillance camera. ing. There are other similar products, but I have the impression that the manuals on the support site are relatively substantial, so I choose the SV3C one.

It’s important to support ** RTSP ** and ** ONVIF **, but it’s rare for today’s IP cameras to support it.

1-1: IP camera setup

Set up the camera before installing it outdoors (on the edge of the house).

The following explanation is based on the SV3C SV-801W-1080P-HX, but I think that the procedure will be similar for cameras from other companies. I’m sorry if it’s different.

1-1-1: Micro SD card

First, attach the micro SD card (64GB, 1,596 yen) that you bought together to the camera.

This product is a little more difficult to work with because you can’t access the card slots on the board without removing the lens cover and pulling out the contents. However, once inserted, it is a card that will never be taken out, so I think this is fine.

The camera works without a card. You don’t need a card for video distribution, and even if you use it for crime prevention, you can omit the card when connecting to NVR (Network Video Recorder).

However, if you have a card installed, you can automatically record and save videos and snapshots. Besides, adding cards after installation is a hassle. It’s cheap, so it’s better to wear it from the beginning.

1-1-2: Connect to home LAN

Turn on the camera by connecting it to a router (or hub, etc.) on your home LAN with a LAN cable.

The router’s DHCP will now get the camera a dynamic IP address.

1-1-2 : CamHi

Install and launch an app called CamHi on your smartphone. By searching for and connecting to an IP camera connected to your home LAN with this app, you will be able to watch videos and access camera settings. Needless to say, smartphones need to be connected to the home LAN via WiFi in advance.

Subsequent settings can be done with CamHi, but it is easier to access the camera settings screen with a web browser, so just make a note of the camera’s IP address and CamHi will quit. (It will be used again later to check the image during outdoor installation work.)

1-1-3: Setting by web browser

Access the camera’s IP address with a web browser and configure the camera settings.

The browser uses ** Internet Explorer **. You will first be asked to install the ActiveX for video playback. I wonder what this is, but follow the instructions. It can be set with other browsers, but it is inconvenient because the image is not displayed. Give up and use IE.

There are a wide variety of items that can be set. For items that you do not understand well, leave the default settings and make the following initialization and setting changes that are considered to be the minimum necessary.

–Change the administrator password
–The IP address is a static address (here, 192.168.0.101)
–Set the time zone to GMT +09: 00
–Set the NTP server to ntp.nict.jp
–Initialize SD card

This time, we will go with a wired connection in consideration of the installation location and stability, so turn off WiFi. Also, since the purpose is different, it is set not to use functions for crime prevention such as infrared night vision, motion detection, alarm by e-mail or FTP.

1-2: Outdoor installation work of IP camera

Install an IP camera on the eaves of your home, where you will be shooting videos.

While checking the image with CamHi of the smart phone, decide the installation position and shooting direction and fix it. Since it is a wide-angle lens, it is inevitable that the peripheral part will be distorted, but since the human eye is sensitive to horizontal deviation, the angle of the camera is determined by paying close attention to the horizontal and vertical parts of the center of the image.

Since it is a place exposed to rain, the joint between the LAN cable and the power cable should be waterproofed with self-bonding tape.

1-3: Delivery of still images

With the SV3C HX series, it will be possible to deliver still images at this point.

There is a function to upload snapshots to an external FTP server on a regular basis, so if you take advantage of this and perform appropriate processing on the web server side, you can display almost real-time still images on a web page. You can.

photo.png

This time, we will create a page to distribute still images in case the video distribution stops.

1-3-1: Client side (HTML + javascript)

<img id="live-img" width="950" height="534" 
  src="/livecam/snapshot" 
  alt="Live camera snapshot" />

The source of the image is the URL / livecam / snapshot. It makes the work on the server side easier than specifying it by file name like " snapshot.jpg ". You no longer have to worry about the negative effects of the file cache.

function updateImage() {
    $('#live-img').attr('src', '/livecam/snapshot');
}
var timer = setInterval(updateImage, 30000);

Then the javascript timer requests the image from the server every 30 seconds.

1-3-2: Server side

On the server side, the image data is sent to the client from the action corresponding to the URL / livecam / snapshot.

Since snapshots from the camera are being uploaded one after another to the directory specified in advance, select the newest file among them, read the contents, and add the header of 'Content-Type: image / jpeg'. And send it.

To put it in detail, it requires some troublesome processing such as resizing images and deleting unnecessary files, but I will omit the details.

2: Video distribution

2-1: Schematic diagram

movie.png

In order to distribute videos from IP cameras, ** video conversion server ** and ** video distribution server ** are required in addition to the conventional web server, as shown in the figure.

First, the ** video conversion server ** converts the stream of video data output by the camera according to ** RTSP ** (Real Time Streaming Protocol) into data according to ** RTMP ** (Real Time Messaging Protocol). Convert. The substance of this video conversion server is an application program called ** ffmpeg **.

Then, the ** video distribution server ** that receives the output of ** RTMP ** from the video conversion server distributes the stream converted to the ** HLS ** (HTTP Live Streaming) protocol to the web client. The substance of this video distribution server is a web server program called ** NGINX ** equipped with ** nginx-rtmp-module **.

Although not supported this time and not shown in the figure, this video distribution server can distribute ** RTMP ** streams as they are, or ** MPEG-DASH ** protocol (DASH is Dynamic Adaptive Streaming over HTTP). It is also possible to convert it to) and distribute it.

2-2: Video server

Make a used laptop computer into a server that combines video conversion and video distribution, and install it on your home LAN.

In some cases, it may be better to have only a video conversion server on the home LAN and let a web server on the Internet also serve as video distribution.

2-2-1 : CentOS 8

Install CentOS 8 on your laptop. Nothing has changed in particular.

The reason for CentOS is simply because you’re used to it, and there’s no other reason. It should be any linux distribution.

The IP address of this video server on the home LAN is 192.168.0.99.

2-2-2 : ffmpeg

There are many articles on the net that build ffmpeg from source, but if you go there, you’ll usually be in distress. Until a decade ago, I would have had no choice but to do so, but now that I have a package, I don’t have to worry about it.

Specifically, install ffmpeg using the ** RPM Fusion ** repository.

First, the ʻEPEL` repository is required, so install it.

# dnf -y install epel-release

Then enable the repositories PowerTools and ʻepel-playground`.

# dnf config-manager --set-enabled PowerTools
# dnf config-manager --set-enabled epel-playground

Then install the RPM Fusion repository.

# rpm -ivh https://download1.rpmfusion.org/free/el/rpmfusion-free-release-8.noarch.rpm

You can now install ffmpeg.

# dnf install ffmpeg

For details, see ** “Install FFmpeg on CentOS 8 with RPMFusion repo” **. The title is English, but the article is in Japanese.

2-2-3 : NGINX + nginx-rtmp-module

If you only use NGINX, you can use the package, but in order to use nginx-rtmp-module, you need to get the source and build it.

** NGINX official website ](https://www.nginx.com) technical blog [ “Enabling Video Streaming for Remote Learning with NGINX and NGINX Plus” **.

First, install the tools you use to build.

$ sudo yum update
$ sudo yum groupinstall "Development Tools"
$ sudo yum install git

Next, install the dependent packages.

$ sudo yum groupinstall pcre-devel zlib-devel openssl-devel

Then, create an appropriate build directory, go into it, and clone the sources of nginx-rtmp-module and nginx from github to get them.

$ cd /path/to/build/dir
$ git clone https://github.com/arut/nginx-rtmp-module.git
$ git clone https://github.com/nginx/nginx.git

Then go into the nginx directory, add nginx-rtmp-module to your configuration, and run the build and install.

$ cd nginx
$ ./auto/configure --add-module=../nginx-rtmp-module
$ make
$ sudo make install

This will make NGINX work, so check it just in case.

$ sudo systemctl start nginx

When you access the home page of the video server (http://192.168.0.99/) from a personal computer connected to your home LAN, the NGINX welcome page should be displayed.

I can’t stream the video yet (naturally because I haven’t set it up yet), but once I put in ** ffmpeg ** and ** NGINX + nginx-rtmp-module **, it’s like winning. ..

The rest is the setting of video conversion by ffmpeg and the setting of video distribution by NGINX, but before that, I will finish the work of environment maintenance necessary for the operation of the video server.

2-2-4: Video server environment maintenance

2-2-4-1: Firewall

Open ports for http, https, RTSP, and RTMP.

$ sudo firewall-cmd --permanent --add-service=http 
$ sudo firewall-cmd --permanent --add-service=https 
$ sudo firewall-cmd --permanent --add-service=rtsp
$ sudo firewall-cmd --permanent --add-port=1935/tcp
$ sudo firewall-cmd --reload

1935 / tcp is the standard port for RTMP. RTSP uses 554 / tcp and 554 / udp as standard ports, but in CentOS 8 it can be set using --add-service = rtsp.

2-2-4-2: Router port mapping

Change the port mapping setting of the router of the home LAN so that the video server can be accessed from the Internet, and the incoming call to the WAN side global address is the local address of the LAN side video server (192.168.0.99). Try to go to.

You can just use http (80), https (443), rtmp (1935), but also map ssh (22) for remote management.

2-2-4-3 : DDNS (Dynamic DNS)

Use the DDNS (Dynamic DNS) service so that you can specify the video server by domain name instead of IP address.

Change server_name in nginx.conf to the DDNS domain name (assuming it is camsvr.on.ddns) and restart NGINX.

nginx.conf


http {
    server {
        server_name  camsvr.on.ddns;

At this point, I’d like to see if the router’s port mapping and DDNS are working as expected, but to do that I need to go out of my home LAN. When I access http://camsvr.on.ddns/ with a web browser on a PC connected to my home LAN, the NGINX welcome page of the video server is not displayed, and the home page of the router (http:: //192.168.0.1/) is displayed. In short, port mapping does not work for access from within the LAN. It’s a good idea to use a smartphone browser with WiFi turned off for testing.

2-2-4-4 : Let’s Encrypt

The plan is that the video distribution web page will be a mix of content from the new video server with the page provided by the existing web server. The web server is already SSL and provides the https page as a whole. If there is a http content that does not support SSL, it will be sick.

Therefore, let’s Encrypt is used to make the video server SSL.

For the procedure, please refer to ** “Simple free SSL conversion to CentOS8 (nginx) using certbot & SSL automatic update” **.

After completing the above (1) firewall, (2) router port mapping, and (3) DDNS settings, (4) start certbot with NGINX running. Then, at the same time as getting the certificate, it will make appropriate changes to nginx.conf and make the video server SSL.

nginx.conf


http {
    server {
        server_name  camsvr.on.ddns;
        listen 443 ssl; # managed by Certbot
        ssl_certificate /etc/letsencrypt/live/camsvr.on.ddns/fullchain.pem; # managed by Certbot
        ssl_certificate_key /etc/letsencrypt/live/camsvr.on.ddns/privkey.pem; # managed by Certbot
        include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    }
    server {
        if ($host = camsvr.on.ddns) {
            return 301 https://$host$request_uri;
        } # managed by Certbot
        listen 80;
        server_name  camsvr.on.ddns;
        return 404; # managed by Certbot
    }
}

The commented # managed by Certbot is where certbot rewrote or added.

2-2-4-5: CORS header

As mentioned just above, video distribution web pages will be a mix of content from the new video server with pages provided by existing web servers. At this time, the problem of CORS (Cross-Origin Resource Sharing) arises.

To deal with this, add a CORS-enabled header to the response from the video server.

nginx.conf


http {
    server {
        location / {
            # CORS start
            add_header 'Access-Control-Allow-Origin' 'https://my.web.server' always;
            # Allow CORS preflight requests
            if ($request_method = 'OPTIONS') {
                add_header 'Access-Control-Allow-Origin' 'https://my.web.server';
                add_header 'Access-Control-Max-Age' 1728000;
                add_header 'Content-Type' 'text/plain charset=UTF-8';
                add_header 'Content-Length' 0;
                return 204;
            }
            # CORS end
        }
    }
}

The setting is to allow only specific origins who know their identity. To be honest, I’m not sure about CORS. For the time being, shake it off to the safe side.

2-2-5: Video distribution by NGINX

** “Enabling Video Streaming for Remote Learning with NGINX and NGINX Plus” ** Add the video distribution settings to nginx.conf.

The following are the settings for HLS.

nginx.conf


http { 
    server { 
        location / { 
            root /tmp/hls; 
        } 
    }
    types {
        application/vnd.apple.mpegurl m3u8;
        video/mp2t ts;
        text/html html;
    } 
}
rtmp { 
    server { 
        listen 1935; 
        application livecam { 
            live on; 
            interleave on;
            hls on; 
            hls_path /tmp/hls; 
            hls_fragment 5s; 
        } 
    } 
} 

http> server> location / root changed to / tmp / hls
–Additional settings for http> types blocks
–In addition to html, set the types of m3u8 and ts for HLS
–Additional settings for rtmp block
hls_path should be / tmp / hls

The location> root setting on the http side and the hls_path setting on the rtmp side are paired. This video server is set to deliver HLS videos directly under / .

2-2-6: Video conversion by ffmpeg

Finally, ffmpeg converts the IP camera’s RTSP stream into an RTMP stream and sends it to the video distribution server.

$ ffmpeg -i rtsp://192.168.0.101/12.amp -c copy -an -f flv rtmp://192.168.0.99/livecam/std

-i rtsp: //192.168.0.101/12.amp … Specify the RTSP stream of the IP camera as input.
–The 12 part depends on the IP camera used.
–SV3C SV-801W-1080P-HX provides two streams, 11 (1920 x 1080) and 12 (640 x 352). The latter is used here.
-c copy … Leave the codec as input.
-an … No audio output.
-f flv … Specify the output format. FLV is Flash Video.
rtmp: //192.168.0.99/livecam/std … Specify the output destination.
livecam … application name.
std … Stream name.
–The URL for RTMP will be rtmp: //camsvr.on.ddns/livecam/std.
–The URL for HLS will be https://camsvr.on.ddns/std.m3u8.

If you don’t need to process the video, you can use -c copy. It saves you the trouble of decoding the input and encoding the output, so there is almost no load on the CPU.

Resizing the image and adjusting the tint can be a bit more complicated and CPU-intensive.

$ ffmpeg -i rtsp://192.168.0.101/12.amp -c:v libx264 -b:v 512k -r 15 -vf hue=h=10 -an -f flv rtmp://192.168.0.99/livecam/std

-c: v libx264 … Specify the video codec. It is H.264.
-b: v 512k … Specify the bit rate of the video. 512kb / sec.
-r 15 … Specifying the frame rate. 15 fps.
-vf hue = h = 10 … Specify the video filter. Rotate the hue 10 degrees.

The final hue adjustment is to correct the redness of the image, whether it is a characteristic of this IP camera as a model or an individual.

The strength of ffmpeg is endless.

2-2-6-1: ffmpeg monitoring (obsoleted)

If the RTSP stream is disturbed due to a malfunction of the IP camera, ffmpeg may end. That’s not good as a video conversion server, so create a shell script that monitors the operation of ffmpeg and restarts it if it stops.

#!/usr/bin/bash
# The script runs for 18 hours (12 x 60 x 18 = 12960)
limit=12960
counter=0
while [ $counter -le $limit ]; do
    sleep 5
    alive=`ps -aef | grep ffmpeg | grep livecam | wc -l`
    # echo `date` ":ffmpeg alive ="$alive
    if [ $alive = 0 ]; then
        echo `date` " : ffmpeg is not running."
        echo "starting ffmpeg ..."
        ffmpeg -i rtsp://192.168.0.101/12.amp -c:v libx264 -an -r 15 -b:v 512k -vf hue=h=10 -f flv rtmp://192.168.0.99/livecam/std 2>>/var/log/nginx/ffmpeg.log &
        echo "done."
    fi
    ((counter++))
done

Check ffmpeg for survival every 5 seconds for 18 hours and launch if dead. Start this script with cron every day at 3:00 AM. It is a crazy setting that you can die between 9:00 PM and 3:00 AM.

2-2-6-2: Start ffmpeg on NGINX

Actually, you don’t have to start ffmpeg yourself and monitor it as described above. Just start ffmpeg on NGINX.

nginx.conf


        application livecam { 
            live on; 
            interleave on;
            hls on; 
            hls_path /tmp/hls; 
            hls_fragment 5s;
            exec_static /usr/bin/ffmpeg -i rtsp://192.168.0.101/12.amp -c:v libx264 -an -r 15 -b:v 512k -f flv rtmp: //192.168.0.99/livecam/std 2>>/var/log/nginx/ffmpeg-std.log;
        } 

I’m using ʻexec_static here because, for some reason, ʻexec_push doesn’t start ffmpeg as expected in my environment. This failure is also recorded as an open issue on github of nginx-rtmp-module, which seems to bother a lot of people.

Fortunately, ʻexec_static` will start successfully. And even if you kill the launched ffmpeg, another instance will be launched immediately, probably because NGINX is monitoring it. When you quit NGINX, ffmpeg also quits. This is fine.

2-3: Client side

On the client side, use the JavaScript video playback library ** VIDEO JS **.

<head>
    <link href="https://vjs.zencdn.net/7.8.4/video-js.css" rel="stylesheet" />
</head>

<body>
    <video id="live-cam" class="video-js" controls autoplay
            width="640" height="352" data-setup="{}">
        <source src="https://camsvr.on.ddns/std.m3u8" type="application/x-mpegURL" />
        <p class="vjs-no-js">
To watch this video, enable JavaScript and
Use a browser that supports the HTML5 video tag.
        </p>
    </video>

    <script src="https://vjs.zencdn.net/7.8.4/video.js"></script>
</body>

For details, see ** “Getting Started” ](https://videojs.com/getting-started) and documentation on [ VIDEO JS Official Site **. Please refer.

That’s it for publishing IP camera videos on web pages.

If there is something wrong, strange, or something that needs improvement, please let us know.