这篇是之前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

AVPro Video Documentation

完整代码请查看Record_Screen_In_Unity