本文介绍日常工作中模块间解耦,并抽象封装的一个例子。
一、问题提出
在一个嵌入式设备中,视频相关业务流程如下,DSP采集编码后,生成H264数据,然后对H264数据分别进行MP4、RTP、PS封装,封装后形成的数据进入对应的缓存队列。缓存队列是DSP和APP共享的,DSP写入,APP读取。
业务层(APP层)的录像模块(包括循环录像、事件录像等)从mp4数据包缓存队列
中读取数据进行存储,实时预览模块从RTP数据包缓存队列
中读取数据发送给客户端,平台接入模块从PS数据包缓存队列
中读取数据发送给平台。
我们先停下来想想,这种业务流程存在哪些问题?
- 录像存储是设备的主动行为,所以开机就要进行MP4封装,这个没问题;但是,实时预览和平台接入都是被动行为,RTP、PS封装是一直工作还是有任务的时候再工作?
- 如果一直工作,很多时候是在做无用功,白白浪费了资源;
- 如果外界触发的时候再工作,需要在APP和DSP之间增加控制指令,增加了交互的复杂性。
- 如果业务扩展,需要增加一个视频流类型怎么办?比如,对接一个新的客户端,视频流是TS流,需要修改以下几点:
- DSP层增加一个H264转TS的视频封装模块
- 增加一个TS流的共享缓存队列
- APP层增加TS业务处理流程
- 多个缓存队列,对内存资源是个挑战
- 录像、预览、平台接入等业务模块都是直接操作缓存队列,如果缓存队列的实现机制发生变化,缓存队列的所有使用者都需要修改。
- 我们不妨从团队分工协作的角度考虑一下(一般情况下DSP和APP是不同的团队),录像、预览、平台接入这些业务功能和DSP有关系吗?好像没有。那这些码流封装逻辑放在DSP会带来其他的好处吗,比如性能提升等?好像也没有。这样做只会导致业务的协作链特别长,带来的问题就是开发效率低,容易出问题,出了问题比较难定位。
二、优化方案
下图是优化后的流程图,变更点如下(绿色方框中的为主要变更内容):
- MP4、RTP、PS等码流封装模块从DSP层上移到APP层
- DSP和APP之间只有一个共享的
H264数据缓存队列
- 抽象出一个
帧读取器对象
,APP层的录像、预览、平台接入等模块不再直接操作缓存队列,而是通过帧读取器获取帧数据。
那么,这样做的好处在哪里?
- MP4封装、RTP封装、PS封装等任务由业务层按需启停,现在控制方便
- 如果业务扩展,DSP层不需要参与,只需要APP层修改以下几点:
- APP层增加一个H264转TS的视频封装模块
- APP层增加TS业务处理流程
- DSP和APP之间只有一个共享缓存队列,节省了内存资源
-
帧读取器对象
封装了缓存队列
的操作流程,如果缓存队列的实现机制变更,只需修改帧读取器对象即可。(这里类似设计模式中的策略模式) - 从团队分工协作的角度考虑:
- DSP只负责出H264数据流,APP层负责业务的多样性,二者都更加聚焦;
- 类似业务扩展不再需要DSP参与,协作链变短了,开发效率变高,出问题的几率变小,出了问题也比较好定位。