Camera API筆記

說明

最近在學習音視頻相關知識,把一些需要注意的點記錄一下方便後續查閱,可能有些翻譯不準確,如有錯誤歡迎指正,後面不再說明。以下內容都是摘自官方API文檔。

正文

如果要訪問設備的相機,首先要添加Manifest.permission.CAMERA權限,如果是6.0以上不要忘記權限申請,還有就是要包含 清單元素聲明在你的應用中使用的相機功能。例如,你使用了相機及自動對焦功能,你的清單文件應該包含下面幾項:

<uses-permission android:name="android.permission.CAMERA" />
 <uses-feature android:name="android.hardware.camera" />
 <uses-feature android:name="android.hardware.camera.autofocus" />

使用相機類拍照的步驟如下

  1. 使用open(int)方法獲取一個Camera實例
  2. 使用getParameters()方法獲取現有(默認)的設置
  3. 如有必要,修改返回的 Camera.Parameters 對象並調用 setParameters(Camera.Parameters)方法
  4. 調用 setDisplayOrientation(int) 方法保證正確的預覽方向
  5. 重要:給setPreviewDisplay(SurfaceHolder)方法傳一個完全初始化的SurfaceHolder。沒有surface,相機將不能開始預覽。
  6. 重要:調用 startPreview() 方法開始更新預覽顯示。在你能夠拍照之前必須要先開始預覽。
  7. 當你想要通過調用 takePicture(Camera.ShutterCallback, Camera.PictureCallback, Camera.PictureCallback, Camera.PictureCallback) 方法來捕獲一張照片時。等待回調返回真實的圖像數據。
  8. 拍照後預覽顯示將停止,如果想拍更多的照片,請再次調用startPreview() 方法
  9. 調用 stopPreview() 停止更新預覽顯示
  10. 重要:調用 release() 方法釋放相機以供其他應用使用。應用應該在Activity.onPause()方法立即釋放相機( 並在 Activity.onResume()方法重新創建).

快速切換到錄像模式步驟如下

  1. 跟上面拍照步驟一樣獲取一個相機實例並開始預覽
  2. 調用 unlock() 方法來允許媒體進程訪問相機
  3. 將相機實例傳遞給MediaRecorder.setCamera(Camera)
  4. 錄製完成後,調用 reconnect() 方法重新獲取並鎖定相機
  5. 如果需要,請重新開始預覽拍攝更多的照片和視頻
  6. 跟拍照描述的那樣調用 stopPreview() 和 release()

Camera類非線程安全,適用於事件線程。大多數長時間運行的操作(如預覽、對焦、拍照等)都是異步發生的,並在需要時調用回調。回調會在調用 open(int) 的事件線程中調用。一定不要同時在多個線程中調用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訪問相機

要訪問主攝像頭,請使用Camera.open()方法並確保捕獲任何異常,如下面的代碼所示:

/** A safe way to get an instance of the Camera object. */
public static Camera getCameraInstance(){
    Camera c = null;
    try {
        c = Camera.open(); // attempt to get a Camera instance
    } catch (Exception e){
        // Camera is not available (in use or does not exist)
    }
    return c; // returns null if camera is unavailable
}

警告:適用Camera.open()時請務必要檢查異常。如果相機正在使用或不存在導致檢查異常失敗,系統將會關閉你的應用。
如果一個設備上有多個相機,上面的代碼會訪問第一個後攝像頭。

3創建一個基本的相機預覽類

/** A basic Camera preview class */
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
    private SurfaceHolder mHolder;
    private Camera mCamera;

    public CameraPreview(Context context, Camera camera) {
        super(context);
        mCamera = camera;

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = getHolder();
        mHolder.addCallback(this);
        // deprecated setting, but required on Android versions prior to 3.0
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, now tell the camera where to draw the preview.
        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
        } catch (IOException e) {
            Log.d(TAG, "Error setting camera preview: " + e.getMessage());
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // empty. Take care of releasing the Camera preview in your activity.
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.

        if (mHolder.getSurface() == null){
          // preview surface does not exist
          return;
        }

        // stop preview before making changes
        try {
            mCamera.stopPreview();
        } catch (Exception e){
          // ignore: tried to stop a non-existent preview
        }

        // set preview size and make any resize, rotate or
        // reformatting changes here

        // start preview with new settings
        try {
            mCamera.setPreviewDisplay(mHolder);
            mCamera.startPreview();

        } catch (Exception e){
            Log.d(TAG, "Error starting camera preview: " + e.getMessage());
        }
    }
}

4拍照

如果想要實現一個JPEG格式的圖片,你首先要實現Camera.PictureCallback接口用來接收圖像數據並寫入到文件,請看下面的示例:

private PictureCallback mPicture = new PictureCallback() {

    @Override
    public void onPictureTaken(byte[] data, Camera camera) {

        File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
        if (pictureFile == null){
            Log.d(TAG, "Error creating media file, check storage permissions");
            return;
        }

        try {
            FileOutputStream fos = new FileOutputStream(pictureFile);
            fos.write(data);
            fos.close();
        } catch (FileNotFoundException e) {
            Log.d(TAG, "File not found: " + e.getMessage());
        } catch (IOException e) {
            Log.d(TAG, "Error accessing file: " + e.getMessage());
        }
    }
};

下面是調用拍照的方法

// get an image from the camera
mCamera.takePicture(null, null, mPicture);

5MediaRecorder錄製視頻

使用MediaRecorder類錄製視頻時,必須要按照特定的順序執行配置。下面的示例演示了怎麼正確的配置並準備MediaRecorder類來錄製視頻:

private boolean prepareVideoRecorder(){

    mCamera = getCameraInstance();
    mMediaRecorder = new MediaRecorder();

    // Step 1: Unlock and set camera to MediaRecorder
    mCamera.unlock();
    mMediaRecorder.setCamera(mCamera);

    // Step 2: Set sources
    mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
    mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);

    // Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
    mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));

    // Step 4: Set output file
    mMediaRecorder.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString());

    // Step 5: Set the preview output
    mMediaRecorder.setPreviewDisplay(mPreview.getHolder().getSurface());

    // Step 6: Prepare configured MediaRecorder
    try {
        mMediaRecorder.prepare();
    } catch (IllegalStateException e) {
        Log.d(TAG, "IllegalStateException preparing MediaRecorder: " + e.getMessage());
        releaseMediaRecorder();
        return false;
    } catch (IOException e) {
        Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage());
        releaseMediaRecorder();
        return false;
    }
    return true;
}

6使用相機功能

大部分相機功能可以通過 Camera.Parameters 對象激活並控制。你可以首先通過相機對象獲得 Camper.Parameters 對象的實例,然後調用 getParameters() 方法,修改返回的參數對象並重新設置給相機對象。示例代碼如下:

// get Camera parameters
Camera.Parameters params = mCamera.getParameters();
// set the focus mode
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
// set Camera parameters
mCamera.setParameters(params);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章