文章同步发布于 csdn 与 简书
前段时间接触到了部分手机的无人直播系统。
说是无人直播,实际上应该算是视频转录播放功能。并不是完全的无人操作,还是需要有人录制视频,然后操作手机播放
从想法上,大概也能猜到是使用了 mp4 的帧,去替换摄像头的帧,从而实现视频流的替换,做到无人直播
无人直播系统实现原理
实际上就是用 mp4 的帧替换掉 Camera 的视频帧
Camera 视频流分析
做 Android 开发的都知道,要想实现视频直播,需要调用
Camera
预览,才能获取到视频流数据
如果使用旧的 Camera Api,那么调用的是 Camera.open()
方法,获取到Camera 对象,设置回调,视频流数据会通过回调返回,是 byte[]
数组
如果使用新的 Camera2 APi,那么需要构造 CaptureRequest
,经过许多操作,从而获取到每一帧的 Image
对象,视频流就在每一个 Image
对象中,用户自行编写代码可以获取到 byte[]
数组
如何实现视频流替换?
经过上面分析,可以知道,每一帧视频流都是使用回调,从而提供给 APP 的,那么能否修改这个回调,在提供给 APP 前,将里面的 byte[]
替换掉呢?
其实是可以的,实现方式主要有两种,一种是使用 Xposed 框架 Hook 系统,在回调执行时替换
xposed 框架实现方式有可能会被检测到,从 app 角度出发,可以检测手机上是否安装 Xposed 框架、检测当前堆栈是否有 Xposed 的栈信息等等。
另一种是修改系统 framework ,在系统层面实现视频流的替换,这里简单介绍第二种
定制系统实现视频流替换
如果要自行定制系统,那么选择一款开源的系统必不可少。
目前开源使用比较广泛的是 Lineage OS
。魔趣系统也有
但时至今日(2021),还在频繁更新的是 Lineage OS
?
既然第一步思路已经明确,在 Framework 的 Camera 中替换 byte[] 数组。那么如何获取 mp4 的 byte[] 数组?
如果使用系统原生提供的 Api,那么可以使用 MediaCodec
MediaCodec 解码视频时,一般要求传入 SurfaceView
,实现视频画面展示
实际上 MediaCodec 可以获取 Image
对象,自行从 Image
对象中取出 byte[] 数组即可。然后在合适的地方替换掉视频流
需要考虑的兼容问题
当然,大致思路如此。但实际上视频流有多种格式:NV21
YUV420
等等。对于这些不同的视频流格式,需要自行转换。
实际上实现定制系统替换视频流的步骤对于个人开发者而言,还是比较麻烦的
首先需要使用 Ubuntu 编译开源系统,然后修改 Framework,解码 mp4 ,替换视频流。
简单的替换当然可以实现。但如果使用系统层面替换视频流,那么需要处理的问题就比较多了,例如视频帧率、视频分辨率、视频流的格式、Mp4 解码格式、App 兼容性,错误处理等等
结尾
目前手上有多款无人直播系统:
小米6
红米6 pro
红米 note8
具体的实现方式,以及功能使用,可以留言咨询