本讲是Android Camera性能分析专题的第22讲,我们介绍录像使用PersistInputSurface,包括如下内容:
- 为什么要使用PersistentInputSurface
- 使用PersistentInputSurface的步骤
- GeekCamera2 录像使用PersistInputSurface实战
- 录像使用PersistInputSurface Trace简单分析
资源 | 描述 |
---|---|
在线课程 | 极客笔记在线课程 |
知识星球 | 星球名称:深入浅出Android Camera 星球ID: 17296815 |
极客笔记圈 |
为什么要使用PersistentInputSurface
-
App完全掌控录像Surface的生命周期,可以避免如下难以处理的问题
- 当Video Encoder发生错误时(比如Storage满了,无法正常写入),会先release recording Surface再返回错误给Camera App,而此时可能Camera Framework正在送Buffer给Recording Surface,Surface如果被突然销毁,Camera Framework会抛Exception
-
当重复录像时,第二次录像可以省掉MediaRecorder.prepare时间
- 理论上可行,留给同学们去验证
使用PersistentInputSurface的步骤
可以分为如下步骤:
Surface persistSurface = MediaCodec.createPersistentInputSurface()
MediaRecorder.setInputSurface(persistSurface)
MediaRecorder.prepare()
createCaptureSession with persist input surface
persistSurface.release()
- 通过MediaCodec.createPersistentInputSurface()创建一个Surface,此时Surface的属性,比如宽、高、format、Usage等都未指定
- 将创建好的Persistent Input Surface通过
MediaRecorder.setInputSurface
设置给MediaRecorder - 调用MediaRecorder的prepare方法,这样该Surface就可以拿去用了
- 创建Camera Capture Session时可以使用该Surface了
- 当退出Video模式时(切其他模式或进入Setting去切录像分辨率),销毁Persistent Input Surface,否则每次录像可以重用该Surface
该Surface的生命周期完全可以由App来控制
GeekCamera2 录像使用PersistentInputSurface实战
具体见视频讲解,核心函数如下:
public void copyToMediaRecorder(MediaRecorder media_recorder, boolean slow_motion, Surface persistSurface) {
if( MyDebug.LOG )
Log.d(TAG, "copyToMediaRecorder: " + media_recorder + toString());
if( record_audio && !slow_motion) {
if( MyDebug.LOG )
Log.d(TAG, "record audio");
media_recorder.setAudioSource(this.audioSource);
}
media_recorder.setVideoSource(this.videoSource);
// n.b., order may be important - output format should be first, at least
// also match order of MediaRecorder.setProfile() just to be safe, see https://stackoverflow.com/questions/5524672/is-it-possible-to-use-camcorderprofile-without-audio-source
media_recorder.setOutputFormat(this.fileFormat);
if (slow_motion) {
media_recorder.setVideoFrameRate(30);
} else {
media_recorder.setVideoFrameRate(this.videoFrameRate);
}
media_recorder.setCaptureRate(this.videoCaptureRate);
media_recorder.setVideoSize(this.videoFrameWidth, this.videoFrameHeight);
media_recorder.setVideoEncodingBitRate(this.videoBitRate);
media_recorder.setVideoEncoder(this.videoCodec);
if( record_audio && !slow_motion) {
media_recorder.setAudioEncodingBitRate(this.audioBitRate);
media_recorder.setAudioChannels(this.audioChannels);
media_recorder.setAudioSamplingRate(this.audioSampleRate);
media_recorder.setAudioEncoder(this.audioCodec);
}
if( MyDebug.LOG )
Log.d(TAG, "done: " + media_recorder);
if (persistSurface != null) {
media_recorder.setInputSurface(persistSurface);
}
}
注意,使用Persistent Input Surface后不能再从MediaRecorder去getSurface()了。
录像使用PersistentInputSurface Trace简单分析
从GeekCamera App的进程我们能看到GraphicBufferSource的Trace