ONVIF Server 功能完善开发计划

ONVIF Server 功能完善开发计划

当前状态分析

已实现

  • WebSocket 连接管理 (WebsocketHandler / WebsocketSessionManger)
  • 设备/通道/平台 CRUD + 缓存(OnvifDeviceServiceImpl / OnvifDeviceChannelServiceImpl
  • IOnvifService 的基础实现:discoveryqueryChannelInfoplaystopptzStartptzStop
  • WebsocketMessageHandler 处理 INFO / DISCOVERY / CAMERA_INFO 三种消息
  • 数据库表:onvif_device / onvif_device_channel / onvif_platform

完全为空(返回 null)的实现

文件 缺失功能
PlayServiceForOnvifImpl playstopPlaycloseStream
PlaybackServiceForOnvifImpl playbackstopPlaybackplaybackPauseplaybackResumeplaybackSeekplaybackSpeedqueryRecorddownload
PtzServiceForOnvifImpl ptzfrontEndCommandpresetfitourscanauxiliarywiperqueryPresetList
TalkServiceForOnvifImpl getBroadcastUrlbroadcastbroadcastStopbroadcastInUse
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

  1. 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)
  2. 创建 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(用于后续媒体操作)
  • 将获取到的 profileTokenmediaServiceUrlptzServiceUrl 更新到 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 时验证无人观看)

实现步骤:

  1. 调用 OnvifClient.getStreamUri(channel) 获取 RTSP 地址(含用户名密码)
  2. 复用 OnvifServiceImpl.play() 中的 ZLM 拉流逻辑(zlmApiUtils.addStreamProxy
  3. 将 RTSP 地址持久化到 OnvifDeviceChannel.liveStreamTcp/Udp/Multicast
  4. 删除 OnvifServiceImpl.play() 中的 System.out.println

Task 4:完善回放服务

目标文件: PlaybackServiceForOnvifImpl.java

ONVIF 规范对应(Media + Recording Service):

  • queryRecordGetRecordingSummary + GetRecordingInformation (可选 FindRecordings)
  • playbackGetReplayUri(profileToken, startTime) → 返回带时间范围的 RTSP URI
  • stopPlayback → 关闭 ZLM 代理流
  • playbackPause → ZLM pauseRtpCheck(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}}) / Stop
  • ptz(FrontEndControlCodeForPTZ) → 转换控制码后调用 ContinuousMove
  • frontEndCommand → 按 cmdCode 路由至对应 PTZ 操作
  • preset → SetPreset / GotoPreset / RemovePreset(按 frontEndControlCode.getAction 区分)
  • fi(FrontEndControlCodeForFI) → Imaging Service Move(Zoom/Focus)
  • tour → PTZ GotoHomePosition 或 自定义路径(ONVIF Tour Profile)
  • scanContinuousMove 以固定速度持续移动
  • auxiliary → PTZ SendAuxiliaryCommand
  • wiperSendAuxiliaryCommand("tt:Wiper|On") / "tt:Wiper|Off"
  • queryPresetListGetPresets(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.javaWebsocketHandler.javaWebsocketSessionManger.java

改进点:

  1. WebsocketHandler.onOpen:鉴权改为读取配置项 onvif.server-id(替换硬编码 "fastbee"
  2. WebsocketSessionManger:增加心跳检测,定时向所有 Session 发送 PING,超时未响应则移除
  3. WebsocketMessageHandler.handMessage
    • 补充 TALK_START / TALK_STOP / SNAPSHOT / PLAYBACK_QUERY 消息处理分支
    • 统一错误响应处理(当前 CAMERA_INFO 失败时有注释掉的错误响应代码)
  4. OnvifSessionTask.run:取消注释 initDeviceStatus(),在启动时将所有设备状态重置为离线

Task 8:完善快照功能

目标文件: IOnvifService.java(新增)、OnvifServiceImpl.java(新增)

ONVIF 规范: GetSnapshotUri(profileToken) → 返回 HTTP URI → 可直接访问或下载

java 复制代码
// IOnvifService 新增
String getSnapshotUri(Integer channelId);
  • 实现:通过 OnvifClient.getSnapshotUri(channel) 获取快照 HTTP 地址
  • 快照地址需携带用户名密码(Basic Auth 或在 URL 中)

Task 9:数据库表结构扩展

目标文件: onvif.sqlOnvifDeviceChannel.java、对应 Mapper XML

新增字段(onvif_device_channel 表):

sql 复制代码
profile_token VARCHAR(64) COMMENT 'ONVIF配置文件Token',
media_service_url VARCHAR(255) COMMENT 'Media服务地址',
ptz_service_url VARCHAR(255) COMMENT 'PTZ服务地址',
snapshot_uri VARCHAR(255) COMMENT '快照地址',
support_ptz TINYINT(1) DEFAULT 0 COMMENT '是否支持PTZ',
encoding VARCHAR(32) COMMENT '视频编码格式',
resolution_width INT COMMENT '分辨率宽',
resolution_height INT COMMENT '分辨率高'

新增字段(onvif_device 表):

sql 复制代码
ip VARCHAR(64) COMMENT '设备IP(WS-Discovery 发现的地址)',
last_heartbeat DATETIME COMMENT '最后心跳时间'

Task 10:错误处理与异常完善

目标文件: 所有 Service impl 文件

改进点:

  1. 统一 ONVIF SOAP 错误解析:将 SOAP Fault(env:Fault)转换为 ServiceException,错误码区分:
    • ONVIF_AUTH_FAILED(401)
    • ONVIF_DEVICE_UNREACHABLE(设备不通)
    • ONVIF_UNSUPPORTED_OPERATION(设备不支持该操作)
  2. OnvifClient 内增加重试机制(网络超时 3 次重试)
  3. play() 删除 System.out.println,改为 log.debug
  4. ptzStart() 删除 System.out.println
  5. 所有 Service 实现增加入参校验(通道为 null、profileToken 为空等)

Task 11:Service 层单元测试

目标目录: fastbee-server/onvif-server/src/test/java/com/fastbee/onvif/

参照 fastbee-test 模块基类规范,创建以下测试类:

  • OnvifServiceImplTest:测试 discoveryqueryChannelInfoplaystopptzStartptzStop(Mock WebsocketSessionMangerZlmApiUtils
  • PlayServiceForOnvifImplTest:测试 playstopPlay(Mock OnvifClientIMediaCacheService
  • PtzServiceForOnvifImplTest:测试 ptzpresetqueryPresetList(Mock OnvifClient
  • PlaybackServiceForOnvifImplTest:测试 playbackqueryRecord(Mock OnvifClient

测试重点:

  • 设备不存在时抛出 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(单元测试)
相关推荐
蘑菇小白2 小时前
网络:TCP
网络·tcp/ip·udp
汤愈韬2 小时前
ip-prefix(IP前缀列表)
linux·服务器·网络协议·tcp/ip
dldw77710 小时前
IE无法正常登录windows2000server的FTP服务器
运维·服务器·网络
运维有小邓@11 小时前
什么是重放攻击?如何避免成为受害者?
运维·网络·安全
光路科技11 小时前
工业数字化三大核心概念拆解:IIoT、工业互联网与工业4.0
网络
汤愈韬11 小时前
下一代防火墙通用原理
运维·服务器·网络·security
有代理ip13 小时前
网络隐私防护指南:代理服务与换 IP 工具的科学结合
网络·tcp/ip·web安全
不是书本的小明14 小时前
阿里云专有云网络架构
网络·阿里云·架构
mounter62514 小时前
【内核前沿】从 veth 到 netkit:深度解析 TCP devmem 穿透容器屏障的“队列租赁”黑科技
网络·ebpf·linux kernel·devmem tcp·netkit·队列租赁