背景
????????Android開發工作過程中,經常需要用到camera相關能力,比如:人臉識別,ai識別,拍照預覽,攝像頭錄制等等需求。都需要使用到camera,且需要拿到camera的預覽數據。但是每次開發這塊代碼都比較繁瑣,一大堆的接口(尤其是camera2),用錯一個就容易出現意想不到的結果。所以這里我們將Android的camera做一次簡單易用的封裝,再也不用擔心API用錯了。
一、Camera的歷史
在封裝之前,我們先簡單了解下camera的發展歷史。目前Android有camera1和camera2兩個不同版本的API。且camera1已經逐漸被拋棄了。那她兩到底啥區別?
- Camera1(2010年推出):
- 簡單但僵化:采用同步阻塞模型,調用
takePicture()
時整個相機管線阻塞,導致延遲高、功耗大。 - 有限控制:參數調整(如曝光、對焦)通過
Camera.Parameters
實現,僅支持基礎設置,無法精細控制。 - 高延遲:拍照后需等待圖像處理完成才能繼續操作。
- 資源浪費:預覽和拍照無法并行,導致CPU/GPU利用率低。
- 硬件抽象層(HAL)簡單:無法適配多攝像頭、高幀率傳感器(>30fps)或RAW格式。
- 功能缺失:不支持HDR+、人像模式等計算攝影需求。
- 獨占式訪問:僅允許單應用占用相機,其他應用需等待釋放(如掃碼時無法同時視頻通話)。
- 簡單但僵化:采用同步阻塞模型,調用
- Camera2(2014年推出,Android 5.0+):
- 異步管道模型:引入
CaptureRequest
和CaptureSession
,支持非阻塞操作(如連拍、實時預覽并行處理)。 - 精準控制:可獨立配置傳感器、閃光燈、處理算法(如手動調節ISO、快門速度)。
- 零復制流水線:圖像數據直接傳遞到
Surface
(如TextureView),減少內存拷貝。 - 批處理請求:單次提交多個
CaptureRequest
(如同時預覽+對焦+測光),提升幀率和能效比。 - 標準化HAL接口:統一控制不同廠商的相機硬件(如雙攝、TOF傳感器)。
- 高級功能支持:原生實現RAW拍攝、手動對焦軌跡、邏輯多攝像頭(融合多個傳感器數據)。
- 并發共享機制:通過
CameraManager
協調多應用訪問(如后臺AR應用與前臺相機APP共存)。
- 異步管道模型:引入
特性 | Camera1 | Camera2 |
---|---|---|
架構模型 | 同步阻塞 | 異步非阻塞管道 |
性能 | 高延遲、低吞吐量 | 低延遲、高吞吐量(支持4K/60fps) |
硬件適配 | 僅基礎單攝 | 多攝/RAW/高幀率傳感器 |
功能擴展 | 基礎拍照/錄像 | HDR+/手動模式/計算攝影 |
多應用支持 | 獨占訪問 | 并發共享 |
?二、封裝核心能力
工作場景下對camera最常用的核心能力:開啟攝像頭,切換攝像頭,預覽,關閉攝像頭,獲取攝像頭預覽數據。
所以我們要封裝的話就直接將這幾個能力抽象成對應的接口。
package com.qt.camera.baseimport android.graphics.SurfaceTexture
import android.hardware.Camera
import android.util.Range
import com.qt.camera.FUCameraConstants
import com.qt.camera.enumeration.FUCameraFacingEnum
import com.qt.camera.listener.OnFUCameraListener/**** DESC:Camera抽象類* Created on 2021/10/22* @author Jason Lu*/
abstract class FUAbstractCamera {/*** 前置相機id*/@Volatilevar mFrontCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT/*** 后置相機id*/@Volatilevar mBackCameraId = Camera.CameraInfo.CAMERA_FACING_BACK/*** 曝光補償*/@Volatilevar mExposureCompensation = FUCameraConstants.EXPOSURE_COMPENSATION/*** 相機采集幀率模式* true:最大幀率輸出 false:最大可選范圍區間輸出*/@Volatilevar mIsHighestRate = false/*** 相機后置角度*/@Volatilevar mBackCameraOrientation = FUCameraConstants.BACK_CAMERA_ORIENTATION/*** 當前相機前置角度*/@Volatilevar mFrontCameraOrientation = FUCameraConstants.FRONT_CAMERA_ORIENTATION/*** 當前相機朝向*/@Volatilevar mCameraFacing = FUCameraFacingEnum.CAMERA_FRONT/*** 當前相機輸出分辨率-寬*/@Volatilevar mCameraWidth: Int = 1280/*** 當前相機輸出分辨率-高*/@Volatilevar mCameraHeight: Int = 720/*** 當前相機角度*/@Volatilevar mCameraOrientation = mFrontCameraOrientation/*** 當前相機綁定紋理 Id*/@Volatilevar mCameraTexId = 100/*** 當前相機綁定 SurfaceTexture*/@Volatilevar mSurfaceTexture: SurfaceTexture? = null/*** 用戶設置的相機綁定 SurfaceTexture*/@Volatilevar mCustomSurfaceTexture: SurfaceTexture? = null/*** 是否正在預覽狀態*/@Volatileprotected var mIsPreviewing = false/*** 是否只讀ImageReader流*/@Volatilevar onlyReadImage = false/*** 是否需要停止預覽*/@Volatileprotected var mIsNeedStopPreviewing = false/*** 事件回調*/@Volatileprotected var mCameraListener: OnFUCameraListener? = null/*** 自定義攝像頭幀率范圍* 針對camera2*/var mRangeFps: Range<Int>? = null/*** 綁定數據回調* @param listener OnFUCameraListener*/fun bindCameraListener(listener: OnFUCameraListener?) {this.mCameraListener = listener}/*** 資源釋放*/open fun release() {if (mIsPreviewing) {closeCamera()}mCameraListener = null}/*** 初始化相機*/abstract fun initCameraInfo()/*** 打開相機*/abstract fun openCamera()/*** 開啟預覽*/abstract fun startPreview()/*** 對焦* @param viewWidth Int* @param viewHeight Int* @param rawX Float* @param rawY Float* @param areaSize Int*/abstract fun handleFocus(viewWidth: Int, viewHeight: Int, rawX: Float, rawY: Float, areaSize: Int)/*** 獲取亮度* @return Float*/abstract fun getExposureCompensation(): Float/*** 設置亮度* @param value Float*/abstract fun setExposureCompensation(value: Float)/*** 分辨率變更處理* @param cameraWidth Int* @param cameraHeight Int*/abstract fun changeResolution(cameraWidth: Int, cameraHeight: Int)/*** 關閉相機* @param releaseSurface 是否釋放SurfaceTexture資源*/abstract fun closeCamera(releaseSurface:Boolean = true)/*** 切換相機前后置*/fun switchCamera(surfaceTexture: SurfaceTexture?) {closeCamera(mCustomSurfaceTexture == null || surfaceTexture !=null)//如果使用用戶自定義的surfaceTexture或者之前設置過surfaceTexture就releasemCameraFacing = if (mCameraFacing == FUCameraFacingEnum.CAMERA_FRONT) FUCameraFacingEnum.CAMERA_BACK else FUCameraFacingEnum.CAMERA_FRONTmCameraOrientation = if (mCameraFacing == FUCameraFacingEnum.CAMERA_FRONT) mFrontCameraOrientation else mBackCameraOrientationif(surfaceTexture!= null){mCustomSurfaceTexture = surfaceTexture}openCamera()}/*** 設置相機放大等級*/abstract fun setZoomRatio(zoomRatio: Float)}
核心能力抽象出來后,剩下要做的就是camera1和camera2分別實現了。具體的實現這里就不貼代碼了,給個github鏈接,各位自己下載直接用吧:GitHub - 279154451/Camera: Camera工具