鍍金池/ 教程/ Android/ android.hardware.camera2 使用指南
多分辨率適配常用目錄
Android 開發(fā)環(huán)境(Eclipse+ADT+Android 5.0)
Android 原型設計工具探索
Makefile 快速入門
Android Studio的NDK開發(fā)
人臉檢測-靜態(tài)
getprop 與 dumpsys 命令
Maven 編譯開源二維碼掃描項目 zxing
畫布 Canvas
組合控件
Linux 下的模擬器硬件加速
讀取 Excel
android.hardware.camera2 使用指南
橫豎屏切換
Ubuntu 下切換 JDK 版本
拍照和錄像 with Camera
文本與布局
按鈕控制 ViewPager 的左右翻頁
用 TableLayout 偽裝表格顯示數(shù)據(jù)
Preference Activity 使用詳解
模擬器如何重啟?試試 Genymotion!
獲得屏幕物理尺寸、密度及分辨率
語音識別
了解 native activity
Android Studio 導入第三方類庫、jar 包和 so 庫
啟動另一個 App/apk 中的 Activity
APK 簽名
兩個開源的圖表/報表控件
android studio 導出 jar 包(Module)并獲得手機信息
圖片的 Base64 編解碼
混淆與反編譯
Android Studio 和 Gradle
Android 5.1 SDK 下載與配置
persistableMode 與 Activity 的持久化
adb 取出安裝在手機中的 apk
Android Studio 中的源代碼管理
Handler 使用中可能引發(fā)的內存泄漏

android.hardware.camera2 使用指南

API 21中將原來的 camera API 棄用轉而推薦使用新增的 camera2 API,這是一個大的動作,因為新 API 換了架構,讓開發(fā)者用起來更難了。

先來看看 camera2包架構示意圖:

http://wiki.jikexueyuan.com/project/android-actual-combat-skills/images/33-1.png" alt="fig.1" />

這里引用了管道的概念將安卓設備和攝像頭之間聯(lián)通起來,系統(tǒng)向攝像頭發(fā)送 Capture 請求,而攝像頭會返回 CameraMetadata。這一切建立在一個叫作 CameraCaptureSession 的會話中。

下面是 camera2包中的主要類:

http://wiki.jikexueyuan.com/project/android-actual-combat-skills/images/33-2.png" alt="fig.2" />

其中 CameraManager 是那個站在高處統(tǒng)管所有攝像投設備(CameraDevice)的管理者,而每個 CameraDevice 自己會負責建立 CameraCaptureSession 以及建立 CaptureRequest。

CameraCharacteristics 是 CameraDevice 的屬性描述類,非要做個對比的話,那么它與原來的 CameraInfo 有相似性。

類圖中有著三個重要的 callback,雖然這增加了閱讀代碼的難度,但是你必須要習慣,因為這是新包的風格。其中 CameraCaptureSession.CaptureCallback 將處理預覽和拍照圖片的工作,需要重點對待。

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

http://wiki.jikexueyuan.com/project/android-actual-combat-skills/images/33-3.png" alt="fig.3" />

我是用 SurfaceView 作為顯示對象(當然還可以 TextureView 去顯示,詳見參考中的項目)

核心代碼如下:

        mCameraManager = (CameraManager) this.getSystemService(Context.CAMERA_SERVICE);
        mSurfaceView = (SurfaceView)findViewById(R.id.surfaceview);
        mSurfaceHolder = mSurfaceView.getHolder();
        mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                initCameraAndPreview();
            }
        });
     private void initCameraAndPreview() {
            Log.d("linc","init camera and preview");
            HandlerThread handlerThread = new HandlerThread("Camera2");
            handlerThread.start();
            mHandler = new Handler(handlerThread.getLooper());
            try {
                mCameraId = ""+CameraCharacteristics.LENS_FACING_FRONT;
                mImageReader = ImageReader.newInstance(mSurfaceView.getWidth(), mSurfaceView.getHeight(),
                        ImageFormat.JPEG,/*maxImages*/7);
                mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mHandler);

                mCameraManager.openCamera(mCameraId, DeviceStateCallback, mHandler);
            } catch (CameraAccessException e) {
                Log.e("linc", "open camera failed." + e.getMessage());
            }
        }
    private CameraDevice.StateCallback DeviceStateCallback = new CameraDevice.StateCallback() {

            @Override
            public void onOpened(CameraDevice camera) {
                Log.d("linc","DeviceStateCallback:camera was opend.");
                mCameraOpenCloseLock.release();
                mCameraDevice = camera;
                try {
                    createCameraCaptureSession();
                } catch (CameraAccessException e) {
                    e.printStackTrace();
                }
            }
        };
    private void createCameraCaptureSession() throws CameraAccessException {
            Log.d("linc","createCameraCaptureSession");

            mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            mPreviewBuilder.addTarget(mSurfaceHolder.getSurface());
            mState = STATE_PREVIEW;
            mCameraDevice.createCaptureSession(
                    Arrays.asList(mSurfaceHolder.getSurface(), mImageReader.getSurface()),
                    mSessionPreviewStateCallback, mHandler);
        }
    private CameraCaptureSession.StateCallback mSessionPreviewStateCallback = new
                CameraCaptureSession.StateCallback() {

            @Override
            public void onConfigured(CameraCaptureSession session) {
                Log.d("linc","mSessionPreviewStateCallback onConfigured");
                mSession = session;
                try {
                    mPreviewBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                          CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
                    mPreviewBuilder.set(CaptureRequest.CONTROL_AE_MODE,
                           CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
                    session.setRepeatingRequest(mPreviewBuilder.build(), mSessionCaptureCallback, mHandler);
                } catch (CameraAccessException e) {
                    e.printStackTrace();
                    Log.e("linc","set preview builder failed."+e.getMessage());
                }
            }
        };
    private CameraCaptureSession.CaptureCallback mSessionCaptureCallback =
                new CameraCaptureSession.CaptureCallback() {

            @Override
            public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
                                           TotalCaptureResult result) {
    //            Log.d("linc","mSessionCaptureCallback, onCaptureCompleted");
                mSession = session;
                checkState(result);
            }

            @Override
            public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request,
                                            CaptureResult partialResult) {
                Log.d("linc","mSessionCaptureCallback,  onCaptureProgressed");
                mSession = session;
                checkState(partialResult);
            }

            private void checkState(CaptureResult result) {
                switch (mState) {
                    case STATE_PREVIEW:
                        // NOTHING
                        break;
                    case STATE_WAITING_CAPTURE:
                        int afState = result.get(CaptureResult.CONTROL_AF_STATE);

                        if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||
                             CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState
                                ||  CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED == afState
                                || CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED == afState) {
                            //do something like save picture
                        }
                        break;
                }
            }

        };

按下 capture 按鈕:

    public void onCapture(View view) {
        try {
            Log.i("linc", "take picture");
            mState = STATE_WAITING_CAPTURE;
            mSession.setRepeatingRequest(mPreviewBuilder.build(), mSessionCaptureCallback, mHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

測試用 genemotion 模擬器,直接調用筆記本的攝像頭。

配置圖如下:

http://wiki.jikexueyuan.com/project/android-actual-combat-skills/images/33-4.png" alt="fig.4" />

demo 界面如下圖:

http://wiki.jikexueyuan.com/project/android-actual-combat-skills/images/33-5.png" alt="fig.5" />

源碼:

請參考 github 中的兩個 demo 項目:

https://github.com/pinguo-yuyidong/Camera2

https://github.com/googlesamples/android-Camera2Basic

上一篇:畫布 Canvas下一篇:了解 native activity