安防视频之录像存储

需求:

1。按时间存储

2。循环存储(指定天数以及指定空间)

3。指定空间存储

4。录像计划的制定

5.每一段录像的存储大小

 

 设计思路:

1.动态生成摄像机索引表,每一路摄像机一张表

2.文件块的管理,初始化的时候,就先把磁盘直接占满,以后不再进行磁盘的删除操作,一切都在应用层处理

3.文件快从头开始写入视频数据,图像索引从后往前写

4。每个文件通过xml的形式组建文件块,并进行重新进行命名,生成新的文件大小

5.循环存储分为按照时间存储以及按照空间存储,如果大小不够,直接开始循环

6.为了能够快速索引,需要能够很好的标识关键帧的位置,

7.需要能够适应时间跳变的问题

8.需要考虑正在录像还未形成一段文件的录像如何检索以及查看

模块划分:

 第一步先完成如下任务:

1.数据库建表

2.文件存储格式定义

3.文件xml的定义

 

文件存储格式定义如下:

 

 文件块大小为64M,视频帧裸数据从前往后写,视频的索引数据从后往前写,中间会有大约10K个字节的空隙,但是是可以接受的。

这里有个问题,就是海康的40字节头数据,我不打算每个文件再开始写的时候,都保存一份海康字节头,我计划保存再数据库里面。这样写文件的代码可以做到统一。就是来什么数据就写什么数据,而不需要做一些特殊处理了。

下面是每个字段的介绍:

DecoderId:解码ID

FrameRealTime:时间戳

M:标识是否为关键帧

Pt:音频为0,视频为1,解码头为2

lenth:当前帧的长度

SeekPos:当前帧位于文件的位置

索引个数:整个帧的数量

insigma:结束符

文件块的组织成文件的xml格式:

<file>
    <fileSize>256</fileSize>
    <fileStartTime>2019-02-26 10:00:00</fileStartTime>
    <fileEndTime>2019-02-26 11:00:00</fileEndTime>
    <item>
        <fileId>1</fileId>
        <filePath>d://1.mp4</filePath>
        <fileHead>40</fileHead>
        <fileStartTime></fileStartTime>
        <fileEndTime></fileEndTime>
    </item>
    <item>
        <fileId>1</fileId>
        <filePath>d://2.mp4</filePath>
        <fileHead>40</fileHead>
        <fileStartTime></fileStartTime>
        <fileEndTime></fileEndTime>
    </item>
</file>

 推荐一款xml编辑工具:

http://tools.jb51.net/code/xmlcodeformat

 

数据库设计:

每个录像卷一张表,并单独保存64M的文件块的信息

每个通道一张表,并单独保存录像文件的索引

另外就是录像计划的安排

 

需要开发的任务如下:

1.配置

2.回放服务

3.平台对接dll

4.录像服务

暂时不做配置的动态生效,放到第二期来开发。

文件块的申请与释放是整个系统的核心的核心,不依耐操作系统的文件系统,只能靠自己的文件块的管理。

每一个录像块的文件块数量巨大,大到百万级别,如何在这样一个数量级的文件块中设计出一套简单,使用的文件块的申请与回收的方法,显得尤为重要。

大概流程为:

申请文件块:申请的文件块可能会由于程序的异常关闭,或者系统的异常关闭,导致最终没有使用,当系统再次重启之后,应该还能再次被申请。

消耗文件块:当文件块消耗掉之后,需要确保文件块的标志位设置为被消耗。

回收文件块:当文件块块枯竭之后,需要能够把消耗的文件块释放出来使用。

整个录像服务核心就是围绕着文件块的申请,消耗,回收在运转。所以文件块状态表使用频率及其高。

申请文件块:需要设置文件块状态为被申请

消耗文件块:需要设置文件块状态为被消耗

回收文件块:需要设置文件块状态为回收

我们假设100路高清视频,计算一下文件块的表的使用频率:

假设视频一路4M,那么64M的文件块需要128s才能消耗掉。当录满之后,又需要再回收一个文件块

所以:

128秒需要操作文件块表:3*100 = 300次。

平均每秒操作3次

为了降低数据库的更新操作,我把申请文件块的状态备注在内存里面,假设100路视频,那么每次只有100个块处于被申请状态,

这样会存在一个问题,当我再次去数据库获取空闲的状态块的时候,此时获取到的状态是空闲,会出现状态不一致的情况,这种时候,我们需要进行二次计算,同步这种状态,使得他的状态还是被申请状态,这样就可以完美的减少一次数据库的更新操作,可以把文件块的状态表减少到每秒2次。

另外,计算一下假设保证系统时刻有1000个空闲文件块的话,计算一下大小:64M*1000 = 64G的空间,就是每个录像块需要时刻保持64G的空闲空间。这里如果时刻保持1000个空闲文件块的话,有一种场景比较麻烦,当录像卷里面只有一个摄像机的时候,怎么办呢?所以,我现在重新思考了一下,决定把空闲文件块设置为摄像机数量*10的个数。这样就可以弹性伸缩。

 录像服务的设计:

如下图:

 

思路如下:

1.每个录像块一个类

2.录像块类又包含设备类,块管理类

3。设备类又分为取流和写文件两个线程

4.块管理类包括数据库类,实现数据库的插入和写入,以及空闲文件块的回收与申请,单线程作业

 

************************************2019-03-07***********************************

今天看了下微软的api,写文件可以通过异步方式进行写,这样的话,我就不需要另外开一个线程去控制写了。

直接回调出来,直接业务逻辑控制写。

但是带来了一个很大的问题:

比较难控制了,同步写的时候,代码逻辑简单,关闭文件都比较方便。

举个简单的例子:

我的录像计划设置录像录1分钟,那么1分钟到了,我取流关闭了,我什么时候去关闭文件呢?

如果关闭取流了,就立马去关闭文件,肯定不行了,因为可能异步写还没结束啊。

 如果可以解决异步写的控制问题,我想尝试一下异步写这个函数。

如果采用同步方式的话,我会设置一个写的队列,然后一直在写,还可以监视队列的缓存情况。

对于异步写的话,我也需要感知我现在有几个文件在执行异步写,这里我设置一个int 的数,当异步写一个值后,

这个值加一,当异步操作完成之后,这个值减一,当这个值超过一个阈值之后,我们要开始考虑丢帧策略了。

另外还有一个是当一个文件块的使命完成之后,我们需要关闭这个文件块,再重新申请这个文件块。如果采用异步写的话,

可能所有的写操作还没有完成,这个时候,我们需要调用FlushAsync强制刷新,等待结束之后,所有的写操作即完成。

另外,控制文件关闭,我想放在一个单独的监控线程在做操作,通过一个标志位来标识这个文件已经完成了使命,然后把文件关闭,再执行后续的数据库操作。这一块放在单独的线程来执行。

**************************如何写文件新思路********************

我不准备在回调里面直接写文件,而是以一个gop为间隔,把视频流保存起来,然后再外面开启一个线程,比如每隔一秒,定期的去检查缓存情况,符合要求,即写文件。

这样的好处如下:

1。可以很好的控制文件申请与释放,单线程控制文件操作,不需要担心多线程同步。

2.业务处理起来十分简单,不会应为视频码流没了,而影响其他操作。

3。在做丢帧策略时候也什么方便

********************************20190301***************************

今天写了下写录像的逻辑图,发现居然业务逻辑如此复杂,把图记录下来,作为后面的编码参考。

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值