网络媒体设备控制协议
网络媒体设备控制协议
媒体设备接入 API
摄像机通过 MQTT 协议连接到云平台,可以实现按需推流和云台控制等功能
消息格式
摄像机和平台使用统一的物联网平台消息格式,具体请参考 设备接入协议
{
"did": String,
"mid": String,
"type": String,
"sign": String,
"token": String,
"timestamp": Number,
"data": {
}
}
公共属性:
did
必需,设备的 ID,平台范围内须保证唯一,实际情况下常使用 mac 地址或产品序列号等mid
消息 ID,在 RPC 类消息中是必需,如action
消息,应答消息和请求消息的 mid 必须相同,但不同消息间不能重复type
必需,消息的类型,如regiser
,action
,event
等sign
设备签名,只在注册时需要token
开启权限时必需,访问凭证,访问不同的资源需要提供相应的凭证timestamp
可选,时间戳,表示消息的发送时间data
消息的内容
设备注册
推流摄像机
一台推流设备只能推送一支流
摄像机->MQ: 订阅 (actions/{did})
设备管理服务->MQ: 订阅 (messages/{did})
摄像机->MQ: 注册 (摄像机)
MQ->设备管理服务: 注册
设备管理服务->MQ: 注册结果
MQ->摄像机: 注册结果
- 推流摄像机通过 MQTT 连接到云平台
- 推流摄像机向云台平注册并等待推流请求
- 每次注册有效期期满前需要更新注册
消息上报主题
下面假设摄像机的设备 ID 为 001122334455
PUBLISH mqtt://{domain-name}/messages/001122334455
- 应用程序 ID: 同 did
- username 不需要
- password 不需要
摄像机注册消息
{
"did": "001122334455",
"type": "register",
"sign": "1234567890abcdef",
"data": {
}
}
did
摄像机设备 IDsign
设备签名type
总是为register
data
摄像机设备描述信息
应答消息:
{
"did": "001122334455",
"type": "register",
"result": {
"id": "3434689jkjsdf34398095829",
"expires": 3600,
"token": "39409080928349028592"
}
}
did
摄像机设备 IDtype
总是为 `registerresult
注册结果id
由服务端会配的 IDtoken
设备访问令牌expires
访问令牌有效时间,单位为秒
推流网关
一台网关设备可以关联多台摄像机并推送多支流
网络摄像机->推流网关: 绑定
推流网关->MQ: 订阅 'actions/{gateway}'
设备管理服务->MQ: 订阅 'messages/+'
推流网关->MQ: 注册 (网关)
MQ->设备管理服务: 注册
设备管理服务->MQ: 注册结果
MQ->推流网关: 注册结果
推流网关->MQ: 注册子设备 (摄像机)
MQ->设备管理服务: 注册
设备管理服务->MQ: 注册结果
MQ->推流网关: 注册结果
- 一个网关可以管理多台摄像机,每台摄像机有一个唯一 DID
- 网关通过 ONVIF 协议连接和管理摄像机
- 摄像机可以在网关安装时绑定
- 网关通过 MQTT 协议注册到云端
- 网关代为每一个摄像机注册到云端并订阅相应 ID 的操作命令接收主题
设备通过注册来激活设备以及获取设备 token.
消息上报主题
下面假设网关的设备 ID 为 001122334455
PUBLISH mqtt://{domain-name}/messages/001122334455
- 应用程序 ID: 同 did
- username 不需要
- password 不需要
网关注册消息
{
"did": "001122334455",
"type": "register",
"sign": "012345678900123456789012:md5",
"data": {
}
}
did
网关设备 IDsign
设备签名type
总是为register
data
网关设备描述信息
应答消息:
{
"did": "001122334455",
"type": "register",
"result": {
"id": "3434689jkjsdf34398095829",
"expires": 3600,
"token": "39409080928349028592"
}
}
did
网关设备 IDtype
总是为 `registerresult
注册结果id
由服务端会配的 IDtoken
设备访问令牌expires
访问令牌有效时间,单位为秒
设备控制
摄像机->网关: 绑定
网关->MQ: 订阅(actions/{did})
设备管理服务->MQ: 订阅 (messages/+)
应用程序->设备管理服务: 操作命令 (HTTP)
设备管理服务->MQ: 操作命令
MQ->网关: 操作命令
网关->摄像机: 执行操作
摄像机->网关: 返回结果
网关->MQ: 操作结果 (messages/{did})
MQ->设备管理服务: 返回结果
设备管理服务->应用程序: 返回结果 (HTTP)
- 因为 MQTT 是异常通信,所以操作命令和操作结果消息中的
mid
必需相同,且不要和其他消息重复 - 网关收到摄像机操作命令后,根据指令内容操作相应 ID 的摄像机并回复操作结果
- 操作请求消息和回复消息一一对应
- 应用程序 HTTP 请求如果超时(默认 5 秒)没有收到应答,则操作失败
设备启动后需要订阅下面的主题来接收云端控制命令
SUBSCRIBE mqtt://{domain-name}/actions/001122334455
应答消息回复地址
PUBLISH mqtt://{domain-name}/messages/001122334455
网络摄像机
通用监控摄像机
- 通过以太网通信
- 通信协议: ONVIF/RTSP/RTMP
- 数据格式: JSON/H.264
播放 - play
流媒体服务器通过发送 play
和 stop
操作请求,控制摄像机按需推送音视频流,应用程序则只需直接连接和播放流媒体服务器的地址即可,不需要直接和摄像机通信。
流媒体服务器会定时发送通知,告知前端摄像机当前应用程序播放状态,前端摄像机可以根据请求自动开始或停止推送,以便节省带宽资源。
开始播放
由流媒体服务器发送消息给设备:
{
"did": "001122334455",
"mid": "1234",
"token": "play-token",
"type": "action",
"data": {
"play": {
"url": String,
"players": Number
}
}
}
did
设备 IDmid
消息 IDtype
消息类型,总是为action
data
操作数据play
播放操作url
推流地址, 如rtmp://{domain-name}/live/001122334455
,摄像机需要推流到这个地址players
当前正在播放的客户端数量,摄像机不需要关心这个值, 且不管有多个少客户端同时播放都只需要上传一支流
应答消息:
PUBLISH messages/001122334455
{
"did": "001122334455",
"mid": "1234",
"type": "action",
"result": {
"play": {
"code": 0
}
}
}
- 摄像机收到 play 命令后需要立即开始推流
- play 会定期重复发送直到发送 stop 命令为止
心跳消息
为了使摄像机一直向服务端推送视频流,流媒体服务器需要定时 (每隔 60 秒) 重复发送 play 消息给设备
停止播放
当所有应用程序都停止播放后,流媒体服务器会通知摄像机停止推流 (通常会延时 60 秒后发送,以免频繁关停推流)
由流媒体服务器发送给设备:
{
"did": "001122334455",
"mid": "1234",
"token": "play-token",
"type": "action",
"data": {
"stop": {
"reason": "It's all play done"
}
}
}
did
设备 IDmid
消息 IDtype
消息类型,总是为action
data
操作数据stop
停止播放操作reason
建议提供,表示停止推流的原因
应答消息:
PUBLISH messages/001122334455
{
"did": "001122334455", // 必需, 设备 ID
"mid": "1234", // 必需, 消息 ID
"type": "action", // 必需, 消息类型
"result": {
"stop": {
"code": 0 // 必需, 表示调用成功
}
}
}
- 摄像机收到 stop 命令后可以立即停止推流
- 摄像机在超过 120 秒后没有收到过 play 命令也需要停止推流
云台 - ptz
start
转动去台stop
停止转动
开始转动
通过这个命令可以控制摄像机镜头上下左右摆动,或者放大缩小
{
"did": "001122334455",
"mid": "1234",
"token": "ptz-token",
"type": "action",
"data": {
"ptz": {
"start": {
"direction": Number,
"speed": Number
}
}
}
}
did
设备 IDmid
消息 IDtype
消息类型,总是为action
data
操作数据ptz
云台操作method
云台操作方法, 总是为start
direction
方向0
上1
下2
左3
右4
左上5
左下6
右上7
右下8
放大9
缩小
speed
云台速度:0
慢1
适中2
快
应答消息:
{
"did": "001122334455",
"mid": "1234",
"type": "action",
"result": {
"ptz": {
"code": 0
}
}
}
停止转动
通过这个命令可以控制摄像机镜头停止摆动或缩放,就算摄像机没有成功收到这个命令,也需要在超过一定时间后自动停止摆动或缩放 (巡航等模式除外)
由流媒体服务器发送给设备:
{
"did": "001122334455",
"mid": "1234",
"token": "ptz-token",
"type": "action",
"data": {
"ptz": {
"stop": {}
}
}
}
did
设备 IDmid
消息 IDtype
消息类型,总是为action
data
操作数据ptz
云台操作method
云台操作方法, 总是为stop
应答消息:
{
"did": "001122334455",
"mid": "1234",
"token": "ptz-token",
"type": "action",
"result": {
"ptz": {
"code": 0
}
}
}
错误应答消息
{
"did": "001122334455",
"mid": "1234",
"type": "action",
"result": {
"ptz": {
"code": Number,
"error": String
}
}
}
did
必需, 设备 IDmid
必需, 消息 IDtype
必需, 消息类型,总是为action
result
操作结果ptz
云台操作code
必需, 错误码error
必需, 错误类型
错误码:
CODE | ERROR |
---|---|
60000 | 该设备不支持云台控制 |
60001 | 没有云台控制权限 |
60002 | 设备云台旋转达到上限位 |
60003 | 设备云台旋转达到下限位 |
60004 | 设备云台旋转达到左限位 |
60005 | 设备云台旋转达到右限位 |
60006 | 云台当前操作失败,请稍后再试 |
60009 | 正在调用预置点 |
60020 | 不支持该命令 |
预置位 - preset
read
预置位列表set
设置预置位remove
删除预置位goto
转到预置位
设置预置位
将当前云台位置设置为指定的预置位
由流媒体服务器发送给设备:
{
"did": "001122334455",
"mid": "1234",
"token": "preset-token",
"type": "action",
"data": {
"preset": {
"set": {
"index": 1,
"name": "[name]"
}
}
}
}
did
摄像机 IDmid
消息 ID, 不同消息不可重复type
总是为action
data
操作数据preset
预置位操作set
设置预置位操作index
必需,预置位索引,1-128name
可选,预置位显示名称
返回结果:
{
"did": "001122334455",
"mid": "1234",
"type": "action",
"result": {
"preset": {
"code": 0
}
}
}
did
摄像机 IDmid
消息 ID, 必须同请求消息一致type
总是为action
result
操作结果preset
预置位操作code
操作结果,0 表示成功
查询预置位列表
查询摄像机已设置的预置位列表
由流媒体服务器发送给设备:
{
"did": "001122334455",
"mid": "1234",
"token": "preset-token",
"type": "action",
"data": {
"preset": {
"list": {}
}
}
}
did
摄像机 IDmid
消息 ID, 不同消息不可重复type
总是为action
data
操作数据preset
预置位操作list
查询预置位列表
返回结果:
{
"did": "001122334455",
"mid": "1234",
"token": "preset-token",
"type": "action",
"result": {
"preset": {
"presets": [{
"index": 1,
"name": "[name]"
}]
}
}
}
did
摄像机 IDmid
消息 ID, 必须同请求消息一致type
总是为action
result
操作结果preset
预置位操作presets
预置位数组index
预置位索引name
预置位名称
调用预置位
转到指定的预置位
由流媒体服务器发送给设备:
{
"did": "001122334455",
"mid": "1234",
"token": "preset-token",
"type": "action",
"data": {
"preset": {
"goto": {
"index": Number
}
}
}
}
did
摄像机 IDmid
消息 ID, 不同消息不可重复type
总是为action
data
操作数据preset
预置位操作goto
index
预置位索引,1-128
应答消息:
{
"did": "001122334455",
"mid": "1234",
"type": "action",
"result": {
"preset": {
"code": 0
}
}
}
did
摄像机 IDmid
消息 ID, 必须同请求消息一致type
总是为action
result
操作结果preset
预置位操作code
操作结果0
表示操作成功
删除预置位
删除指定的预置位
由流媒体服务器发送给设备:
{
"did": "001122334455",
"mid": "1234",
"token": "preset-token",
"type": "action",
"data": {
"preset": {
"remove": {
"index": Number
}
}
}
}
did
摄像机 IDmid
消息 ID, 不同消息不可重复type
总是为action
data
操作数据preset
预置位操作remove
index
预置位索引,1-128
应答消息:
{
"did": "001122334455",
"mid": "1234",
"type": "action",
"result": {
"preset": {
"code": 0
}
}
}
did
摄像机 IDmid
消息 ID, 必须同请求消息一致type
总是为action
result
操作结果preset
预置位操作code
操作结果0
表示操作成功
错误应答消息
{
"did": "001122334455",
"mid": "1234",
"type": "action",
"result": {
"{action}": {
"code": Number,
"error": String
}
}
}
did
必需, 设备 IDmid
必需, 消息 IDtype
必需, 消息类型,总是为action
result
操作结果action
操作名称code
必需, 错误码error
必需, 错误类型
错误码:
CODE | ERROR |
---|---|
60000 | 该设备不支持云台控制 |
60001 | 没有云台控制权限 |
60006 | 云台当前操作失败,请稍后再试 |
60009 | 正在调用预置点 |
60020 | 不支持该命令 |
60007 | 预置点个数超过最大值 |
60010 | 该预置点已经是当前位置 |
60011 | 预置点不存在 |
图像抓拍
请求消息
由流媒体服务器发送给设备:
{
"did": "001122334455",
"mid": "1234",
"token": "capture-token",
"type": "action",
"data": {
"capture": {
"url": "https://{domain-name}/v2/storage/upload"
}
}
}
- did 必需, 设备 ID
- mid 必需, 消息 ID
- type 必需, 消息类型,总是为
action
- result 操作结果
- capture 抓拍操作
- url 必需, 用于上传抓拍后的图片的地址
- capture 抓拍操作
应答消息
{
"did": "001122334455",
"mid": "1234",
"type": "action",
"result": {
"capture": {
"url": "https://{domain-name}/v2/storage/file/20191010-101010.jpeg"
}
}
}
- did 必需, 设备 ID
- mid 必需, 消息 ID
- type 必需, 消息类型,总是为
action
- result 操作结果
- capture 抓拍操作
- url 必需, 抓拍后的图片的访问地址
- capture 抓拍操作
参数设置
应用程序可以设置部分最常用的摄像机设置,方便日常使用
读取设置
{
"did": "001122334455",
"mid": "1234",
"type": "action",
"token": "config-token",
"data": {
"read": ["config"]
}
}
-
图像设置
- 画面反转
- 是/否
- 日夜模式
- 白天模式
- 晚上模式
- 自动
- 时间水印
- 是/否
- 画面反转
-
告警
- 移动侦测
- 是/否
- 灵敏度
- 高/中/低
- 时间段
- 全天
- 是/否
- 开始时间
- 结束时间
- 重复
- 周一,周二,周三,周四,周五,周六,周日
- 全天
- 频率
- 3/5/10/30/60 一次
- 检测是否有人
- 是/否
- 移动侦测
-
云台控制
- 巡航
-
存储管理
- 录像模式
- 不间断模式
- 触发模式
- 录像模式
修改设置
{
"did": "001122334455",
"mid": "1234",
"type": "action",
"token": "config-token",
"data": {
"write": {
"config": {
"name": <value>
}
}
}
}
网络录像机
录像和回放
摄像机或网络录像机设备可以包含录像组件,通过录像组件可以实现录像查询以及回放等功能。
查询录像时间段列表
查询指定时间范围内有录像的时间段
通过消息队列发送给前端设备:
{
"did": "001122334455",
"mid": "1234",
"token": "replay-token",
"type": "action",
"data": {
"segment": {
"find": {
"start": Date,
"end": Date,
"channel": Number,
"stream": Number,
"type": Number
}
}
}
}
- did 必需, 设备 ID
- mid 必需, 消息 ID
- type 必需, 消息类型,总是为
action
- data 操作数据
- segment 查询录像文件
- find
- start 开始时间,Unix 时间戳,单位为毫秒
- end 结束时间,Unix 时间戳,单位为毫秒
- channel 录像通道,从 1 开始
- stream 码流类型,0 表示主码流,1 表示次码流
- type 录像类型,1 表示普通录像类型
- find
- segment 查询录像文件
应答消息
{
"did": "001122334455",
"mid": "1234",
"type": "action",
"result": {
"segment": {
"find": {
"params": {},
"segments": [{
"start": Date,
"end": Date,
"type": Number
}]
}
}
}
}
- did 必需, 设备 ID
- mid 必需, 消息 ID
- type 必需, 消息类型,总是为
action
- result 操作结果
- segment查询回放文件操作
- params 查询参数
- segments 时间段列表
- start 开始时间,Unix 时间戳,单位为毫秒
- end 结束时间,Unix 时间戳,单位为毫秒
- type 录像文件类型
- segment查询回放文件操作
录像回放推流
- 通过 RTSP 协议从 NVR 拉取录制的音视频流
- 通过 RTMP 协议将音视频流推送到媒体服务器
- 通过 MQTT 协议控制回放速度
回放推流地址
rtmp://{domain}:{port}/v2/meida/live/{did}_replay_{channel}_{stream}_{start}_{end}
- domain 媒体服务器 IP 地址或域名
- port 媒体服务器端口, 默认为
1935
- did NVR 设备 ID
- channel 录像通道, 从 1 开始
- stream 码流类型, 0 表示主码流, 1 表示次码流
- start 开始时间,如
20200725112233
- end 结束时间,如
20200725235959
回放地址
http://{domain}/v2/meida/live/{did}_replay_{channel}_{stream}_{start}_{end}.flv
- 参数同推流地址
上传录像文件
注意:这个接口还在实验中,随时可能更改
录像文件推送消息
{
"did": "001122334455",
"mid": "1234",
"token": "upload-token",
"type": "action",
"data": {
"upload": {
"url": 'http://{domain-name}/v2/live/upload/:did/',
"file": '{filename}'
}
}
}
摄像机推送文件
POST http://{domain-name}/v2/media/upload/:did/?token={token}
服务器缓存时间
默认情况下服务器会缓存 7 天,缓存期间可随时访问,期满后会自动删除
拉取录像文件
注意:这个接口还在实验中,随时可能更改
应用程序下载录像文件
GET http://{domain-name}/v2/media/upload/:did/:filename?token={token}
安全
设备密钥
设备密钥由云服务生成,保存在数据库中。同时需要烧录到相应 ID 的摄像机设备中。
设备需要对发往服务端的注册消息使用设备密钥进行签名,这样服务器可以用来验证是否是合法的请求。
同样服务器也可以使用设备密钥对发往设备的消息进行签名,防止其他人仿冒服务器发送消息给摄像机。
注册签名
认证时不可以直接在网上传输设备密钥,而是使用密钥签名的方式:
简单签名方式:
sign = md5string(did + ':' + deviceSecret)
基于时间戳签名方式:
sign = md5string(did + ':' + deviceSecret + ':' + timestamp)
基于时间戳的签名方式更安全,但需要设备有时间同步能力
注册成功后服务器会返回一个设备访问 token, 可以用来和服务器通信,这个 token 只有注册有效期内可用。
推流凭证
推流时使用设备访问 token 即可:
rtmp://{domain-name}/live/test?token={token}