简介

  • 复盘工地智能盒子项目,输出项目文档,以后其他项目参考

背景

  • 基于已有的技术积累,制作固定功能的产品,打造低成本的边缘检测盒子,

架构

  • 按照功能分为三层
    • 底层流媒体和模型的处理
    • 后端数据库和业务处理
    • 前端页面交互
  • 我主要负责后端,数据库表设计,业务实现.

后端

  • 按功能分为几个模块
    • 数据库
    • 共享内存方式的流媒体存取
    • 检测业务判断
    • HTTP RESTFUL接口通讯
    • 告警推送

数据库模块

  • 使用sqlite3数据库,理由是 在硬件资源有限且性能要求不高的情况下,少依赖,轻量化的数据库是最佳的选择

  • 数据库表有
    • 用户模块
    • 算法模块
    • 相机模块
    • 设备模块
    • 任务模块
    • 用户模块
    • 告警模块
  • 用户模块,存储用户相关的信息,创建该表的sql语句
    1
    
    CREATE TABLE IF NOT EXISTS user (id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE, password TEXT);
    
    • id : 用户数据的索引
    • username : 用户名字
    • password : 用户密码
  • 算法模块,存储模型文件相关的信息,创建该表的sql语句
    1
    
    CREATE TABLE IF NOT EXISTS algorithm (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, product TEXT, vendor TEXT, detector_path TEXT, model_conf TEXT, time TEXT);
    
    • id : 模型数据的索引
    • name : 模型的名字
    • product : 型号
    • vendor : 厂商
    • detector_path : 模型的检测器配置文件路径
    • model_conf : 模型配置参数(json字符串)
    • time : 时间戳字符串
  • 相机模块,存储相机相关的信息,创建该表的sql语句
    1
    
    CREATE TABLE IF NOT EXISTS camera (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE, url TEXT, time TEXT, url_suffix TEXT);
    
    • id : 相机数据的索引
    • name : 相机的名字
    • url : 相机的地址
    • time : 相机的时间戳字符串
    • url_suffix : 相机的后缀,这个字段用于存储向nvr增加相机返回的后缀,之后,程序内部所有媒体数据流使用nvr固定的内部地址拼接后缀得到的地址,这样避免了向相机多次拉流导致通道被占满,也避免了网络传输带宽的消耗.
  • 任务模块,存储任务相关的信息,创建该表的sql语句
    1
    
    CREATE TABLE IF NOT EXISTS task (id INTEGER PRIMARY KEY AUTOINCREMENT, identification TEXT, name TEXT UNIQUE, start INT, model_start TEXT, model_end TEXT, model_duration TEXT, algorithm INT,  camera INT, models TEXT, scheduler_type TEXT, running INT, sound_platform INT, song_address TEXT);
    
    • id : 任务数据的索引
    • identification : 任务id
    • name : 任务名称
    • start : 是否自启动
    • model_start : 模型
    • model_end :
    • model_duration :
    • algorithm : 算法索引
    • camera : 相机索引
    • models :
    • scheduler_type :
    • running : 是否运行
    • sound_platform : 音柱平台数据索引
    • song_address : 音频地址
  • 告警模块,存储告警相关的信息,创建该表的sql语句
    1
    
    CREATE TABLE IF NOT EXITS warning_record (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, url TEXT, task TEXT, camera INT, remark INT, time TEXT, boxes TEXT, unix_timestamp, event_id INT, height INT, width INT);
    
    • id : 告警数据索引
    • name : 告警事件名称呢个
    • url : 告警图片路径
    • task : 产生告警事件的任务
    • camera : 产生告警事件的相机
    • remark : 是否被标记
    • time : 告警事件的事件
    • boxes : 检测框的结构化数据(以json形式存储)
    • unix_timestamp : 事件戳
    • event_id : 事件id
    • height : 图片高度
    • width : 图片宽度
  • 平台模块,存储需要推送的平台相关的信息,创建该表的sql语句
    1
    
    CREATE TABLE IF NOT EXITS cloud_platform (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE, type TEXT, protocol TEXT, address TEXT, appKeyId TEXT, appKeySecret TEXT);
    
    • id : 平台数据的索引
    • name : 平台的名称
    • type : 平台的类型.目前分为两类: 事件推送和视频点播
    • protocol : 平台的协议类型.通过这个字段向不同平台不同协议推送告警数据
    • address : 推送地址
    • appKeyId : 账号
    • appKeySecret : 密码
  • 音频模块,存储需要播放的音频平台相关信息,创建该表的sql语句
    1
    
    CREATE TABLE IF NOT EXISTS sound_platform (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE, product TEXT, sn TEXT, address TEXT);
    
    • id : 音频数据的索引
    • name : 音频平台的名称
    • product : 音频平台的厂商
    • sn : 音频平台的序列号
    • address : 音频平台的地址

共享内存方式的流媒体存取

  • 流媒体的处理是在底层,底层和后端之间的流媒体是以共享内存的方式进行传输的.

  • 大致流程是

    • 启动后端服务时,更新底层程序的许可证
    • 创建任务时,返回一个任务id,此时,会在/dev/shm/目录下产生两类文件,一类是生产者索引文件,存储着已生产的图片索引;另一类是实体图片,图片文件的命名是任务id加索引.
    • 根据返回的任务,在/dev/shm/下创建消费者索引文件,存储着已经消费的图片索引
    • 索引只增不减,如果消费者索引小于生产者索引,就根据索引取出对应图片,同时消费者索引加一
    • 底层服务会保证生产者索引始终大于消费者索引,期间缓存的图片数量默认为五,即消费者索引和生产者索引距离最大为五

后端数据库和业务处理

  • 从共享内存的方式读取图片后,图片的数据存储结构如下所示
    1
    2
    
    |原图数据|缩略图数据|JSON字符串数据|原图数据的大小|缩略图数据的大小|JSON字符串数据的大小|
    | nbytes| nbytes | nbytes      | 20bytes   | 20bytes     | 20bytes          |
    
  • mjpeg图片中读取原图数据和JSON字符串数据。原图数据用于播放,JSON字符串数据用于业务处理进而生成告警事件

前端页面交互

  • 前端页面交互,是基于HTTP协议,第三方库用的是Mongoose。

  • 视频播放。支持多任务切换播放

    • 每一个HTTP链接都有一个用户自定义缓冲区,存储用户定义的数据。在请求某一任务播放视频时,服务器会收到任务的id,此时,将任务id存储到这个HTTP链接的用户自定义缓冲区
    • 在服务器启动时,启动定时器任务,这个任务定义检查保存的所有HTTP链接,取出该链接中用户自定义缓冲区的数据,在类成员变量中保存的任务id容器查找是否存在,如果存在,就通过回调函数取出任务id对应的图片,发送给链接的对端。