来源 | HaaS技术社区
1、前言
近些年来,安防监控市场需求广泛。安防监控已经成众多细分行业,如金融、教育、医疗、交通等,安全的必需品。消费类市场中,随着人们对人身及财产安全意识的不断提升,中小企业、商铺、家庭逐渐成为安防监控消费的中坚力量。以网络摄像机(IP Camera)为例,其年全球出货量已达亿级别,且保持每年20%的持续增长。
图 1 网络摄像机产品的基本形态
市场需求的增长和应用场景的多元化,将推动安防监控设备终端的产出和升级。安防监控方案商在不断地优化、调整设备端的方案,希望基于一套通用、易用的技术底座,快速打造新品,以投放市场。
而这套技术底座的重要组成部分是由芯片厂商提供的软件开发包(Software Development Kit)。磨刀不误砍柴工——一款高效的安防监控芯片SDK不仅能够缩短方案商的开发周期,还能为产品的性能指标提供竞争力的保障。尤其是低功耗、快速启动、低资源消耗等特性,是SDK能够赋予产品的最佳标签。
本文将围绕如何打造一款高效的安防监控芯片SDK,介绍芯片厂商在输出给方案商SDK之前需要考虑的方方面面。本文是根据笔者近期IPC设备端项目经验总结,对于庞杂的安防监控行业,难免有坐井观天之嫌,不足之处请指正。
2、芯片厂商SDK的组成
一款家用网络摄像机设备端的方案,分为硬件与软件两部分。硬件部分,主要包括主控芯片、图像采集器(Sensor)、图像处理器(ISP)、音频采集/播放(AI/AO)、Flash、SD卡、WiFi/4G/Ethernet、电机、红外传感器、电源等。而软件部分,从业务功能的角度,主要包括P2P视频流、视频本地/云端存储、网络录像机(NVR)、外设控制等。
首先,芯片厂商的SDK提供的功能应与业务保持独立,以保障通用性。SDK的基本功能包括视频输入/输出、视频编码/解码(H264、MJPEG)、屏幕信息显示(OSD)、音频输入/输出、音频编码/解码(AAC、MP3)、网络传输(TCP/IP、HTTP)、本地存储(SD卡、Flash)、外设操控等。
其次,芯片厂商的SDK需要模块化管理,以保障可维护性应与可扩展性。SDK按模块可划分为内核、驱动、Bootloader、设备树、中间件、三方库、应用示例等。
此外,一个成熟的芯片厂商SDK,还应提供独立的编译体系、工具链、烧录、调试等辅助工具。
图 2 安防监控芯片厂商SDK基本组成
3、SDK使用流程
在讨论芯片厂商对SDK的优化之前,我们先了解一下方案商拿到SDK后使用的基本步骤。
步骤一:建开发环境。该步骤主要为后续编译准备必要的软件环境,例如安装Python、Scons。
步骤二:安装SDK。芯片厂商输出的SDK一般为一个安装包或者压缩包。该步骤主要将SDK包里的内容,提取到开发环境中,并对SDK进行板级配置,例如选择芯片类型、所需网络、Flash类型。
步骤三:安装交叉工具链。工具链可以在SDK包中获取,按照开发指导文档,解压到指定路径,并配置环境变量。
步骤四:接口适配。同样地,首次使用时,方案商需要基于SDK提供的中间件、Posix接口进行适配。例如,方案商的代码之前都是运行在Linux上的,而SDK是RTOS版本,那么需要考虑到接口行为可能存在的差异性。
步骤五:编译链接。SDK开发指导文档中,该步骤往往是按照芯片厂商的自己编译体系来介绍的,只需执行编译脚本即可。但实际上,方案商通常有自己的代码仓库和编译体系。首次使用时,需要对自己的编译体系做一定的修改,才能完成该步骤,例如,编译、链接参数的配置。
步骤六:烧录。芯片厂商一般会提供多种烧录方式,例如USB烧录、UART烧录、TFTP烧录,以满足调试、产测不同场景下烧录需求。此外,该步骤需要允许用户根据固件大小对Flash分区进行配置。
步骤七:调试。对于SDK调试需求可以分为两部分,一部分是与音视频业务相关的问题调试,例如定位图像生成质量的问题。另一部分是业务无关的问题调试,例如程序运行异常。该步骤会很大程度上影响量产进度。因此,SDK需要具备有效的调试工具。
图 3 SDK使用流程
在IPC设备端项目中,笔者参与了芯片厂商的基于AliOS Things的SDK打造与首个方案商对接的全过程。以调通P2P功能为结束时间,以上步骤所需大致时间占比如下图所示,可以看出步骤五、步骤七占据了大部分时间。
图 4 各步骤所需时间占比
4、基于RTOS的SDK方案
为了帮助合作伙伴提高基于SDK的开发与支持效率,笔者所在的嵌入式操作系统团队与芯片厂商进行了深度的合作,从内核、驱动、编译、中间件、外部库,对SDK进行多轮优化。本章将挑选一些关于提高开发效率的优化点进行描述。这些优化的核心目标,是让方案商能够获得RTOS性能指标的同时,能够独立地在用户态开发,无需感知RTOS内核编译与运行。
4.1、内核
在开展合作前,芯片厂商的SDK里已支持了以Linux与另一款RTOS为内核的版本,并且基于该版本已有大量出货。然而,该RTOS版本是单态运行,无法在运行时隔离用户态逻辑与内核态逻辑。在出现问题的时候,方案商开发同学无法很好的区分是应用缺陷还是内核或驱动缺陷导致的。因此,经常需要芯片厂商投入大量FAE现场支持,但有时因为定位手段的匮乏,还会导致项目进度的阻塞。而Linux版本虽然可以区分用户态与内核态,并且有成熟的调试工具,但由于没有RTOS轻盈,在IPC关键的性能指标上不占优势。
4.1.1、双态模式
图5 AliOS Things支持用户态与内核态分离
AliOS Things 支持双态模式,即一个内核进程与一个用户进程。双态运行模式采用以下机制:
1)内核进程运行在特权模式,而用户进程运行在非特权模式。
2)用户态任务采用双栈设计。如下图所示,内核任务在正常运行时只使用其内核栈。而用户任务运行在非特权模式时,使用其用户栈,在执行系统调用时使用其内核栈。用户任务运行在非特权模式时,不能访问其内核栈。
图6 用户态任务双栈设计
3)内核态和用户态之间内存访问隔离。用户进程有独立的地址空间,与内核进程地址空间不重叠。用户进程通过独立的堆进行内存分配。
4)用户进程只通过系统调用获取内核服务。系统调用支持Posix、VFS、网络相关等接口。
这些机制有效地保障了用户进程与内核进程在运行时的内存隔离,把可能的用户态问题限制在用户进程,减少了因问题初判不明确导致定位周期拉长。
4.1.2、维测手段
除了双态特性,AliOS Things支持丰富的维测手段,包括死循环定位、异常调用栈显示、任务调用栈显示、任务CPU占用率显示以及内存占用信息Dump。开发者可以利用这些特性快速定位Crash问题。这大大减少了方案商与芯片商的后顾之忧,有效避免了项目进度因某一内存踩踏而阻塞。
4.2、驱动
芯片厂商SDK的核心是驱动。方案商对SDK的重要诉求之一便是音视频驱动的能力使用,例如ISP、PCM。在双态模式下,驱动运行在内核态。但考虑到驱动的功能独立性与可维护性,将驱动作为单独模块进行维护,而不是将其整个囫囵吞枣地纳入内核模块。这里所谓的“独立”是指,如果把整个驱动模块给disable掉,内核依旧是可以起来,至少串口是工作的。之所以这样做,是希望在内核态里,芯片厂商开发人员只需关心驱动的行为,而内核同学也可以更专注于内核的通用行为。
为了实现这一点,做了两方面的工作:
4.2.1、内核驱动最小化
内核启动是需要一定基础驱动,例如时钟、中断、Flash、UART。因此,我们在内核里只保留这部分驱动的实现。内核与该部分驱动属于紧耦合,可直接调用这部分驱动接口,例如get_tick_count。
4.2.2、驱动解耦
除了最小化内核驱动,其余的驱动(如isp、i2c、usb)可以根据配置进行增删。如果该驱动编译链接,则在内核启动时自动注册。为了实现这一点,驱动的注册函数使用函数属性used,在内核特定段中保留一个全局函数。内核启动时,将已注册的函数,进行按序逐一调用。
除了驱动注册,内核提供了设备驱动框架。各驱动设备通过该框架注册到内核的虚拟文件系统(VFS)。用户态通过这些VFS接口(open、read、write、ioctl、poll、select)的系统调用访问驱动设备。这种方式保证了驱动可用性,同时降低了驱动的耦合度。
图7 驱动框架图
4.3、中间件
图8 中间件架构图
合作厂商SDK的中间件主要包括媒体处理、应用扩展、OS适配层。其中,媒体处理为中间件的核心,提供基础的音视频接口;应用扩展主要提供应用示例;而OS适配层,用于屏蔽OS的差异,向上提供统一的接口。
4.3.1、OS适配层裁剪
虽然该适配层可以屏蔽OS接口的差异性,提升中间件的通用性,但是这某种程度上掩盖了OS接口不通用性的事实。因为,如果OS接口不通用,那么SDK最终用户是方案商的开发人员也会面临同样问题,需要类似的适配层。而方案商一般都有自己成熟的业务代码,一般基于Linux开发,并使用的是Posix接口。方案商期望的是尽量不改或少改业务层代码,做到一份代码可以在多个平台上运行。以安防监控业务对接SDK所需时间为例,SDK所支持Posix接口数量与对接所需天数成反比,OS支持Posix接口约多,对接所需天数越少,如图所示。
图9 安防监控业务对接SDK所需时间与已支持Posix接口数量成反比
因此,在针对OS适配层优化时,我们采用的提前暴露问题的策略——裁剪OS适配层,中间件尽量直接使用Posix接口。这种方式对OS的Posix接口支持起到了查漏补缺的作用,降低了方案商对接时接口缺失的概率。目前,通过对OS Posix接口的完善,AliOS Things的Posix支持数量已经接近200个,涵盖了线程操作、文件系统操作、网络操作等视频监控业务所必须的接口。
4.3.2、媒体处理
安防监控芯片SDK一般包括以下媒体处理模块,如表1所示。
表1 媒体处理模块列表
模块 |
说明 |
|
视频 |
VI |
视频输入,IP Camera关键模块之一。负责ISP的参数配置、设备通道管理,并向上提供V4L2接口 |
VO |
视频输出,用于带屏设备显示场景。负责参数配置与视频显示。 |
|
ISP |
图像处理接口,该模块主要提供ISP设备提供的图像参数配置接口。例如,获取或配置图像饱和度。 |
|
VPSS |
视频处理子系统,该模块包括OSD屏幕叠加、MD移动侦测、效果调节等 |
|
VENC |
视频编码,如H264、H265、MJPEG |
|
VDEC |
视频解码 |
|
OSD |
屏幕信息显示,例如,显示当前时间戳 |
|
音频 |
AI |
音频输入,提供音频数据采集功能 |
AO |
音频输出,提供音频播放功能 |
|
AENC |
视频编码,如AAC、MP3、WMA |
|
ADEC |
视频解码 |
|
音视频 |
MUX |
音视频合成,对音视频数据流按指定格式的合成,例如avi、mp4 |
DEMUX |
音视频解析,对支持的文件格式音视频文件进行解析 |
这些模块是整个SDK的核心功能。这部分优化主要围绕在性能指标,由合作厂商主导,而我们提供OS层面的支持。例如,如何支持快速快启出图、如何优化图像采集时大内存分配、解决网络传输时音视频卡顿等。这些都是IP Camera产品化过程中绕不开的问题。同时,这些问题的解决方案也使OS得到了相应的技术沉淀,我们将在后续文章中详细介绍,此处不再赘述。
4.4、编译体系
图10 编译体系融合
4.4.1、编译体系融合
AliOS Things有独立的编译体系,具有完整的生成内核与用户态固件的方法。然而,芯片厂商也有自己的编译体系,为了向前兼容已出货方案,芯片厂商断然不会放弃已有的编译体系。那么,这就需要一套兼容双方的融合方案。
由于双态分离的运行模式,内核固件与用户态固件可以保持相互独立。很自然地,内核地固件生成可以沿用AliOS Things的编译体系;而用户态固件的生成,可以采用芯片厂商已有的编译体系。
那么,这两部分编译体系是否一点联系都没有呢?非也。如前文所述,驱动是运行在内核态,同时编译依然在芯片厂商的编译体系里。为此,编译生成的驱动库,将链进内核固件。而用户态所需的基础库,如Posix实现、C库重载、系统调用等,需要由内核提供库,并链接进入用户态固件。具体编译、链接生成固件关系,见上图。
此外,我们通过改进自动编译脚本的脚本,芯片厂商可以沿用原来的配置与编译方式,一键自动完成全部的编译、链接与打包。
4.4.2、方案商的编译方式
方案商拿到SDK后,只需关心用户态的编译与链接。方案商原有编译脚本主要修改点包括:工具链路径、编译参数、链接参数、用户态库的头文件引用路径与链接路径。
当内核固件更新时,只要用户态库、头文件没有发生变化,用户态固件则无需重新生成。这样带来的好处是,当方案商需要协助调试时,可以将该出现问题的用户态固件发出来,由芯片厂商源码编译内核进行问题复现与调试。否则,每次修改尝试都需要方案商整体编译固件,调试效率将大打折扣。
4.5、第三方库
第三方库可以扩展SDK的功能,满足方案商的定制化需求。例如,IP Camera业务场景,大概率会用到二维码、人脸识别、人形识别等。这时,就需要基于源码仓库编译、生成这些第三方库。一般情况的做法是运行./configure进行配置,生成Makefile,并基于这一份Makefile进行编译、链接。然而,在RTOS的编译环境一般无法支持直接配置与编译。为了提高开发效率,我们对工具链进行了相应优化,使得开发者能够直接对三方库配置与编译。具体做法,我们将在后续文章中详细介绍,此处不做赘述。
5、结束语
通过与合作厂商的共同努力,AliOS Things已成为其主推的音视频芯片SDK默认携带的操作系统。并且,这套SDK已经在方案商低功耗摄像机产品上大展拳脚。实践证明,一款好的OS对于安防监控产品SDK的性能与开发效率会有本质的影响。相信这款SDK经过量产的打磨与验证,一定能成为AliOS Things在安防监控领域一个经典之作。
</div>