Gocv+websocket實現視頻直播

數據流向圖

數據流

實現方式

  1. 通過opencv抓取攝像頭的視頻數據按幀處理
  2. 將每一幀壓縮成jpg格式並編碼成base64格式
  3. 通過websocket協議將base64圖像傳輸給前端頁面
  4. 前端解析每一幀並更新顯示

本文使用了iris框架的websocket封裝,因此opencv也使用了go語言的版本GoCV。

主要功能點

從攝像頭獲取視頻數據

img:=gocv.NewMat()
camera,err:=gocv.VideoCaptureDevice(0)
camera.Read(&img)

圖像Base64編碼

data,err:=gocv.IMEncode(".jpg",img)
n:=base64.StdEncoding.EncodedLen(len(data))
dst:=make([]byte,n)
base64.StdEncoding.Encode(dst,data)
urldata:="data:image/jpeg;base64,"+string(dst)

Websocket服務

ws:=websocket.New(websocket.DefaultGorillaUpgrader,websocket.Events{
	websocket.OnNativeMessage:func(nsConn*websocket.NSConn,msgwebsocket.Message)error{
		log.Printf("Servergot:%sfrom[%s]",msg.Body,nsConn.Conn.ID())
		return nil
	},
})
app:=iris.New()
app.Get("/video",websocket.Handler(ws))
app.Run(iris.Addr(":8080"))

通過websocket廣播

mg:=websocket.Message{
	Body:[]byte(urldata),
	IsNative:true,
}
ws.Broadcast(nil,mg)

完整代碼

這裏貼出完整代碼,也可以到GitHub上查看
https://github.com/chenguan1/go-h5-video-demo

go

package main

import (
	"encoding/base64"
	"fmt"
	"github.com/kataras/iris/v12"
	"github.com/kataras/iris/v12/websocket"
	"gocv.io/x/gocv"
	"log"
	"time"
)

func main() {
	ws := websocket.New(websocket.DefaultGorillaUpgrader, websocket.Events{
		websocket.OnNativeMessage: func(nsConn *websocket.NSConn, msg websocket.Message) error {
			log.Printf("Server got: %s from [%s]", msg.Body, nsConn.Conn.ID())
			return nil
		},
	})

	ws.OnConnect = func(c *websocket.Conn) error {
		log.Printf("[%s] Connected to server!", c.ID())
		return nil
	}

	ws.OnDisconnect = func(c *websocket.Conn) {
		log.Printf("[%s] Disconnected from server", c.ID())
	}

	ws.OnUpgradeError = func(err error) {
		log.Printf("Upgrade Error: %v", err)
	}

	go func() {
		camera, err := gocv.VideoCaptureDevice(0)
		if err != nil {
			panic(err)
		}

		img := gocv.NewMat()

		for {
			camera.Read(&img)
			data, err := gocv.IMEncode(".jpg", img)
			if err != nil {
				fmt.Println(err)
			} else {
				n := base64.StdEncoding.EncodedLen(len(data))
				dst := make([]byte, n)
				base64.StdEncoding.Encode(dst, data)
				urldata := "data:image/jpeg;base64," + string(dst)
				mg := websocket.Message{
					Body:     []byte(urldata),
					IsNative: true,
				}
				ws.Broadcast(nil, mg)
			}
			time.Sleep(time.Millisecond * time.Duration(50))
		}
	}()

	app := iris.New()
	app.HandleDir("/", "./html")
	app.Get("/video", websocket.Handler(ws))

	app.Run(iris.Addr(":8080"))
}

html5

<html>
<head>
    <title>video</title>
</head>
<body style="padding:10px;">
<img id="target" style="display:inline;"/>
<canvas id="canvas" style="display:inline;"/>
<script type="text/javascript">
    var HOST = "localhost:8080"

    w = new WebSocket("ws://" + HOST + "/video");
    w.onopen = function () {
        console.log("Websocket connection enstablished");
    };

    w.onclose = function () {
        console.log("Websocket disconnected");
    };

    var canvas = document.getElementById("canvas");
    var img = new Image()
    img.onload = function(){
        canvas.width = img.width
        canvas.height = img.height
        canvas.getContext("2d").drawImage(img,0,0,img.width,img.height);
    };
    w.onmessage = function (message) {
        img.src = message.data;
    };
</script>
</body>
</html>

效果圖

效果圖

參考

https://github.com/kataras/iris/tree/v12/_examples/websocket

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章