前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android Camera2详解

Android Camera2详解

作者头像
雪月清
发布2020-06-23 16:16:39
2.4K0
发布2020-06-23 16:16:39
举报
文章被收录于专栏:雪月清的随笔雪月清的随笔

Camera API2是Google从Android5.0开始推出的配合HAL3使用的一套新架构,相比于API1,对应用层开发者而言开放了更多的自主控制权,主要特性包括:

  • 可以获取更多的帧(预览/拍照)信息以及手动控制每一帧的参数;
  • 对Camera的控制更加精细(比如支持调整focus distance,对焦曝光模式等);
  • 支持更多图片格式(yuv/raw);
  • 高速连拍

当然,就像硬币总是存在正反两面,Camera2架构在让我们获得更多控制权的同时也增加了使用的复杂度.

基本架构

Android设备和Camera是通过管道pipeline的概念将两者进行串联的,在一个会话Session过程中系统发送Request,摄像头返回MetaData进行来回交互;预览和拍照等数据的传递是通过Surface进行.

Camera2主要类

CameraManager:

相机管理类,用于打开,关闭摄像头和获取相机属性描述信息,通过

getSystemService(Context.CAMERA_SERVICE)获取实例;

CameraDevice:具体的相机实例,用于建立会话;

CameraCaptureSession:用于向相机发送获取图像的请求

CameraMetaData:相机属性描述的基类;

CameraCharacteristics:相机静态属性描述类,获取它管理的属性是不依赖于摄像头打开的。比如闪光灯支持的模式,预览、拍照支持的size列表等;

CaptureRequest和CaptureResult:两者是在Camera会话期间使用,系统发送CaptureRequest,摄像头返回CaptureResult

基本使用流程

启动预览

启动预览需要3个步骤,每一步都有StateCallback,在相应的callback中开启下一步。流程梳理起来比较简洁,但是实际用java编写代码的时候,callback的嵌套就让流程看起来不那么友好了...

此处吹一波kotlin的协程

代码语言:javascript
复制
lifecycleScope.launch(Dispatchers.Main) {
    // 1. Open the selected camera
    camera = openCamera(cameraManager, args.cameraId, cameraHandler)

    // 2. Create session
    // 显示预览可以使用GLSurfaceView, SurfaceView或者TextureView
    // 此处viewFinder使用SurfaceView
    // Creates list of Surfaces where the camera will output frames
    val targets = listOf(viewFinder.holder.surface, imageReader.surface)

    // Start a capture session using our open camera and list of Surfaces where frames will go
    session = createCaptureSession(camera, targets, cameraHandler)

    // 3. Start preview
    val captureRequest = camera.createCaptureRequest(
               CameraDevice.TEMPLATE_PREVIEW).apply { addTarget(viewFinder.holder.surface) }

     // This will keep sending the capture request as frequently as possible until the
     // session is torn down or session.stopRepeating() is called
     session.setRepeatingRequest(captureRequest.build(), null, cameraHandler)
}

拍照

存在拍照需求时,在创建Session的时候需要提前配置用于拍照的Surface

代码语言:javascript
复制
// Initialize an image reader which will be used to capture still photos
val size = characteristics.get(
            CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)!!
             .getOutputSizes(args.pixelFormat).maxBy { it.height * it.width }!!
imageReader = ImageReader.newInstance(
             size.width, size.height, args.pixelFormat, IMAGE_BUFFER_SIZE)

// Creates list of Surfaces where the camera will output frames
val targets = listOf(viewFinder.holder.surface, imageReader.surface)

点击拍照按钮进行拍照时,向Session提交一次携带了拍照Surface的Request,

照片数据可在OnImageAvailableListener回调获取

代码语言:javascript
复制
imageReader.setOnImageAvailableListener({ reader ->
            val image = reader.acquireNextImage()
            Log.d(TAG, "Image available in queue: ${image.timestamp}")
        }, imageReaderHandler)
session.capture(...)

获取预览数据

在Camera API1中,预览数据是直接通过byte[]的形式返回给开发者的。Camera2中要获取预览数据则需要额外配置一下。

首先需要通过ImageReader创建的Surface在创建session的时候配置进去.

比如创建一个获取YUV格式的Surface

代码语言:javascript
复制
imageReader = ImageReader.newInstance(
                size.width, size.height, ImageFormat.YUV_420_888, IMAGE_BUFFER_SIZE
      )

‍‍然后对该imageReader设置数据回调,并在启动预览的Request中将它的Surface添加进去,这样每一帧预览生成时就能通过数据回调获得Image对象,从这个数据包装对象中我们就可以拿到Y,U,V各个通道的数据了。

总结

Camera2的基本使用总结到这里,使用起来肯定是不如Camera1方便,不过能让应用层有更多的操作空间总是值得的,而且从Android9.0开始也不得不使用这套架构了

(文章的代码引用自官方的例子Camera2Basic)

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-03-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 雪月清的随笔 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档