package service import ( "VideoStream/dao" "VideoStream/proto" "VideoStream/worker" "fmt" "github.com/ulule/deepcopier" "gocv.io/x/gocv" "image" "image/color" "log" "net/http" "sync" "time" ) var DeviceRWMap = &sync.Map{} var DeviceCurrentFrameMap = &sync.Map{} var DeviceFrameCount = &sync.Map{} var DeviceIsGettingFrame = &sync.Map{} var Device1CurrentFrame gocv.Mat var Device50CurrentFrame gocv.Mat func SetDeviceCurrentFrame(frame gocv.Mat, device_id int) error { //获取读写锁 mutex_, ok := DeviceRWMap.Load(device_id) if !ok { return fmt.Errorf("设备:%s 读写锁不存在", device_id) } mutex := mutex_.(*sync.RWMutex) mutex.Lock() defer mutex.Unlock() //获取前一帧,将前一帧释放 framePrev, ok := DeviceCurrentFrameMap.Load(device_id) if ok { frame_, ok2 := framePrev.(gocv.Mat) if ok2 { err2 := frame_.Close() if err2 != nil { log.Printf("设备:%d, 错误: 无法关闭帧\n", device_id) } } } //设置当前帧 DeviceCurrentFrameMap.Store(device_id, frame) frame_count, ok := DeviceFrameCount.Load(device_id) if !ok { return fmt.Errorf("设备:%s 当前帧计数不存在", device_id) } frame_count_ := frame_count.(int) frame_count_++ DeviceFrameCount.Store(device_id, frame_count_) return nil } func SetDeviceCurrentFrameV2(frame *gocv.Mat, device_id int) error { //获取读写锁 mutex_, ok := DeviceRWMap.Load(device_id) if !ok { return fmt.Errorf("设备:%s 读写锁不存在", device_id) } mutex := mutex_.(*sync.RWMutex) mutex.Lock() defer mutex.Unlock() //设置当前帧 switch device_id { case 1: //err := Device1CurrentFrame.Close() //if err != nil { // log.Printf("设备:%d, 错误: 无法关闭帧\n", device_id) //} deepcopier.Copy(frame).To(&Device1CurrentFrame) //Device1CurrentFrame = *frame case 50: //err := Device50CurrentFrame.Close() //if err != nil { // log.Printf("设备:%d, 错误: 无法关闭帧\n", device_id) //} //Device50CurrentFrame = *frame deepcopier.Copy(frame).To(&Device50CurrentFrame) } frame_count, ok := DeviceFrameCount.Load(device_id) if !ok { return fmt.Errorf("设备:%s 当前帧计数不存在", device_id) } frame_count_ := frame_count.(int) frame_count_++ DeviceFrameCount.Store(device_id, frame_count_) return nil } func GetDeviceCurrentFrameV2(frame *gocv.Mat, deviceId int) int { defer func() { if err := recover(); err != nil { log.Printf("设备:%d 错误: %v\n", deviceId, err) } }() //获取读写锁 mutex_, ok := DeviceRWMap.Load(deviceId) if !ok { log.Printf("DeviceRWMap 读写锁不存在,device_id: %d \n", deviceId) return -1 } mutex, ok := mutex_.(*sync.RWMutex) if !ok { log.Printf("DeviceRWMap 存储的不是 *sync.RWMutex 类型,device_id: %d \n", deviceId) return -1 } mutex.RLock() defer mutex.RUnlock() var frame_ gocv.Mat //获取当前帧 frameIface, ok := DeviceCurrentFrameMap.Load(deviceId) if !ok { return -1 } frame_, ok = frameIface.(gocv.Mat) if !ok { log.Printf("DeviceCurrentFrameMap 存储的不是 gocv.Mat 类型,device_id: %d \n", deviceId) } *frame = frame_ frame_countIface, ok := DeviceFrameCount.Load(deviceId) if !ok { return -1 } frame_count, ok := frame_countIface.(int) if !ok { log.Printf("DeviceFrameCount 存储的不是 int 类型,device_id: %d", deviceId) } return frame_count } func GetDeviceCurrentFrameV3(deviceId int) (gocv.Mat, int) { defer func() { if err := recover(); err != nil { log.Printf("设备:%d 错误: %v\n", deviceId, err) } }() //获取读写锁 mutex_, ok := DeviceRWMap.Load(deviceId) if !ok { log.Printf("DeviceRWMap 读写锁不存在,device_id: %d \n", deviceId) return gocv.NewMat(), -1 } mutex, ok := mutex_.(*sync.RWMutex) if !ok { log.Printf("DeviceRWMap 存储的不是 *sync.RWMutex 类型,device_id: %d \n", deviceId) return gocv.NewMat(), -1 } mutex.RLock() defer mutex.RUnlock() //获取当前帧 var frame gocv.Mat switch deviceId { case 1: frame = Device1CurrentFrame //查看帧状态 log.Printf("frame:%v,Device1CurrentFrame:%v \n", frame.Empty(), Device1CurrentFrame.Empty()) case 50: frame = Device50CurrentFrame //查看帧状态 log.Printf("frame:%v,Device50CurrentFrame:%v\n", frame.Empty(), Device50CurrentFrame.Empty()) } frame_countIface, ok := DeviceFrameCount.Load(deviceId) if !ok { return gocv.NewMat(), -1 } frame_count, ok := frame_countIface.(int) if !ok { log.Printf("DeviceFrameCount 存储的不是 int 类型,device_id: %d", deviceId) } //查看地址 log.Printf("frame:%p,Device1CurrentFrame:%p,Device50CurrentFrame:%p\n", &frame, &Device1CurrentFrame, &Device50CurrentFrame) return frame, frame_count } func GetDeviceCurrentFrame(deviceId int) (gocv.Mat, int) { defer func() { if err := recover(); err != nil { log.Printf("设备:%d 错误: %v\n", deviceId, err) } }() //获取读写锁 mutex_, ok := DeviceRWMap.Load(deviceId) if !ok { log.Printf("DeviceRWMap 读写锁不存在,device_id: %d \n", deviceId) return gocv.NewMat(), -1 } mutex, ok := mutex_.(*sync.RWMutex) if !ok { log.Printf("DeviceRWMap 存储的不是 *sync.RWMutex 类型,device_id: %d \n", deviceId) return gocv.NewMat(), -1 } mutex.RLock() defer mutex.RUnlock() //获取当前帧 frameIface, ok := DeviceCurrentFrameMap.Load(deviceId) if !ok { return gocv.NewMat(), -1 } frame, ok := frameIface.(gocv.Mat) if !ok { log.Printf("DeviceCurrentFrameMap 存储的不是 gocv.Mat 类型,device_id: %d \n", deviceId) } frame_countIface, ok := DeviceFrameCount.Load(deviceId) if !ok { return gocv.NewMat(), -1 } frame_count, ok := frame_countIface.(int) if !ok { log.Printf("DeviceFrameCount 存储的不是 int 类型,device_id: %d", deviceId) } return frame, frame_count } func getVideoFrame(device proto.DeviceInfo) { //捕获异常 defer func() { if err := recover(); err != nil { log.Printf("设备:%d 错误: %v\n", device.ID, err) } }() webcam, err := gocv.OpenVideoCapture(device.Stream) if err != nil { log.Printf("设备:%d 错误: 无法打开视频流,err: %v\n", device.ID, err) return } defer func(webcam *gocv.VideoCapture) { err2 := webcam.Close() if err2 != nil { log.Printf("设备:%d 错误: 无法关闭视频流,%s \n", device.ID, err2.Error()) } }(webcam) // 字体相关设置,对应OpenCV默认字体等,这里简化处理,实际可按需求调整 font := gocv.FontHersheySimplex fontScale := 0.5 fontColor := color.RGBA{G: 255} lineType := 2 z := 0 var frame gocv.Mat for { if device.LogFrame > 0 && z%device.LogFrame == 0 { log.Printf("设备:%d 当前帧: %d\n", device.ID, z) } if device.NextStop { break } frame = gocv.NewMat() ok := webcam.Read(&frame) if !ok { log.Printf("设备:%v 错误: 无法从视频流中读取帧\n", device) break } if frame.Empty() { log.Printf("设备:%s 错误: 无法从视频流中读取帧\n", device) //等待50ms time.Sleep(50 * time.Millisecond) continue } height := frame.Rows() width := frame.Cols() if height < device.CheckFrameHeight || width < device.CheckFrameWidth { log.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) //需要将帧付给全局变量 err3 := SetDeviceCurrentFrameV2(&frame, device.ID) if err3 != nil { log.Printf("设备:%d 错误: 无法设置当前帧,err:%s \n", device.ID, err3.Error()) } z++ //关闭帧 err4 := frame.Close() if err4 != nil { log.Printf("设备:%d 错误: 无法关闭帧,err:%s \n", device.ID, err4.Error()) } } //关闭帧 err4 := frame.Close() if err4 != nil { log.Printf("设备:%d 错误: 无法关闭帧,err:%s \n", device.ID, err4.Error()) } } // 发起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) { defer func() { if err := recover(); err != nil { log.Printf("设备:%d 错误: %v\n", id, err) } }() is_get, ok := DeviceIsGettingFrame.Load(id) if !ok { log.Printf("device: %d not found", id) return } if is_get == true { log.Printf("device: %d is running!", id) return } 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.Printf("device: %d not found", id) break } is_get, ok = DeviceIsGettingFrame.Load(id) if is_get == true { log.Printf("for device:%d is running!", id) break } if device.NextStop { DeviceIsGettingFrame.Store(id, false) break } //设置设备控制信息 status := Get(device.Control) DeviceIsGettingFrame.Store(id, true) log.Printf("device: %d set control info status: %d", device.ID, status) getVideoFrame(device) DeviceIsGettingFrame.Store(id, false) //等待1s time.Sleep(1 * time.Second) } } func DoGetVideoStream() { for _, device := range proto.Config.DeviceInfo { go GetVideoStream(device.ID) } } func GetDevice(id, auth_id int) dao.Device { return dao.FindDeviceByID(id, auth_id) } func SetConfigRedis(key, config string) { worker.SetRedis(key, config) }