Android Camera2學(xué)習(xí)筆記

前言

自從Android 5.0之后,Android有了新的Camera Api,但是現(xiàn)在網(wǎng)上的資料很少,只有谷歌的官方示例以及SDK文檔,一些相關(guān)的資料,但由于想做一個相機(jī)App,所以我決定研究這個Api。

在Camera2的Api中,將一個Camera Device比作管道,輸入一個個請求,返回包含一些圖像的元數(shù)據(jù)和一系列的圖像緩沖,Camera Device對于一系列的請求是按順序處理。

我們可以獲取的Camera Device不止一個,可能會有許多個,現(xiàn)在大家基本上的手機(jī)都會有2個Camera Device,一個前置的和一個后置的,如果我們還在手機(jī)上連了其他的攝像頭外設(shè),我們可以獲取的Camera Device就會更多了。

那么,我們要怎么獲取這些Camera Device對象呢?在Android中內(nèi)置了一個CameraManager的系統(tǒng)級服務(wù),我們可以這樣子輕松獲取

CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);

選擇合適的相機(jī)

每個不同的Camera Device都包含有關(guān)于這個設(shè)備的一些特性參數(shù),比如輸出圖像的大小,是否支持閃光燈等信息,這些信息都通過鍵值對的形式儲存在CameraCharacteristics對象中,這個CameraCharacteristics對象由CameraManager管理,根據(jù)每只Camera Device的Id獲取

for (String cameraId : cameraManager.getCameraIdList()) {
    CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
}

當(dāng)獲取到CameraCharacteristics對象后,我們要根據(jù)需要使用的功能選擇合適的相機(jī)。
比如是否需要閃光燈支持

 Boolean available = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
mFlashSupported = available == null ? false : available;

是否為前置攝像頭

 Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);

以及獲取圖片輸出的尺寸和預(yù)覽畫面輸出的尺寸

StreamConfigurationMap configurationMap = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);

if (configurationMap == null) continue;

//獲取圖片輸出的尺寸
configurationMap.getOutputSizes(ImageFormat.JPEG);
//獲取預(yù)覽畫面輸出的尺寸,因為我使用TextureView作為預(yù)覽
configurationMap.getOutputSizes(SurfaceTexture.class)

等等,都儲存在CameraCharacteristics對象中,我們需要選擇出符合我們條件要求的相機(jī),并記錄下相應(yīng)的CameraId。

打開相機(jī)

獲取了CameraId后,就可以根據(jù)CameraId打開相應(yīng)的Camera,獲取CameraDevice對象。

CameraManager manager = (CameraManager) mActivity.getSystemService(Context.CAMERA_SERVICE);
try {
    manager.openCamera(mCameraId, mStateCallback, mMainHandler);
} catch (CameraAccessException e) {
    e.printStackTrace();
}

查看API,openCamera需要三個參數(shù)


image_1apnlgr2anpu19mpguodps1jjb9.png-22.7kB
image_1apnlgr2anpu19mpguodps1jjb9.png-22.7kB

第一個是我們之前獲取的CameraId,第二個參數(shù)是當(dāng)CameraDevice被打開時的回調(diào)StateCallback,在這個回調(diào)里我們可以獲取到CameraDevice對象,第三個參數(shù)是一個Handler,決定了回調(diào)函數(shù)觸發(fā)的線程,若為null,則選擇當(dāng)前線程。

在StateCallback中,我們要實現(xiàn)三個方法,分別為CameraDevice被打開時觸發(fā)的方法,失去連接時觸發(fā)的方法,發(fā)生異常時觸發(fā)的方法。在第一個方法中我們可以成功獲取到CameraDevice對象,從而進(jìn)行接下來的相關(guān)操作。

private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
        @Override
        public void onOpened(@NonNull CameraDevice camera) {
            //打開成功,可以獲取CameraDevice對象
        }

        @Override
        public void onDisconnected(@NonNull CameraDevice camera) {
           //斷開連接
        }

        @Override
        public void onError(@NonNull CameraDevice camera, final int error) {
            //發(fā)生異常
        }
    };

發(fā)送預(yù)覽請求

在發(fā)送預(yù)覽請求之前,我們必須先通過CameraDevice對象創(chuàng)建一個CameraCaptureSession的會話對象,通過CameraCaptureSession對象發(fā)送預(yù)覽請求
創(chuàng)建CameraCaptureSession對象同樣需要三個參數(shù),第一個是相機(jī)預(yù)覽數(shù)據(jù)輸出的Surface的集合,第二個是回調(diào),在這個回調(diào)中我們可以獲取CameraCaptureSession對象,第三個參數(shù)是Handler,回調(diào)觸發(fā)的線程。

 mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
                    new CameraCaptureSession.StateCallback() {
                        @Override
                        public void onConfigured(@NonNull CameraCaptureSession session) {
                            mCaptureSession = session;
                            //發(fā)送預(yù)覽請求
                            sendRepeatPreviewRequest();

                        }

                        @Override
                        public void onConfigureFailed(@NonNull CameraCaptureSession session) {

                        }
                    }, mCameraHandler);

sendRepeatPreviewRequest函數(shù)

private boolean sendRepeatPreviewRequest() {
        try {
            CaptureRequest.Builder builder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            builder.addTarget(mPreviewSurface);
            builder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
            builder.setTag(RequestTag.Preview);
            addBaselineCaptureKeysToRequest(builder);

            mCaptureSession.setRepeatingRequest(builder.build(),
                    mFocusStateListener,
                    mCameraHandler);
            return true;
        } catch (CameraAccessException e) {
            e.printStackTrace();
            return false;
        }
    }

發(fā)送拍攝請求

CaptureRequest.Builder builder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
            builder.setTag(RequestTag.Capture);
            addBaselineCaptureKeysToRequest(builder);
            builder.set(CaptureRequest.JPEG_ORIENTATION,
                    CameraUtil.getJPEGOrientation(parameters.getOrientation(), mCameraCharacteristics));
            builder.addTarget(mPreviewSurface);
            builder.addTarget(mImageReader.getSurface());
            mCaptureSession.capture(builder.build(),
                    mFocusStateListener,
                    mCameraHandler);

由于Android Camera2 的API使用不是那么友好,所以大家在使用前最好學(xué)習(xí)一下相關(guān)的開源項目。
我也寫了一個簡單的APP,目前支持預(yù)覽,點擊對焦,前后攝像頭切換,閃光燈模式切換,未來還會添加許多新的功能,利用Camera2 的API。

如果你有興趣,那么和我一起來開發(fā)吧。

項目地址:PoiCamera

device-2016-07-31-215411.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • public classCamera.Parametersextends Objectjava.lang.Obje...
    冉冉升起的小太陽閱讀 11,200評論 0 7
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,872評論 25 709
  • 上一篇介紹了如何使用系統(tǒng)相機(jī)簡單、快速的進(jìn)行拍照,本篇將介紹如何使用框架提供的API直接控制攝像機(jī)硬件。 你還在為...
    Xiao_Mai閱讀 7,372評論 4 18
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,142評論 4 61
  • 在iOS開發(fā)中,大家經(jīng)常會使用NSLog跟蹤應(yīng)用中可能產(chǎn)生的問題。但是NSLog會消耗資源,所以在Release的...
    JohnnySheng閱讀 3,037評論 0 52

友情鏈接更多精彩內(nèi)容