Android如何将外部设备采集的视频流推送到远程服务器?
实现方案
你原本的屏幕/指定区域采集思路不推荐使用:一来会引入额外的屏幕编码性能开销,二来视图如果被其他悬浮窗、系统弹窗遮挡会导致推流内容异常,且无法获得原始高质量的摄像头输入流,直接处理你当前拿到的原始bitmap流是最优解。
二、分步骤实现方案
1. Bitmap流本地渲染展示
这部分对应你要在MainActivity展示输入流的需求,直接操作原始流即可:
- 自定义一个
SurfaceView或者TextureView放在MainActivity的布局对应位置,作为渲染载体 - 拿到眼镜设备输出的每一帧Bitmap后,直接锁定Surface的Canvas绘制Bitmap即可,注意要在子线程做绘制操作,避免阻塞主线程
- 如果出现Bitmap宽高和视图宽高不匹配的情况,提前做矩阵缩放裁剪,避免拉伸变形
2. Bitmap流转推流所需的编码帧
常规直播推流需要H.264/H.265编码的视频帧,你需要把Bitmap转成YUV格式再喂给编码器:
- 首先根据推流的目标分辨率(比如720P/1080P)对原始Bitmap做缩放,减少后续编码的性能开销
- 把ARGB格式的Bitmap转换成编码所需的I420/NV21格式的YUV数据,转换操作可以用libyuv库实现,效率远高于纯Java实现
- 初始化Android自带的
MediaCodec硬编码器,配置对应分辨率、帧率、码率参数,把YUV数据喂给编码器就能拿到编码后的H.264裸流
3. 推流到远程服务器
编码之后的音视频数据按标准协议封装后推流即可:
- 如果你的服务器支持RTMP协议,直接把编码后的H.264帧加上SPS/PPS头,封装成RTMP包推送到服务器地址即可,也可以用现成的RTMP封装库处理,不用自己从零实现协议逻辑
- 如果你的直播包含音频输入,要注意音视频时间戳对齐,避免播放端出现音画不同步的问题
(可选)特殊场景的视图采集方案
如果你的需求确实要推「叠加了其他UI元素的展示视图」而不是原始摄像头流,再用这个方案,不要采集整个屏幕,直接拿视图的绘制缓存即可:
- 给你要采集的MainActivity里的展示视图开启绘制缓存:
view.setDrawingCacheEnabled(true) - 每次需要拿帧的时候调用
view.getDrawingCache()就能拿到对应视图的Bitmap,后续处理逻辑和上面的编码推流逻辑一致 - 注意用完之后要及时调用
view.destroyDrawingCache()释放内存,避免内存泄漏
三、性能优化注意点
- Bitmap转YUV、编码、推流全部放在单独的子线程处理,不要和主线程的渲染逻辑抢资源
- 控制推流帧率和编码码率,根据眼镜输出的Bitmap帧率调整,不要做多余的丢帧或者补帧操作
- 每帧Bitmap处理完之后及时回收,不要持有多余引用,避免OOM问题
内容的提问来源于stack exchange,提问作者giordy16
相关产品推荐
相关产品推荐

