RTSP live streaming on browsers using flv.js

I encounter the problem that a live RTSP would be better played on browsers. Here is my solution: joy4 [1] library is used to convert rtsp stream to flv stream and flv.js [2] library is used to play flv streams on modern browsers.

The benefits are clear. No video decoding and encoding are performed and ffmpeg library is not depended on the server side. It costs almost no CPU usage when there’s only one client streaming. On the browser side, minimal CPU usage is also archieved considering mp4/h264 is well supported.

The browser side code looks like:

<script src="./flv.js"></script>
<video width="640" height="480" id="theVideo" controls></video>
<script>
    if (flvjs.isSupported()) {
        var videoElement = document.getElementById('theVideo');
        var flvPlayer = flvjs.createPlayer({
            type: 'flv',
            url: './video/'
        });
        flvPlayer.attachMediaElement(videoElement);
        flvPlayer.load();
        flvPlayer.play();
    }
</script>

The server side code looks like:

package main

import (
	"fmt"
	"io"
	"net/http"

	"github.com/nareix/joy4/av/avutil"
	"github.com/nareix/joy4/format"
	"github.com/nareix/joy4/format/flv"
	"github.com/nareix/joy4/format/rtsp"
)

type writeFlusher struct {
	httpflusher http.Flusher
	io.Writer
}

func (self writeFlusher) Flush() error {
	self.httpflusher.Flush()
	return nil
}

func init() {
	format.RegisterAll()
}

func main() {
	http.Handle("/", http.FileServer(http.Dir(".")))
	http.HandleFunc("/video/", func(w http.ResponseWriter, r *http.Request) {
		defer r.Body.Close()
		fmt.Println("serving:", r.RemoteAddr)
		if c, err := rtsp.Dial("rtsp://admin:admin@192.168.1.25:554/sub/av_stream"); nil != err {
			panic(err)
		} else {
			fmt.Println("rstp connected")
			c.Streams()
			defer c.Teardown()

			w.Header().Set("Content-Type", "video/flv")
			w.Header().Set("Transfer-Encoding", "chunked")
			w.Header().Set("Access-Control-Allow-Origin", "*")
			w.WriteHeader(200)

			fmt.Println("head wrote")
			flusher := w.(http.Flusher)
			flusher.Flush()

			muxer := flv.NewMuxerWriteFlusher(writeFlusher{httpflusher: flusher, Writer: w})

			if _, err := c.Streams(); nil != err {
				panic(err)
			}

			if err := avutil.CopyFile(muxer, c); nil != err {
				panic(err)
			}
		}

	})

	http.ListenAndServe(":8089", nil)
}

[1] https://github.com/nareix/joy4/
[2] https://github.com/Bilibili/flv.js/