android下自定义相机com.otaliastudios.cameraview源码解析(一)
android下自定义相机com.otaliastudios.cameraview源码解析(二)
最近在android下相机下的开发,引入了com.otaliastudios.cameraview,这个第三方类,顺便看了下它的源码,在这里记录一下,以便以后查询,在平时的开发,都是调用系统的相机,并没有自己去定义一个相机来使用,发现这里还是有不少问题的。这里是以2.4.0版本源码为基础进行分析的。
支持相机和视频的控件,android目前提供了两个一个是TextureView,一个是SurfaceView,是用来展示相机的,视频也是使用这两个控件。
一、主类
CameraView是这个类的主类,入口类,在这里进行了一切的操作。在它的构造函数都会执行一个【initialize】初始化方法,这里初始化了属性、插件(如网格线GridLinesLayout等)、Engine类(是使用camera1还是camera2)、自定义属性等
1.1 Engine
doInstantiateEngine()方法,是在初始化中调用,再通过调用instantiateCameraEngine方法,引入了Engine类,实现了使用camera1还是camera2的选择
1.2 生命周期
定义了生命周期OnLifecycleEvent,这里是androidx的内容,主要是定义了三个生命周期。这三个生命周期是可以对外的调用的,可以学习下的使用方法。
open(@OnLifecycleEvent(Lifecycle.Event.ON_RESUME))这里是打开,配合退到后台进行一系列的操作。
close(@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)),这里是暂停的生命周期
destroy(@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY))这个是销毁的生命周期。
在这里,cameraview类是一个统筹的类,所以的其它子控件都是围绕它使用的。
二 、触摸
2.1 Gesture和GestureAction
第一步,这里分为了两个方法,一个是定义手势,一个是定义触摸,定义了以下几个手势,用这个图我们可以看到,当你选择不同的手势时,效果是不同的。在这里是通过mapGesture方法进行的初始化,主要是把手势写入到mGestureMap,这个HashMap中,在mGestureMap,会存储Gesture和对应的GestureAction。在mapGesture,还行了一系列的Finder操作。这里学到的技巧就是我们可以在定义通过一些变量把一些复杂和行为进行拆分类分后,非常清晰。
Gesture(手势) | GestureAction(手势行为) |
TAP(点击) | AUTO_FOCUS TAKE_PICTURE NONE |
LONG_TAP | AUTO_FOCUS TAKE_PICTURE NONE |
PINCH(缩放) | ZOOM EXPOSURE_CORRECTION FILTER_CONTROL_1 FILTER_CONTROL_2 NONE |
SCROLL_HORIZONTAL(水平滚动) | ZOOM EXPOSURE_CORRECTION FILTER_CONTROL_1 FILTER_CONTROL_2 NONE |
SCROLL_VERTICAL(垂直滚动) | ZOOM EXPOSURE_CORRECTION FILTER_CONTROL_1 FILTER_CONTROL_2 NONE |
第二步是使用:
这里是在onTouch方法中进行调用的,会通过【mCameraEngine.getCameraOptions()】方法,获取相机的选项,然后根据不同的Finde来进行【onGesture】,这里就是通过mGestureMap,获取到gestureMap来进行不同的操作。
2.2 GestureType
在这里他又分为了是单次的,还是连续的。定义了两个字段GestureType
ONE_SHOT | 单次 |
CONTINUOUS | 连续 |
然后又定义了Gesture和GestureAction,主要是定义了三种手势和用户可以要进行的行为。
2.3 GestureFinder
下面有三个PinchGestureFinder,ScrollGestureFinder,TapGestureFinder,这三类在CameraView中使用的,主要作用是从屏幕上获取手势进行解析。主要是【handleTouchEvent】这个方法,在这里进行处理的。
在GestureFinder构造函数中会定义系统的手势检测器GestureDetector,对用户的手势进行检测。
类名 | 系统手势类 | 系统手势方法 |
PinchGestureFinder | ScaleGestureDetector | onScale(缩放) |
ScrollGestureFinder | GestureDetector | onScroll(滚动) |
GestureDetector | GestureDetector | onSingleTapUp(单击) onLongPress(长按) |
三、渲染
主要分为两个包一个是filter,一个是filters,这两个包就是进行渲染的操作,filter主要是提供行为,而filters主要是提供各种类型的渲染方法。
3.1 Filter接口结构图
定义了接口filter,实现的类的BaseFilter,在这里filter只是定义了限制规则在camearView调用的就是setFilter(接口),接口的onDraw方法就是用来执行滤镜操作的。
onCreate(int programHandle) | 创建 |
draw(long timestampUs, float[] transformMatrix) | 画的周期 |
onDestroy | |
getVertexShader | |
getFragmentShader |
3.2 BaseFilter
在这里会去实现两个默认的Vertex和Fragment,进行调用,然后调用draw进行绘画。
在BaseFilter的子类中实现了OneParameterFilter和TwoParameterFilter两个方法
3.3 MultiFilter
是一个可以进行多个过滤的类,以ArrayList为基础进行存储
3.4 调用图
在CameraView中去设置setFilter,这里会调用GlCameraPreview或者MockCameraPreview的setFilter方法,然后进入到EglViewport的setFilter方法,在EglViewport的drawFrame方法中,会有四个地方调用到
GlCameraPreview | ->Renderer继承于GLSurfaceView.Renderer(系统的) |
OverlayDrawer | SnapshotGlPictureRecorder(图片解码) TextureMediaEncoder(视频解码) |
SnapshotGlPictureRecorder | (图片解码) |
TextureMediaEncoder | (视频解码) |
3.5 Filters包,提供渲染器‘
在这里的渲染器是基于opengl使用的,会在第五步中介绍。
AutoFixFilter | 自动修正渲染器 |
BlackAndWhiteFilter | 黑白渲染器 |
ContrastFilter | 对比渲染器 |
CrossProcessFilter | 跨进程渲染器 |
DocumentaryFilter | 写实 |
DuotoneFilter | 双色调 |
FillLightFilter | |
GammaFilter | |
GrainFilter | |
GrayscaleFilter | |
HueFilter | |
InvertColorsFilter | |
LomoishFilter | |
PosterizeFilter | |
SaturationFilter | |
SepiaFilter | |
SharpnessFilter | 清晰度 |
TemperatureFilter | |
TintFilter | |
VignetteFilter |
四、internal
这个下面有egl包名,是用来渲染图片的
EglBaseSurface
所有的渲染操作都是在这里进行的,通过调用CameraView的setFilter方法,都会执行这个方法。
在这里需要介绍一下opengl在安卓下的调用流程,
5.1 初始化
在初始化的时候,需要一个Program,通过 GlUtils.createProgram(mFilter.getVertexShader(), mFilter.getFragmentShader());这里的VertexShader和FragmentShader是渲染器定义的。
5.2 绘画
GlUtils.checkError("draw start");
// Select the program and the active texture.
GLES20.glUseProgram(mProgramHandle);
GlUtils.checkError("glUseProgram");
GLES20.glActiveTexture(mTextureUnit);
GLES20.glBindTexture(mTextureTarget, textureId);
// Draw.
mFilter.draw(timestampUs, textureMatrix);
// 释放
GLES20.glBindTexture(mTextureTarget, 0);
GLES20.glUseProgram(0);
具体的opengl学习可以参考这篇文章:https://blog.csdn.net/junzia/article/details/52801772
处理标记的
可以在图片上绘画