Files
SecMPS/doc/整合方案/Vol.Pro_Owl_ZLMediaKit_整合方案_v1.0.md
2026-05-15 23:22:48 +08:00

39 KiB
Raw Permalink Blame History

Vol.Pro + Owl + ZLMediaKit 视频监控整合方案

版本: v1.0 日期: 2026-04-29 编制: 浮浮酱 状态: 待确认(未实施)


一、项目概述

1.1 需求背景

现有项目包含四个模块:

模块 技术栈 用途
api_sqlsugar .NET 8 + SqlSugar + Vol.Pro框架 后端API服务
web.vite Vue3 + Vite + TypeScript Vol.Pro管理端管理后台
warehouse Vue3 + 自定义前端 用户端(大屏展示/业务端)
owl_zlmediakit Docker + Owl + ZLMediaKit GB28181视频监控平台

目标: 在Vol.Pro管理端中管理NVR和摄像机增删改查通过Vol.Pro后端对接Owl获取实时流/回放流地址,向两个前端(管理端+用户端)提供播放接口,实现浏览器中的实时监控、历史回放和云台控制。

1.2 核心问题

  1. warehouse已有视频UI框架Live.vueHistory.vueVideoWall.vue),但无实际播放器集成,数据为硬编码模拟数据
  2. Vol.Pro后端尚无摄像机/NVR相关实体和控制器
  3. Owl与Vol.Pro的数据模型不兼容,需要中间层转换
  4. 播放器选型浏览器播放GB28181流的方案

1.3 关键前提:所有修改独立于框架代码

经过对Vol.Pro框架源码和文档的调研确认所有自定义代码均可完全独立于框架自动生成代码进行开发和维护。

Vol.Pro框架的设计核心原则是"自动生成代码不修改自定义代码写Partial/扩展文件"。具体体现在:

层级 自动生成文件位置 扩展文件位置 扩展方式
Controller Controllers/模块/表名Controller.cs Controllers/模块/Partial/表名Controller.cs partial class
Service Services/模块/表名Service.cs Services/模块/Partial/表名Service.cs partial class + override/委托钩子
Entity DomainModels/模块/表名.cs DomainModels/模块/partial/表名.cs partial class + [NotMapped]
前端(Vue) views/模块/表名.vue + options.js extension/模块/表名.jsx.vue 扩展组件/自定义逻辑
独立服务 新建文件,实现IDependency Autofac自动IOC注入

框架生成的文件中明确注释

"代码由框架生成任何更改都可能导致被代码生成器覆盖。如果要增加方法请在当前目录下Partial文件夹编写。"

结论

  • 代码生成器重新生成时,只会覆盖自动生成的文件,不会触碰Partial/partial/extension/目录下的自定义代码
  • 所有视频监控相关的业务代码Owl对接、取流、回放、云台将写在扩展文件中与框架代码完全隔离
  • 新增的服务(如OwlApiService)通过实现IDependency接口由Autofac自动注册无需修改框架的任何配置
  • 框架升级时只需重新运行代码生成器覆盖自动生成的CRUD文件所有自定义业务逻辑完全保留

二、系统架构设计

2.1 整体架构

┌─────────────────────────────────────────────────────────────────────────┐
│                              客户端层                                    │
│  ┌─────────────────────┐    ┌─────────────────────┐                     │
│  │   web.vite 管理端    │    │   warehouse 用户端   │                     │
│  │  (设备管理+视频查看)  │    │  (大屏+实时监控墙)   │                     │
│  └──────────┬──────────┘    └──────────┬──────────┘                     │
└─────────────┼──────────────────────────┼────────────────────────────────┘
              │                          │
              ▼                          ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                          Vol.Pro 后端 (api_sqlsugar)                     │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │  自动生成CRUD模块 (VideoDevice / VideoChannel / VideoRecord)      │   │
│  │  ├─ 设备管理 (增删改查)                                          │   │
│  │  ├─ 通道管理 (增删改查)                                          │   │
│  │  └─ 录像管理 (查询)                                              │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │  扩展API模块 (VideoStreamController)                              │   │
│  │  ├─ POST /api/VideoStream/live   → 获取实时流地址                │   │
│  │  ├─ POST /api/VideoStream/playback → 获取回放流地址             │   │
│  │  ├─ POST /api/VideoStream/ptz    → 云台控制                     │   │
│  │  ├─ POST /api/VideoStream/snapshot → 获取快照                  │   │
│  │  └─ POST /api/VideoStream/stop   → 停止播放                    │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │  Owl对接服务 (OwlApiService)                                      │   │
│  │  ├─ 设备同步 (定时从Owl拉取设备列表)                             │   │
│  │  ├─ JWT Token管理 (缓存/刷新)                                   │   │
│  │  ├─ 流地址获取 (调用Owl /channels/:id/play)                     │   │
│  │  ├─ 回放查询 (调用Owl /recordings)                              │   │
│  │  └─ 云台控制 (调用Owl /channels/:id/ptz/control)               │   │
│  └─────────────────────────────────────────────────────────────────┘   │
└──────────────────────────────┬──────────────────────────────────────────┘
                               │ HTTP API
                               ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                          Owl (GoWVP) 平台                               │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │  SIP信令层 (GB28181设备注册/心跳/控制)                            │   │
│  │  HTTP API层 (设备/通道/播放/回放/云台)                            │   │
│  │  WebHook层 (接收ZLM事件回调)                                      │   │
│  └─────────────────────────────────────────────────────────────────┘   │
└──────────────────────────────┬──────────────────────────────────────────┘
                               │ HTTP API / WebHook
                               ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                          ZLMediaKit 流媒体服务器                         │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │  RTP收流 / RTMP推流 / RTSP拉流                                   │   │
│  │  协议转换 (HLS/FLV/WebRTC/RTMP/RTSP)                              │   │
│  │  录像存储 (MP4切片)                                               │   │
│  └─────────────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────────────┘

2.2 关键设计原则

  1. Owl作为主设备源: Owl负责GB28181设备接入、SIP信令、流管理Vol.Pro不直接对接设备只对接Owl的HTTP API
  2. 数据双写: 设备在Owl中注册后通过同步机制将设备信息写入Vol.Pro数据库实现Vol.Pro管理端对设备的CRUD管理
  3. 播放地址代理: Vol.Pro后端作为统一入口前端不直接访问Owl所有取流请求经Vol.Pro转发便于权限控制和日志记录
  4. 播放器统一: 两个前端使用同一套播放器组件支持FLV/HLS/WebRTC多协议

三、数据库表设计

3.1 表结构说明

设备统一管理设计本方案与MC4.0采集网关方案共用统一设备主表 Base_Device,实现视频监控设备和采集网关设备的统一管理,并支持在三维地图上统一标记展示。

3.1.0 统一设备主表 (Base_Device) 【与MC4.0方案共用】

字段名 类型 必填 说明
DeviceId uniqueidentifier 主键Vol.Pro系统内部ID
DeviceName nvarchar(100) 设备名称
DeviceCategory int 设备大类1=视频监控, 2=采集网关
DeviceType int 设备细分类型根据Category解释不同值
SourceId nvarchar(64) 源系统设备IDOwlDeviceId或Mc4DeviceId
IpAddress nvarchar(50) IP地址
Port int 端口
IsOnline int 是否在线0=离线, 1=在线
Location nvarchar(200) 安装位置描述
Lat float 纬度WGS84坐标系
Lng float 经度WGS84坐标系
MapModelId nvarchar(100) 三维地图模型IDVgoMap中对应模型的唯一标识
MapModelScale float 三维模型缩放比例默认1.0
MapModelRotation nvarchar(100) 三维模型旋转角度JSON格式{"x":0,"y":0,"z":0}
Enable int 启用状态0=禁用, 1=启用
Remark nvarchar(500) 备注
CreateID / Creator / CreateDate Vol.Pro标准审计字段
ModifyID / Modifier / ModifyDate Vol.Pro标准审计字段

MapModelId 字段说明

  • 用于在warehouse前端三维地图VgoMap中标记设备位置
  • 值由三维地图系统提供标识对应三维模型的唯一ID
  • 管理端可在设备编辑页面中配置/修改此字段
  • 三维地图加载时根据MapModelId将设备图标/模型绑定到地图对应位置

3.1.1 视频设备扩展表 (Device_Video_Ext)

存储视频监控设备特有的扩展信息通过DeviceId关联Base_Device主表。

字段名 类型 必填 说明
ExtId uniqueidentifier 主键
DeviceId uniqueidentifier 关联Base_Device.DeviceId
OwlDeviceId nvarchar(64) Owl系统设备IDGB28181的DeviceID
Protocol int 接入协议1=GB28181, 2=ONVIF, 3=RTMP, 4=RTSP
Manufacturer nvarchar(100) 厂商
Model nvarchar(100) 型号
ChannelCount int 通道数量
OwlStatus nvarchar(50) Owl中的原始状态JSON

3.1.2 视频通道表 (Video_Channel)

字段名 类型 必填 说明
ChannelId uniqueidentifier 主键Vol.Pro系统内部ID
OwlChannelId nvarchar(64) Owl系统通道ID
DeviceId uniqueidentifier 关联Video_Device.DeviceId
ChannelName nvarchar(100) 通道名称
ChannelNo int 通道编号
OwlStreamApp nvarchar(50) Owl中的stream app如rtp
OwlStreamName nvarchar(100) Owl中的stream name
HasPtz int 是否支持云台0=否, 1=是
HasRecording int 是否支持录像0=否, 1=是
RecordMode int 录像模式0=不录像, 1=设备录像(SD卡), 2=中心录像(Owl云录像)
IsOnline int 是否在线
SnapshotUrl nvarchar(500) 快照图片URL
Location nvarchar(200) 安装位置
Lat float 纬度
Lng float 经度
Enable int 启用状态
Remark nvarchar(500) 备注
CreateID / Creator / CreateDate 标准审计字段
ModifyID / Modifier / ModifyDate 标准审计字段

3.1.3 云录像记录表 (Video_Record)

字段名 类型 必填 说明
RecordId uniqueidentifier 主键
OwlRecordId nvarchar(64) Owl录像记录ID
ChannelId uniqueidentifier 关联Video_Channel.ChannelId
StartTime datetime 开始时间
EndTime datetime 结束时间
Duration int 时长(秒)
FileSize bigint 文件大小(字节)
FilePath nvarchar(500) 文件路径
RecordType int 录像类型1=定时录像, 2=告警录像, 3=手动录像
ThumbUrl nvarchar(500) 缩略图URL
CreateDate datetime 创建时间

3.2 建表SQL (SQL Server)

-- ============================================
-- 统一设备主表与MC4.0采集网关方案共用)
-- ============================================
CREATE TABLE Base_Device (
    DeviceId UNIQUEIDENTIFIER PRIMARY KEY DEFAULT NEWID(),
    DeviceName NVARCHAR(100) NOT NULL,
    DeviceCategory INT NOT NULL,        -- 1=视频监控, 2=采集网关
    DeviceType INT,                     -- 细分类型根据Category解释
    SourceId NVARCHAR(64) NOT NULL,     -- 源系统设备IDOwlDeviceId或Mc4DeviceId
    IpAddress NVARCHAR(50),
    Port INT,
    IsOnline INT DEFAULT 0,
    Location NVARCHAR(200),             -- 安装位置描述
    Lat FLOAT,                          -- 纬度
    Lng FLOAT,                          -- 经度
    MapModelId NVARCHAR(100),           -- 三维地图模型IDVgoMap
    MapModelScale FLOAT DEFAULT 1.0,    -- 三维模型缩放比例
    MapModelRotation NVARCHAR(100),     -- 三维模型旋转角度JSON
    Enable INT DEFAULT 1,
    Remark NVARCHAR(500),
    CreateID INT,
    Creator NVARCHAR(30),
    CreateDate DATETIME DEFAULT GETDATE(),
    ModifyID INT,
    Modifier NVARCHAR(30),
    ModifyDate DATETIME
);
CREATE INDEX IX_Base_Device_Category ON Base_Device(DeviceCategory);
CREATE INDEX IX_Base_Device_SourceId ON Base_Device(SourceId);
CREATE INDEX IX_Base_Device_IsOnline ON Base_Device(IsOnline);
CREATE INDEX IX_Base_Device_MapModelId ON Base_Device(MapModelId);

-- ============================================
-- 视频监控设备扩展表
-- ============================================
CREATE TABLE Device_Video_Ext (
    ExtId UNIQUEIDENTIFIER PRIMARY KEY DEFAULT NEWID(),
    DeviceId UNIQUEIDENTIFIER NOT NULL,
    OwlDeviceId NVARCHAR(64) NOT NULL,
    Protocol INT DEFAULT 1,             -- 1=GB28181, 2=ONVIF, 3=RTMP, 4=RTSP
    Manufacturer NVARCHAR(100),
    Model NVARCHAR(100),
    ChannelCount INT DEFAULT 0,
    OwlStatus NVARCHAR(50),
    FOREIGN KEY (DeviceId) REFERENCES Base_Device(DeviceId)
);
CREATE INDEX IX_Device_Video_Ext_DeviceId ON Device_Video_Ext(DeviceId);
CREATE INDEX IX_Device_Video_Ext_OwlDeviceId ON Device_Video_Ext(OwlDeviceId);

-- 视频通道表
CREATE TABLE Video_Channel (
    ChannelId UNIQUEIDENTIFIER PRIMARY KEY DEFAULT NEWID(),
    OwlChannelId NVARCHAR(64) NOT NULL,
    DeviceId UNIQUEIDENTIFIER NOT NULL,
    ChannelName NVARCHAR(100) NOT NULL,
    ChannelNo INT DEFAULT 1,
    OwlStreamApp NVARCHAR(50),
    OwlStreamName NVARCHAR(100),
    HasPtz INT DEFAULT 0,
    HasRecording INT DEFAULT 0,
    RecordMode INT DEFAULT 0,
    IsOnline INT DEFAULT 0,
    SnapshotUrl NVARCHAR(500),
    Enable INT DEFAULT 1,
    Remark NVARCHAR(500),
    CreateID INT,
    Creator NVARCHAR(30),
    CreateDate DATETIME DEFAULT GETDATE(),
    ModifyID INT,
    Modifier NVARCHAR(30),
    ModifyDate DATETIME,
    FOREIGN KEY (DeviceId) REFERENCES Base_Device(DeviceId)
);
CREATE INDEX IX_Video_Channel_DeviceId ON Video_Channel(DeviceId);
CREATE INDEX IX_Video_Channel_OwlChannelId ON Video_Channel(OwlChannelId);
CREATE INDEX IX_Video_Channel_IsOnline ON Video_Channel(IsOnline);

-- 云录像记录表
CREATE TABLE Video_Record (
    RecordId UNIQUEIDENTIFIER PRIMARY KEY DEFAULT NEWID(),
    OwlRecordId NVARCHAR(64) NOT NULL,
    ChannelId UNIQUEIDENTIFIER NOT NULL,
    StartTime DATETIME NOT NULL,
    EndTime DATETIME NOT NULL,
    Duration INT,
    FileSize BIGINT,
    FilePath NVARCHAR(500),
    RecordType INT DEFAULT 1,
    ThumbUrl NVARCHAR(500),
    CreateDate DATETIME DEFAULT GETDATE()
);
CREATE INDEX IX_Video_Record_ChannelId ON Video_Record(ChannelId);
CREATE INDEX IX_Video_Record_StartTime ON Video_Record(StartTime);
CREATE INDEX IX_Video_Record_EndTime ON Video_Record(EndTime);

四、Vol.Pro后端扩展方案

4.1 代码生成步骤

使用Vol.Pro代码生成器自动生成3个模块的CRUD代码

  1. Base_Device统一设备主表DeviceCategory=1表示视频监控设备
  2. Device_Video_Ext(视频设备扩展信息)
  3. Video_Channel(视频通道)
  4. Video_Record(云录像)

生成后获得:

  • Base_DeviceController / Base_DeviceService / IBase_DeviceService / Base_Device实体
  • Device_Video_ExtController / Device_Video_ExtService / IDevice_Video_ExtService / Device_Video_Ext实体
  • Video_ChannelController / Video_ChannelService / IVideo_ChannelService / Video_Channel实体
  • Video_RecordController / Video_RecordService / IVideo_RecordService / Video_Record实体

4.2 Owl对接服务 (OwlApiService)

在Vol.Pro后端创建完全独立的自定义服务封装对Owl的所有HTTP调用

// 文件位置api_sqlsugar/Warehouse/Services/Owl/OwlApiService.cs
// (新建文件,不修改任何框架代码)

/// <summary>
/// Owl API 对接服务
/// </summary>
public interface IOwlApiService : IDependency
{
    /// <summary>获取Owl JWT Token带缓存</summary>
    Task<string> GetTokenAsync();
    
    /// <summary>同步Owl设备列表到本地</summary>
    Task<WebResponseContent> SyncDevicesAsync();
    
    /// <summary>同步Owl通道列表到本地</summary>
    Task<WebResponseContent> SyncChannelsAsync();
    
    /// <summary>获取实时流播放地址</summary>
    Task<StreamPlayResult> GetLiveUrlAsync(string owlChannelId, string protocol = "ws_flv");
    
    /// <summary>获取回放流地址</summary>
    Task<StreamPlaybackResult> GetPlaybackUrlAsync(string owlChannelId, DateTime start, DateTime end);
    
    /// <summary>云台控制</summary>
    Task<WebResponseContent> PtzControlAsync(string owlChannelId, PtzCommand command);
    
    /// <summary>获取快照</summary>
    Task<byte[]> GetSnapshotAsync(string owlChannelId);
    
    /// <summary>停止播放</summary>
    Task<WebResponseContent> StopPlayAsync(string owlChannelId);
}

实现要点

  1. 新建文件实现IOwlApiService,不修改任何框架代码
  2. 实现IDependency接口Autofac自动注册到IOC容器
  3. 使用 IHttpClientFactory 创建HTTP客户端
  4. Token缓存到内存/Redis过期前自动刷新
  5. 所有方法内部处理Owl的JWT认证自动附加Authorization header
  6. 返回值统一转换为Vol.Pro的 WebResponseContent 格式

4.3 扩展API控制器 (VideoStreamController)

在Vol.Pro中新增独立的Controller文件(不修改任何框架代码),提供取流、回放、云台等扩展接口:

// 文件位置api_sqlsugar/Warehouse/Controllers/VideoStreamController.cs
// (全新文件,与框架代码无任何耦合)

namespace Warehouse.Controllers
{
    [Route("api/VideoStream")]
    [JWTAuthorize]
    public class VideoStreamController : VolController
    {
        private readonly IOwlApiService _owlApi;
        private readonly IVideo_ChannelService _channelService;
        
        public VideoStreamController(
            IOwlApiService owlApi, 
            IVideo_ChannelService channelService)
        {
            _owlApi = owlApi;
            _channelService = channelService;
        }
        
        /// <summary>
        /// 获取实时流播放地址
        /// </summary>
        [HttpPost, Route("GetLiveUrl")]
        public async Task<ActionResult> GetLiveUrl([FromBody] LiveUrlInput input)
        {
            var channel = await _channelService.GetChannelByIdAsync(input.ChannelId);
            if (channel == null) return Json(new WebResponseContent().Error("通道不存在"));
            
            var result = await _owlApi.GetLiveUrlAsync(channel.OwlChannelId, input.Protocol);
            return Json(new WebResponseContent().OK(null, result));
        }
        
        /// <summary>
        /// 获取回放流地址
        /// </summary>
        [HttpPost, Route("GetPlaybackUrl")]
        public async Task<ActionResult> GetPlaybackUrl([FromBody] PlaybackUrlInput input)
        {
            var channel = await _channelService.GetChannelByIdAsync(input.ChannelId);
            if (channel == null) return Json(new WebResponseContent().Error("通道不存在"));
            
            var result = await _owlApi.GetPlaybackUrlAsync(
                channel.OwlChannelId, input.StartTime, input.EndTime);
            return Json(new WebResponseContent().OK(null, result));
        }
        
        /// <summary>
        /// 云台控制
        /// </summary>
        [HttpPost, Route("PtzControl")]
        public async Task<ActionResult> PtzControl([FromBody] PtzInput input)
        {
            var channel = await _channelService.GetChannelByIdAsync(input.ChannelId);
            if (channel == null) return Json(new WebResponseContent().Error("通道不存在"));
            if (channel.HasPtz != 1) return Json(new WebResponseContent().Error("该通道不支持云台"));
            
            var result = await _owlApi.PtzControlAsync(channel.OwlChannelId, new PtzCommand
            {
                Action = input.Action,
                Direction = input.Direction,
                Speed = input.Speed
            });
            return Json(result);
        }
        
        /// <summary>
        /// 获取通道快照
        /// </summary>
        [HttpGet, Route("GetSnapshot")]
        public async Task<IActionResult> GetSnapshot(Guid channelId)
        {
            var channel = await _channelService.GetChannelByIdAsync(channelId);
            if (channel == null) return Json(new WebResponseContent().Error("通道不存在"));
            
            var bytes = await _owlApi.GetSnapshotAsync(channel.OwlChannelId);
            return File(bytes, "image/jpeg");
        }
        
        /// <summary>
        /// 停止播放
        /// </summary>
        [HttpPost, Route("StopPlay")]
        public async Task<ActionResult> StopPlay([FromBody] StopPlayInput input)
        {
            var channel = await _channelService.GetChannelByIdAsync(input.ChannelId);
            if (channel == null) return Json(new WebResponseContent().Error("通道不存在"));
            
            var result = await _owlApi.StopPlayAsync(channel.OwlChannelId);
            return Json(result);
        }
    }
}

独立性说明VideoStreamController全新创建的文件,不继承任何自动生成的控制器,也不修改任何框架文件。它通过构造函数注入IOwlApiServiceIVideo_ChannelService完全依赖IOC容器解耦。

4.4 设备同步机制

由于Owl是设备的真实数据源GB28181设备直接注册到OwlVol.Pro数据库中的设备需要通过定时同步手动同步保持与Owl一致。

同步方案

  1. 定时同步推荐使用Vol.Pro内置的Quartz定时任务每5分钟执行一次设备同步
  2. 手动同步:管理端提供"同步设备"按钮点击后立即拉取Owl设备列表
  3. Webhook同步可选高级方案Owl支持Webhook回调当设备注册/注销时回调Vol.Pro接口

同步逻辑

1. 调用 Owl GET /devices 获取设备列表
2. 调用 Owl GET /channels 获取通道列表
3. 对比本地数据库,执行增删改
4. 更新 Video_Device 和 Video_Channel 表

五、前端对接方案

5.1 播放器选型

浏览器播放GB28181视频流需要支持以下协议

协议 延迟 浏览器兼容性 推荐场景
WebRTC < 500ms Chrome/Firefox/Edge 实时监控首选
WS-FLV 1-3s 全浏览器 监控备用
HTTP-FLV 1-3s 全浏览器 简单场景
HLS 5-10s 全浏览器 回放首选
RTMP 2-5s 需Flash/插件 不推荐浏览器

推荐方案

  • 实时监控: WebRTC延迟最低+ WS-FLV兼容性备用
  • 历史回放: HLS (m3u8)
  • 播放器库:

最终推荐:使用 Jessibucampegts.js(两者都是纯前端,无需插件,支持多协议切换)

⚠️ WebRTC配置前置条件 ZLMediaKit默认不开启WebRTC,需在zlm-config.ini中配置:

[rtc]
port=8000

同时需要配置DTLS证书。如果部署环境不满足WebRTC条件默认使用WS-FLV

建议联调阶段先验证WS-FLV可用再按需开启WebRTC。

5.2 管理端 (web.vite) 对接

在Vol.Pro管理端中通过代码生成器生成设备/通道/录像的CRUD页面后需要扩展以下功能。所有扩展均写在独立的扩展文件中,不修改代码生成器生成的文件:

Vol.Pro前端扩展机制

  • 自动生成的代码:views/模块/表名.vue + views/模块/表名/options.js
  • 自定义业务代码:extension/模块/表名.jsx.vue(通过import extend from "@/extension/..."引入)
  • 代码生成器重新生成时,不会覆盖extension/目录下的扩展文件
  1. 设备列表页扩展(写在extension/warehouse/Base_Device.jsx

    • 添加"同步设备"按钮调用后端同步接口仅对DeviceCategory=1显示
    • 添加"在线状态"实时显示
    • 添加"查看通道"操作列
    • 添加DeviceCategory筛选条件(默认筛选视频监控设备)
  2. 通道列表页扩展(写在extension/warehouse/Video_Channel.jsx

    • 添加"实时预览"按钮(弹窗播放视频)
    • 添加"云台控制"按钮(在弹窗中显示云台面板)
    • 添加"回放"按钮(跳转回放页面)
  3. 新增视频播放页面views/video/VideoPlayer.vue,全新文件):

    • 使用Jessibuca播放器组件
    • 支持协议切换WebRTC/FLV/HLS
    • 集成云台控制面板
  4. 新增回放查询页面views/video/VideoPlayback.vue,全新文件):

    • 日期时间选择器
    • 时间轴组件
    • HLS播放器

扩展方式:在代码生成后的 .jsx 扩展文件中编写自定义逻辑参考Vol.Pro文档的 view-grid 扩展方式。

5.3 用户端 (warehouse) 对接

warehouse已有 Live.vueHistory.vueVideoWall.vue,但均为占位符。需要:

  1. Live.vue 改造

    • 替换硬编码数据为真实API调用
    • 集成Jessibuca播放器替换"正在加载..."占位符
    • 摄像头列表从 Video_Channel API获取
    • 点击摄像头获取流地址并播放
  2. History.vue 改造

    • 集成日期范围选择查询录像列表
    • 调用回放API获取HLS地址
    • 使用HLS播放器播放
  3. VideoWall.vue 改造(最复杂):

    • 将随机图片替换为真实视频播放器实例
    • 每个格子是一个独立的Jessibuca实例
    • 布局切换时动态创建/销毁播放器
    • 云台控制按钮调用Vol.Pro后端PTZ API

API调用示例warehouse前端

// 获取通道列表
import http from '@/api/http'

// 获取通道列表Vol.Pro标准分页接口
const getChannels = () => {
  return http.post('/api/Video_Channel/GetPageData', {
    page: 1,
    rows: 100,
    sort: 'CreateDate',
    order: 'desc'
  })
}

// 获取实时流地址
const getLiveUrl = (channelId: string, protocol = 'ws_flv') => {
  return http.post('/api/VideoStream/GetLiveUrl', {
    channelId,
    protocol
  })
}

// 云台控制
const ptzControl = (channelId: string, direction: string, speed = 0.5) => {
  return http.post('/api/VideoStream/PtzControl', {
    channelId,
    action: 'continuous',
    direction,
    speed
  })
}

// 获取回放地址
const getPlaybackUrl = (channelId: string, startTime: string, endTime: string) => {
  return http.post('/api/VideoStream/GetPlaybackUrl', {
    channelId,
    startTime,
    endTime
  })
}

六、关键API接口文档

6.1 Vol.Pro后端对外接口

6.1.1 获取实时流地址

POST /api/VideoStream/GetLiveUrl
Authorization: Bearer <Vol.Pro JWT Token>

Request:
{
  "channelId": "guid",      // Vol.Pro通道ID
  "protocol": "ws_flv"      // 可选: webrtc / ws_flv / http_flv / hls / rtmp / rtsp
}

Response:
{
  "status": true,
  "message": "ok",
  "data": {
    "channelId": "guid",
    "channelName": "仓库入口",
    "protocol": "ws_flv",
    "url": "ws://192.168.3.108/proxy/sms/rtp/gb_xxx.live.flv",
    "backupUrls": {
      "webrtc": "webrtc://192.168.3.108/proxy/sms/...",
      "hls": "http://192.168.3.108/proxy/sms/..."
    }
  }
}

6.1.2 获取回放流地址

POST /api/VideoStream/GetPlaybackUrl
Authorization: Bearer <Vol.Pro JWT Token>

Request:
{
  "channelId": "guid",
  "startTime": "2026-04-28 08:00:00",
  "endTime": "2026-04-28 18:00:00"
}

Response:
{
  "status": true,
  "message": "ok",
  "data": {
    "channelId": "guid",
    "playlistUrl": "http://192.168.3.108/api/VideoStream/playback.m3u8?cid=xxx&start=...",
    "recordCount": 12,
    "totalDuration": 36000
  }
}

6.1.3 云台控制

POST /api/VideoStream/PtzControl
Authorization: Bearer <Vol.Pro JWT Token>

Request:
{
  "channelId": "guid",
  "action": "continuous",    // continuous / stop
  "direction": "up",         // up / down / left / right / zoom_in / zoom_out
  "speed": 0.5               // 0.0 ~ 1.0
}

Response:
{
  "status": true,
  "message": "ok"
}

6.1.4 获取快照

GET /api/VideoStream/GetSnapshot?channelId=guid
Authorization: Bearer <Vol.Pro JWT Token>

Response: image/jpeg (二进制图片数据)

6.2 Owl内部接口Vol.Pro后端调用不暴露给前端

接口 说明 用途
GET /devices 设备列表 同步设备
GET /channels 通道列表 同步通道
POST /channels/:id/play 获取流地址 取流
POST /channels/:id/stop 停止播放 停止
POST /channels/:id/ptz/control 云台控制 PTZ
GET /recordings?cid=xxx 录像查询 回放
GET /channels/:id/snapshot 获取快照 截图

七、实施计划

所有代码均写在独立文件中,不修改任何框架自动生成的代码。框架升级时只需重新运行代码生成器,自定义业务完全保留。

阶段一数据库与代码生成2天

  1. 执行建表SQL创建4张表Base_DeviceDevice_Video_ExtVideo_ChannelVideo_Record
  2. 使用Vol.Pro代码生成器生成4个模块的CRUD代码实体、Service、Controller、前端页面
  3. 验证生成后的增删改查功能正常
  4. 验证:确认Partial/extension/目录未被覆盖

阶段二Owl对接服务3天

新建文件(完全不触碰框架代码)

  1. 创建 Warehouse/Services/Owl/IOwlApiService.cs(接口)
  2. 创建 Warehouse/Services/Owl/OwlApiService.cs(实现)
  3. 实现JWT Token获取与缓存内存/Redis
  4. 实现设备/通道同步逻辑调用Owl /devices/channels
  5. 实现取流、回放、云台、快照接口
  6. 创建 Warehouse/Controllers/VideoStreamController.cs全新Controller
  7. 添加Quartz定时同步任务写在Partial中扩展或新建Job

阶段三管理端前端扩展2天

扩展文件(不修改生成的.vue/options.js

  1. 引入Jessibuca播放器组件npm install全局注册
  2. 创建 web.vite/src/extension/warehouse/Base_Device.jsx扩展设备列表页添加DeviceCategory=1筛选
  3. 创建 web.vite/src/extension/warehouse/Video_Channel.jsx(扩展通道列表页)
  4. 创建 web.vite/src/views/video/VideoPlayer.vue(视频播放弹窗,全新文件)
  5. 创建 web.vite/src/views/video/VideoPlayback.vue(回放查询页面,全新文件)

阶段四warehouse用户端改造3天

修改warehouse自有代码与Vol.Pro框架无关

  1. 修改 warehouse/src/view/video/Live.vue替换模拟数据为真实API调用集成Jessibuca播放器
  2. 修改 warehouse/src/view/video/History.vue实现回放查询和HLS播放
  3. 修改 warehouse/src/view/video/VideoWall.vue:将图片占位符替换为真实视频播放器实例
  4. 对接云台控制API调用Vol.Pro后端的/api/VideoStream/PtzControl

阶段五联调测试2天

  1. 设备注册到Owl后同步到Vol.Pro
  2. 实时播放测试WebRTC/FLV
  3. 回放功能测试
  4. 云台控制测试
  5. 多路视频墙测试
  6. 框架升级测试:重新运行代码生成器,验证所有自定义代码未被覆盖

总计预计工期: 15个工作日含3天联调缓冲

代码独立性检查清单

实施过程中每完成一个模块,对照以下清单确认无框架代码被修改:

检查项 通过标准
Controller扩展 新增接口写在Partial/或全新Controller文件中
Service扩展 业务逻辑写在Services/模块/Partial/
Entity扩展 新增字段写在DomainModels/模块/partial/中,加[NotMapped]
前端扩展 自定义逻辑写在extension/目录下的.jsx.vue
独立服务 OwlApiService等新建服务实现IDependency,不修改框架文件
配置修改 仅在appsettings.json中添加Owl相关配置不修改框架其他配置

八、风险与注意事项

8.1 已知限制

  1. Owl云台控制不完整: 仅支持 continuousstop,预置位/绝对位置未实现
  2. GB28181首次播放延迟: SIP信令协商需要1-3秒首次播放有延迟
  3. WebRTC兼容性: 旧版浏览器不支持WebRTC必须准备FLV备用方案
  4. HLS回放延迟: HLS切片默认2秒端到端延迟约5-10秒不适合实时监控

8.2 安全建议

  1. Owl的JWT Token3天有效期需要安全存储建议用Redis缓存
  2. 播放地址应通过Vol.Pro后端代理不要暴露Owl直连地址给前端
  3. ZLMediaKit的 secret 在生产环境必须修改
  4. 云台控制接口需要权限校验Vol.Pro的 [ApiActionPermission]

8.3 性能建议

  1. 视频墙多路播放时建议限制同时播放路数如最大16路
  2. 使用 stop 接口及时释放不再观看的流,减少服务器压力
  3. 快照图片可做CDN缓存
  4. 录像查询建议分页,避免大时间范围查询

附录A统一设备管理与三维地图标记

A.1 统一设备管理设计

本方案与MC4.0采集网关方案共用 Base_Device 统一设备主表,实现视频监控设备和采集网关设备的统一管理:

设备大类 (DeviceCategory) 细分类型 (DeviceType) 扩展表 对接系统
1 = 视频监控 1=IPC, 2=NVR, 3=Platform Device_Video_Ext Owl + ZLMediaKit
2 = 采集网关 1=区域, 2=设备 Device_IoT_Ext MC4.0 采集网关

Video_Device 表已拆分为

  • Base_Device公共字段设备名称、IP、位置、经纬度、MapModelId等
  • Device_Video_Ext视频特有字段OwlDeviceId、Protocol、ChannelCount等

A.2 三维地图标记 (VgoMap)

所有设备通过 Base_Device 表中的 MapModelId 字段,在 warehouse 前端的 VgoMap 三维地图上进行统一标记。

字段 类型 说明
MapModelId nvarchar(100) 三维地图模型唯一标识
MapModelScale float 模型缩放比例
MapModelRotation nvarchar(100) 模型旋转角度JSON

前端集成要点

// 加载所有设备到三维地图
const devices = await http.post('/api/Base_Device/GetPageData', { ... });
devices.forEach(d => {
  if (d.MapModelId) {
    window.$map.setModelData(d.MapModelId, { 
      deviceId: d.DeviceId, 
      deviceName: d.DeviceName,
      isOnline: d.IsOnline 
    });
    window.$map.setModelColor(d.MapModelId, 
      d.IsOnline === 1 ? '#67c23a' : '#f56c6c');
  }
});

详见《Vol.Pro_MC4.0_整合方案_v1.0.md》附录A.2完整说明。


文档结束 版本: v1.0 最后更新: 2026-04-29 状态: 待主人确认后实施