• 作者:老汪软件技巧
  • 发表时间:2024-10-02 15:01
  • 浏览量:

​Android Camera2

Android Camera2 是 Android 系统中用于相机操作的一套高级应用程序接口(API),它取代了之前的 Camera API。以下是关于 Android Camera2 的一些主要信息:

主要特点:核心类与组件:使用步骤:获取 CameraManager:首先需要获取 CameraManager 对象,这是进行所有相机操作的前提。可以通过 Context.getSystemService(Context.CAMERA_SERVICE) 方法来获取 CameraManager。打开相机设备:使用 CameraManager 的 openCamera(String cameraId, CameraDevice.StateCallback callback, Handler handler) 方法打开指定的摄像头。其中,cameraId 是要打开的摄像头的标识符,callback 用于监听摄像头的状态变化,handler 表示执行回调的线程。创建 CameraCaptureSession:当摄像头打开后,通过 CameraDevice.createCaptureSession(List outputs, CameraCaptureSession.StateCallback callback, Handler handler) 方法创建 CameraCaptureSession。

outputs 是一个包含所有需要从该摄像头获取图片的 Surface 的列表,callback 用于监听会话的创建过程,handler 表示执行回调的线程。创建 CaptureRequest:调用 CameraDevice.createCaptureRequest(int templateType) 方法创建 CaptureRequest.Builder,其中 templateType 可以是 TEMPLATE_PREVIEW(预览)、TEMPLATE_RECORD(拍摄视频)、TEMPLATE_STILL_CAPTURE(拍照)等。然后使用 CaptureRequest.Builder 设置拍照的各种参数。开始预览或拍照:调用 CameraCaptureSession.setRepeatingRequest() 方法开始预览,或调用 capture() 方法进行拍照。拍照的优先级比预览的优先级高,如果需要多次拍照,可以多次调用 capture() 方法。支持的版本和兼容性:Android Camera2 从 Android 5.0(API 级别 21)开始支持。但需要注意的是,虽然 Android 5.0 及更高版本的设备支持 Camera2,但部分设备可能并不支持所有的 Camera2 功能。在实际开发中,需要根据设备的具体特性和支持情况进行适配和处理。相比Camera API技术优势

Android Camera2 与 Camera API 相比,具有以下优势:

功能与控制方:支持 RAW 图像捕获:Camera2 支持 RAW 格式的图像捕获,RAW 格式的图像包含了更多的原始图像信息,为后期处理提供了更大的空间和更高的灵活性,可以让用户在后期对图像的色彩、对比度、锐度等进行更精细的调整。相比之下,Camera API 通常只能获取经过压缩和处理的图像格式,丢失了很多原始信息14。高速连拍模式:Camera2 支持高速连拍功能,能够以更快的速度连续拍摄多张照片,这对于捕捉快速运动的物体或瞬间的精彩场景非常有帮助。而在 Camera API 中,实现连拍功能相对较为困难,且连拍速度和效果可能不尽如人意4。性能优化方面:架构与兼容性方面:设备特性支持与检测方面:Android Camera2 RAW图像捕获

要使用 Android Camera2 进行 RAW 图像捕获,你可以按照以下步骤进行操作:

检查设备支持:首先,确保你的设备支持 Camera2 API 并且支持 RAW 图像捕获。你可以通过查询设备的 CameraCharacteristics 来获取相关信息123。获取 CameraManager:通过Context.getSystemService(Context.CAMERA_SERVICE)获取 CameraManager 实例123。打开相机设备:使用 CameraManager 的openCamera(String cameraId, CameraDevice.StateCallback callback, Handler handler)方法打开相机设备。你需要指定要打开的相机 ID 以及相应的回调和处理程序123。创建 CaptureRequest.Builder:创建一个 CaptureRequest.Builder 对象,并设置相关的参数,如对焦模式、曝光模式等。同时,将图像格式设置为ImageFormat.RAW_SENSOR以指定捕获 RAW 图像1。创建 CameraCaptureSession:使用 CameraDevice 的createCaptureSession(List outputs, CameraCaptureSession.StateCallback callback, Handler handler)方法创建一个 CameraCaptureSession。将包含 RAW 图像的 Surface 添加到输出列表中1。开始捕获:调用 CameraCaptureSession 的capture(CaptureRequest request, CameraCaptureSession.CaptureCallback callback, Handler handler)方法开始捕获 RAW 图像。你可以指定相应的回调来处理捕获结果1。处理 RAW 图像数据:在 CaptureCallback 的onCaptureCompleted方法中,你将接收到包含 RAW 图像数据的 CaptureResult 对象。你可以从 CaptureResult 中获取图像数据,并进行相应的处理或保存。

示例代码如下:

import android.content.Context;
import android.graphics.ImageFormat;
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.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.view.Surface;
public class RawImageCapture {
    private CameraManager cameraManager;
    private String cameraId;
    private CameraDevice cameraDevice;
    private CameraCaptureSession cameraCaptureSession;
    private CaptureRequest.Builder captureRequestBuilder;
    public void startRawImageCapture(Context context) {
        // 获取CameraManager
        cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
        try {
            // 获取相机设备ID
            cameraId = cameraManager.getCameraIdList()[0];
            // 打开相机设备
            cameraManager.openCamera(cameraId, new CameraDevice.StateCallback() {
                @Override
                public void onOpened(CameraDevice camera) {
                    cameraDevice = camera;
                    createCaptureSession();
                }
                @Override
                public void onDisconnected(CameraDevice camera) {
                    cameraDevice.close();
                }
                @Override
                public void onError(CameraDevice camera, int error) {
                    cameraDevice.close();
                }
            }, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }
    private void createCaptureSession() {
        try {
            // 创建CaptureRequest.Builder
            captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
            captureRequestBuilder.addTarget(new Surface(ImageFormat.RAW_SENSOR));
            // 创建CameraCaptureSession
            cameraDevice.createCaptureSession(Arrays.asList(new Surface(ImageFormat.RAW_SENSOR)), new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(CameraCaptureSession session) {
                    cameraCaptureSession = session;
                    startCapture();
                }
                @Override
                public void onConfigureFailed(CameraCaptureSession session) {
                }
            }, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }
    private void startCapture() {
        try {
            cameraCaptureSession.capture(captureRequestBuilder.build(), new CameraCaptureSession.CaptureCallback() {
                @Override
                public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
                    // 处理RAW图像数据
                    Log.d("RawImageCapture", "RAW image captured");
                }
            }, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }
}

如何对接Android Camera2

大牛直播SDK前几年在做Android平台RTMP推送和轻量级RTSP服务的时候,实际上就已经支持了Camera2的采集和数据投递,考虑到,目前5.0以下版本的设备越来越少,后面的GB28181设备接入模块,更是以Camera2的demo为准。

Camera2数据回调并投递到底层jni示例代码如下:

/*
 * Camera2MainActivity.java
 * Author:daniusdk.com
 * WeChat: xinsheng120
 */
@Override
public void onCameraImageData(Image image) {
	Image.Plane[] planes = image.getPlanes();
	if (image.getFormat() != ImageFormat.YUV_420_888) {
		Log.i(TAG,  "image format is not YUV_420_888, format:" + image.getFormat());
		return;
	} else {
	   // Log.i(TAG,  "image format is YUV_420_888, format:" + image.getFormat());
	}
	int w = image.getWidth(), h = image.getHeight();
	int y_offset = 0, u_offset = 0, v_offset = 0;
	Rect crop_rect = image.getCropRect();
	if (crop_rect != null && !crop_rect.isEmpty()) {
		w = crop_rect.width();
		h = crop_rect.height();
		y_offset += crop_rect.top * planes[0].getRowStride() + crop_rect.left * planes[0].getPixelStride();
		u_offset += (crop_rect.top / 2) * planes[1].getRowStride() + (crop_rect.left / 2) * planes[1].getPixelStride();
		v_offset += (crop_rect.top / 2) * planes[2].getRowStride() + (crop_rect.left / 2) * planes[2].getPixelStride();
		;
		// Log.i(TAG, "crop w:" + w + " h:" + h + " y_offset:"+ y_offset + " u_offset:" + u_offset + " v_offset:" + v_offset);
	}
	int scale_w = 0, scale_h = 0, scale_filter_mode = 0;
	scale_filter_mode = 3;
	int rotation_degree = cameraImageRotationDegree_;
	if (rotation_degree < 0) {
		Log.i(TAG, "onCameraImageData rotation_degree < 0, may need to set orientation_ to 0, 90, 180 or 270");
		return;
	}
	for (LibPublisherWrapper i : publisher_array_)
		i.PostLayerImageYUV420888ByteBuffer(0, 0, 0,
			planes[0].getBuffer(), y_offset, planes[0].getRowStride(),
			planes[1].getBuffer(), u_offset, planes[1].getRowStride(),
			planes[2].getBuffer(), v_offset, planes[2].getRowStride(), planes[1].getPixelStride(),
			w, h, 0, 0,
			scale_w, scale_h, scale_filter_mode, rotation_degree);
}

总结

Android Camera2 API 是从 Android 5.0(Lollipop)开始引入的,相对Camera API,优势非常明显,如果需要通过Android平台采集视频数据,在设备支持的前提下,建议尽可能用Camera2做数据采集。