ONVIF Server 功能完善开发计划
ONVIF Server 功能完善开发计划
当前状态分析
已实现
- WebSocket 连接管理 (
WebsocketHandler/WebsocketSessionManger) - 设备/通道/平台 CRUD + 缓存(
OnvifDeviceServiceImpl/OnvifDeviceChannelServiceImpl) IOnvifService的基础实现:discovery、queryChannelInfo、play、stop、ptzStart、ptzStopWebsocketMessageHandler处理INFO/DISCOVERY/CAMERA_INFO三种消息- 数据库表:
onvif_device/onvif_device_channel/onvif_platform
完全为空(返回 null)的实现
| 文件 | 缺失功能 |
|---|---|
PlayServiceForOnvifImpl | play、stopPlay、closeStream |
PlaybackServiceForOnvifImpl | playback、stopPlayback、playbackPause、playbackResume、playbackSeek、playbackSpeed、queryRecord、download |
PtzServiceForOnvifImpl | ptz、frontEndCommand、preset、fi、tour、scan、auxiliary、wiper、queryPresetList |
TalkServiceForOnvifImpl | getBroadcastUrl、broadcast、broadcastStop、broadcastInUse |
DeviceInfoServiceForOnvifImpl | getDeviceInfo |
其他问题
WebsocketMessageType缺少回放、对讲、快照等消息类型WebsocketHandler.onOpen中鉴权硬编码"fastbee"(TODO 注释)OnvifSessionTask.run注释掉了initDeviceStatus()play()中有System.out.println调试代码ptzStart()中有System.out.println调试代码ConstantHolder缺少回放、对讲等常量OnvifDevice缺少心跳时间、IP 地址等字段
ONVIF 标准协议对应关系
| 功能模块 | ONVIF Service | 关键 Operation |
|---|---|---|
| 设备发现 | WS-Discovery (UDP 广播 239.255.255.250:3702) | Probe/ProbeMatches |
| 设备信息 | Device Service (/onvif/device_service) | GetDeviceInformation,GetCapabilities,GetProfiles |
| 实时流 | Media Service | GetStreamUri(RTSP) |
| 回放流 | Media Service / Recording | GetRecordingSummary,GetRecordingInformation,GetReplayUri |
| PTZ 控制 | PTZ Service | ContinuousMove,Stop,GotoPreset,SetPreset,GetPresets,AbsoluteMove,RelativeMove |
| 焦距/光圈 | PTZ Service / Imaging Service | GetImagingSettings,SetImagingSettings |
| 音视频对讲 | Media Service | GetAudioOutputs,GetAudioSources,GetAudioOutputConfigurationOptions |
| 快照 | Media Service | GetSnapshotUri |
| 事件订阅 | Event Service | Subscribe,PullMessages,Renew,Unsubscribe |
Task 1:引入 onvif4j 依赖并生成 SOAP Stub
目标文件:fastbee-server/onvif-server/pom.xml、父pom.xml
- 在
onvif-server/pom.xml中添加de.onvif:onvif4j依赖(或使用wsdl2java插件生成 Stub)。- 推荐引入
org.onvif:onvif4j:0.2.1或使用 Apache CXF wsdl2java 从以下 WSDL 生成:devicemgmt.wsdl(设备管理)media.wsdl(媒体流)ptz.wsdl(云台)replay.wsdl(回放)recording.wsdl(录像查询)
- 同时引入
org.apache.httpcomponents:httpclient(已有) 用于 WS-Security (Digest Auth)
- 推荐引入
- 创建
OnvifClient工具类(com.fastbee.onvif.util.OnvifClient),封装:- WS-Security UsernameToken 头生成(ONVIF 要求 Digest + Nonce + Created)
- SOAP envelope 构建
- HTTP 调用(基于 Apache HttpClient)
- 响应 XML 解析
Task 2:完善设备发现与设备信息查询
目标文件:
IOnvifService.java新增getDeviceInfo(Integer channelId)方法声明OnvifServiceImpl.java补充实现WebsocketMessageType.java新增SNAPSHOT(7, "snapshot")、TALK_START(8, "talk_start")、TALK_STOP(9, "talk_stop")、PLAYBACK_START(10, "playback_start")、PLAYBACK_STOP(11, "playback_stop")、PLAYBACK_QUERY(12, "playback_query")ConstantHolder.java补充常量DeviceInfoServiceForOnvifImpl.java实现getDeviceInfo
实现要点(符合 ONVIF Device Service 规范):
getDeviceInfo → SOAP: GetDeviceInformation → 返回 Manufacturer, Model, FirmwareVersion, SerialNumber, HardwareId getCapabilities → SOAP: GetCapabilities(All) → 获取 MediaServiceAddress, PTZServiceAddress getProfiles → SOAP: GetProfiles → 获取 ProfileToken(用于后续媒体操作)- 将获取到的
profileToken、mediaServiceUrl、ptzServiceUrl更新到OnvifDeviceChannel OnvifDeviceChannel需新增字段:profileToken VARCHAR(64)、mediaServiceUrl VARCHAR(255)、ptzServiceUrl VARCHAR(255)- 对应更新
onvif.sql
Task 3:完善视频流播放服务
目标文件:PlayServiceForOnvifImpl.java
ONVIF 规范对应:
play(channel)→GetStreamUri(StreamSetup{RTPUnicast/RTPMulticast, RTSP}, profileToken)→ 返回 RTSP URI → 通过 ZLM 拉流代理stopPlay(channel)→ 关闭 ZLM 代理流closeStream(channel, stream, check)→ 条件关闭(check 为 true 时验证无人观看)
实现步骤:
- 调用
OnvifClient.getStreamUri(channel)获取 RTSP 地址(含用户名密码) - 复用
OnvifServiceImpl.play()中的 ZLM 拉流逻辑(zlmApiUtils.addStreamProxy) - 将 RTSP 地址持久化到
OnvifDeviceChannel.liveStreamTcp/Udp/Multicast - 删除
OnvifServiceImpl.play()中的System.out.println
Task 4:完善回放服务
目标文件:PlaybackServiceForOnvifImpl.java
ONVIF 规范对应(Media + Recording Service):
queryRecord→GetRecordingSummary+GetRecordingInformation(可选FindRecordings)playback→GetReplayUri(profileToken, startTime)→ 返回带时间范围的 RTSP URIstopPlayback→ 关闭 ZLM 代理流playbackPause→ ZLMpauseRtpCheck(RTSP PAUSE 命令通过 ZLM API)playbackResume→ ZLM 继续播放(RTSP PLAY 命令)playbackSeek→ 重新拉起带 seek 时间的流(ONVIF Replay URI 带 starttime 参数)playbackSpeed→ ONVIF 暂未标准化,通过 ZLM 控制播放速率download→ 与playback相同 URI,速率设为指定downloadSpeed
依赖:IOnvifService(通过 Autowired 调用OnvifClient)
Task 5:完善 PTZ 云台控制服务
目标文件:PtzServiceForOnvifImpl.java
ONVIF PTZ Service 规范对应:
ptz(PtzInput)→ContinuousMove(profileToken, velocity{PanTilt{x,y}, Zoom{x}})/Stopptz(FrontEndControlCodeForPTZ)→ 转换控制码后调用ContinuousMovefrontEndCommand→ 按 cmdCode 路由至对应 PTZ 操作preset → SetPreset/GotoPreset/RemovePreset(按frontEndControlCode.getAction区分)fi(FrontEndControlCodeForFI)→ Imaging ServiceMove(Zoom/Focus)tour→ PTZGotoHomePosition或 自定义路径(ONVIF Tour Profile)scan→ContinuousMove以固定速度持续移动auxiliary→ PTZSendAuxiliaryCommandwiper→SendAuxiliaryCommand("tt:Wiper|On")/"tt:Wiper|Off"queryPresetList→GetPresets(profileToken)→ 返回List<Preset>
数据转换:将 FastBee 的速度值(-100~100)转换为 ONVIF 的 -1.0~1.0 浮点数
Task 6:完善对讲服务
目标文件:TalkServiceForOnvifImpl.java
ONVIF 规范对应:
- ONVIF 对讲通过 Media Service 的 Audio 部分实现,实际音频通过 ZLM 推流
getBroadcastUrl(channel)→GetAudioOutputs+ 构建 ZLM 推流地址broadcast(channel)→ 创建 ZLM 推流会话,返回推流地址(WebRTC/RTMP)broadcastStop(channel)→ 关闭 ZLM 推流会话broadcastInUse(channel)→ 检查 ZLM 当前是否有活跃的对讲流
Task 7:完善 WebSocket 通信机制
目标文件:WebsocketMessageHandler.java、WebsocketHandler.java、WebsocketSessionManger.java
改进点:
WebsocketHandler.onOpen:鉴权改为读取配置项onvif.server-id(替换硬编码"fastbee")WebsocketSessionManger:增加心跳检测,定时向所有 Session 发送 PING,超时未响应则移除WebsocketMessageHandler.handMessage:- 补充
TALK_START/TALK_STOP/SNAPSHOT/PLAYBACK_QUERY消息处理分支 - 统一错误响应处理(当前 CAMERA_INFO 失败时有注释掉的错误响应代码)
- 补充
OnvifSessionTask.run:取消注释initDeviceStatus(),在启动时将所有设备状态重置为离线
Task 8:完善快照功能
目标文件:IOnvifService.java(新增)、OnvifServiceImpl.java(新增)
ONVIF 规范:GetSnapshotUri(profileToken)→ 返回 HTTP URI → 可直接访问或下载
// IOnvifService 新增StringgetSnapshotUri(IntegerchannelId);- 实现:通过
OnvifClient.getSnapshotUri(channel)获取快照 HTTP 地址 - 快照地址需携带用户名密码(Basic Auth 或在 URL 中)
Task 9:数据库表结构扩展
目标文件:onvif.sql、OnvifDeviceChannel.java、对应 Mapper XML
新增字段(onvif_device_channel表):
profile_tokenVARCHAR(64)COMMENT'ONVIF配置文件Token',media_service_urlVARCHAR(255)COMMENT'Media服务地址',ptz_service_urlVARCHAR(255)COMMENT'PTZ服务地址',snapshot_uriVARCHAR(255)COMMENT'快照地址',support_ptzTINYINT(1)DEFAULT0COMMENT'是否支持PTZ',encodingVARCHAR(32)COMMENT'视频编码格式',resolution_widthINTCOMMENT'分辨率宽',resolution_heightINTCOMMENT'分辨率高'新增字段(onvif_device表):
ipVARCHAR(64)COMMENT'设备IP(WS-Discovery 发现的地址)',last_heartbeatDATETIMECOMMENT'最后心跳时间'Task 10:错误处理与异常完善
目标文件:所有 Service impl 文件
改进点:
- 统一 ONVIF SOAP 错误解析:将 SOAP Fault(
env:Fault)转换为ServiceException,错误码区分:ONVIF_AUTH_FAILED(401)ONVIF_DEVICE_UNREACHABLE(设备不通)ONVIF_UNSUPPORTED_OPERATION(设备不支持该操作)
OnvifClient内增加重试机制(网络超时 3 次重试)play()删除System.out.println,改为log.debugptzStart()删除System.out.println- 所有 Service 实现增加入参校验(通道为 null、profileToken 为空等)
Task 11:Service 层单元测试
目标目录:fastbee-server/onvif-server/src/test/java/com/fastbee/onvif/
参照fastbee-test模块基类规范,创建以下测试类:
OnvifServiceImplTest:测试discovery、queryChannelInfo、play、stop、ptzStart、ptzStop(MockWebsocketSessionManger、ZlmApiUtils)PlayServiceForOnvifImplTest:测试play、stopPlay(MockOnvifClient、IMediaCacheService)PtzServiceForOnvifImplTest:测试ptz、preset、queryPresetList(MockOnvifClient)PlaybackServiceForOnvifImplTest:测试playback、queryRecord(MockOnvifClient)
测试重点:
- 设备不存在时抛出
ServiceException - WebSocket 未连接时抛出
ServiceException - ONVIF 调用失败时的错误传播
Task 12:WebSocket 消息协议文档说明
在onvif-server/src/main/resources/下创建onvif-websocket-protocol.md(仅在用户明确要求时)
此任务按需执行,不强制创建文档。
实施顺序
Task 1(依赖引入)→ Task 9(DB扩展)→ Task 2(设备信息)→ Task 7(WebSocket改进) → Task 3(播放)→ Task 4(回放)→ Task 5(PTZ)→ Task 6(对讲)→ Task 8(快照) → Task 10(错误处理)→ Task 11(单元测试)