Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android.Camera2相機超詳細講解

Android.Camera2相機超詳細講解

編輯:關於Android編程

在API21中Google就發布了Camera2類來取代Camera類,那麼這個Camera2類到底改變了那些地方呢,我們來看官方的說法:

Camera2 API

  • Supports 30fps full resolution with burst mode
    支持30fps的全高清連拍
  • Supports change on manual camera settings between frame capture
    支持幀之間的手動設置
  • Supports RAW image capture
    支持RAW格式的圖片拍攝
  • Supports Zero Shutter Lag & Movie Snapshot
    支持快門0延遲以及電影速拍
  • Supports setting other manual camera device controls including level of Noise Cancelling
  • 支持相機其他方面的手動控制包括噪音消除的級別

還有部分新功能沒有列出

查看了一下API,發現Camera2相對於Camera類架構都改變了,所以代碼肯定是不通用的了,相比之前的代碼應該算是比較難了一點了。

先來看看camera2包架構示意圖:
Camera2 流程圖

Google采用了pipeline(管道)的概念,將Camera Device相機設備和AndroidDevice安卓設備連接起來, Android Device通過管道發送CaptureRequest拍照請求給Camera Device,Camera Device通過管道返回CameraMetadata數據給Android Device,這一切建立在一個叫作CameraCaptureSession的會話中。

下面是camera2包中的主要類:
Camear2類圖
其中CameraManager是所有相機設備(CameraDevice)的管理者,而每個CameraDevice自己會負責建立CameraCaptureSession以及建立CaptureRequest。CameraCharacteristics是CameraDevice的屬性描述類,在CameraCharacteristics中可以進行相機設備功能的詳細設定(當然了,首先你得確定你的相機設備支持這些功能才行)。

類圖中有著三個重要的callback,其中CameraCaptureSession.CaptureCallback將處理預覽和拍照圖片的工作,需要重點對待。

這些類是如何相互配合的?下面是簡單的流程圖:
Camera2類流程圖

  1. 可以看出調用openCamera方法後會回調CameraDevice.StateCallback這個方法,在該方法裡重寫onOpened函數。
  2. 在onOpened方法中調用createCaptureSession,該方法又回調CameraCaptureSession.StateCallback方法。
  3. 在CameraCaptureSession.StateCallback中重寫onConfigured方法,設置setRepeatingRequest方法(也就是開啟預覽了)。
  4. setRepeatingRequest又會回調
    CameraCaptureSession.CaptureCallback方法。
  5. 重寫CameraCaptureSession.CaptureCallback中的
  6. onCaptureCompleted方法,result就是未經過處理的元數據了。

順便提一下onCaptureProgressed方法很明顯是在Capture過程中的,也就是在onCaptureCompleted之前,所以,在這之前相對圖像干什麼就看你的了,像美顏等操作就可以在這個方法中實現了。

可以看出Camera2相機使用的邏輯還是比較簡單的,其實就是3個Callback函數的回調,先說一下:setRepeatingRequest和capture方法其實都是向相機設備發送獲取圖像的請求,但是capture就獲取那麼一次,而setRepeatingRequest就是不停的獲取圖像數據,所以呢,使用capture就想拍照一樣,圖像就停在那裡了,但是setRepeatingRequest一直在發送和獲取,所以需要連拍的時候就調用它,然後在onCaptureCompleted中保存圖像就行了。(注意了,圖像的預覽也是用的setRepeatingRequest,只是你不處理數據就行了)

下面貼出代碼,我用的TextureView來顯示圖像:

首先權限不能忘:

布局:




    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mThreadHandler = new HandlerThread("CAMERA2");
        mThreadHandler.start();
        mHandler = new Handler(mThreadHandler.getLooper());
        mPreviewView = (TextureView) findViewById(R.id.textureview);
        mPreviewView.setSurfaceTextureListener(this);
    }


    @SuppressWarnings("ResourceType")
    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
        CameraManager cameraManager = (CameraManager) getSystemService(CAMERA_SERVICE);
        try {
            String[] CameraIdList = cameraManager.getCameraIdList(); 
            //獲取可用相機設備列表
            CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(CameraIdList[0]);
            //在這裡可以通過CameraCharacteristics設置相機的功能,當然必須檢查是否支持
            characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
            //就像這樣
            cameraManager.openCamera(CameraIdList[0], mCameraDeviceStateCallback, mHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {}

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
        return false;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {}

    private CameraDevice.StateCallback mCameraDeviceStateCallback = new CameraDevice.StateCallback() {
        @Override
        public void onOpened(CameraDevice camera) {
            try {
                startPreview(camera);
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onDisconnected(CameraDevice camera) {}

        @Override
        public void onError(CameraDevice camera, int error) {}
    };

    private void startPreview(CameraDevice camera) throws CameraAccessException {
        SurfaceTexture texture = mPreviewView.getSurfaceTexture();
        texture.setDefaultBufferSize(mPreviewView.getWidth(), mPreviewView.getHeight());
        Surface surface = new Surface(texture);
        try {
            mPreviewBuilder = camera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
        mPreviewBuilder.addTarget(surface);
        camera.createCaptureSession(Arrays.asList(surface), mSessionStateCallback, mHandler);
    }

    private CameraCaptureSession.StateCallback mSessionStateCallback = new CameraCaptureSession.StateCallback() {
        @Override
        public void onConfigured(CameraCaptureSession session) {
            try {
                //session.capture(mPreviewBuilder.build(), mSessionCaptureCallback, mHandler);
                session.setRepeatingRequest(mPreviewBuilder.build(), mSessionCaptureCallback, mHandler);
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onConfigureFailed(CameraCaptureSession session) {}
    };


    private CameraCaptureSession.CaptureCallback mSessionCaptureCallback =
            new CameraCaptureSession.CaptureCallback() {

                @Override
                public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
                                               TotalCaptureResult result) {}

                @Override
                public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request,
                                                CaptureResult partialResult){}};
}

如需按鍵,就加一個Button,寫上

mSession.setRepeatingRequest(mPreviewBuilder.build(), mSessionCaptureCallback, mHandler);
或者
session.capture(mPreviewBuilder.build(), mSessionCaptureCallback, mHandler);就可以了

其實過程還是挺簡單的,主要是邏輯比較簡單,就是不停的Callback,然後在onCaptureCompleted中處理數據就行了。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved