近期,Google 的 Jetpack 組件又出了新的庫:CameraX 。android
顧名思義:CameraX 就是用來進行 Camera 開發的官方庫了,並且後續會有 Google 進行維護和升級。這對於廣大 Camera 開發工程師和即將成爲 Camera 的程序員來講,真是個好消息~~~git
原文地址:glumes.com/post/androi…程序員
官方有給出一個示例的工程,我 fork 了以後,加入使用 OpenGL 黑白濾鏡渲染的操做,具體地址以下:github
官方並無提到 CameraX 庫具體如何進行 OpenGL 線程渲染的, 繼續往下看,你會找到答案的~~~微信
關於 CameraX 更多的介紹,建議看看 Google I/O 大會上的視頻記錄,比看文檔能瞭解更多內容~~~app
在視頻中提到,目前有不少應用都開始接入了 CameraX,好比 Camera360、Tik Tok 等。post
關於 Camera 的開發,以前也有寫過相關的文章🤔性能
對於一個簡單能用的 Camera 應用(Demo 級別)來講,關注兩個方面就行了:預覽和拍攝。
而預覽和拍攝的圖像都受到分辨率、方向的影響。Camera 最必備的功能就是能針對預覽和拍攝提供兩套分辨率,所以就得區分場景去設置。
對於拍攝還好說一點,要得到最好的圖像質量,就選擇同比例中分辨率最大的吧。
而預覽的圖像最終要呈現到 Android 的 Surface 上,所以選擇分辨率的時候要考慮 Surface 的寬高比例,不要出現比例不匹配致使圖像拉伸的現象。
另外,若是要作美顏、濾鏡類的應用,就要把 Camera 預覽的圖像放到 OpenGL 渲染的線程上去,而後由 OpenGL 去作圖像相關的操做,也就沒 Camera 什麼事了。等到拍攝圖片時,能夠由 OpenGL 去獲取圖像內容,也能夠由 Camera 得到圖像內容,而後通過 OpenGL 作離屏處理~~~
至於 Camera 開發的其餘功能,好比對焦、曝光、白平衡、HDR 等操做,不必定全部的 Camera 都可以支持,並且也能夠在上面的基礎上當作 Camera 的一個 feature 去拓展開發,並不算難事,這也是一個 Camera 開發工程師進階所要掌握的內容~~
CameraX 目前的版本是 1.0.0-alpha01
,在使用時要添加以下的依賴:
// CameraX
def camerax_version = "1.0.0-alpha01"
implementation "androidx.camera:camera-core:${camerax_version}"
implementation "androidx.camera:camera-camera2:${camerax_version}"
複製代碼
CameraX 向後兼容到 Android 5.0(API Level 21),而且它是基於 Camera 2.0 的 API 進行封裝的,解決了市面上絕大部分手機的兼容性問題~~~
相比 Camera 2.0 複雜的調用流程,CameraX 就簡化不少,只關心咱們須要的內容就行了,不像前者得本身維護 CameraSession 會話等狀態,而且 CameraX 和 Jetpack 主打的 Lifecycle 綁定在一塊兒了,何時該打開相機,何時該釋放相機,都交給 Lifecycle 生命週期去管理吧
上手 CameraX 主要關注三個方面:
不論是 預覽 仍是 圖像分析、圖像拍攝,CameraX 都是經過一個建造者模式來構建參數 Config 類,再由 Config 類建立預覽、分析器、拍攝的類,並在綁定生命週期時將它們傳過去。
// // Apply declared configs to CameraX using the same lifecycle owner
CameraX.bindToLifecycle(
lifecycleOwner: this, preview, imageCapture, imageAnalyzer)
複製代碼
既能夠綁定 Activity 的 Lifecycle,也能夠綁定 Fragment 的。
當須要解除綁定時:
// Unbinds all use cases from the lifecycle and removes them from CameraX.
CameraX.unbindAll()
複製代碼
關於預覽的參數配置,若是你有看過以前的文章:Android 相機開發中的尺寸和方向問題 想必就會很瞭解了。
提供咱們的目標參數,由 CameraX 去判斷當前 Camera 是否支持,並選擇最符合的。
fun buildPreviewUseCase(): Preview {
val previewConfig = PreviewConfig.Builder()
// 寬高比
.setTargetAspectRatio(aspectRatio)
// 旋轉
.setTargetRotation(rotation)
// 分辨率
.setTargetResolution(resolution)
// 先後攝像頭
.setLensFacing(lensFacing)
.build()
// 建立 Preview 對象
val preview = Preview(previewConfig)
// 設置監聽
preview.setOnPreviewOutputUpdateListener { previewOutput ->
// PreviewOutput 會返回一個 SurfaceTexture
cameraTextureView.surfaceTexture = previewOutput.surfaceTexture
}
return preview
}
複製代碼
經過建造者模式建立 Preview
對象,而且必定要給 Preview 對象設置 OnPreviewOutputUpdateListener
接口回調。
相機預覽的圖像流是經過 SurfaceTexture 來返回的,而在項目例子中,是經過把 TextureView 的 SurfaceTexture 替換成 CameraX 返回的 SurfaceTexture,這樣實現了 TextureView 控件顯示 Camera 預覽內容。
另外,還須要考慮到設備的選擇方向,當設備橫屏變爲豎屏了,TextureView 也要相應的作旋轉。
preview.setOnPreviewOutputUpdateListener { previewOutput ->
cameraTextureView.surfaceTexture = previewOutput.surfaceTexture
// Compute the center of preview (TextureView)
val centerX = cameraTextureView.width.toFloat() / 2
val centerY = cameraTextureView.height.toFloat() / 2
// Correct preview output to account for display rotation
val rotationDegrees = when (cameraTextureView.display.rotation) {
Surface.ROTATION_0 -> 0
Surface.ROTATION_90 -> 90
Surface.ROTATION_180 -> 180
Surface.ROTATION_270 -> 270
else -> return@setOnPreviewOutputUpdateListener
}
val matrix = Matrix()
matrix.postRotate(-rotationDegrees.toFloat(), centerX, centerY)
// Finally, apply transformations to TextureView
cameraTextureView.setTransform(matrix)
}
複製代碼
TextureView 旋轉的設置一樣在 OnPreviewOutputUpdateListener
接口中去完成。
在 bindToLifecycle
方法中,imageAnalyzer
參數並非必需的。
ImageAnalysis
能夠幫助咱們作一些圖像質量的分析,須要咱們去實現 ImageAnalysis.Analyzer
接口的 analyze
方法。
fun buildImageAnalysisUseCase(): ImageAnalysis {
// 分析器配置 Config 的建造者
val analysisConfig = ImageAnalysisConfig.Builder()
// 寬高比例
.setTargetAspectRatio(aspectRatio)
// 旋轉
.setTargetRotation(rotation)
// 分辨率
.setTargetResolution(resolution)
// 圖像渲染模式
.setImageReaderMode(readerMode)
// 圖像隊列深度
.setImageQueueDepth(queueDepth)
// 設置回調的線程
.setCallbackHandler(handler)
.build()
// 建立分析器 ImageAnalysis 對象
val analysis = ImageAnalysis(analysisConfig)
// setAnalyzer 傳入實現了 analyze 接口的類
analysis.setAnalyzer { image, rotationDegrees ->
// 能夠獲得的一些圖像信息,參見 ImageProxy 類相關方法
val rect = image.cropRect
val format = image.format
val width = image.width
val height = image.height
val planes = image.planes
}
return analysis
}
複製代碼
在圖像分析器的相關配置中,有個 ImageReaderMode
和 ImageQueueDepth
的設置。
ImageQueueDepth 會指定相機管線中圖像的個數,提升 ImageQueueDepth 的數量會對相機的性能和內存的使用形成影響
其中,ImageReaderMode 有兩種模式:
在圖像分析的 analyze
方法中,能經過 ImageProxy 類拿到一些圖像信息,並基於這些信息作分析。
拍攝一樣有一個 Config 參數構建者類,並且設定的參數和預覽相差不大,也是圖像寬高比例、旋轉方向、分辨率,除此以外還有閃光燈等配置項。
fun buildImageCaptureUseCase(): ImageCapture {
val captureConfig = ImageCaptureConfig.Builder()
.setTargetAspectRatio(aspectRatio)
.setTargetRotation(rotation)
.setTargetResolution(resolution)
.setFlashMode(flashMode)
// 拍攝模式
.setCaptureMode(captureMode)
.build()
// 建立 ImageCapture 對象
val capture = ImageCapture(captureConfig)
cameraCaptureImageButton.setOnClickListener {
// Create temporary file
val fileName = System.currentTimeMillis().toString()
val fileFormat = ".jpg"
val imageFile = createTempFile(fileName, fileFormat)
// Store captured image in the temporary file
capture.takePicture(imageFile, object : ImageCapture.OnImageSavedListener {
override fun onImageSaved(file: File) {
// You may display the image for example using its path file.absolutePath
}
override fun onError(useCaseError: ImageCapture.UseCaseError, message: String, cause: Throwable?) {
// Display error message
}
})
}
return capture
}
複製代碼
在圖像拍攝的相關配置中,也有個 CaptureMode
的設置。
它有兩種選項:
以上是關於 CameraX 的簡單應用方面的內容,更關心的是如何用 CameraX 去作 OpenGL 渲染實現美顏。濾鏡等效果。
還記得在圖像預覽 Preview 的 setOnPreviewOutputUpdateListener 方法中,會返回一個 SurfaceTexture
,相機的圖像流就是經過它返回的。
那麼要實現 OpenGL 線程的渲染,首先就要基於 EGL 去建立 OpenGL 繪製環境,而後利用 SurfaceTexture 的 attachToGLContext
方法,將 SurfaceTexture 添加到 OpenGL 線程去。
attachToGLContext 的參數是一個紋理 ID ,這個紋理就必須是 OES 類型的紋理。
而後再把這紋理 ID 繪製到 OpenGL 對應的 Surface 上,這能夠當作是兩個不一樣的線程在容許,一個 Camera 預覽線程,一個 OpenGL 繪製線程。
若是你不是很理解的話,建議仍是看看上面提供的代碼地址:
也能夠關注個人微信公衆號 【紙上淺談】,裏面有一些關於 OpenGL 學習和實踐的文章~~~
若是你看了 Google I/O 大會的視頻,那確定瞭解 CameraX 的拓展屬性。
在視頻中提到 Google 也正在和華爲、三星、LG、摩托摩拉等廠商進行合做,爲了得到廠商系統相機的一些能力,好比 HDR 等。
不過考慮到目前的形勢,可能和華爲的合做難以繼續下去了吧...
但仍是期待 CameraX 能給帶來更多的新特性吧~~~
文章推薦
以爲文章不錯,歡迎關注和轉發微信公衆號:【紙上淺談】,得到最新文章推送~~~