这篇文章的主要学习内容是:使用 Camera API 采集视频数据并保存到文件,分别使用 SurfaceView、TextureView 来预览 Camera 数据,取到 NV21 的数据回调。
Android 中预览相机画面主要用 SurfaceView 和 TextureView。
SurfaceView:SurfaceView 是一个有自己 Surface 的 View。界面渲染可以放在单独线程而不是主线程中。它更像是一个 Window,自身不能做变形和动画。
TextureView:TextureView 同样也有自己的 Surface。但是它只能在拥有硬件加速层的 Window 中绘制,它更像是一个普通 View,可以做变形和动画。
更多关于 SurfaceView 和 TextureView 的知识可以看这篇文章 Android 5.0(Lollipop)中的SurfaceTexture,TextureView, SurfaceView和GLSurfaceView[1]。
Android 5.0 之前系统提供了 Camera API ,5.0 之后提供了 Camera2 API。
不同手机厂商对 Camera2 的支持程度各不相同,即便是 Android 5.0 以上的手机,也存在对 Camera2 支持非常差的情况,这个时候就要降级使用 Camera。
官方的开源库 cameraview [2] 给出的方案:
API Level | Camera API | Preview View |
---|---|---|
9-13 | Camera1 | SurfaceView |
14-20 | Camera1 | TextureView |
21-23 | Camera2 | TextureView |
24 | Camera2 | SurfaceView |
接下来,我们使用 SurfaceView 和 TextureView 实现相机预览的功能。
1、Camera
1.1 使用 SurfaceView
SurfaceView 用于展示相机画面,SurfaceView 持有 SurfaceHolder,我们通过 SurfaceHolder 中的回调可以知道 Surface 的状态(创建、变化、销毁)。
【学习地址】:FFmpeg/WebRTC/RTMP/NDK/Android音视频流媒体高级开发
【文章福利】:免费领取更多音视频学习资料包、大厂面试题、技术视频和学习路线图,资料包括(C/C++,Linux,FFmpeg webRTC rtmp hls rtsp ffplay srs 等等)有需要的可以点击1079654574加群领取哦~
继承 SurfaceView,实现 SurfaceHolder.CallBack 接口。在 surfaceCreated
方法中打开相机预览,在 surfaceDestroyed
方法中关闭相机预览就可以了。Camera 的 open
方法有些耗时,为了避免阻塞 UI 线程,可以创建子线程打开相机。
public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
private Camera mCamera;
public CameraSurfaceView(Context context) {
this(context, null);
}
public CameraSurfaceView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CameraSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
getHolder().addCallback(this);
}
@Override
public void surfaceCreated(final SurfaceHolder holder) {
ThreadHelper.getInstance().runOnHandlerThread(new Runnable() {
@Override
public void run() {
openCamera();
startPreview(holder);
}
});
}
@Override
public void surfaceChanged(S