如何在SurfaceView上显示相机预览?

时间:2016-10-06 10:16:46

标签: android camera android-camera surfaceview surfaceholder

我正在尝试在SurfaceView上打开相机硬件。在布局中,我创建了一个SurfaceView,然后打开相机,如下面的代码所示。当我运行代码时,CameraAvailableCB中的toast出现并显示“onCameraAvailable”,但SurfaceView上没有任何内容。

如何在SurfaceView上显示相机显示?

代码

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    this.mBtnCapture = (Button) findViewById(R.id.actMain_btn_capture);
    this.mSurfaceView = (SurfaceView) findViewById(R.id.actMain_surfaceView);
    this.mSurfaceHolder = this.mSurfaceView.getHolder();
    this.mSurfaceHolder.addCallback(this);
    this.mCameraManager = (CameraManager) this.getSystemService(Context.CAMERA_SERVICE);

    try {
        cameraIDsList = this.mCameraManager.getCameraIdList();

        for (String id : cameraIDsList) {
            Log.v(TAG, "CameraID: " + id);
        }

    } catch (CameraAccessException e) {
        e.printStackTrace();
    }

    cameraStateCB = new CameraDevice.StateCallback() {
        @Override
        public void onOpened(CameraDevice camera) {
            Toast.makeText(getApplicationContext(), "onOpened", Toast.LENGTH_SHORT).show();

            //requesting permission
            int permissionCheck = ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA);
            if (permissionCheck != PackageManager.PERMISSION_GRANTED) {

                if (ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.CAMERA)) {

                } else {
                    ActivityCompat.requestPermissions(activity, 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();
            }

            //opening the camera
            try {
                mCameraManager.openCamera(cameraIDsList[1], cameraStateCB, new Handler());

            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }

        @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();
        }
    };

    CameraManager.AvailabilityCallback cameraAvailableCB = new CameraManager.AvailabilityCallback() {
        @Override
        public void onCameraAvailable(String cameraId) {
            super.onCameraAvailable(cameraId);

            Toast.makeText(getApplicationContext(), "onCameraAvailable", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onCameraUnavailable(String cameraId) {
            super.onCameraUnavailable(cameraId);

            Toast.makeText(getApplicationContext(), "onCameraUnavailable", Toast.LENGTH_SHORT).show();
        }
    };
    this.mCameraManager.registerAvailabilityCallback(cameraAvailableCB, new Handler());
}



@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 (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
                // Open Camera
                break;
    }
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
    Log.w(TAG, "surfaceCreated");
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    Log.w(TAG, "surfaceChanged");
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    Log.w(TAG, "surfaceDestroyed");
}

2 个答案:

答案 0 :(得分:30)

要使用Camera2 API显示来自相机的预览,您应该执行以下步骤:

  1. 获得使用相机设备的许可
  2. 使用CameraManager打开与相机的连接
  3. 准备好Surface预览
  4. 使用打开的相机设备和所需的表面(它不仅可以包括预览表面)创建CaptureSession
  5. 创建CaptureSession后,您需要创建并配置CaptureRequest并将其提交给CaptureSession
  6. 需要注意的是,准备曲面和打开与相机的连接是独立的过程,因此您需要确保在创建CaptureSession之前它们都已完成。

    以下是在屏幕上显示相机预览的活动示例:

    public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback, Handler.Callback {
        static final String TAG = "CamTest";
        static final int MY_PERMISSIONS_REQUEST_CAMERA = 1242;
        private static final int MSG_CAMERA_OPENED = 1;
        private static final int MSG_SURFACE_READY = 2;
        private final Handler mHandler = new Handler(this);
        SurfaceView mSurfaceView;
        SurfaceHolder mSurfaceHolder;
        CameraManager mCameraManager;
        String[] mCameraIDsList;
        CameraDevice.StateCallback mCameraStateCB;
        CameraDevice mCameraDevice;
        CameraCaptureSession mCaptureSession;
        boolean mSurfaceCreated = true;
        boolean mIsCameraConfigured = false;
        private Surface mCameraSurface = null;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            this.mSurfaceView = (SurfaceView) findViewById(R.id.SurfaceViewPreview);
            this.mSurfaceHolder = this.mSurfaceView.getHolder();
            this.mSurfaceHolder.addCallback(this);
            this.mCameraManager = (CameraManager) this.getSystemService(Context.CAMERA_SERVICE);
    
            try {
                mCameraIDsList = this.mCameraManager.getCameraIdList();
                for (String id : mCameraIDsList) {
                    Log.v(TAG, "CameraID: " + id);
                }
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
    
            mCameraStateCB = new CameraDevice.StateCallback() {
                @Override
                public void onOpened(CameraDevice camera) {
                    Toast.makeText(getApplicationContext(), "onOpened", Toast.LENGTH_SHORT).show();
    
                    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();
                }
            };
        }
    
        @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
        protected void onStop() {
            super.onStop();
            try {
                if (mCaptureSession != null) {
                    mCaptureSession.stopRepeating();
                    mCaptureSession.close();
                    mCaptureSession = null;
                }
    
                mIsCameraConfigured = false;
            } catch (final CameraAccessException e) {
                // Doesn't matter, cloising device anyway
                e.printStackTrace();
            } catch (final IllegalStateException e2) {
                // Doesn't matter, cloising device anyway
                e2.printStackTrace();
            } finally {
                if (mCameraDevice != null) {
                    mCameraDevice.close();
                    mCameraDevice = null;
                    mCaptureSession = null;
                }
            }
        }
    
        @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);
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
    
            mIsCameraConfigured = true;
        }
    
    
        @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;
            }
        }
    
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            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;
        }
    
        private class CaptureSessionListener extends
                CameraCaptureSession.StateCallback {
            @Override
            public void onConfigureFailed(final CameraCaptureSession session) {
                Log.d(TAG, "CaptureSessionConfigure failed");
            }
    
            @Override
            public void onConfigured(final CameraCaptureSession session) {
                Log.d(TAG, "CaptureSessionConfigure onConfigured");
                mCaptureSession = session;
    
                try {
                    CaptureRequest.Builder previewRequestBuilder = mCameraDevice
                            .createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
                    previewRequestBuilder.addTarget(mCameraSurface);
                    mCaptureSession.setRepeatingRequest(previewRequestBuilder.build(),
                            null, null);
                } catch (CameraAccessException e) {
                    Log.d(TAG, "setting up preview failed");
                    e.printStackTrace();
                }
            }
        }
    }
    

答案 1 :(得分:0)

有了 CameraX ,现在很容易。

    // Create a preview use case instance
val preview = Preview.Builder().build()

// Bind the preview use case and other needed user cases to a lifecycle
val camera = cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview, imageAnalysis, imageCapture)

// Create a surfaceProvider using the bound camera's cameraInfo
val surfaceProvider = previewView.createSurfaceProvider(camera.cameraInfo)

// Attach the surfaceProvider to the preview use case to start preview
preview.setSurfaceProvider(surfaceProvider)


<androidx.camera.view.PreviewView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:scaleType="fitEnd" />

https://medium.com/androiddevelopers/display-a-camera-preview-with-previewview-86562433d86c