这篇是之前iOS中录制和截取Unity屏幕的扩展,介绍如何在集成Unity的Android原生项目中截取和录制屏幕和声音
完整代码请查看Record_Screen_In_Unity
主要思路还是跟iOS一样,在Unity里获取当前屏幕截图,传给native,原生使用MediaCodec进行视频的合成
1. 准备工作
我们还是使用之前的Unity项目,Unity端的采集方法不变,在NativeInterface.cs
中添加安卓的接口。参考Integrating Unity as a library into standard Android app将Unity项目导出到AndroidBuild文件夹下并集成到原生工程中
导出时模式选择
IL2CPP
模式时需要在gradle.properties
文件中添加unityStreamingAssets=.unity3d
修改unityLibrary的
build.gradle
文件,添加implementation 'androidx.appcompat:appcompat:1.1.0'
将
UnityPlayerActivity
的父类由Activity
修改为AppCompatActivity
2.视频帧和音频的传输
按照iOS的思路,安卓采用常规的AndroidJavaClass.Call
的方式给原生传输视频帧,经过测试发现这种方式非常卡,出来的视频帧率还不到15,经过调研,采取c库中转的方式传输。使用CMake建立RecordSDK
库,其中维护一个TPCircularBuffer
,缓存最多三帧数据,Unity通过copyVideoBuffer2Cyc
将数据传输给TPCircularBuffer
缓存,安卓端通过一个循环询问是否有数据,如果有则通过consumeVideoBuffer
获取,编码后通过recycleVideoBuffer
释放这一帧数据,好接受新的视频帧。音频数据也是同样的原理。
3. Native端
由于Unity采集的数据为BGRA32
格式并且是垂直镜像的,将KEY_COLOR_FORMAT
设置为COLOR_Format32bitBGRA8888
后发现手机不支持这个颜色格式导致编码不成功,只能在c库接收数据时通过libyuv
转成nv21
格式,还要根据手机支持的颜色格式转成对应的yuv格式和镜像旋转。
//input为Camera预览格式NV21数据
if (mColorFormat == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar) {
//nv21格式转为nv12格式
Nv21ToNv12(input, yuvBuffer, mWidth, mHeight);
} else if (mColorFormat == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar) {
//用于NV21格式转换为I420(YUV420P)格式
Nv21ToI420(input, yuvBuffer, mWidth, mHeight);
} else if (mColorFormat == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedSemiPlanar) {
System.arraycopy(input, 0, yuvBuffer, 0, mWidth * mHeight * 3 / 2);
}else if (mColorFormat == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedPlanar) {
//用于NV21格式转换为YV12格式
Nv21ToYv12(input, yuvBuffer, mWidth, mHeight);
}
MirrorYuv(yuvBuffer,mWidth,mHeight);
4. 音频录制
音频采集和iOS端是一样的,不过经过测试,使用Unity原生的VideoPlayer
在录制时视频播放声音会产生卡顿,并且在安卓端VideoPlayer
的兼容性也不好,经常会因为视频有坏帧导视卡住,所以替换成了第三方的AVPro Video
。
添加MediaPlayer
组件进行播放,并且添加AudioOutput
把声音通过AudioSource
传输,这样我们就可以通过OnAudioFilterRead(float[] data, int channels)
采集声音传给Native端,需要注意的是VideoApi需要选为Exo Player
并且Audio Output
为Unity
参考
Integrating Unity as a library into standard Android app
完整代码请查看Record_Screen_In_Unity