Camera2 打开相机预览界面

camera2 是21之后的api用于代替Camera,提供更加牛X的对相机hardware操作的api

参考资料:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0428/2811.html
http://www.tuicool.com/articles/6b67Nra

此篇笔记主要是记录打开预览界面
后面会记录Camera打开相机预览的代码,对比一下

界面布局


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.arvin.camera3.view.AutoFitTextureView
        android:id="@+id/surface"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/capturebtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:text="拍照" />

    <ImageView
        android:id="@+id/preview"
        android:layout_width="120dp"
        android:layout_height="120dp"
        android:layout_alignParentBottom="true" />

RelativeLayout>

AutoFitTextureView 继承自 TextureVeiw

1.首先要初始化view,就是一些findviewbyid

2.示例代码是在onResume中,能否有更好方式????

if (surfaceView.isAvailable()) {
    // FIXME: 2016/6/13
    try {
        openCamera(surfaceView.getWidth(), surfaceView.getHeight());
    } catch (Exception e) {
        e.printStackTrace();
    }
} else {
    surfaceView.setSurfaceTextureListener(mSurfaceTextureListener);
}

surfaceView即TextureView

判断TextureView状态
可用,打开相机,否则设置相应的回调

先看打开相机的代码

private void openCamera(int width, int height) throws Exception {
    Activity activity = getActivity();
    CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
    if (mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
        manager.openCamera(mCameraId,deviceStateCallback,mPreviewHandler );
    }
}

首先调用getSystemService(Context.CAMERA_SERVICE),拿到CameraManager实例,
注:Api 21 新增的,无兼容包,估计也不会发布兼容包吧,21之后 Camera已弃用
然后通过CameraManager实例的 openCamera()方法打开相机预览
我们看下openCamera的声明

@RequiresPermission(android.Manifest.permission.CAMERA)
public void openCamera(@NonNull String cameraId,
        @NonNull final CameraDevice.StateCallback callback, @Nullable Handler handler)
        throws CameraAccessException {

    if (cameraId == null) {
        throw new IllegalArgumentException("cameraId was null");
    } else if (callback == null) {
        throw new IllegalArgumentException("callback was null");
    } else if (handler == null) {
        if (Looper.myLooper() != null) {
            handler = new Handler();
        } else {
            throw new IllegalArgumentException(
                    "Handler argument is null, but no looper exists in the calling thread");
        }
    }

    openCameraDeviceUserAsync(cameraId, callback, handler);
}

@RequiresPermission(android.Manifest.permission.CAMERA)

需要camera权限,在camera声明,android 6.0之后需要请求,属于runtime permission

需要传入三个参数
cameraId : “0”表示后置摄像头,“1”表示前置摄像头
callback : CameraDevice.StateCallback 相机状态回调
注:CameraDevice 实例代表一个相机
handler : hanlder

回头看如果TextureView不可用的状态下

surfaceView.setSurfaceTextureListener(mSurfaceTextureListener);

看下 mSurfaceTextureListener是个什么东西

private final TextureView.SurfaceTextureListener mSurfaceTextureListener = new TextureView.SurfaceTextureListener() {
    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
        try {
            openCamera(width, height);
        } catch (Exception 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) {

    }
};

这个有点和SurfaceView的回调相似了
设置回调,然后当surface可用的时候openCamera(),回到上面的流程去了
包含四个方法,分别对应可用,尺寸发生变化,TextureView销毁,以及更新的时候回调

继续看manager.openCamera();
已经说了第一个参数camreaId,“0”代表后置摄像头,“1”代表前置摄像头
第二个参数CameraDevice.StateCallback, 直接看

CameraDevice.StateCallback deviceStateCallback = new CameraDevice.StateCallback() {
    @Override
    public void onOpened(CameraDevice camera) {
        mCameraOpenCloseLock.release();
        mCameraDevice = camera;
        try {
            createCameraPreviewSession();
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onDisconnected(CameraDevice camera) {
        mCameraOpenCloseLock.release();
        camera.close();
        mCameraDevice = null;
    }

    @Override
    public void onError(CameraDevice camera, int error) {
        mCameraOpenCloseLock.release();
        camera.close();
        mCameraDevice = null;
        Toast.makeText(getActivity(), "onError,error--->" + error, Toast.LENGTH_SHORT).show();
    }
};

通过代码可知,CameraDevice.StateCallback 提供了三个回调方法,分别对应于camrea打开,失去连接,打开错误的时候回调,
在打开的时候会调用createCameraPreviewSession() ,看一下方法定义

private void createCameraPreviewSession() throws CameraAccessException {
    initSurface();
    mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
    mPreviewBuilder.addTarget(mSurface);

    mCameraDevice.createCaptureSession(Arrays.asList(mSurface), mCaptureSessionStateCallback, mPreviewHandler);
}

private void initSurface() {
    SurfaceTexture sufaceTexture = surfaceView.getSurfaceTexture();
    assert sufaceTexture != null;
    sufaceTexture.setDefaultBufferSize(surfaceView.getWidth(), surfaceView.getHeight());
    mSurface = new Surface(sufaceTexture);
}

首先通过TextureView的getSurfaceTexture() 拿到 对应 SurfaceTexture 是不是SurfaceView的getSurfaceHolder()很像
设置显示大小,创建Surface实例
之后,调用 CameraDevice createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW) 创建预览请求
并设置target, CaptureRequest.Builder addTarget(Surface surface)
然后调用CameraDevice createCaptureSession(),创建一个相机回话

createCaptureSession()需要传入三个参数
看下声明

public abstract void createCaptureSession(@NonNull List outputs,
        @NonNull CameraCaptureSession.StateCallback callback, @Nullable Handler handler)

List outputs 我的理解是预览的输出载体列表,在上面的代码中,我们传入了new Surface(TextureView.getSurface()) 对象
ImageReader 也有 getSurface()方法,ImageReader也可以作为输出载体

第二个参数CameraCaptureSession.StateCallback 摄像头采集状态回调
直接看代码

private CameraCaptureSession.StateCallback mCaptureSessionStateCallback = new CameraCaptureSession.StateCallback() {
    @Override
    public void onConfigured(CameraCaptureSession session) {
        if (null == mCameraDevice) {
            return;
        }
        mSession = session;
        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);
        try {
            session.setRepeatingRequest(mPreviewBuilder.build(), mSessionCaptureCallback, mPreviewHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onConfigureFailed(CameraCaptureSession session) {

    }

};

设置拍摄模式,这里设置了连拍,flash,其他的模式嘛,我也不清楚了

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, mPreviewHandler);

设置重复请求,字面上这么理解

同样是三个参数
第一个是CaptureRequest.Builder buildI() 这个是前面采集请求builder 通过CameraDevice createCaptureRequest创建的
第二个是摄像头采集回话采集状态的回调

private CameraCaptureSession.CaptureCallback mSessionCaptureCallback = new CameraCaptureSession.CaptureCallback() {
    @Override
    public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
        super.onCaptureCompleted(session, request, result);
    }

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

包含两个状态,采集进行,采集完成
可以在这里面去做处理,
贴上一段代码

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

        @Override
        public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
            mSession = session;
            if (!PreferenceHelper.getCameraFormat(getActivity()).equals("DNG")) {
                checkState(result);
            }

        }

        @Override
        public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request, CaptureResult partialResult) {
            mSession = session;
            if (!PreferenceHelper.getCameraFormat(getActivity()).equals("DNG")) {
                checkState(partialResult);
            }
        }

        private void checkState(CaptureResult result) {
//            mFrameBitmap = mPreviewView.getBitmap();
//            mMainHandler.sendEmptyMessage(1);
            switch (mState) {
                case STATE_PREVIEW:
                    // NOTHING
                    break;
                case STATE_WAITING_CAPTURE:
                    int afState = result.get(CaptureResult.CONTROL_AF_STATE);
                    Log.i("checkState", "afState--->" + afState);
                    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) {
                        Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
                        Log.i("checkState", "进来了一层,aeState--->" + aeState);
                        if (aeState == null || aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
                            Log.i("checkState", "进来了第二层");
                            mState = STATE_TRY_DO_CAPTURE;
                            doStillCapture();
                        } else {
                            mState = STATE_TRY_CAPTURE_AGAIN;
                            tryCaptureAgain();
                        }
                    }
                    break;
                case STATE_TRY_CAPTURE_AGAIN:
                    Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
                    if (aeState == null ||
                            aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE ||
                            aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) {
                        mState = STATE_TRY_DO_CAPTURE;
                    }
                    break;
                case STATE_TRY_DO_CAPTURE:
                    aeState = result.get(CaptureResult.CONTROL_AE_STATE);
                    if (aeState == null || aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {
                        mState = STATE_TRY_DO_CAPTURE;
                        doStillCapture();
                    }
                    break;
            }
        }
};

至此,打开相机预览的代码就结束了,后续比如拍照,录像什么的以后再分析啦,这里的api还没在学习中

最后附上Camera打开预览的代码,感觉要简单好多呀

//布局文件
"@+id/surface"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

Camera camera;
surfaceView = (SurfaceView) findViewById(R.id.surface);
holder = surfaceView.getHolder();
holder.addCallback(this);  //设置回调

@Override
public void surfaceCreated(SurfaceHolder holder) {
    camera = Camera.open();
    try {
        camera.setPreviewDisplay(holder);
    } catch (IOException e) {
        e.printStackTrace();
    }
    camera.startPreview();
}

//将camera预览界面绑定到SurfaceView
//startPreview()

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {

}

代码是不是比camera2简单多了,不过这个预览界面挺难看的,其他设置也没有仔细研究,用到的时候再说吧

文中参考了
Android实战技巧之三十三:android.hardware.camera2使用指南
再此对原作者表示感谢

你可能感兴趣的:(android学习)