TSINGSEE青犀视频开发的人脸识别视频智能安防系统EasyCVR的V1.1.12版本修改了实时快照和定时快照的处理逻辑。目前的版本可以通过调用接口的方式返回实时快照,返回形式为快照地址或者base64快照数据两种。
此次更新过后虽解决了原本的问题,但引入了其他的问题。如果用户采用按需播放的情况并且开启了快照,快照间隔时间1分钟,则会出现按需播放1-2分钟的时候,画面卡顿1-2s然后恢复正常播放的情况。
测试人员反馈该问题,通过复现,发现现象很有规律,进一步定位和快照有关,因此检查相关代码,代码显示没有对正在按需播放的情况进行处理,没有判断当前拉流状态。
因此我们添加判断逻辑即可解决该bug,参考代码如下:
if dataType == DATA_TYPE_VIDEO_FRAME {
//[v1.0.25] 解决265 级联播放花屏
client.PtsMs += 40
if avFrame.u32VFrameType == C.EASY_SDK_VIDEO_FRAME_I {
flag := true
thisTime := time.Now()
snapInterval := utils.Conf().Section("base_config").Key("channel_snap_interval").MustInt(-1)
if snapInterval > 0 {
//保存快照
if thisTime.After(client.SnapTime.Add(client.SnapDuration)) || client.GetSourceBase().Snaping {
client.SnapTime = thisTime
jpg, _ := h264.GetJPG(C.GoBytes(unsafe.Pointer(avFrame.pBuffer), C.int(avFrame.u32AVFrameLen)))
channelDB, err := cvrdao.GetChannelDao().Get(client.channelID)
if err == nil {
if err := ioutil.WriteFile(channelDB.SnapPath(), jpg, 0644); err != nil {
log.Println(err.Error())
//break
}
if channelDB.Online == 0 {
channelDB.Online = 1
cvrdao.GetChannelDao().Update(channelDB)
}
}
if utils.Debug {
log.Println("快照生成成功")
log.Println(client.GetSourceBase().Snaping)
}
flag = false
if client.GetSourceBase().Snaping {
client.GetSourceBase().Snaping = false
if channelDB.OnDemand != 0 {
if utils.Debug {
log.Println("快照临时拉流,关闭流")
}
if client.GetSourceBase().AfterSnapCloseSource {
go client.Close()
}
}
}
}
}
if flag && client.GetSourceBase().RealSnaping {
client.SnapTime = thisTime
jpg, _ := h264.GetJPG(C.GoBytes(unsafe.Pointer(avFrame.pBuffer), C.int(avFrame.u32AVFrameLen)))
channelDB, err := cvrdao.GetChannelDao().Get(client.channelID)
if err == nil {
if err := ioutil.WriteFile(channelDB.SnapPath(), jpg, 0644); err != nil {
log.Println(err.Error())
//break
}
if channelDB.Online == 0 {
channelDB.Online = 1
cvrdao.GetChannelDao().Update(channelDB)
}
}
log.Println("快照生成成功")
client.GetSourceBase().RealSnaping = false
}
}
} else if dataType == DATA_TYPE_AUDIO_FRAME {
channelDB, err := cvrdao.GetChannelDao().Get(client.channelID)
if err == nil {
if channelDB.EnableAudio == 0 {
return
}
}
}
sinks := client.Base.GetSinks()
for _, value := range sinks {
if value.GetSinkID() == 0 && !client.Base.Record { //录像计划
continue
}
if err := value.SendRTMPEx(uintptr(unsafe.Pointer(avFrame)), int(client.MediaInfo.u32VideoCodec), client.PtsMs); err != nil {
log.Println(err.Error())
}
}
}