• Camera2相机预览流程


    Android5之后,Camera的api有了很大变化,称为Camera2

     

    Camera2的功能更多更强大,同时也更加复杂

     

    在camera2中管道pipeline(也可以叫做流),照片,视频都是从流中获取的。

     

    分析这张图,可以简单得到预览其实有三步

     

    1. 打开相机,创建与相机的会话(即建立管道)

     

    1. 发起CaptureRequest,获取流内容

     

    1. 建立Surface,将内容输出到Surface(即输出到手机屏幕)

     

    当然,这只是将相机预览流程进行了抽象,实际相机预览流程没有那么简单,下面是一个简单的demo,实现相机预览

     

     

     

     

     

    入口MainActivity

     

    package com.example.camera2test;

     

    import androidx.appcompat.app.AppCompatActivity;

     

    import android.os.Bundle;

    import android.view.View;

    import android.widget.FrameLayout;

     

    public class MainActivity extends AppCompatActivity {

     

        public static final String TAG = "MainActivity";

        private Camera2Preview mCameraPreview;

        private FrameLayout parentView;

        @Override

        protected void onCreate(Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);

            setContentView(R.layout.activity_main);

     

            mCameraPreview = new Camera2Preview(this);

     

            parentView = (FrameLayout) findViewById(R.id.camera_preview);

     

            parentView.addView((View) mCameraPreview);

           

            findViewById(R.id.button_switch).setOnClickListener(new View.OnClickListener() {

                @Override

                public void onClick(View v) {

                    mCameraPreview.switchCameraFacing();

                }

            });

        }

     

        @Override

        protected void onResume() {

            super.onResume();

            if (mCameraPreview != null)

                mCameraPreview.onResume();

        }

     

        @Override

        protected void onPause() {

            super.onPause();

            if (mCameraPreview != null)

                mCameraPreview.onPause();

        }

    }

     

     

     

     

    接口CameraView

    /**

     * 功能描述

     *

     * @author y50003490

     * @since 2019-08-20

     */

    public interface CameraView {

     

        /**

         * 与生命周期onResume调用

         */

        void onResume();

     

        /**

         * 与生命周期onPause调用

         */

        void onPause();

     

        /**

         * 切换相机摄像头

         */

        void switchCameraFacing();

    }

     

    相机预览Camera2Preview

     

    package com.example.camera2test;

     

    import androidx.annotation.NonNull;

    import androidx.appcompat.app.AppCompatActivity;

    import androidx.core.app.ActivityCompat;

     

    import android.Manifest;

    import android.content.Context;

    import android.content.pm.PackageManager;

    import android.graphics.Matrix;

    import android.graphics.RectF;

    import android.graphics.SurfaceTexture;

    import android.hardware.camera2.CameraAccessException;

    import android.hardware.camera2.CameraCaptureSession;

    import android.hardware.camera2.CameraCharacteristics;

    import android.hardware.camera2.CameraDevice;

    import android.hardware.camera2.CameraManager;

    import android.hardware.camera2.CaptureRequest;

    import android.os.Bundle;

    import android.os.Handler;

    import android.os.HandlerThread;

    import android.util.AttributeSet;

    import android.util.Log;

    import android.util.Size;

    import android.view.Surface;

    import android.view.TextureView;

    import android.view.View;

    import android.view.WindowManager;

    import android.widget.FrameLayout;

     

    import java.util.Arrays;

     

    public class Camera2Preview extends TextureView implements CameraView {

     

        private static final String TAG = "Camera2Preview";

        private Context mContext;

     

        public Camera2Preview(Context context) {

            this(context, null);

        }

     

        public Camera2Preview(Context context, AttributeSet attrs) {

            this(context, attrs, 0);

        }

     

        public Camera2Preview(Context context, AttributeSet attrs, int defStyle) {

            super(context, attrs, defStyle);

            mContext = context;

        }

     

        /**

         * ID of the current {@link CameraDevice}.

         */

        private String mCameraId;

     

        /**

         * 相机预览要用到的{@link CameraCaptureSession } .

         */

        private CameraCaptureSession mCaptureSession;

     

        /**

         * A reference to the opened {@link CameraDevice}.

         */

        private CameraDevice mCameraDevice;

     

        /**

         * 相机预览的 {@link android.util.Size}

         */

        private Size mPreviewSize;

        /**

         * 用于运行不应该阻止UI的任务的附加线程。

         */

        private HandlerThread mBackgroundThread;

     

        /**

         * 在后台运行任务的Handler。

         */

        private Handler mBackgroundHandler;

     

        /**

         * {@link CaptureRequest.Builder} for the camera1 preview

         */

        private CaptureRequest.Builder mPreviewRequestBuilder;

     

        /**

         * {@link CaptureRequest} generated by {@link #mPreviewRequestBuilder}

         */

        private CaptureRequest mPreviewRequest;

     

        /**

         * 当前相机(前置、后置)

         */

        private int mCurrentCameraFacing = CameraCharacteristics.LENS_FACING_BACK;

     

     

        /**

         * 同生命周期 onResume

         */

        @Override

        public void onResume() {

     

            startBackgroundThread();

            // 当关闭并打开屏幕时,SurfaceTexture已经可用,并且不会调用“onSurfaceTextureAvailable”。

            // 在这种情况下,我们可以打开相机并从这里开始预览(否则,我们将等待,直到Surface在SurfaceTextureListener中准备好)。

            if (isAvailable()) {

                Log.d(TAG, "onResume: openCamera");

                openCamera();

            } else {

                setSurfaceTextureListener(mSurfaceTextureListener);

                Log.d(TAG, "onResume: is not Available");

            }

     

        }

     

        /**

         * 同生命周期 onPause

         */

        @Override

        public void onPause() {

            closeCamera();

            stopBackgroundThread();

            Log.d(TAG, "onPause: close Camera");

        }

     

        /**

         * 打开指定的相机(mCameraId)

         */

        private void openCamera() {

            Log.d(TAG, "openCamera: ");

            if (mCameraId == null) {

                mCameraId = String.valueOf(0);

            }

     

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

            try {

                //检查相机权限

     

                if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {

                    Log.d(TAG, "openCamera: no Camera Permission");

                    return;

                }

     

                //打开对应mCameraId的摄像头

                Log.d(TAG, "openCamera: 2");

                manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);

            } catch (CameraAccessException e) {

                Log.d(TAG, "openCamera: ERROR");

                e.printStackTrace();

            } finally {

                Log.d(TAG, "finally: openCamera");

            }

        }

     

        /**

         * 关闭相机

         */

        private void closeCamera() {

            if (null != mCaptureSession) {

                mCaptureSession.close();

                mCaptureSession = null;

            }

            if (null != mCameraDevice) {

                mCameraDevice.close();

                mCameraDevice = null;

            }

        }

     

        /**

         * {@link CameraDevice.StateCallback} is called when {@link CameraDevice} changes its state.

         */

        private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {

     

            @Override

            public void onOpened(@NonNull CameraDevice cameraDevice) {

                Log.d(TAG, "onOpened: ");

                // 当相机打开时调用此方法。我们在这里开始相机预览。

                mCameraDevice = cameraDevice;

                //创建相机预览会话

                createCameraPreviewSession();

            }

     

            @Override

            public void onDisconnected(@NonNull CameraDevice cameraDevice) {

                Log.d(TAG, "onDisconnected: ");

                cameraDevice.close();

                mCameraDevice = null;

            }

     

            @Override

            public void onError(@NonNull CameraDevice cameraDevice, int error) {

                Log.d(TAG, "onError: ");

                cameraDevice.close();

                mCameraDevice = null;

                Log.e(TAG, "CameraDevice.StateCallback onError errorCode= " + error);

            }

     

        };

     

        /**

         * 创建一个新的 {@link CameraCaptureSession} 用于相机预览.

         */

        private void createCameraPreviewSession() {

            try {

                //获得SurfaceTexture

                SurfaceTexture texture = getSurfaceTexture();

                if(texture == null){

                    Log.d(TAG, "createCameraPreviewSession: texture is null");

                }

     

     

                // 我们需要开始预览输出Surface

                Surface surface = new Surface(texture);

     

                // 我们建立了一个具有输出Surface的捕获器。

                mPreviewRequestBuilder

                        = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);

                mPreviewRequestBuilder.addTarget(surface);

     

                // 这里,我们创建了一个用于相机预览的CameraCaptureSession

                // test delete m mImageReader.getSurface()

     

                mCameraDevice.createCaptureSession(Arrays.asList(surface),

                        new CameraCaptureSession.StateCallback() {

     

                            @Override

                            public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {

                                Log.d(TAG, "onConfigured: ");

                                // 相机已经关闭

                                if (null == mCameraDevice) {

                                    return;

                                }

     

                                // 当session准备好后,我们开始显示预览

                                mCaptureSession = cameraCaptureSession;

                                try {

                                    // 相机预览时应连续自动对焦

     

                                    //mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);

                                    // 设置闪光灯在必要时自动打开

                                    //setAutoFlash(mPreviewRequestBuilder);

     

                                    // 最终,显示相机预览

                                    mPreviewRequest = mPreviewRequestBuilder.build();

                                    //test delte mCaptureCallback

                                    mCaptureSession.setRepeatingRequest(mPreviewRequest,

                                            null, mBackgroundHandler);

                                } catch (CameraAccessException e) {

                                    e.printStackTrace();

                                }

                            }

     

                            @Override

                            public void onConfigureFailed(

                                    @NonNull CameraCaptureSession cameraCaptureSession) {

                                Log.e(TAG, "CameraCaptureSession.StateCallback onConfigureFailed");

                            }

                        }, null

                );

     

            } catch (CameraAccessException e) {

                e.printStackTrace();

            }

     

        }

     

        /**

         * 启动后台线程和Handler.

         */

        private void startBackgroundThread() {

            mBackgroundThread = new HandlerThread("CameraBackground");

            mBackgroundThread.start();

            mBackgroundHandler = new Handler(mBackgroundThread.getLooper());

        }

     

        /**

         * 停止后台线程和Handler.

         */

        private void stopBackgroundThread() {

            mBackgroundThread.quitSafely();

            try {

                mBackgroundThread.join();

                mBackgroundThread = null;

                mBackgroundHandler = null;

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        }

     

        /**

         * {@link TextureView.SurfaceTextureListener} handles several lifecycle events on a

         * {@link TextureView}.

         */

        private final TextureView.SurfaceTextureListener mSurfaceTextureListener

                = new TextureView.SurfaceTextureListener() {

     

            @Override

            public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {

                openCamera();

            }

     

            @Override

            public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) {

                configureTransform(width, height);

            }

     

            @Override

            public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {

                return true;

            }

     

            @Override

            public void onSurfaceTextureUpdated(SurfaceTexture texture) {

            }

     

        };

     

        /**

         * 配置必要的 {@link android.graphics.Matrix} 转换为 `mTextureView`.

         * <p>

         * 该方法应该在setUpCameraOutputs中确定相机预览大小以及“mTextureView”的大小固定之后调用。

         *

         * @param viewWidth  The width of `mTextureView`

         * @param viewHeight The height of `mTextureView`

         */

        private void configureTransform(int viewWidth, int viewHeight) {

            if (null == mPreviewSize || null == mContext) {

                return;

            }

            WindowManager mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);

            int rotation = mWindowManager.getDefaultDisplay().getRotation();

            Matrix matrix = new Matrix();

            RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);

            RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());

            float centerX = viewRect.centerX();

            float centerY = viewRect.centerY();

            if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {

                bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());

                matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);

                float scale = Math.max(

                        (float) viewHeight / mPreviewSize.getHeight(),

                        (float) viewWidth / mPreviewSize.getWidth());

                matrix.postScale(scale, scale, centerX, centerY);

                matrix.postRotate(90 * (rotation - 2), centerX, centerY);

            } else if (Surface.ROTATION_180 == rotation) {

                matrix.postRotate(180, centerX, centerY);

            }

            setTransform(matrix);

        }

     

        @Override

        public void switchCameraFacing() {

            mCurrentCameraFacing = mCurrentCameraFacing == CameraCharacteristics.LENS_FACING_BACK ?

                    CameraCharacteristics.LENS_FACING_FRONT : CameraCharacteristics.LENS_FACING_BACK;

     

            mCameraId = String.valueOf(mCurrentCameraFacing);

            if (mCameraId == null) {

                mCameraId = String.valueOf(1);

            }

            closeCamera();

            openCamera();

        }

    }

     

     

  • 相关阅读:
    二、Elasticsearch核心配置文件详解
    javax.mail.AuthenticationFailedException: 535 authentication failed
    Java compiler level does not match the version of the installed java project facet
    一、设置cookie报非法参数异常
    slf4j的使用规范
    基于token的身份验证JWT
    单点登录
    spring的bean不能注入原因分析
    规避空指针异常规范
    Git远程操作详解
  • 原文地址:https://www.cnblogs.com/shineyoung/p/11395180.html
Copyright © 2020-2023  润新知