1. 程式人生 > >Android Camera API使用指南

Android Camera API使用指南

1. Camera簡介

雖然前文說道Android在5.0之後就推出了Camera2 API,但是各個廠家的基本未適配,導致目前市場上大部分機型使用的仍然是Camera1 API。

PS:Android 9.0 Google強制要求各個平臺廠商(高通/MTK/華為等)支援Camera2,不再相容Camera1。

Camera API是Android非常古老的API,Google在5.0推出Camera2後就再也沒有更新Camera。相比於Camera2來說,Camera API使用非常簡單,由於這套框架使用很久了所以穩定性和相容性還是值得信賴的。另外Camera API只提供基本的功能,其曝光/白平衡/曝光基本無法調節,這是相對於Camera2來說比較弱的地方。

2. Camera使用

有一點需要注意的是: Camera裝置是獨佔,也就是說你的APP在使用Camera裝置的話,其它應用就沒法使用。 所以要求在APP切換到後臺時需要關閉Camera裝置,重入時在重新開啟。

2.1 Camera主要類

Camera

Camera可以說是底層相機裝置的對映,所有對相機裝置的操作都是通過Camera這個類完成。 常用方法:

  • open 開啟相機裝置,並返回一個Camera物件。
  • getParameters 獲取Camera.Parameters
  • setParameters 設定Camera.Parameters
  • setPreviewTexture 設定用於輸出的SurfaceTexture
  • startPreview 開始預覽
  • stopPreview 結束預覽
  • release 釋放裝置

Camera.Parameters

儲存Camera裝置支援的資料,允許使用者設定響應的引數(主要是影象大小、格式、預覽FPS等)。

2.2 Camera 操作流程

2.2.1 獲取Camera許可權

  1. APP Manifest 宣告
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.permission.camera"/>
  1. 程式碼中許可權檢查
/** Check if this device has a camera */
private boolean checkCameraHardware(Context context) {
    if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
        // this device has a camera
        return true;
    } else {
        // no camera on this device
        return false;
    }
}

2.2.2 開啟Camera

開啟Camera比較簡單,需要注意兩件事:

  • 可以選擇要開啟的是前置還是後置相機,用CameraFacing標識:
        public static final int CAMERA_FACING_BACK = 0;
        public static final int CAMERA_FACING_FRONT = 1;
  • 在開啟Camera之前需要檢查是否已經開啟
        try {
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.FROYO) {
                int numberOfCameras = Camera.getNumberOfCameras();

                Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
                for (int i = 0; i < numberOfCameras; i++) {
                    Camera.getCameraInfo(i, cameraInfo);
                    if (cameraInfo.facing == facing) {
                        mDefaultCameraID = i;
                        mFacing = facing;
                    }
                }
            }
            stopPreview();
            if (mCameraDevice != null)
                mCameraDevice.release();

            if (mDefaultCameraID >= 0) {
                mCameraDevice = Camera.open(mDefaultCameraID);
            } else {
                mCameraDevice = Camera.open();
                mFacing = Camera.CameraInfo.CAMERA_FACING_BACK; //default: back facing
            }

            mRotation = setOrientationDegrees(0);
            TELogUtil.d(TAG, "Camera rotation = " + mRotation);
        } catch (Exception e) {
            TELogUtil.e(TAG, "Open Camera Failed!");
            e.printStackTrace();
            mCameraDevice = null;
            return false;
        }

2.2.3 配置Camera

Camera開啟後可以配置 Camera.Parameters: 以設定影象大小的操作順序為例:

  1. 獲取Camera.Parameters
param = camera.getParameters();
  1. 查詢裝置支援情況
List<Camera.Size> prevSizes = params.getSupportedPreviewSizes();
  1. 修改Camera.Parameters
prevSize = getBestMatchSize(prevSizes, desireSize);
params.setPreviewSize(prevSize.width, prevSize.height);
  1. 把Camera.Parameters設定給Camera
camera.setParameters(params);

常用的配置項:

        //影象格式
        mParams.setPictureFormat(ImageFormat.NV21);
        //影象解析度
        mParams.setPreviewSize(prevSz.width, prevSz.height);
        //預覽幀率
        mParams.setPreviewFrameRate(30);
        //對焦方式
        if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
            mParams.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
        }

2.2.4 開始預覽

Camera的輸出支援多種方式:

  • SurfaceTexture:以紋理的形式輸出 設定Camera.setPreviewTexture(surfaceTexture) 通過SurfaceTexture的onFrameAvailable回撥輸出每一幀
  • Buffer:以Buffer形式輸出 通過Camera.setPreviewCallbackWithBuffer(buffer)介面輸出
  • Surface:輸出到Surface 通過設定Camera.setPreviewDisplay(surfaceHolder);

下面是SurfaceTexture輸出程式碼示例:

    public synchronized void startPreview(SurfaceTexture texture) {
        TELogUtil.i(TAG, "Camera startPreview...");
        if (mIsPreviewing) {
            TELogUtil.w(TAG, "Camera is previewing...");
//            stopPreview();
            return;
        }

        if (mCameraDevice != null) {
            try {
                mCameraDevice.setPreviewTexture(texture);
                mCameraDevice.startPreview();
                mIsPreviewing = true;
            } catch (Exception e) {
                e.printStackTrace();
                TELogUtil.e(TAG, "startPreview: Error " + e.getMessage());
                mIsPreviewing = false;
                try {
                    mCameraDevice.release();
                } catch (Exception e2) {
                    e2.printStackTrace();
                }
                mCameraDevice = null;
            }
        }
    }

2.2.5 關閉Camera

mCameraDevice.stopPreview();
mCameraDevice.close()