Android Camera2 簡介

Camera2簡介

在Google 推出Android 5.0的時候, Android Camera API 版本升級到了API2(android.hardware.camera2), 以前使用的API1(android.hardware.camera)就被標爲 Deprecated 了. Camera API2相較於API1有很大不一樣, 而且API2是爲了配合HAL3進行使用的, API2有不少API1不支持的特性, 好比:android

  1. 更先進的API架構
  2. 能夠獲取更多的幀(預覽/拍照)信息以及手動控制每一幀的參數
  3. 對Camera的控制更加徹底(好比支持調整focus distance, 剪裁預覽/拍照圖片)
  4. 支持更多圖片格式(yuv/raw)以及高速連拍
    ......

上面列舉的只是一部分, 而且實際功能支持狀況要看HAL層是否完成了相關功能, 也就是說API有不少功能來知足拍照/錄像需求, 但實際是否能用和具體設備有關.git

基本架構

在API架構方面, Camera2和以前的Camera有很大區別, APP和底層Camera以前能夠想象成用管道方式鏈接, 以下圖:github

如上圖所示, Camera APP 經過CameraCaptureSession發送CaptureRequest, CameraDevices收到請求後返回對應數據到對應的Surface,預覽數據通常都是到TextureView, 拍照數據則在ImageReader中, 總體來講就是一個請求--響應過程, 請求完成後, 能夠在回調中查詢到相應的請求參數和CameraDevice當前狀態, 總的來講, Camera2中預覽/拍照/錄像數據統一由Surface來接收, CaptureRequest表明請求控制的Camera參數, CameraMetadata(CaptureResult)則表示當前返回幀中Camera使用的參數以及當前狀態.架構

使用流程

API使用流程大致以下:ui

  1. 經過context.getSystemService(Context.CAMERA_SERVICE) 獲取CameraManager.
  2. 調用CameraManager .open()方法在回調中獲得CameraDevice.
  3. 經過CameraDevice.createCaptureSession() 在回調中獲取CameraCaptureSession.
  4. 構建CaptureRequest, 有三種模式可選 預覽/拍照/錄像.
  5. 經過 CameraCaptureSession發送CaptureRequest, capture表示只發一次請求, setRepeatingRequest表示不斷髮送請求.
  6. 拍照數據能夠在ImageReader.OnImageAvailableListener回調中獲取, CaptureCallback中則可獲取拍照實際的參數和Camera當前狀態.

查詢Camera2功能支持狀況

上面說過, 不是因此手機都支持完整的Camera2功能, 如今都2018了, Camera2出來都有4年左右了, 但估計還有些中低端手機使用的HAL1, 使用HAL1就會致使Camera2一些高級功能都無法使用了, 下面講一下如何查詢設備對應Camera2的支持狀況.
INFO_SUPPORTED_HARDWARE_LEVEL
硬件層面支持的Camera2功能等級, 主要分爲5個等級:google

  • INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY
  • INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED
  • INFO_SUPPORTED_HARDWARE_LEVEL_FULL
  • INFO_SUPPORTED_HARDWARE_LEVEL_3
  • INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL

LEVEL_LEGACY: 向後兼容模式, 若是是此等級, 基本沒有額外功能, HAL層大機率就是HAL1(我遇到過的都是)
LEVEL_LIMITED: 有最基本的功能, 還支持一些額外的高級功能, 這些高級功能是LEVEL_FULL的子集
LEVEL_FULL: 支持對每一幀數據進行控制,還支持高速率的圖片拍攝
LEVEL_3: 支持YUV後處理和Raw格式圖片拍攝, 還支持額外的輸出流配置
LEVEL_EXTERNAL: API28中加入的, 應該是外接的攝像頭, 功能和LIMITED相似spa

各個等級從支持的功能多少排序爲: LEGACY < LIMITED < FULL < LEVEL_3
獲取代碼以下:code

// CameraCharacteristics  可經過 CameraManager.getCameraCharacteristics() 獲取
private int isHardwareSupported(CameraCharacteristics characteristics) {
        Integer deviceLevel = characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
        if (deviceLevel == null) {
            Log.e(TAG, "can not get INFO_SUPPORTED_HARDWARE_LEVEL");
            return -1;
        }
        switch (deviceLevel) {
            case CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL:
                Log.w(TAG, "hardware supported level:LEVEL_FULL");
                break;
            case CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY:
                Log.w(TAG, "hardware supported level:LEVEL_LEGACY");
                break;
            case CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3:
                Log.w(TAG, "hardware supported level:LEVEL_3");
                break;
            case CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED:
                Log.w(TAG, "hardware supported level:LEVEL_LIMITED");
                break;
        }
        return deviceLevel;
    }

REQUEST_AVAILABLE_CAPABILITIES
上面講的幾個等級是從總體上說明Camera2支持狀況, 咱們還能夠查詢更多細節功能,REQUEST_AVAILABLE_CAPABILITIES 則能夠知道具體支持哪些實際功能, 具體有以下功能:排序

BACKWARD_COMPATIBLE READ_SENSOR_SETTINGS
MANUAL_SENSOR BURST_CAPTURE
MANUAL_POST_PROCESSING YUV_REPROCESSING
RAW DEPTH_OUTPUT
PRIVATE_REPROCESSING CONSTRAINED_HIGH_SPEED_VIDEO

各個功能具體含義請參考官網的解釋 :官網 的解釋, 我沒有深刻研究.
大多數支持等級爲 LEGACY 的設備, 只支持 BACKWARD_COMPATIBLE , 也就是說前面提到的Camera2新功能都不支持......圖片

Camera2 AE/AF Region

在使用Camera2 API過程當中, 設置測光和對焦區域這部分剛開始一直不知道該怎麼寫代碼, 後面折騰了一番, 終於找到正確的方法了, 在此記錄一下.
AE/AF 區域須要經過用戶在屏幕上的點擊位置來進行設置, 所以咱們要作的就是將屏幕點擊點映射到底層對焦和測光位置點, 同時發送請求觸發對焦這個動做. 首先要知道一點就是, 屏幕點擊點座標和Camera底層座標不是對應的, 基本關係以下圖:

 

 

AF_Coordinate.jpg

x,y座標系表示屏幕座標, x1,y1表示Camera對應座標
可見屏幕點擊和底層有個90度旋轉關係, 實際設置AF/AE區域步驟以下:

1.首先獲取SENSOR_INFO_ACTIVE_ARRAY_SIZE, 即底層Camera座標點的範圍, API中經過一個Rect表示

characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE)

獲得``Rect```一般爲支持的最大圖片尺寸, 好比(0, 0, 4160, 3120)

2.座標映射
咱們須要將屏幕點擊點映射到 SENSOR_INFO_ACTIVE_ARRAY_SIZE對應的Rect中, 從圖中能夠很容易看出, 座標轉換關係爲 : x1 = y , y1 = previewWidth - x, 座標轉換完成後只需乘以 圖片寬度/預覽寬度的比例便可獲得轉換後的座標, 而後以座標點爲中心生成一個矩形, 這個矩形就是咱們要的結果, 實際代碼片斷以下:

private MeteringRectangle calcTapAreaForCamera2(CameraCharacteristics c, int areaSize, int
            weight) {
        // 獲取Size
        Rect rect = c.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
        Log.d(TAG, "active Rect:" + rect.toString());
        Rect newRect;
        int leftPos, topPos;
        // 座標轉換
        float newX = currentY;
        float newY = previewWidth - currentX;
        // 大小轉換
        leftPos = (int) ((newX / previewHeight) * rect.right);
        topPos = (int) ((newY / previewWidth) * rect.bottom);
        // 以座標點爲中心生成一個矩形, 須要防止上下左右的值溢出
        int left = clamp(leftPos - areaSize, 0, rect.right);
        int top = clamp(topPos - areaSize, 0, rect.bottom);
        int right = clamp(leftPos + areaSize, leftPos, rect.right);
        int bottom = clamp(topPos + areaSize, topPos, rect.bottom);
        newRect = new Rect(left, top, right, bottom);
        Log.d(TAG, newRect.toString());
        // 構造MeteringRectangle
        return new MeteringRectangle(newRect, weight);
    }

    private int clamp(int x, int min, int max) {
        if (x > max) {
            return max;
        }
        if (x < min) {
            return min;
        }
        return x;
    }

注: 此處座標映射能夠經過Matrix進行, 熟悉Matrix的同窗能夠嘗試下

3.設置AE/AF區域並觸發對焦, 代碼片斷以下

public void startControlAFRequest(MeteringRectangle rect,
                                        CameraCaptureSession.CaptureCallback captureCallback) {

    MeteringRectangle[] rectangle = new MeteringRectangle[]{rect};
    // 對焦模式必須設置爲AUTO
    mPreviewBuilder.set(CaptureRequest.CONTROL_AF_MODE,CaptureRequest.CONTROL_AF_MODE_AUTO);
    //AE
    mPreviewBuilder.set(CaptureRequest.CONTROL_AE_REGIONS,rectangle);
    //AF 此處AF和AE用的同一個rect, 實際AE矩形面積比AF稍大, 這樣測光效果更好
    mPreviewBuilder.set(CaptureRequest.CONTROL_AF_REGIONS,rectangle);
    try {
        // AE/AF區域設置經過setRepeatingRequest不斷髮請求
        mSession.setRepeatingRequest(mPreviewBuilder.build(), null, mHandler);
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
    //觸發對焦
    mPreviewBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,CaptureRequest.CONTROL_AF_TRIGGER_START);
    try {
        //觸發對焦經過capture發送請求, 由於用戶點擊屏幕後只需觸發一次對焦
        mSession.capture(mPreviewBuilder.build(), captureCallback, mHandler);
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

總結

Camera2 API和舊的Camera API區別很大, 剛開始用可能會很不習慣, 但Camera2有不少優點, 提供了很是多的參數供咱們控制, 後面API1可能會被移除, 因此能夠儘早將項目用Camera2重寫, 另外若是對API和HAL版本對應關係不清楚的, 能夠參考我以前寫的文章 Android Camera API和HAL版本對應關係.
基於Camera2 API, 我寫了個Demo, 功能還算完善, 有興趣的能夠看下: Github: Camera2, 目前沒有錄像功能, 後續會加上.

相關文章
相關標籤/搜索