Android视频监控系统技术总结
一、系统概述
这是一款基于 Android 平台的实时视频监控应用,采用 C/S 架构,由两个独立 APK 组成:
- security_camera(摄像机端):部署在采集设备上,负责视频采集、编码、本地存储与网络推流
- security_monitor(监视器端):部署在观看设备上,负责视频流接收、解码与实时显示
系统基于 Android 原生 MediaCodec 实现硬件编解码,通过 WebSocket 进行实时视频流传输,整体延迟低、资源占用少,支持 H.264/H.265 两种编码格式自适应。
二、整体架构
2.1 架构分层
系统采用清晰的分层设计,从下到上依次为:
| 层级 | 摄像机端 | 监视器端 | 职责 |
|---|---|---|---|
| 采集/输出层 | CameraX + ImageAnalysis | SurfaceView | 原始帧采集 / 最终画面渲染 |
| 编解码层 | VideoEncoder(MediaCodec) | StreamDecoder(MediaCodec) | 视频硬编码 / 硬解码 |
| 传输层 | StreamWebSocketServer(WebSocket 服务端) | StreamClient(WebSocket 客户端) | 视频帧网络传输 |
| 业务层 | StreamManager / MyCameraManager | StreamViewModel | 生命周期管理、状态协调 |
| 表现层 | Jetpack Compose(MainSurface/SettingsSurface) | Jetpack Compose(MainScreen) | 用户交互界面 |
2.2 数据流全景
摄像机端:
CameraX 预览 → ImageAnalysis(YUV_420_888)
→ 水印叠加(WatermarkOverlay)
→ VideoEncoder 硬编码(H.264/H.265)
├→ MediaMuxer → MP4 文件(本地录像)
└→ OnEncodedDataListener → StreamManager → WebSocket Server → 网络
监视器端:
网络 → WebSocket Client(OkHttp)
→ StreamClient 协议解析
├→ 配置消息(JSON)→ StreamDecoder.configure()
└→ 帧数据(二进制)→ StreamDecoder.feedData()
→ MediaCodec 解码 → Surface 渲染
三、摄像机端核心实现
3.1 相机采集:CameraX + ImageAnalysis
相机子系统以 MyCameraManager 为核心管理器,基于 CameraX 库实现:
- 预览用例(Preview):绑定 PreviewView 实现实时取景,支持 PERFORMANCE 模式
- 图像分析用例(ImageAnalysis):以 YUV_420_888 格式输出每一帧,供编码和水印处理使用
- 分辨率策略:支持 SD(640×480)、HD(1280×720)、FHD(1920×1080)三档,通过 ResolutionSelector 配置
- 背压策略 :采用
STRATEGY_KEEP_ONLY_LATEST,确保编码线程始终处理最新帧,避免帧堆积
帧率控制方面,低帧率模式下通过时间戳对比主动跳帧,确保编码帧率稳定在设定值。
3.2 视频编码:双输出解耦设计
VideoEncoder 是编码层的核心,其最大特点是编码器核心与输出目标解耦:
MediaCodec(编码器核心)
├→ 输出 1:MediaMuxer → MP4 文件(本地录像)
└→ 输出 2:OnEncodedDataListener → 网络流(StreamManager)
关键设计点:
-
双路独立启停:文件录制和网络流传输可分别启动/停止,互不影响。编码器根据输出目标活跃度自动启停------只要有一路输出活跃,编码器就保持运行;全部停止时编码器自动释放。
-
编码格式自适应:初始化时检测设备 HEVC 支持能力,优先使用 H.265 编码,不支持则回退到 H.264(Baseline Profile)。
-
动态 Muxer 初始化:MediaMuxer 不在编码器创建时初始化,而是在开始录制时才创建,支持随时启停录像而不中断编码流。
-
输出格式缓存:编码器输出格式变化(含 SPS/PPS)时缓存格式信息,后续启动文件输出或新客户端连接时可直接使用。
3.3 水印叠加:YUV 层面处理
WatermarkOverlay 在编码前的 YUV 数据上直接叠加时间戳水印:
- 工作在 YUV 色彩空间,避免 YUV→RGB→YUV 的多次格式转换开销
- 支持动态分辨率适配(根据实际帧尺寸更新水印位置)
- 叠加操作在 ImageAnalysis 的分析线程中完成,与编码流水线串行
3.4 网络推流:WebSocket 服务端
传输层由 StreamManager (单例)和 StreamWebSocketServer 组成:
协议设计:
- 文本帧(JSON):传输编码器配置信息,包括 mime 类型、分辨率、csd-0/csd-1(Base64 编码的 SPS/PPS)
- 二进制帧 :传输实际编码数据,帧结构为
[1字节帧类型][8字节时间戳(大端)][NAL数据] - 帧类型定义:
0x01=Config帧、0x02=关键帧、0x03=P帧
关键机制:
-
Config 帧缓存:服务器缓存编码器的配置帧(SPS/PPS),新客户端连接时立即推送,确保客户端无需等待下一个关键帧即可开始解码。
-
多客户端广播:支持多个监视器同时连接观看,编码数据通过 WebSocket 广播给所有已连接客户端。
-
前台服务保活:VideoStreamService 以前台服务形式运行,显示常驻通知,防止系统在后台杀死推流进程。
3.5 本地录像与存储管理
- 分段录制:视频按固定时长分段保存,每段结束后自动启动下一段,保证长时间连续录制
- 循环覆盖:存储空间不足时自动删除最旧的视频文件,实现滚动存储
- 文件命名:SECURITY_ + 时间戳 + .mp4,按文件名即可判断录制时间
3.6 息屏模式
系统支持息屏监控模式:
- 降低屏幕亮度至最低,减少功耗
- 保持 CameraX 和编码器正常运行
- 通过 WakeLock 保持 CPU 唤醒
- 启动前台服务防止进程被杀
- 适用于长时间无人值守监控场景
四、监视器端核心实现
4.1 流客户端:OkHttp WebSocket
StreamClient 基于 OkHttp 的 WebSocket 实现客户端连接:
- 自动心跳:配置 pingInterval(30秒),保持长连接活跃
- 消息分发:区分文本消息和二进制消息,分别走配置解析和帧数据处理路径
- 连接状态回调:通过 onConnectionChanged / onError 回调通知上层连接状态变化
4.2 视频解码:异步输出轮询
StreamDecoder 基于 MediaCodec 实现硬件解码,采用 独立线程轮询输出 的模式:
解码流程:
- 收到配置消息 → 创建 MediaFormat(设置 csd-0/csd-1)→ configure + start
- 收到帧数据 → dequeueInputBuffer → 写入数据 → queueInputBuffer
- 独立线程 drainOutputLoop → dequeueOutputBuffer → releaseOutputBuffer(render=true) → Surface 渲染
关键设计点:
-
Surface 延迟就绪处理:考虑到 SurfaceView 创建可能晚于配置消息到达,解码器缓存所有配置参数(mime、宽高、csd-0/1、旋转角度),Surface 就绪后自动重新配置解码器。
-
独立解码线程:输出缓冲区的读取在独立线程中循环进行,不阻塞网络接收线程,避免帧延迟累积。
-
旋转角度支持:通过 MediaFormat.KEY_ROTATION 设置视频旋转角度,适配摄像机端不同的安装方向。
4.3 MVVM 架构
监视器端采用 Jetpack Compose + ViewModel 的 MVVM 架构:
- StreamViewModel:管理连接状态、视频参数、帧计数等 UI 状态
- MainScreen:Compose 实现的主界面,包含地址输入、连接按钮、视频显示区域
- 状态驱动 UI,数据流向清晰
五、传输协议详解
5.1 握手阶段
客户端连接后,服务端立即发送两条消息:
- 配置 JSON(文本帧):
json
{
"type": "config",
"mime": "video/avc",
"width": 640,
"height": 480,
"csd0": "J0K0HkCqQ...", // Base64 编码的 SPS
"csd1": "A4A8sA==" // Base64 编码的 PPS
}
- Codec Config 二进制帧:携带完整的 csd-0/csd-1 二进制数据,帧类型 0x01
5.2 数据阶段
后续以二进制帧持续发送编码数据:
| 偏移 | 长度 | 字段 | 说明 |
|---|---|---|---|
| 0 | 1 字节 | frame_type | 0x02=关键帧,0x03=P帧 |
| 1 | 8 字节 | pts | presentationTimeUs,大端序(高位字节在前) |
| 9 | N 字节 | nal_data | NAL 单元数据 |
六、技术亮点
- 纯硬件编解码:全程使用 MediaCodec 硬编硬解,CPU 占用低,支持高清实时传输
- 编码器双输出解耦:一份编码数据同时供给本地录像和网络推流,两路独立启停
- Config 帧缓存机制:新客户端秒开,无需等待下一个关键帧
- Surface 就绪适配:优雅处理 Surface 晚于配置到达的时序问题
- 低延迟设计:ImageAnalysis 直连编码器,WebSocket 二进制帧传输,解码线程独立轮询
- 后台保活方案:前台服务 + WakeLock 双重保障,息屏模式下持续运行
- H.265 自适应:根据设备能力自动选择最优编码格式
七、模块依赖
| 依赖库 | 用途 |
|---|---|
| CameraX | 相机预览与帧采集 |
| Android MediaCodec | 硬件编解码 |
| Java-WebSocket(org.java-websocket) | WebSocket 服务端 |
| OkHttp | WebSocket 客户端 |
| Jetpack Compose | UI 界面 |
| AndroidX Lifecycle / ViewModel | 生命周期与状态管理 |
| SharedPreferences | 配置持久化 |
八、用户界面


