目錄
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
處理標記的
可以在圖片上繪畫