前言
在移动音视频业务中,让一台 Android 设备持续采集摄像头和麦克风,并对外提供实时视频流,是一个非常典型但并不简单的需求。
从表面上看,这似乎只是打开摄像头、调用编码器,再发布一条视频流。但真正落地时,开发者需要同时处理 Android 后台运行限制、Camera2 数据采集、音视频编码、画面旋转与镜像、RTSP 服务启动、客户端连接管理,以及底层资源释放等一系列问题。
基于大牛直播 SDK(SmartMediaKit)的 SmartCamera2Service 示例,可以看到一条比较完整的工程化实现路径:
通过前台 Service 承载媒体生命周期,使用 Camera2 和 AudioRecord 采集原始音视频数据,由 SmartMediaKit 完成 H.264/H.265、AAC 编码、音视频同步和协议封装,同时在 Android 设备本地启动轻量级 RTSP Server,使手机、平板、车载主机、机器人控制器或工业终端直接成为一个可被访问的实时视频节点。
一、用 Android 设备构建实时视频节点
传统实时视频系统中的前端视频源,通常来自 IPC、NVR、专业编码器或专用采集终端。
但随着 Android 设备形态不断丰富,越来越多行业项目希望 Android 设备不仅承担观看和控制功能,还能够直接完成摄像头采集、音视频编码和实时流发布。

常见设备形态包括:
- Android 手机和平板;
- 移动执法终端;
- 智能安全帽;
- 车载 Android 主机;
- 工业巡检设备;
- 机器人控制终端;
- 便携式布控设备;
- Android 边缘计算终端。
这些设备通常已经具备摄像头、麦克风、硬件编码器、网络连接和本地计算能力。如果在设备内部完成采集、编码与 RTSP 发布,就可以形成一条完整的视频链路:
bash
摄像头、麦克风
↓
Android 后台采集
↓
H.264/H.265、AAC 编码
↓
设备本地 RTSP Server
↓
VLC、FFplay、NVR 或业务平台拉流
设备启动服务后,可以提供类似下面的 RTSP 地址:
bash
rtsp://192.168.1.100:8554/stream1
局域网或专网中的播放器、NVR、监控平台和自研业务系统,只要网络可达,就可以直接拉取实时音视频。
这种模式与传统 RTMP 云端推流有所不同。
RTMP 更适合中心化直播、云端转发和公网分发;设备本地 RTSP Server 则更适合局域网、专网、边缘现场、设备直连和临时视频源等场景。
它的核心特点是:
- Android 设备自己提供视频服务;
- 客户端根据需要主动拉取;
- 局域网项目不一定需要额外部署流媒体服务器;
- 音视频传输链路更短;
- 现场调试和系统对接更加直接。
如果设备位于运营商 NAT、复杂防火墙或跨公网环境中,仍需要配合 VPN、端口映射、边缘网关或中心转发服务。轻量级 RTSP Server 主要解决的是设备侧视频服务能力,并不替代所有公网穿透和大规模分发系统。
二、架构设计
这套示例中,一个重要的架构设计是:摄像头采集、麦克风采集、编码和 RTSP 发布,并不直接依赖 Activity 生命周期。
Activity 主要负责:
- 权限申请;
- 参数配置;
- 本地画面预览;
- 前后摄像头切换;
- 麦克风控制;
- RTSP Server 和 RTSP Stream 启停;
- RTSP URL 和 SDK 事件展示;
- 当前客户端会话数查询。
真正的媒体核心则运行在 StreamMediaCameraService 和 NTStreamMediaCameraEngineImpl 中。

Service 创建时主要完成以下工作:
- 加载 SmartPublisher 原生库;
- 初始化 SmartMediaKit RTSP Server SDK;
- 创建独立的
HandlerThread; - 创建媒体引擎实例;
- 通过 Binder 向 Activity 提供控制接口。
StreamMediaCameraService 在创建时初始化 RTSP Server SDK、启动独立媒体线程,并构建 NTStreamMediaCameraEngineImpl。Activity 通过 NTStreamMediaBinder 获取媒体引擎,但摄像头、麦克风、编码器和 RTSP Server 仍由 Service 统一管理。
这种设计可以让媒体链路与页面解耦。
Activity 可以退出、重建或暂时关闭预览,而摄像头采集和 RTSP 发布不必立即停止。对于移动执法、车载监控、工业巡检和智能穿戴设备来说,媒体服务不应依赖用户始终停留在某个界面。
为了适配 Android 高版本的后台摄像头和麦克风访问限制,项目需要使用前台 Service,并在 AndroidManifest.xml 中声明相应权限和服务类型,例如:
bash
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" />
Service 通常还需要声明:
bash
android:foregroundServiceType="camera|microphone"
示例 Service 会创建前台通知,并根据系统版本和权限设置 Camera、Microphone 前台服务类型,同时通过 START_STICKY 提升服务被系统回收后的恢复能力。
Activity 中还包含电池优化白名单相关处理,用于降低后台服务被系统省电策略限制的概率。
需要说明的是,前台 Service 和电池优化白名单只能提高持续运行能力,并不能保证应用在所有设备上绝对不会被终止。正式项目仍需要针对不同厂商的后台管理策略进行适配和测试。
三、音视频数据采集与投递
Activity 与 Service 绑定成功后,示例会自动触发:
bash
open_camera_microphone_and_start_rtsp_stream();
整个启动过程可以概括为:

示例默认参数大致为:
- 分辨率:1280×720;
- 帧率:25fps;
- GOP:50;
- 码率:3500kbps;
- 编码方式:H.264 软编码、H.264 硬编码或 H.265 硬编码。
Camera2 同时支持预览和编码
Camera2Helper 使用 ImageReader 创建 YUV 输出:
bash
ImageReader.newInstance(
width,
height,
ImageFormat.YUV_420_888,
3
);
如果需要显示本地画面,Camera2 采集会话会同时输出到:
TextureView对应的 Surface;ImageReader对应的 Surface。
如果不需要预览,则只向 ImageReader 输出数据。
这意味着视频编码并不依赖 Activity 中的预览画面。即使关闭 TextureView,摄像头仍然可以通过 ImageReader 持续向 SmartMediaKit 提供 YUV 数据。
代码中采集请求优先使用:
bash
CameraDevice.TEMPLATE_RECORD
如果设备不支持,再回退到:
bash
CameraDevice.TEMPLATE_PREVIEW
同时还会根据设备能力选择合适的帧率范围,并尝试开启光学防抖、视频防抖和连续视频自动对焦。
使用 acquireLatestImage() 避免帧积压
实时视频与视频文件录制的诉求不同。
如果编码或系统调度短时间跟不上摄像头采集速度,按顺序处理所有旧帧会导致画面延迟不断累积。示例使用 acquireLatestImage() 获取最新帧,在出现积压时主动舍弃已经失去实时价值的旧画面。
这更符合移动执法、机器人视觉、车载监控和现场调度等场景:
相比保证每一帧都不丢,实时业务更关心当前最新画面。
YUV 数据直接投递 SmartPublisher
Android 的 YUV_420_888 通常由多个 Plane 组成,不同设备还可能存在不同的:
- row stride;
- pixel stride;
- crop 范围;
- UV 排布;
- 内存对齐方式。
NTStreamMediaCameraEngineImpl.onCameraImageData() 会读取 Y、U、V 三个 Plane 的 ByteBuffer,并将 stride、crop、画面宽高、旋转角度和水平翻转状态一起传给 SmartPublisher:
bash
PostLayerImageYUV420888ByteBuffer(...)
这种数据路径不需要将每帧图像转换成 Bitmap,也不需要经过 UI 截图或 RGB 中转,可以减少内存复制、格式转换和垃圾回收压力。
麦克风采集
当前示例使用:
bash
start_audio_record(48000, 1);
也就是以 48kHz、单声道方式启动麦克风采集。
采集到的 PCM 音频数据通过回调直接投递给 SmartPublisher,由 SDK 完成 AAC 编码和音视频时间戳同步。
四、音视频编码
完成摄像头和麦克风采集后,SmartMediaKit 会创建 SmartPublisher 实例:
bash
SmartPublisherOpen(
context,
audio_opt,
video_opt,
width,
height
);
其中,audio_opt 和 video_opt 用于指定输入的是编码前还是编码后的音视频数据。
当前示例主要使用原始 PCM 和 YUV 数据输入,由 SmartMediaKit 完成编码、同步和发布。

视频编码能力
示例支持:
- H.264 软件编码;
- H.264 硬件编码;
- H.265/HEVC 硬件编码。
H.264 硬编码场景下,还可以配置:
- 编码码率;
- 码率控制模式;
- 编码复杂度;
- 编码质量;
- AVC Profile;
- AVC Level;
- 是否使用 Native Media NDK。
H.265 场景则调用 HEVC 硬编码接口。
Android MediaCodec 在不同芯片和系统版本上的能力差异较大。不同设备可能支持不同的 CBR、VBR、CQ、Profile、Level 和 H.265 编码能力,因此实际项目需要根据设备能力进行参数回退和兼容处理。

音频编码
示例使用 PCM 音频输入,由 SmartPublisher 完成 AAC 编码,同时可以配置:
- 音频码率;
- 输入音量;
- 静音状态;
- 音频采样参数。
GOP 和码率
例如 25fps、GOP 50,意味着大约每两秒生成一个关键帧。
GOP 较短时:
- 客户端起播更快;
- 丢包后恢复更快;
- 关键帧带宽占用更高。
GOP 较长时:
- 编码压缩效率可能更高;
- 客户端等待关键帧时间更长;
- 网络异常后的恢复速度可能降低。
因此,GOP、码率和帧率需要结合局域网带宽、播放器缓冲和业务实时性要求综合设置。
编码参数具有状态约束
这套示例并不允许业务层在任何时刻随意修改分辨率、帧率、GOP 和编码方式。
LibPublisherWrapper 内部分别维护:
- RTMP 推流状态;
- 本地录像状态;
- RTSP 发布状态;
- GB28181 媒体流状态。
同时通过读写锁保护 Native Handle 和发布状态。
同一套采集链路支持多种输出
虽然当前示例重点演示 RTSP,但 SmartPublisher Wrapper 同时保留了:
- RTMP 推流;
- 本地 MP4 录像;
- RTSP Stream;
- GB28181 Media Stream。
这意味着同一套摄像头、麦克风和编码链路,可以根据业务需要组合为:
bash
┌─ RTSP 本地服务
摄像头、麦克风 ───┼─ RTMP 推流
├─ 本地 MP4 录像
└─ GB28181 媒体流
业务系统不需要为每一种协议重复建设采集和编码模块,这也是 SmartMediaKit 相对于单一协议 Demo 的重要价值。
五、构建轻量级RTSP服务
这套方案最有特点的部分,是在 Android 设备内部直接启动 RTSP Server。
它不是将音视频推送到外部 RTSP 服务器,而是在设备本地完成:
- 创建 RTSP Server;
- 设置监听端口;
- 设置可选用户名和密码;
- 启动网络监听;
- 设置 RTSP Stream Name;
- 绑定 SmartPublisher;
- 启动和停止 RTSP Stream;
- 查询当前客户端会话数;
- 停止并释放 RTSP Server。
整体关系可以表示为:

RTSP Server 与 RTSP Stream 相互解耦
启动 RTSP Server,主要是让 Android 设备开始监听指定端口,例如 8554。
真正发布媒体资源时,还需要:
- 创建或确认 Publisher;
- 设置 Stream Name;
- 将 Publisher 绑定到 RTSP Server;
- 启动 RTSP Stream;
- 等待 SDK 回调最终 RTSP URL。
媒体引擎接口中分别提供了 RTSP Server 和 RTSP Stream 的启停、状态查询和会话数查询方法。
这种解耦方式便于业务分别控制:
- 网络监听是否开放;
- 摄像头和麦克风是否启动;
- 某一路流是否发布;
- RTMP 是否同时推送;
- 当前是否有客户端连接;
- 无客户端时是否关闭采集或进入节能状态。
客户端会话数
RTSP Server 可以查询当前连接会话数。
业务系统可以基于会话数实现:
- 显示当前观看客户端数量;
- 无客户端时降低帧率或停止编码;
- 限制最大并发连接;
- 发现异常连接数量;
- 记录客户端使用状态。
需要注意的是,设备内置轻量级 RTSP Server 更适合局域网或少量客户端访问。如果需要面向大量用户进行公网分发,仍应使用专业流媒体服务器或 CDN。
这套方案通过缩短数据链路、减少中间转换和避免帧积压,为局域网低延迟实时预览提供了良好的工程基础。
六、技术优势
综合这套代码和架构,可以归纳出 SmartMediaKit 在 Android 后台采集与 RTSP 发布方面的几个主要优势。

1. 媒体生命周期独立于 Activity
通过前台 Service、Binder 和独立媒体线程,将摄像头采集、编码和发布与页面生命周期解耦。
2. 原始数据路径直接
Camera2 输出的 YUV_420_888 数据直接进入 SmartPublisher,不需要先转换成 Bitmap,也不依赖 UI 预览画面。
3. 支持有预览和无预览模式
同一套代码既可以显示本地 TextureView,也可以完全在后台运行,适合无人值守设备和行业终端。
4. 编码能力完整
支持 H.264 软件编码、H.264 硬件编码、H.265 硬件编码和 AAC 音频编码,并提供 GOP、码率、Profile 和码率控制等参数。
5. Android 设备内置 RTSP 服务
不依赖外部 RTSP Server,即可在局域网或专网内对外提供实时音视频。
6. 多种协议共享采集编码链路
在 RTSP 之外,还可以扩展 RTMP、MP4 录像和 GB28181 媒体流,减少重复开发。
7. 处理实际设备差异
代码覆盖了 Camera2 能力枚举、分辨率、帧率、前后摄像头、画面旋转、镜像、防抖和编码器差异。
8. 提供视频图层扩展
示例中的 LayerPostThread 可以向视频中叠加:
- 时间戳;
- 文字;
- 图片;
- 设备编号;
- 企业 Logo;
- 任务信息;
- AI 检测结果。
适合形成的产品形态
基于这套能力,可以构建:
Android 网络摄像机
将普通 Android 手机、平板或定制终端变成局域网 RTSP 视频源。
移动执法和单兵终端
后台持续采集摄像头和麦克风,同时通过 RTSP、RTMP 或 GB28181 提供实时音视频。
工业巡检终端
现场人员使用 Android 设备进行设备、仪表和环境巡检,后台人员通过 RTSP 实时查看。
车载视频节点
车载 Android 主机采集前视、后视或车内摄像头,用于物流、工程车辆和移动指挥。
机器人视觉回传
机器人摄像头画面可以通过 RTSP 提供给控制台、AI 分析模块、远程操作终端或录像系统。
智能安全帽和穿戴设备
即使没有持续显示 Activity,也可以在后台完成音视频采集和发布。
局域网临时视频源
适合展会、实验室、教学演示、项目现场和临时布控,不需要额外部署 IPC 和 RTSP 服务器。
Android 边缘视频网关
结合板载摄像头、USB 摄像头或外部视频数据,进一步扩展为边缘采集和协议转换节点。
七、项目落地
虽然示例已经覆盖了后台采集、编码和 RTSP 发布的核心链路,但正式项目仍需要进一步考虑以下问题。

权限和系统版本
不同 Android 版本对前台 Service、通知、摄像头和麦克风权限的要求不同,需要按系统版本进行处理。
厂商后台策略
部分设备还需要用户开启自启动、允许后台运行或关闭特殊省电限制。
网络地址变化
Wi-Fi、有线网络、热点和移动网络切换后,设备 IP 可能发生变化,RTSP URL 需要重新生成并上报。
Wi-Fi 休眠
设备熄屏后需要确认 Wi-Fi 是否保持连接,必要时使用合理的网络锁策略。
编码器兼容性
不同芯片平台的 MediaCodec 表现差异明显,需要建立参数回退、设备白名单和异常恢复机制。
温度与功耗
长时间摄像头采集和硬编码可能导致设备发热,应根据硬件能力合理设置分辨率、帧率和码率。
播放器缓冲
设备侧链路较短,并不代表客户端一定低延迟。播放器缓存策略同样会显著影响最终延迟。
访问安全
正式项目可以根据需要配置:
- RTSP 用户名和密码;
- 局域网访问控制;
- VPN;
- 最大客户端数量;
- 设备鉴权;
- 服务启停权限。
异常恢复
还需要针对摄像头断开、麦克风失败、编码器异常、网络变化和 Service 重建等情况建立自动恢复机制。
此外,后台媒体服务的可靠性不仅取决于如何启动,也取决于如何停止。
在 StreamMediaCameraService.onDestroy() 中,代码会依次解除 Binder 绑定、通知 Handler 退出、在媒体线程中关闭 Engine,并安全退出 HandlerThread。
LibPublisherWrapper.release() 还会根据当前状态分别停止 RTMP、录像、RTSP 和 GB28181 输出,最后关闭 SmartPublisher Native Handle。
这种明确的资源释放顺序,可以降低摄像头占用、线程泄漏、端口未释放和 Native Handle 残留等问题。
总体来看,Android 后台摄像头采集并不是简单地打开 Camera,再调用一个推流接口。
真正能够用于行业项目的方案,需要同时处理:
- 前台 Service;
- Camera2 和麦克风采集;
- YUV 数据布局;
- 视频编码器适配;
- 音视频时间戳同步;
- 旋转和镜像;
- RTSP Server;
- Publisher 状态;
- 客户端会话;
- 后台运行策略;
- 线程和 Native 资源释放。
SmartCamera2Service 示例展示了一种比较完整的 Android 实时视频节点实现方式:
由前台 Service 承载后台生命周期,通过 Camera2 和 AudioRecord 获取原始音视频数据,使用 SmartMediaKit 完成 H.264/H.265、AAC 编码和协议封装,再通过内置轻量级 RTSP Server,让 Android 设备直接向局域网或专网客户端提供实时流。
它的意义不只是"在 Android 上发布一条 RTSP 流",而是把 Android 手机、平板、车载主机、智能安全帽、机器人控制器和工业终端,从普通应用设备转变为能够持续采集、编码并对外提供实时视频服务的边缘节点。
对于移动执法、工业巡检、车载监控、机器人视觉、便携式布控和局域网实时预览等项目而言,SmartMediaKit 的核心价值,是将摄像头适配、音频采集、编码器管理、音视频同步、RTSP 发布和资源生命周期等复杂环节,收敛为一套可复用、可扩展、便于业务系统集成的工程化能力。