Camera2开发之CameraDevice类

本文深入解析了Android Camera2 API中的CameraDevice类,介绍了不同硬件等级的支持情况、内部类StateCallback的作用及常用的模板和方法。
转载出处: http://www.jianshu.com/p/cad777db008e

本文出自:m2u的简书



 

0x00 说明

该文章为本人个人学习的总结,如果遗漏或错误欢迎在评论区批评指出or补充。如对您有帮助可以细看之,如希望直接查看本人的学习资料来源,可直接跳到0x05 相关资料一节查看。

0x01 概览

CameraDevice是连接在安卓设备上的单个相机的抽象表示,CameraDevice支持在高帧率下对捕获的图像进行细粒度控制和后期处理.

在Camera2 API中,一个相机设备可能支持的硬件等级有以下几种(按每个等级所支持的功能来排序):

LEVEL_3>FULL>LIMIT>LEGACY

按照Google文档的说法,一般手机的相机可能会支持FULLLIMIT,当一个设备支持到LIMIT,此时尽管Camera2 API具有更整洁和高效的接口,然而其只暴露出和旧的Camera API功能相当的API,与使用旧的API无异。
而支持到FULL等级的设备,则提供了比旧的Camera API大大改进的功能,比如支持30fps全高清连拍,支持帧之间的手动设置,支持RAW格式的图片拍摄,快门零延迟以及视频速拍等特性。只有在支持FULL级别的设备上才能完全发挥Camera2的特性。然而经过实测中发现,目前市面上大多安卓手机都只支持到最低级别LEGACY(估计是为了兼容android L 以下的系统?)......也就是说在这样的手机上使用Camera API和Camera2 API并没有太大区别,甚至Camera API的发挥可能还要好一些。不过,尽管如此,还是推荐使用Camera2 API,毕竟旧的Camera API已经被打上deprecated标签,指不定在未来哪个android的版本中Camera API就被移除了。相机设备所支持的硬件等级是由硬件厂商决定的,可以通过以下CameraCharacteristics类获取机子上的相机所支持的硬件等级参数:

CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
int hardwareLevel=characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);

其中managerCameraManager实例,关于CameraManager在上篇文章Camera2开发(1) --CameraManager类中有介绍。hardwareLevel==1FULLhardwareLevel==2LEGACYhardwareLevel==0LIMIThardwareLevel==3LEVEL_3

0x02 内部类

StateCallback

该类用于接收相机的连接状态的更新。这些状态包括一系列的通知如相机启动结束(此时允许调用CameraDevice.createCaptureSession(List, CameraCaptureSession.StateCallback, Handler)创建一个捕获会话),相机断开连接或关闭以及相机出现异常错误等。
在调用CameraDevice.openCamera(String,CameraDevice.StateCallback,Handler)方法打开相机时必须传入一个CameraDevice.StateCallback实例,以用于接收相机状态的更新和后续的处理。
典型的CameraDevice.StateCallback的声明和使用如下:

private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback()
{
    @Override
    public void onOpened(@NonNull CameraDevice camera)
    {
        //当相机打开成功之后会回调此方法
        //一般在此进行获取一个全局的CameraDevice实例,开启相机预览等操作
        mCameraDevice = camera;//获取CameraDevice实例
        createCameraPreviewSession();//创建相机预览会话
    } 
    @Override
    public void onDisconnected(@NonNull CameraDevice camera)
    {
        //相机设备失去连接(不能继续使用)时回调此方法,同时当打开相机失败时也会调用此方法而不会调用onOpened()
        //可在此关闭相机,清除CameraDevice引用
        camera.close();
        mCameraDevice = null;
    }
    @Override
    public void onError(@NonNull CameraDevice camera, int error)
    {
        //相机发生错误时调用此方法
        camera.close();
        mCameraDevice = null;
    }
    @Override
    public void onClosed(CameraDevice camera)
    {
        //相机完全关闭时回调此方法
        super.onClosed(camera);
    }
};

其中onError(@NonNull CameraDevice camera, int error)中的error参数代表出错的代码,可参考Google文档上的错误代码说明。

0x03 常量

int TEMPLATE_MANUAL
Constant Value: 6 (0x00000006)

用于创建一个直接控制相机拍照参数CaptureRequest请求。使用该模板创建的请求,相机的所有自动控制都会被禁用(例如自动曝光,自动白平衡,自动对焦等),并将后期处理参数设置成预览质量。手动控制的参数(曝光,感光度等)将被设置成合理的默认值,用户需要根据自己想要的预期效果来调整这些参数。
兼容性:TEMPLATE_MANUAL在支持MANUAL_SENSOR功能的设备上可用。

int TEMPLATE_PREVIEW
Constant Value: 1 (0x00000001)

用于创建一个相机预览请求。通常情况下,设置了该模板的预览画面,相机会优先保证预览的帧率。该模板适用于相机画面预览,通常将该模板结合setRepeatingRequest(CaptureRequest, CameraCaptureSession.CaptureCallback, Handler)创建一个预览请求。
兼容性:TEMPLATE_PREVIEW在所有相机设备上均适用。

int TEMPLATE_RECORD
Constant Value: 3 (0x00000003)

用于创建录制视频的请求。使用该模板创建的请求将使用标准帧率,并且后期处理效果的质量将被设置成录像级别。
兼容性:TEMPLATE_RECORD可在所有的相机设备上使用.。

int TEMPLATE_STILL_CAPTURE
Constant Value: 2 (0x00000002)

用于创建一个拍照请求。使用该模板创建的请求会优先保证图像的质量,以获得最好的拍照效果。
兼容性:可在所有的相机设备上使用。

int TEMPLATE_VIDEO_SNAPSHOT
Constant Value: 4 (0x00000004)

用于创建录像时拍照请求。使用该模板创建的请求可以最大化地保证照片的质量同时不会破坏正在录制的视频质量。该模板创建的请求通常与CameraCaptureSession.capture(CaptureRequest request, CameraCaptureSession.CaptureCallback callback, Handler handler)结合使用,其中这里的request必须是基于TEMPLATE_RECORD模板创建。
兼容性:硬件支持级别高于LEGACY的所有相机设备可用。

int TEMPLATE_ZERO_SHUTTER_LAG
Constant Value: 5 (0x00000005)

用于创建零延迟拍照请求。使用该模板创建的请求将最大化地保证图片质量并且不会损失预览图像的帧率。此时自动对焦/自动白平衡和自动曝光都应处于auto模式。
兼容性:该模板仅在支持PRIVATE_PEPROCESSINGYUV_PEPROCESSING特性的相机设备上适用。

0x04 常用的方法

close()
尽可能快地关闭当前相机设备的连接。

调用该方法之后,所有调用处于激活状态的sessionCameraDevice其方法的操作都将抛出一个IllegalStateException异常。当相机完全关闭后,CameraDevice.StateCallback.onClosed(CameraDevice)方法会被调用,此时相机就绪以等待下一次被打开。

createCaptureRequest(int templateType)
创建一个用于构建capture request的CaptureRequest.Builder实例,并用templateType模板初始化该实例。

该设置会为当前指定的CameraDevice适配最佳的选项,因此创建的CaptureRequest不建议重用到其他的CameraDevice以免出错。

参数说明:

  • templateType:参考0x03 常量一节。

createCaptureSession(List<Surface> outputs, CameraCaptureSession.StateCallback callback, Handler handler)
通过提供给相机设备的目标输出surface集合创建一个新的相机捕获会话(CameraCaptureSession)实例。

当前活动的capture session决定了相机的每一个capture request的输出surface(每个capture request的输出surface都是outputs的一个子集)。比如当我需要将捕获数据输出到预览surface,则需要将预览surface添加到outputs作为createCaptureSession的参数。
在实际使用中可根据不同的用例和输出目标来构建surface用于接收相机输出的图像数据,这里只列出拍照功能可能用到的几个,有关录像的以后再补充:

  • 绘制到一个SurfaceView:
    使用SurfaceView来显示预览画面时,应在SurfaceViewSurface创建成功后先通过SurfaceHolder设置其大小,再获取Surface实例,如果不设置,则相机会自动为其设置一个小于且最接近1080p的可用预览尺寸:
SurfaceView mSurfaceView = (SurfaceView)findViewById(R.id.surfaceview);
SurfaceHolder mSurfaceHolder = mSurfaceView.getHolder();
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
//获取所有可用的预览尺寸
Size[] sizes=map.getOutputSizes(SurfaceHolder.class);
Size mPreviewSize=sizes[bestSizeIndex];
//设置surface尺寸
mSurfaceHolder.setFixedSize(mPreviewSize.getWidth(),mPreviewSize.getHeight());
//获取预览的surface
Surface surface=mSurfaceHolder.getSurface();
  • 通过SurfaceTexture来访问OpenGL texture:
    使用TextureView来显示预览,要确保手机的硬件加速开启才能进行。
    在创建Surface之前,需要先设置SurfaceTexture的大小,如果不设置,则相机会自动为其设置一个小于且最接近1080p的可用预览尺寸:
//获取SurfaceTexture
SurfaceTexture texture = mTextureView.getSurfaceTexture();
//获取所有可用预览尺寸
Size[] sizes=map.getOutputSizes(SurfactTexture.class);
Size mPreviewSize=sizes[bestSizeIndex];
//设置SurfaceTexture大小
texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
//获取预览的surface
Surface surface = new Surface(texture);
  • 结合MediaCodec进行录像:待补充
  • 结合MediaRecorder进行录像:待补充
  • 结合android.renderscript进行高效的YUV处理:待补充
  • 在程序中访问RAW格式或未压缩的YUV或者压缩的JPEG格式的图像数据:
    可创建一个ImageReader对象,通过ImageReaderSurface来接收相机图像并保存图像数据:
//************************
//**1.创建ImageReader对象**
//************************
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
//获取指定格式的所有支持尺寸
Size[] sizes=map.getOutputSizes(ImageFormat.JPEG);
//计算期望的最佳尺寸,至于怎么计算则看具体需求。如果该ImageReader的大小没有在程序中设置,
//则当前相机设备将自动为该ImageReader设置一个支持的小于1080p的尺寸。
Size largestSize = Collections.max(Arrays.asList(sizes), new CompareSizesByArea());
//创建ImageReader
ImageReader mImageReader = ImageReader.newInstance(largestSize.getWidth(), largestSize.getHeight(), ImageFormat.JPEG,/*maxImages*/2);

//...其他操作

/** 
* 摘自Google Sample:Camera2Basic
* Compares two {@code Size}s based on their areas. 
*/
static class CompareSizesByArea implements Comparator<Size>{
    @Override
    public int compare(Size lhs, Size rhs)
    {
        //We cast here to ensure the multiplications won't overflow
        return Long.signum((long) lhs.getWidth() * lhs.getHeight() - (long) rhs.getWidth() * rhs.getHeight());
    }
}

//...其他操作

//************************
//**2.设置ImageReader.OnImageAvailableListener监听**
//************************
private final ImageReader.OnImageAvailableListener mOnImageAvailableListener = new ImageReader.OnImageAvailableListener()
{
    @Override
    public void onImageAvailable(ImageReader reader)
    {
        //在这里调用(reader.acquireNextImage()获取图像数据
        mBackgroundHandler.post(new ImageSaver(reader.acquireNextImage(), mFile));
    }
};

//...其他操作

mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler);

//************************
//**3.随后可通过ImageReader.getSurface()方法获取Surface**
//************************
Surface surface=mImageReader.getSurface();

参数说明:

  • outputs
    所有可用于捕获相机输出数据的surface集合。
  • callback
    CameraCaptureSession.StateCallback实例,调用CameraDevice.createCaptureSession后会回调callback中相应的方法,可在该回调中处理创建session成功或失败之后的进一步操作。
  • handler
    指定处理该操作的handler

getId()
获取当前相机设备的id

0x05 相关资料

有关CameraDevice的使用实例可参考googlesamples/android-Camera2Basic



作者:m2u
链接:http://www.jianshu.com/p/cad777db008e
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

<think>好的,用户想了解Android Camera2 API的详细开发教程、用法和示例代码。首先,我需要回忆一下Camera2 API的基本结构和核心组件。记得Camera2和之前的Camera API有很大不同,采用了更复杂的模型,比如CameraManager、CameraDevice、CaptureRequest、CaptureSession这些。 用户可能已经有一定的Android开发基础,但需要具体的指导步骤。首先应该解释Camera2 API的核心组件,比如CameraManager负责管理设备,CameraDevice代表摄像头硬件,CaptureRequest设置参数,CaptureSession处理会话流程。这些部分需要详细说明,可能还要比较CameraX和Camera2的区别,因为用户提到参考内容中有CameraX的信息,可能需要指出两者的适用场景。 接下来,用户需要示例代码。我应该提供一个基础的拍照流程,包括打开相机、创建预览会话、捕获图像等步骤。代码结构要清晰,注释明确,方便用户理解。同时,要注意权限处理,比如在AndroidManifest.xml中添加相机权限,还有动态申请运行时权限,这部分可能也需要提及。 另外,用户的问题里提到了CameraX,引用内容里也有CameraX的推荐,所以可能需要简要说明何时选择Camera2而不是CameraX。比如需要更底层的控制或特定功能时使用Camera2,而CameraX更适合快速开发和兼容性。 还要考虑异常处理和资源释放,这是Camera2开发中容易出错的地方。比如在onDestroy中关闭会话和设备,避免内存泄漏。同时,不同设备的兼容性问题,比如配置合适的输出尺寸,检查支持的硬件级别,这些都需要提醒用户注意。 用户可能还想了解如何扩展功能,比如录像或图像处理,所以相关的问题部分可以提到这些方向。此外,性能优化也是一个重点,比如减少延迟、处理图像数据的高效方法等。 最后,确保回答结构清晰,分步骤讲解,代码示例正确,并且引用相关的文档和资料,比如Android官方文档和示例代码库,帮助用户进一步学习。检查是否有遗漏的部分,比如没有提到SurfaceView或TextureView用于预览,或者ImageReader的使用,这些都需要包含在教程中。</think>### Android Camera2 API 开发详解 #### 一、Camera2 核心组件 1. **CameraManager** 管理设备摄像头,提供设备列表查询与摄像头打开功能。 ```java CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); String[] cameraIds = manager.getCameraIdList(); ``` 2. **CameraDevice** 表示物理摄像头设备,通过`createCaptureSession`创建会话。 ```java manager.openCamera(cameraId, new CameraDevice.StateCallback() { @Override public void onOpened(@NonNull CameraDevice camera) { // 摄像头就绪 } }, null); ``` 3. **CaptureRequest** 定义单次捕获请求的参数(如对焦模式、曝光、分辨率等)。 ```java CaptureRequest.Builder requestBuilder = camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); requestBuilder.addTarget(previewSurface); ``` 4. **CameraCaptureSession** 管理捕获请求的会话流程,支持连续预览或单次拍照[^4]。 --- #### 二、基础拍照流程(示例代码) ```java // 1. 初始化CameraManager CameraManager manager = (CameraManager) getSystemService(CAMERA_SERVICE); String cameraId = manager.getCameraIdList()[0]; // 2. 打开摄像头 manager.openCamera(cameraId, new CameraDevice.StateCallback() { @Override public void onOpened(@NonNull CameraDevice camera) { // 3. 创建预览Surface SurfaceTexture texture = textureView.getSurfaceTexture(); Surface previewSurface = new Surface(texture); // 4. 创建CaptureSession camera.createCaptureSession(Arrays.asList(previewSurface), new CameraCaptureSession.StateCallback() { @Override public void onConfigured(@NonNull CameraCaptureSession session) { // 5. 设置重复预览请求 CaptureRequest request = requestBuilder.build(); session.setRepeatingRequest(request, null, null); } }, null); } }, null); ``` --- #### 三、关键注意事项 1. **权限声明** AndroidManifest.xml需添加: ```xml <uses-permission android:name="android.permission.CAMERA" /> ``` 2. **异步操作** Camera2 API的所有回调均在后台线程执行,UI操作需切换至主线程。 3. **设备兼容性** 使用`CameraCharacteristics`检查设备支持的硬件级别: ```java CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId); Integer hardwareLevel = characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); ``` 4. **资源释放** 在`onPause()`或`onDestroy()`中关闭会话和摄像头: ```java if (cameraCaptureSession != null) { cameraCaptureSession.close(); } if (cameraDevice != null) { cameraDevice.close(); } ``` --- #### 四、扩展功能实现 - **拍照捕获** 使用`TEMPLATE_STILL_CAPTURE`模式创建请求,通过`ImageReader`获取图像数据。 - **录像功能** 结合`MediaRecorder`配置视频输出Surface,设置`TEMPLATE_RECORD`请求模板[^3]。 - **手动控制** 调整`SENSOR_EXPOSURE_TIME`、`LENS_FOCUS_DISTANCE`等参数实现专业模式。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值