【Android视频监控系统技术总结】

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)

关键设计点:

  1. 双路独立启停:文件录制和网络流传输可分别启动/停止,互不影响。编码器根据输出目标活跃度自动启停------只要有一路输出活跃,编码器就保持运行;全部停止时编码器自动释放。

  2. 编码格式自适应:初始化时检测设备 HEVC 支持能力,优先使用 H.265 编码,不支持则回退到 H.264(Baseline Profile)。

  3. 动态 Muxer 初始化:MediaMuxer 不在编码器创建时初始化,而是在开始录制时才创建,支持随时启停录像而不中断编码流。

  4. 输出格式缓存:编码器输出格式变化(含 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帧

关键机制:

  1. Config 帧缓存:服务器缓存编码器的配置帧(SPS/PPS),新客户端连接时立即推送,确保客户端无需等待下一个关键帧即可开始解码。

  2. 多客户端广播:支持多个监视器同时连接观看,编码数据通过 WebSocket 广播给所有已连接客户端。

  3. 前台服务保活: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 实现硬件解码,采用 独立线程轮询输出 的模式:

解码流程:

  1. 收到配置消息 → 创建 MediaFormat(设置 csd-0/csd-1)→ configure + start
  2. 收到帧数据 → dequeueInputBuffer → 写入数据 → queueInputBuffer
  3. 独立线程 drainOutputLoop → dequeueOutputBuffer → releaseOutputBuffer(render=true) → Surface 渲染

关键设计点:

  1. Surface 延迟就绪处理:考虑到 SurfaceView 创建可能晚于配置消息到达,解码器缓存所有配置参数(mime、宽高、csd-0/1、旋转角度),Surface 就绪后自动重新配置解码器。

  2. 独立解码线程:输出缓冲区的读取在独立线程中循环进行,不阻塞网络接收线程,避免帧延迟累积。

  3. 旋转角度支持:通过 MediaFormat.KEY_ROTATION 设置视频旋转角度,适配摄像机端不同的安装方向。

4.3 MVVM 架构

监视器端采用 Jetpack Compose + ViewModel 的 MVVM 架构:

  • StreamViewModel:管理连接状态、视频参数、帧计数等 UI 状态
  • MainScreen:Compose 实现的主界面,包含地址输入、连接按钮、视频显示区域
  • 状态驱动 UI,数据流向清晰

五、传输协议详解

5.1 握手阶段

客户端连接后,服务端立即发送两条消息:

  1. 配置 JSON(文本帧)
json 复制代码
{
  "type": "config",
  "mime": "video/avc",
  "width": 640,
  "height": 480,
  "csd0": "J0K0HkCqQ...",  // Base64 编码的 SPS
  "csd1": "A4A8sA=="       // Base64 编码的 PPS
}
  1. 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 单元数据

六、技术亮点

  1. 纯硬件编解码:全程使用 MediaCodec 硬编硬解,CPU 占用低,支持高清实时传输
  2. 编码器双输出解耦:一份编码数据同时供给本地录像和网络推流,两路独立启停
  3. Config 帧缓存机制:新客户端秒开,无需等待下一个关键帧
  4. Surface 就绪适配:优雅处理 Surface 晚于配置到达的时序问题
  5. 低延迟设计:ImageAnalysis 直连编码器,WebSocket 二进制帧传输,解码线程独立轮询
  6. 后台保活方案:前台服务 + WakeLock 双重保障,息屏模式下持续运行
  7. H.265 自适应:根据设备能力自动选择最优编码格式

七、模块依赖

依赖库 用途
CameraX 相机预览与帧采集
Android MediaCodec 硬件编解码
Java-WebSocket(org.java-websocket) WebSocket 服务端
OkHttp WebSocket 客户端
Jetpack Compose UI 界面
AndroidX Lifecycle / ViewModel 生命周期与状态管理
SharedPreferences 配置持久化

八、用户界面

源码链接

相关推荐
AI服务老曹1 天前
边云协同视频分析性能优化指南:多站点部署下的资源瓶颈突破与调优实战
性能优化·音视频
程序员老陆1 天前
FFmpeg6操作 RTMP参数详解
ffmpeg·音视频·rtmp
hunterandroid1 天前
[Android 从零到一] LiveData 粘性事件与单次消费:从重复触发到可靠事件总线
android
hunterandroid1 天前
[Android 从零到一] Android 事件分发机制:从 ACTION_DOWN 到 View 事件消费链路
android
阿巴斯甜1 天前
adb‑shell 全套命令实操总结
android
DogDaoDao1 天前
H.266/VVC 双雄对决:VTM vs VVenC 深度对比分析
音视频·视频编解码·vvc·vtm·h.266·视频压缩·vvenc
奔跑的架构师1 天前
[A-49]ARMv9/v8-PSCI接口规范与工作流程简介
android·linux·arm开发·arm
AFinalStone1 天前
Android 7系统国际化(七)Resources 与 AssetManager 源码剖析
android·国际化·local