本文主要是介绍【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的消费者可以为如下:
SurfaceView
TextureView
GLSurfaceView
在具体阐述这几个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 ES
Canvas 2D
mediaserver
视频解码器
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几种实现方式及其伪代码的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!