diff --git a/content/System Administration/streaming-webcam-raspi.md b/content/System Administration/streaming-webcam-raspi.md new file mode 100644 index 0000000000000000000000000000000000000000..d4fe5dd2c3ea024137ea6304cd04f2db7236a7f7 --- /dev/null +++ b/content/System Administration/streaming-webcam-raspi.md @@ -0,0 +1,180 @@ +Title: Livestreaming with a Raspberry Pi +Description: Broadcast video privately, cheaply, and without ads. +Date: June 30, 2017 +Cover: /media/raspi-webcam.jpg +Featured_Project: true + +These are my notes on broadcasting a USB camera to a webpage. A Raspberry Pi streams +from the camera, and a server running nginx distributes the stream to +many viewers at once. + +## Server setup + +These instructions assume you are using [Debian](https://www.debian.org/), but +should work on just about any Linux. While the Raspberry Pi can be on a private +network, this server needs a public IP address to be accessible from the internet. + +**Note:** Streaming video can use a lot of bandwidth. Do the math to ensure +adequate capacity and avoid billing surprises. + +### nginx + +[Build nginx with the RTMP module](https://github.com/arut/nginx-rtmp-module/wiki/Getting-started-with-nginx-rtmp). Install and configure it, using the config below as an example. + +**Note:** If `./configure` complains about missing zlib, install `zlib1g-dev`. + + +``` +:::nginx +worker_processes 1; +error_log logs/error.log debug; + +events { + worker_connections 1024; +} + + +http { + include mime.types; + default_type application/octet-stream; + sendfile on; + keepalive_timeout 65; + + server { + listen 80; + server_name streamer.example.com; + + # Uncomment if you have an SSL cert. + # listen 443 ssl; + # ssl_certificate /etc/ssl/certs/streamer.example.com.crt; + # ssl_certificate_key /etc/ssl/private/streamer.example.com.key; + + # Configure HLS playback + location /hls { + add_header Cache-Control no-cache; + + # CORS header (allow embedding on other domains) + add_header 'Access-Control-Allow-Origin' '*' always; + + # MIME types for HLS playlist and video files + types { + application/vnd.apple.mpegurl m3u8; + video/mp2t ts; + } + + # See hls_path below. + root /tmp; + } + + } + +} + +rtmp { + server { + listen 1935; + ping 30s; + notify_method get; + application video { + live on; # Enable live streaming + hls on; # Enable HLS output + hls_path /tmp/hls; # Where to write HLS files + } + } +} +``` + +See [the nginx-rtmp-module wiki](https://github.com/arut/nginx-rtmp-module/wiki/Directives) +for details on these settings. + + +## Raspberry Pi Setup + +**Note:** The original Raspberry Pi lacks hardware acceleration for video transcoding, making it unsuitable +for this project. I used a Raspberry Pi 2. + +Install [Raspbian](https://www.raspberrypi.org/downloads/raspbian/) on your Raspberry Pi. +It will need a network connection (eg. + [WiFi](https://wiki.debian.org/WiFi/HowToUse#WPA-PSK_and_WPA2-PSK)) +to access the server. + +Plug in your camera, and make sure it is detected. + +``` +:::bash hl_lines="2" +ls /dev/video* +/dev/video0 +``` + +You will need **avconv**, a fork of **ffmpeg**. + +``` +apt update +apt install avconv +``` + +Finally, you can start the stream. These settings worked well for me. + +``` +:::bash +avconv + -f video4linux2 \ # Input format + -i /dev/video0 \ # Path to your webcam. + -c:v libx264 \ # Use H.264 encoding. + -pix_fmt yuv420p \ # Some browsers (eg. Safari) need this. + -an \ # No audio (I don't need it). + -f flv \ # Output format + rtmp://streamer.example.com/video/example-stream # see below +``` + +* `video` corresponds with the nginx rtmp application name. +* `example-stream` will be the name of your stream, change as desired. + + +## Set up the viewer + +Using [hls.js](https://github.com/video-dev/hls.js) for cross-browser HLS support, create +a page for viewing the video. + +``` +:::html +<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script> +<video id="live-stream"></video> +<script> + if(Hls.isSupported()) { + var source_url = 'http://streamer.example.com/hls/example-stream'; + var video_element = document.getElementById('live-stream'); + var hls = new Hls(); + hls.loadSource(source_url); + hls.attachMedia(video_element); + hls.on(Hls.Events.MANIFEST_PARSED, function() { + video.play(); + }); + } +</script> +``` + +## Live demo + +Here's a live stream using this setup. + +<script src="/theme/lib/hls/hls.js"></script> +<video id="video" src='https://live.ant.sr/hls/fridgecast.m3u8' + autoplay muted playsinline + style="width: 100%;"></video> +<script> + if(Hls.isSupported()) { + var cfg = { + fragLoadingTimeOut: 500, + }; + var src = 'https://streamer.ant.sr/hls/fridgecast.m3u8'; + var video = document.getElementById('video'); + var hls = new Hls(cfg); + hls.loadSource(src); + hls.attachMedia(video); + hls.on(Hls.Events.MANIFEST_PARSED,function() { + video.play(); + }); + } +</script> + diff --git a/content/media/raspi-stream.png b/content/media/raspi-stream.png new file mode 100644 index 0000000000000000000000000000000000000000..c40dbbd7040851755cf1d3dfea64ac61af07da19 Binary files /dev/null and b/content/media/raspi-stream.png differ diff --git a/content/media/raspi-webcam.jpg b/content/media/raspi-webcam.jpg new file mode 100755 index 0000000000000000000000000000000000000000..86b0602b3b0d1178a52ae3e49371ebaee5a2bf73 Binary files /dev/null and b/content/media/raspi-webcam.jpg differ