package main import ( "VideoStream/handler" "VideoStream/proto" "VideoStream/worker" "fmt" "github.com/gin-gonic/gin" "github.com/robfig/cron/v3" "gocv.io/x/gocv" "image" "image/color" "log" "net/http" "sync" "time" ) var DeviceRWMap = make(map[int]sync.RWMutex) var DeviceCurrentFrameMap = make(map[int]gocv.Mat) var DeviceFrameCount = make(map[int]int) var DeviceIsStop = make(map[int]bool) func main() { gin.SetMode(gin.ReleaseMode) r := gin.Default() handler.SetUpToolGroup(r) // Tool err := worker.InitRedis() if err != nil { panic("failed to connect redis:" + err.Error()) } //定时任务 c := cron.New(cron.WithSeconds()) // 添加每 10 秒执行一次的任务 _, err2 := c.AddFunc("@every 10s", myTask) if err2 != nil { log.Fatal("添加定时任务失败: ", err2) } c.Start() err3 := r.Run(":" + proto.Config.SERVER_PORT) if err3 != nil { panic("failed to run server:" + err3.Error()) } } func init() { //读取配置文件 //文件地址/home/videoplayer/vp.conf configPath := "/home/videoplayer/vp_stream.conf" //读取配置文件 err := proto.ReadConfig(configPath) if err != nil { panic("failed to read config file:" + err.Error()) } for _, device := range proto.Config.DeviceInfo { DeviceRWMap[device.ID] = sync.RWMutex{} DeviceCurrentFrameMap[device.ID] = gocv.NewMat() } } func myTask() { log.Println("每10秒执行一次") } func ReadConfigAndSetSystem() { configPath := "/home/videoplayer/vp_stream.conf" //读取配置文件 err := proto.ReadConfig(configPath) if err != nil { panic("failed to read config file:" + err.Error()) } //检测是否需要获取设备流 } func SetDeviceCurrentFrame(frame gocv.Mat, device_id int) error { //获取读写锁 mutex, ok := DeviceRWMap[device_id] if !ok { return fmt.Errorf("设备:%s 读写锁不存在", device_id) } mutex.Lock() defer mutex.Unlock() //设置当前帧 DeviceCurrentFrameMap[device_id] = frame DeviceFrameCount[device_id]++ return nil } func GetDeviceCurrentFrame(device_id int) (gocv.Mat, int) { //获取读写锁 mutex, ok := DeviceRWMap[device_id] if !ok { return gocv.NewMat(), -1 } mutex.RLock() defer mutex.RUnlock() //获取当前帧 return DeviceCurrentFrameMap[device_id], DeviceFrameCount[device_id] } func getVideoFrame(device proto.DeviceInfo) { webcam, err := gocv.OpenVideoCapture(device.Stream) if err != nil { fmt.Printf("设备:%s 错误: 无法打开视频流,err: %v\n", device.ID, err) return } defer webcam.Close() // 字体相关设置,对应OpenCV默认字体等,这里简化处理,实际可按需求调整 font := gocv.FontHersheySimplex fontScale := 0.5 fontColor := color.RGBA{G: 255} lineType := 2 z := 0 for { if device.LogFrame > 0 && z%device.LogFrame == 0 { fmt.Printf("设备:%s 当前帧: %d\n", device.ID, z) } if device.NextStop { break } frame := gocv.NewMat() ok := webcam.Read(&frame) if !ok { fmt.Printf("设备:%s 错误: 无法从视频流中读取帧\n", device) break } if frame.Empty() { fmt.Printf("设备:%s 错误: 无法从视频流中读取帧\n", device) //等待50ms time.Sleep(50 * time.Millisecond) continue } height := frame.Rows() width := frame.Cols() if height < device.CheckFrameHeight || width < device.CheckFrameWidth { fmt.Printf("设备:%s 帧尺寸已改变\n", device) break } currentTime := time.Now().Format("2006-01-02 15:04:05") gocv.PutText(&frame, currentTime, image.Point{10, 20}, font, fontScale, fontColor, lineType) //需要将帧付给全局变量 err := SetDeviceCurrentFrame(frame, device.ID) if err != nil { fmt.Printf("设备:%s 错误: 无法设置当前帧\n", device) } z++ } } // 发起get请求,返回响应状态码 func Get(url string) int { req, err := http.NewRequest("GET", url, nil) var client = &http.Client{} if err != nil { return 500 } resp, err := client.Do(req) if err != nil { return 500 } return resp.StatusCode } func GetVideoStream(id int) { for { var device proto.DeviceInfo var index int //获取设备信息 for i, device1 := range proto.Config.DeviceInfo { if device1.ID == id { device = device1 break } index = i } if index == len(proto.Config.DeviceInfo) { //设备不存在 log.Println("device:", id, " not found") break } if device.NextStop { DeviceIsStop[id] = true break } //设置设备控制信息 status := Get(device.Control) DeviceIsStop[id] = false log.Println("device:", device.ID, " set control info status:", status) getVideoFrame(device) } } func DoGetVideoStream() { for _, device := range proto.Config.DeviceInfo { go GetVideoStream(device.ID) } }