Android camera: how to show preview from camera using Camera2 API

实现预览的步骤

https://stackoverflow.com/questions/39893367/how-to-show-the-camera-preview-on-a-surfaceview?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa

  1. Get permission to use camera device
  2. Using CameraManager open connection to a camera
  3. Have prepared Surface for preview
  4. Using opened camera device and desired surfaces (it can include not only preview surface) create CaptureSession
  5. After CaptureSession created you need to create and configure CaptureRequest and submit it to CaptureSession

对surface的处理过程:

   findViewById:(SurfaceView) -> getHolder(SurfaceHold) -> getSurface(Surface);

        this.mSurfaceView = (SurfaceView) findViewById(R.id.SurfaceViewPreview);

        this.mSurfaceHolder = this.mSurfaceView.getHolder();

        this.mSurfaceHolder.addCallback(this);

   mCameraSurface = holder.getSurface();

提交CaputreRequest的过程

mCameraManager = (CameraManager) this.getSystemService(Context.CAMERA_SERVICE);

mCameraManager.openCamera(mCameraIDsList[1], mCameraStateCB, new Handler());

赋值mCameraDevice: onOpened(CameraDevice);

通过CameraDevice配置Camera: mCameraDevice.createCaptureSession

通过CameraCaptureSession.StateCallback的onConfigured生成CameraCaptureSession

通过CameraDevice的createCaptureRequest创建CaptureRequest

最后调用CameraCaptureSession提交CaptureRequest。


SurfaceHold callback and CameraDevice StateCallback

    @Override

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
       /*怎样得到SurfaceView*/

        this.mSurfaceView = (SurfaceView) findViewById(R.id.SurfaceViewPreview);

        /*从SurfaceView得到SurfaceHold*/

        this.mSurfaceHolder = this.mSurfaceView.getHolder();

      /*赋值SurfaceHolder的Callbak:*/

        this.mSurfaceHolder.addCallback(this);

    /*获得SystemService: CAMERA_SERVICE,使用其中的getCameraIdList*/

        this.mCameraManager = (CameraManager) this.getSystemService(Context.CAMERA_SERVICE);

        try {
            mCameraIDsList = this.mCameraManager.getCameraIdList();
            for (String id : mCameraIDsList) {
                Log.v(TAG, "CameraID: " + id);
            }

        } 

      /*赋值APP实现的StateCallback*/

        mCameraStateCB = new CameraDevice.StateCallback() {
            @Override
            public void onOpened(CameraDevice camera) {

                Toast.makeText(getApplicationContext(), "onOpened", Toast.LENGTH_SHORT).show();

                /*CameraDevice的赋值是通过回调函数的参数*/

                mCameraDevice = camera;
                mHandler.sendEmptyMessage(MSG_CAMERA_OPENED);
            }

            @Override
            public void onDisconnected(CameraDevice camera) {
                Toast.makeText(getApplicationContext(), "onDisconnected", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onError(CameraDevice camera, int error) {
                Toast.makeText(getApplicationContext(), "onError", Toast.LENGTH_SHORT).show();
            }
        };

    }

访问Camera的权限申请及openCamera的调用

    @Override
    protected void onStart() {
        super.onStart();

        //requesting permission
        int permissionCheck = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA);
        if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
            if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
            } else {

                ActivityCompat.requestPermissions

                (this, new String[]{Manifest.permission.CAMERA}, MY_PERMISSIONS_REQUEST_CAMERA);

                Toast.makeText(getApplicationContext(), "request permission", Toast.LENGTH_SHORT).show();
            }
        } else {
            Toast.makeText(getApplicationContext(), "PERMISSION_ALREADY_GRANTED", Toast.LENGTH_SHORT).show();
            try {
                mCameraManager.openCamera(mCameraIDsList[1], mCameraStateCB, new Handler());
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }

    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case MY_PERMISSIONS_REQUEST_CAMERA:

                if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) 

                    == PackageManager.PERMISSION_GRANTED)

                    try {
                        mCameraManager.openCamera(mCameraIDsList[1], mCameraStateCB, new Handler());
                    } catch (CameraAccessException e) {
                        e.printStackTrace();
                    }
                break;
        }
    }

SurfaceHolder Callback

 
 
 
 
 
 
    /**
     * A client may implement this interface to receive information about
     * changes to the surface.
     */
    public interface Callback {
        /**
         * This is called immediately after the surface is first created.
         */
        public void surfaceCreated(SurfaceHolder holder);

        /**
         * This is called immediately after any structural changes (format or
         * size) have been made to the surface.  You should at this point update
         * the imagery in the surface.  This method is always called at least
         * once, after {@link #surfaceCreated}.
         */
        public void surfaceChanged(SurfaceHolder holder, int format, int width,
                int height);

        /**
         * This is called immediately before a surface is being destroyed. After
         * returning from this call, you should no longer try to access this
         * surface.  If you have a rendering thread that directly accesses
         * the surface, you must ensure that thread is no longer touching the
         * Surface before returning from this function.
         *
         * @param holder The SurfaceHolder whose surface is being destroyed.
         */
        public void surfaceDestroyed(SurfaceHolder holder);
    }
    @Override

    public void surfaceCreated(SurfaceHolder holder) {

  /*从holder的得到Surface*/

        mCameraSurface = holder.getSurface();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        mCameraSurface = holder.getSurface();
        mSurfaceCreated = true;
        mHandler.sendEmptyMessage(MSG_SURFACE_READY);
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        mSurfaceCreated = false;

    }

configureCamera: createCaptureSession

    @Override

    public boolean handleMessage(Message msg) {
        switch (msg.what) {
            case MSG_CAMERA_OPENED:
            case MSG_SURFACE_READY:
                // if both surface is created and camera device is opened
                // - ready to set up preview and other things
                if (mSurfaceCreated && (mCameraDevice != null)
                        && !mIsCameraConfigured) {
                    configureCamera();
                }
                break;
        }

        return true;

    }

    private void configureCamera() {
        // prepare list of surfaces to be used in capture requests
        List<Surface> sfl = new ArrayList<Surface>();

        sfl.add(mCameraSurface); // surface for viewfinder preview

        // configure camera with all the surfaces to be ever used
        try {
            mCameraDevice.createCaptureSession(sfl,
                    new CaptureSessionListener(), null);
        } 

        mIsCameraConfigured = true;

    }

  CameraCaptureSession.StateCallback and request submit

    private class CaptureSessionListener extends

            CameraCaptureSession.StateCallback {
        @Override
        public void onConfigureFailed(final CameraCaptureSession session) {
            Log.d(TAG, "CaptureSessionConfigure failed");
        }

  /*当onConfigured时 得到CameraCaptureSession*/
        @Override
        public void onConfigured(final CameraCaptureSession session) {
            Log.d(TAG, "CaptureSessionConfigure onConfigured");
            mCaptureSession = session;

            try { /*构建Request并提交到session */
                CaptureRequest.Builder previewRequestBuilder = mCameraDevice
                        .createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
                previewRequestBuilder.addTarget(mCameraSurface);
                mCaptureSession.setRepeatingRequest(previewRequestBuilder.build(),
                        null, null);
            } 
        }

    }


Create a CaptureRequest.Builder for new capture requests

从上面的mSurfaceSet可以看出需要赋值surface.

CaptureRequest.javaaddTarget(@NonNull Surface outputTarget)

Add a surface to the list of targets for this request

addTarget: mRequest.mSurfaceSet.add(outputTarget)

setRepeatingRequest:





camera 拍照

1.根据不同的View等使用callback 或listener调用CameraManger接口:openCamera, 

2.由CameraDevice.StateCallback: onPened创建 createCaptureRequest, 进而创建CreateCaptureSession

3. 由CameraCaptureSession.StateCallback: onConfigured:提交Request

4. 当提交的request返回image到提交的surface: ImageReader.OnImageAvailableListener: onImageAvailable保存image到文件

5. 由CameraCaptureSession.CaptureCallback: onCaptureProgressed



猜你喜欢

转载自blog.csdn.net/u011279649/article/details/80429171