Android读取摄像头获取视频流

在Android开发中,我们经常会遇到需要读取摄像头获取视频流的需求,比如实现视频聊天、人脸识别等功能。本文将介绍如何在Android应用中使用摄像头获取视频流,并提供相应的代码示例。

准备工作

在开始之前,我们需要进行一些准备工作。

权限申请

首先,在AndroidManifest.xml文件中添加以下权限申请:

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />

添加相机依赖

在app的build.gradle文件中添加相机依赖:

implementation 'androidx.camera:camera-camera2:1.1.0-alpha04'
implementation 'androidx.camera:camera-lifecycle:1.1.0-alpha04'
implementation 'androidx.camera:camera-view:1.0.0-alpha23'

配置CameraX

在MainActivity的onCreate方法中,配置CameraX:

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

    if (allPermissionsGranted()) {
        startCamera();
    } else {
        ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS);
    }
}

private void startCamera() {
    PreviewView previewView = findViewById(R.id.previewView);
    ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(this);

    cameraProviderFuture.addListener(() -> {
        try {
            ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
            bindPreview(cameraProvider);
        } catch (ExecutionException | InterruptedException e) {
            e.printStackTrace();
        }
    }, ContextCompat.getMainExecutor(this));
}

private void bindPreview(ProcessCameraProvider cameraProvider) {
    PreviewView previewView = findViewById(R.id.previewView);
    Preview preview = new Preview.Builder().build();
    CameraSelector cameraSelector = new CameraSelector.Builder()
            .requireLensFacing(CameraSelector.LENS_FACING_BACK)
            .build();

    preview.setSurfaceProvider(previewView.getSurfaceProvider());

    try {
        cameraProvider.unbindAll();
        Camera camera = cameraProvider.bindToLifecycle(this, cameraSelector, preview);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

private boolean allPermissionsGranted() {
    for (String permission : REQUIRED_PERMISSIONS) {
        if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
            return false;
        }
    }
    return true;
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    if (requestCode == REQUEST_CODE_PERMISSIONS) {
        if (allPermissionsGranted()) {
            startCamera();
        } else {
            Toast.makeText(this, "Permissions not granted by the user.", Toast.LENGTH_SHORT).show();
            finish();
        }
    }
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}

实时显示摄像头预览

接下来,我们将实现实时显示摄像头预览。

首先,在activity_main.xml文件中添加PreviewView组件:

<androidx.camera.view.PreviewView
    android:id="@+id/previewView"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

然后,在MainActivity的startCamera方法中绑定预览:

private void bindPreview(ProcessCameraProvider cameraProvider) {
    PreviewView previewView = findViewById(R.id.previewView);
    Preview preview = new Preview.Builder().build();
    CameraSelector cameraSelector = new CameraSelector.Builder()
            .requireLensFacing(CameraSelector.LENS_FACING_BACK)
            .build();

    preview.setSurfaceProvider(previewView.getSurfaceProvider());

    try {
        cameraProvider.unbindAll();
        Camera camera = cameraProvider.bindToLifecycle(this, cameraSelector, preview);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

获取视频流数据

之前我们已经实现了摄像头预览的功能,接下来我们将获取摄像头的视频流数据。

首先,在MainActivity中添加以下代码:

private ImageAnalysis imageAnalysis;

private void bindPreview(ProcessCameraProvider cameraProvider) {
    // ...

    imageAnalysis = new ImageAnalysis.Builder()
            .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
            .build();

    imageAnalysis.setAnalyzer(ContextCompat.getMainExecutor(this), image -> {
        // 处理图像数据
        ByteBuffer buffer = image.getPlanes()[0].getBuffer();
        byte[] data = new byte[buffer.remaining()];
        buffer.get(data);

        // 在这里可以对data进行处理,比如发送给服务器进行识别等

        image.close();
    });

    try {
        cameraProvider.unbindAll();
        Camera camera = cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageAnalysis