本文主要是介绍【Android Camera1】Camera1初始化销毁流程(二) —— 初始化基本框架和CameraView几种实现方式及其伪代码,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
初始化基本框架和CameraView几种实现方式
- 一、摘要
- 二、算法思想讲解
- 2.1 基本框架
- 2.1.1 CameraView
- 2.1.2 CameraManager
- 2.1.3 Camera1Impl
- 2.2 承载CameraView的消费者。
- 2.2.1 Android系统 图形架构
- 2.1.1.1 图像流生产方
- 2.1.1.2 图像流消耗方
- 2.2.2 Surface、SurfaceHolder、SurfaceView、TextureView和GLSurfaceView
- 2.2.2.1 Surface
- 2.2.2.2 SurfaceHolder
- 2.2.2.3 SurfaceView
- 2.2.2.4 TextureView
- 2.2.2.5 总结
- 2.2.3 SurfaceView实现方案
- 2.2.4 TextureView实现方案
- 2.2.5 GLSurfaceView实现方案
一、摘要
本篇文章阐述如何开发一个健壮的Camera1相机应用。可结合【Camera1】Camera1初始化流程(上) —— 官方Demo初始化流程分析一起参看。
本篇文章只阐述算法和思想。具体的代码开发,可参考如下系列文章
- Camera1源码分析
- Camera1官方Demo
- Camera1开源项目分析
二、算法思想讲解
2.1 基本框架
一个相机应用可以抽象为如下具体的类:
2.1.1 CameraView
承载相机预览画面的CameraView,该CameraView应该支持如下功能:
- 初始化SurfaceHolder/ SurfaceTexture
- 监听Camera1Impl类状态来更改相关的UI
- 权限检查和申请
- 初始化和参数设置
- 对焦、闪光灯、曝光调节、缩放基本功能UI
- 拍照、录制功能
- 其他功能UI:分辨率、画幅、场景模式、网格、白平衡、定时拍照、水平检测
初始化功能只涉及到1、2、3点。
2.1.2 CameraManager
Camera管理类
- 提供线程调度管理
- Camera抽象层
2.1.3 Camera1Impl
Camera1具体实现类、实现对应【2.1.1】里相应的功能
2.2 承载CameraView的消费者。
承载CameraView的消费者可以为如下:
SurfaceViewTextureViewGLSurfaceView
在具体阐述这几个View之前,我们先额外说一下Android系统的图形架构以及这几个View之间的差异点。详细的参考资料如下:
- Android系统图形架构
- Surface、SurfaceHolder、SurfaceView、TextureView和GLSurfaceView
2.2.1 Android系统 图形架构
Android 框架提供了各种用于 2D 和 3D 图形渲染的 API,应用开发者可通过三种方式将图像绘制到屏幕上:使用画布、OpenGL ES 或 Vulkan。
无论开发者用什么渲染 API,一切内容都会渲染到 Surface 上。Surface 表示缓冲区队列中的生产方,而缓冲区队列通常会被 SurfaceFlinger 消耗。在 Android 平台上创建的每个窗口都由 Surface 提供支持。所有被渲染的可见 Surface 都被 SurfaceFlinger 合成到屏幕。
下图显示了关键组件如何协同工作

2.1.1.1 图像流生产方
生成图形缓冲区以供消耗的任何内容。
OpenGL ESCanvas 2Dmediaserver视频解码器
2.1.1.2 图像流消耗方
最常见消耗方是 SurfaceFlinger,其他 OpenGL ES 应用也可以消耗图像流如:相机应用会消耗相机预览图像流,ImageReader 类。
2.2.2 Surface、SurfaceHolder、SurfaceView、TextureView和GLSurfaceView
2.2.2.1 Surface
/*** Handle onto a raw buffer that is being managed by the screen compositor.** <p>A Surface is generally created by or from a consumer of image buffers (such as a* {@link android.graphics.SurfaceTexture}, {@link android.media.MediaRecorder}, or* {@link android.renderscript.Allocation}), and is handed to some kind of producer (such as* {@link android.opengl.EGL14#eglCreateWindowSurface(android.opengl.EGLDisplay,android.opengl.EGLConfig,java.lang.Object,int[],int) OpenGL},* {@link android.media.MediaPlayer#setSurface MediaPlayer}, or* {@link android.hardware.camera2.CameraDevice#createCaptureSession CameraDevice}) to draw* into.</p>** <p><strong>Note:</strong> A Surface acts like a* {@link java.lang.ref.WeakReference weak reference} to the consumer it is associated with. By* itself it will not keep its parent consumer from being reclaimed.</p>*/
Surface是一个接口,供生产方与消耗方交换缓冲区。- Consumer:
–SurfaceTexture
–MediaRecorder
–Allocation - Producer:
–android.opengl.EGL14#eglCreateWindowSurface
–android.media.MediaPlayer#setSurface MediaPlayer
–android.hardware.camera2.CameraDevice#createCaptureSession CameraDevice}
2.2.2.2 SurfaceHolder
/*** Abstract interface to someone holding a display surface. Allows you to* control the surface size and format, edit the pixels in the surface, and* monitor changes to the surface. This interface is typically available* through the {@link SurfaceView} class.*/
SurfaceHolder 是系统用于与应用共享 Surface 所有权的接口。与 Surface 配合使用的一些客户端需要 SurfaceHolder,因为用于获取和设置 Surface 参数的 API 是通过 SurfaceHolder 实现的。一个 SurfaceView 包含一个 SurfaceHolder。
与 View 交互的大多数组件都涉及到 SurfaceHolder。一些其他 API(如 MediaCodec)将在 Surface 本身上运行。
2.2.2.3 SurfaceView
SurfaceView 是一个组件,可用于在 View 层次结构中嵌入其他合成层。SurfaceView 采用与其他 View 相同的布局参数,因此可以像对待其他任何 View 一样对其进行操作,但 SurfaceView 的内容是透明的。
当使用外部缓冲区来源(例如 GL 上下文和媒体解码器)进行渲染时,您需要从缓冲区来源复制缓冲区,以便在屏幕上显示这些缓冲区。为此,您可以使用 SurfaceView。
当 SurfaceView 的 View 组件即将变得可见时,框架会要求 SurfaceControl 从 SurfaceFlinger 请求新的 surface。如需在创建或销毁 Surface 时收到回调,请使用 SurfaceHolder 接口。默认情况下,新创建的 Surface 放置在应用界面 Surface 的后面。您可以替换默认的 Z 轴顺序,将新的 Surface 放在前面。
在需要渲染到单独的 Surface(例如,使用 Camera API 或 OpenGL ES 上下文进行渲染)时,使用 SurfaceView 进行渲染很有帮助。使用 SurfaceView 进行渲染时,SurfaceFlinger 会直接将缓冲区合成到屏幕上。如果没有 SurfaceView,需要将缓冲区合成到屏幕外的 Surface,然后该 Surface 会合成到屏幕上,而使用 SurfaceView 进行渲染可以省去额外的工作。使用 SurfaceView 进行渲染后,请使用界面线程与 Activity 生命周期相协调,并根据需要调整 View 的大小或位置。然后,硬件混合渲染器会将应用界面与其他层混合在一起。
新的 Surface 是 BufferQueue 的生产方,其使用方是 SurfaceFlinger 层。可以通过任何可向 BufferQueue 馈送资源的机制更新 Surface,例如,使用提供 Surface 的 Canvas 函数、附加 EGLSurface 并使用 GLES 在 Surface 上绘制,或者配置媒体解码器以写入 Surface。
2.2.2.4 TextureView
TextureView 对象会对 SurfaceTexture 进行包装,从而响应回调以及获取新的缓冲区。在 TextureView 获取新的缓冲区时,TextureView 会发出 View 失效请求,并使用最新缓冲区的内容作为数据源进行绘图,根据 View 状态的指示,以相应的方式在相应的位置进行呈现。
OpenGL ES (GLES) 可以将 SurfaceTexture 传递到 EGL 创建调用,从而在 TextureView 上呈现内容,但这样会引发问题。当 GLES 在 TextureView 上呈现内容时,BufferQueue 生产方和使用方位于同一线程中,这可能导致缓冲区交换调用暂停或失败。例如,如果生产方以快速连续的方式从界面线程提交多个缓冲区,则 EGL 缓冲区交换调用需要使一个缓冲区从 BufferQueue 出列。不过,由于使用方和生产方位于同一线程中,因此不存在任何可用的缓冲区,而且交换调用会挂起或失败。
为了确保缓冲区交换不会停止,BufferQueue 始终需要有一个可用的缓冲区能够出列。为了实现这一点,BufferQueue 在新缓冲区加入队列时舍弃之前加入队列的缓冲区的内容,并对最小缓冲区计数和最大缓冲区计数施加限制,以防使用方一次性消耗所有缓冲区。
2.2.2.5 总结
SurfaceView 和 GLSurfaceView。SurfaceView 结合了 Surface 和 View。SurfaceView 的 View 组件由 SurfaceFlinger(而不是应用)合成,从而可以通过单独的线程/进程渲染,并与应用界面渲染隔离。GLSurfaceView 提供了用于管理 EGL 上下文、线程间通信以及与 Activity 生命周期的交互的辅助程序类(但不是必须使用 GLES)。
SurfaceTexture。 SurfaceTexture 将 Surface 和 GLES 纹理相结合来创建 BufferQueue,而应用是 BufferQueue 的消费者。当生产者将新的缓冲区排入队列时,它会通知应用。应用会依次释放先前占用的缓冲区,从队列中获取新缓冲区并执行 EGL 调用,从而使 GLES 可将此缓冲区作为外部纹理使用。
TextureView。 TextureView 结合了 View 和 SurfaceTexture。TextureView 对 SurfaceTexture 进行包装,并负责响应回调以及获取新的缓冲区。在绘图时,TextureView 使用最近收到的缓冲区的内容作为其数据源,根据 View 状态指示,在它应该渲染的任何位置和以它应该采用的任何渲染方式进行渲染。View 合成始终通过 GLES 来执行,这意味着内容更新可能会导致其他 View 元素重绘。
2.2.3 SurfaceView实现方案
注意以下皆为伪代码
CameraSurfaceView.java
A. 新建一个SurfaceView基本实现类
public class CameraSurfaceView extends SurfaceView {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);}public Surface getSurface() {return getHolder().getSurface();}public SurfaceHolder getSurfaceHolder() {return getHolder();}public boolean isReady() {return getWidth() != 0 && getHeight() != 0;}
}
B. 更新代码->添加SurfaceCallBack
public CameraSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {SurfaceHolder holder = getHolder();holder.addCallback(new SurfaceHolder.Callback() {@Overridepublic void surfaceCreated(SurfaceHolder holder) {Log.i(TAG,"surfaceCreated");}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {Log.i(TAG,"surfaceChanged size = "+width+","+height);}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {Log.i(TAG,"surfaceDestroyed");}});}
C. 计算宽高比,传递SurfaceHolder给Camera1Impl.java。
float aspectRatio = 1;@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {Log.i(TAG,"surfaceChanged size = "+width+","+height);aspectRatio = width*1.0f/height;CameraManager.of().initCamera(holder);}
D.记录CameraId
//默认后置
float mCameraId = 1;@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {Log.i(TAG,"surfaceChanged size = "+width+","+height);//...CameraManager.of().createCamera(mCameraId);CameraManager.of().initCamera(holder);}
E.在surfaceDestroyed 添加releaseCamera方法
@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {Log.i(TAG,"surfaceDestroyed");CameraManager.of().releaseCamera();}
以上为CameraView之SurfaceView实现方式的基本模版代码参考。
2.2.4 TextureView实现方案
基本上和SurfaceView没有太大区别,只需要把SurfaceCallBack修改为如下即可
setSurfaceTextureListener(new SurfaceTextureListener() {@Overridepublic void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {}@Overridepublic void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {}@Overridepublic boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {return false;}@Overridepublic void onSurfaceTextureUpdated(SurfaceTexture surface) {}});
其他基本保持一致。
2.2.5 GLSurfaceView实现方案
其他和【2.2.3】保持一致
public class CameraGLSurfaceView extends GLSurfaceView {public CameraGLSurfaceView(Context context) {super(context);}public CameraGLSurfaceView(Context context, AttributeSet attrs) {super(context, attrs);}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {super.surfaceChanged(holder, format, w, h);}@Overridepublic void surfaceCreated(SurfaceHolder holder) {super.surfaceCreated(holder);}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {super.surfaceDestroyed(holder);}
}
本篇主要介绍了Camera1初始化的基本框架和CameraView几种实现方式,并介绍了SurfaceView、GLSurfaceView、TextureSurface的代码实现以及他们之间的差异点。
后一篇文章将会介绍:
【Camera1】Camera1初始化流程(三) —— 权限申请和线程调度
这篇关于【Android Camera1】Camera1初始化销毁流程(二) —— 初始化基本框架和CameraView几种实现方式及其伪代码的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!