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/

Send template message in WeChat mini program

According to the WeChat Development document, a field form_id should be presented when requesting a template message to be sent to the user. But the problem is that one template message for one corresponding form can’t meet all the needs. So we need to keep collecting available form_ids for future template message sending.

Continue reading Send template message in WeChat mini program