【Android Camera1】Camera1初始化销毁流程(二) —— 初始化基本框架和CameraView几种实现方式及其伪代码

本文主要是介绍【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应该支持如下功能:

  1. 初始化SurfaceHolder/ SurfaceTexture
  2. 监听Camera1Impl类状态来更改相关的UI
  3. 权限检查和申请
  4. 初始化和参数设置
  5. 对焦、闪光灯、曝光调节、缩放基本功能UI
  6. 拍照、录制功能
  7. 其他功能UI:分辨率、画幅、场景模式、网格、白平衡、定时拍照、水平检测

初始化功能只涉及到1、2、3点。

2.1.2 CameraManager

Camera管理类

  1. 提供线程调度管理
  2. 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几种实现方式及其伪代码的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/341081

相关文章

使用Python和OpenCV库实现实时颜色识别系统

《使用Python和OpenCV库实现实时颜色识别系统》:本文主要介绍使用Python和OpenCV库实现的实时颜色识别系统,这个系统能够通过摄像头捕捉视频流,并在视频中指定区域内识别主要颜色(红... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间详解

PostgreSQL中MVCC 机制的实现

《PostgreSQL中MVCC机制的实现》本文主要介绍了PostgreSQL中MVCC机制的实现,通过多版本数据存储、快照隔离和事务ID管理实现高并发读写,具有一定的参考价值,感兴趣的可以了解一下... 目录一 MVCC 基本原理python1.1 MVCC 核心概念1.2 与传统锁机制对比二 Postg

SpringBoot整合Flowable实现工作流的详细流程

《SpringBoot整合Flowable实现工作流的详细流程》Flowable是一个使用Java编写的轻量级业务流程引擎,Flowable流程引擎可用于部署BPMN2.0流程定义,创建这些流程定义的... 目录1、流程引擎介绍2、创建项目3、画流程图4、开发接口4.1 Java 类梳理4.2 查看流程图4

C++中RAII资源获取即初始化

《C++中RAII资源获取即初始化》RAII通过构造/析构自动管理资源生命周期,确保安全释放,本文就来介绍一下C++中的RAII技术及其应用,具有一定的参考价值,感兴趣的可以了解一下... 目录一、核心原理与机制二、标准库中的RAII实现三、自定义RAII类设计原则四、常见应用场景1. 内存管理2. 文件操

C++中零拷贝的多种实现方式

《C++中零拷贝的多种实现方式》本文主要介绍了C++中零拷贝的实现示例,旨在在减少数据在内存中的不必要复制,从而提高程序性能、降低内存使用并减少CPU消耗,零拷贝技术通过多种方式实现,下面就来了解一下... 目录一、C++中零拷贝技术的核心概念二、std::string_view 简介三、std::stri

C++高效内存池实现减少动态分配开销的解决方案

《C++高效内存池实现减少动态分配开销的解决方案》C++动态内存分配存在系统调用开销、碎片化和锁竞争等性能问题,内存池通过预分配、分块管理和缓存复用解决这些问题,下面就来了解一下... 目录一、C++内存分配的性能挑战二、内存池技术的核心原理三、主流内存池实现:TCMalloc与Jemalloc1. TCM

OpenCV实现实时颜色检测的示例

《OpenCV实现实时颜色检测的示例》本文主要介绍了OpenCV实现实时颜色检测的示例,通过HSV色彩空间转换和色调范围判断实现红黄绿蓝颜色检测,包含视频捕捉、区域标记、颜色分析等功能,具有一定的参考... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间

Linux脚本(shell)的使用方式

《Linux脚本(shell)的使用方式》:本文主要介绍Linux脚本(shell)的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录概述语法详解数学运算表达式Shell变量变量分类环境变量Shell内部变量自定义变量:定义、赋值自定义变量:引用、修改、删

mapstruct中的@Mapper注解的基本用法

《mapstruct中的@Mapper注解的基本用法》在MapStruct中,@Mapper注解是核心注解之一,用于标记一个接口或抽象类为MapStruct的映射器(Mapper),本文给大家介绍ma... 目录1. 基本用法2. 常用属性3. 高级用法4. 注意事项5. 总结6. 编译异常处理在MapSt

Python实例题之pygame开发打飞机游戏实例代码

《Python实例题之pygame开发打飞机游戏实例代码》对于python的学习者,能够写出一个飞机大战的程序代码,是不是感觉到非常的开心,:本文主要介绍Python实例题之pygame开发打飞机... 目录题目pygame-aircraft-game使用 Pygame 开发的打飞机游戏脚本代码解释初始化部