如何使用JavaScript通过ONVIF接口获取摄像头录像数据
问题描述
尝试通过ONVIF接口获取VIVOTEK品牌摄像头的录像数据,参照ONVIF官方recording.wsdl文档调用exportRecordedData函数时未得到预期结果,抛出如下错误:
2022-06-10T04:39:59.728Z error: exportRecordedData(): Error: Error: ONVIF SOAP Fault: Operation Action Not Implemented. The requested action operation is not implemented by the device.
需要明确JavaScript环境下通过ONVIF协议正确拉取摄像头录像的实现方式。
故障原因
报错Operation Action Not Implemented的核心原因是VIVOTEK主流在售机型均未实现ONVIF规范中的exportRecordedData接口。该接口属于ONVIF Recording Search服务的可选实现项,不属于ONVIF强制要求厂商适配的功能,直接调用必然返回未实现错误。
正确实现步骤
- 第一步:先做设备能力探测,禁止直接硬编码调用接口。首先调用ONVIF标准的
GetCapabilities接口,查询设备实际支持的服务端点,重点确认设备是否开放Replay服务(对应ONVIF标准的录像回放拉流能力),不要在未做能力探测的前提下直接调用Recording服务下的导出类接口。 - 第二步:查询设备存储的录像列表。依次调用
FindRecordings、GetRecordingSearchResults接口,获取设备本地存储的录像片段对应的时间范围、录像源token信息。调用前需要先登录摄像头Web后台,给对应ONVIF账号开启录像查看权限,否则会返回403权限错误。 - 第三步:获取录像回放流地址。拿到有效录像token和需要拉取的起止时间范围后,调用Replay服务的
GetReplayUri接口,传入流传输配置、录像token、拉流时间范围,获取RTSP格式的录像回放流地址。 - 第四步:拉取并保存录像。拿到RTSP回放地址后,使用Node.js生态下的
ffmpeg封装库、node-rtsp-stream等工具拉取RTSP流,直接保存为本地录像文件或者做后续转码处理即可,不需要通过SOAP接口传输录像二进制数据。
核心实现代码参考(基于常用的onvif npm包):
const onvif = require('onvif'); const { exec } = require('child_process'); // 初始化摄像头连接 const cam = new onvif.Cam({ hostname: '摄像头局域网IP', username: 'ONVIF账号', password: 'ONVIF密码', port: 80 }, async err => { if (err) throw err; // 拉取设备能力列表 await cam.getCapabilities(); const replayServiceAddr = cam.capabilities.replay?.XAddr; if (!replayServiceAddr) throw new Error('当前设备不支持ONVIF标准录像回放服务'); // 构造GetReplayUri请求体 const soapBody = ` <GetReplayUri xmlns="http://www.onvif.org/ver10/replay.wsdl"> <StreamSetup> <Stream xmlns="http://www.onvif.org/ver10/schema">RTP-Unicast</Stream> <Transport xmlns="http://www.onvif.org/ver10/schema"> <Protocol>RTSP</Protocol> </Transport> </StreamSetup> <RecordingToken>查询到的目标录像片段token</RecordingToken> </GetReplayUri>`; // 发送SOAP请求获取回放RTSP地址 cam._request(replayServiceAddr, soapBody, (err, res) => { if (err) throw err; const rtspUrl = res[0].getElementsByTagName('Uri')[0].textContent; console.log('录像回放RTSP地址:', rtspUrl); // 示例:调用ffmpeg拉流保存为mp4文件 exec(`ffmpeg -i "${rtspUrl}" -c copy ./record-${Date.now()}.mp4`, (err) => { if (err) console.error('录像保存失败', err); }); }); });
注意事项:
- 部分旧版本VIVOTEK固件的ONVIF实现存在时区偏差问题,传入拉流起止时间时需要和设备本地时区对齐,否则会返回找不到对应录像的错误。
- 如果
GetReplayUri接口同样返回未实现错误,可以直接使用VIVOTEK私有RTSP回放规则拼接地址,格式为rtsp://账号:密码@摄像头IP:554/live/回放通道号?starttime=YYYYMMDDTHHMMSS&endtime=YYYYMMDDTHHMMSS,无需走ONVIF SOAP接口即可拉取录像。
内容的提问来源于stack exchange,提问作者Aseem Mangla
相关产品推荐
相关产品推荐

