camera功能真的那么难用吗

背景

Android开发工作过程中,经常需要用到camera相关能力,比如:人脸识别,ai识别,拍照预览,摄像头录制等等需求。都需要使用到camera,且需要拿到camera的预览数据。但是每次开发这块代码都比较繁琐,一大堆的接口(尤其是camera2),用错一个就容易出现意想不到的结果。所以这里我们将Android的camera做一次简单易用的封装,再也不用担心API用错了。

一、Camera的历史

在封装之前,我们先简单了解下camera的发展历史。目前Android有camera1和camera2两个不同版本的API。且camera1已经逐渐被抛弃了。那她两到底啥区别?

  • Camera1(2010年推出)
    • 简单但僵化 :采用同步阻塞模型 ,调用takePicture()时整个相机管线阻塞,导致延迟高、功耗大。
    • 有限控制 :参数调整(如曝光、对焦)通过Camera.Parameters实现,仅支持基础设置,无法精细控制。
    • 高延迟:拍照后需等待图像处理完成才能继续操作。
    • 资源浪费:预览和拍照无法并行,导致CPU/GPU利用率低。
    • 硬件抽象层(HAL)简单:无法适配多摄像头、高帧率传感器(>30fps)或RAW格式。
    • 功能缺失:不支持HDR+、人像模式等计算摄影需求。
    • 独占式访问:仅允许单应用占用相机,其他应用需等待释放(如扫码时无法同时视频通话)。
  • Camera2(2014年推出,Android 5.0+)
    • 异步管道模型 :引入CaptureRequestCaptureSession,支持非阻塞操作(如连拍、实时预览并行处理)。
    • 精准控制:可独立配置传感器、闪光灯、处理算法(如手动调节ISO、快门速度)。
    • 零复制流水线 :图像数据直接传递到Surface(如TextureView),减少内存拷贝。
    • 批处理请求 :单次提交多个CaptureRequest(如同时预览+对焦+测光),提升帧率和能效比。
    • 标准化HAL接口:统一控制不同厂商的相机硬件(如双摄、TOF传感器)。
    • 高级功能支持:原生实现RAW拍摄、手动对焦轨迹、逻辑多摄像头(融合多个传感器数据)。
    • 并发共享机制 :通过CameraManager协调多应用访问(如后台AR应用与前台相机APP共存)。
特性 Camera1 Camera2
架构模型 同步阻塞 异步非阻塞管道
性能 高延迟、低吞吐量 低延迟、高吞吐量(支持4K/60fps)
硬件适配 仅基础单摄 多摄/RAW/高帧率传感器
功能扩展 基础拍照/录像 HDR+/手动模式/计算摄影
多应用支持 独占访问 并发共享

二、封装核心能力

工作场景下对camera最常用的核心能力:开启摄像头,切换摄像头,预览,关闭摄像头,获取摄像头预览数据。

所以我们要封装的话就直接将这几个能力抽象成对应的接口。

Kotlin 复制代码
package com.qt.camera.base

import android.graphics.SurfaceTexture
import android.hardware.Camera
import android.util.Range
import com.qt.camera.FUCameraConstants
import com.qt.camera.enumeration.FUCameraFacingEnum
import com.qt.camera.listener.OnFUCameraListener


/**
 *
 * DESC:Camera抽象类
 * Created on 2021/10/22
 * @author Jason Lu
 */
abstract class FUAbstractCamera {

    /**
     * 前置相机id
     */
    @Volatile
    var mFrontCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT

    /**
     * 后置相机id
     */
    @Volatile
    var mBackCameraId = Camera.CameraInfo.CAMERA_FACING_BACK

    /**
     * 曝光补偿
     */
    @Volatile
    var mExposureCompensation = FUCameraConstants.EXPOSURE_COMPENSATION

    /**
     * 相机采集帧率模式
     * true:最大帧率输出 false:最大可选范围区间输出
     */
    @Volatile
    var mIsHighestRate = false

    /**
     * 相机后置角度
     */
    @Volatile
    var mBackCameraOrientation = FUCameraConstants.BACK_CAMERA_ORIENTATION

    /**
     * 当前相机前置角度
     */
    @Volatile
    var mFrontCameraOrientation = FUCameraConstants.FRONT_CAMERA_ORIENTATION

    /**
     * 当前相机朝向
     */
    @Volatile
    var mCameraFacing = FUCameraFacingEnum.CAMERA_FRONT

    /**
     * 当前相机输出分辨率-宽
     */
    @Volatile
    var mCameraWidth: Int = 1280

    /**
     * 当前相机输出分辨率-高
     */
    @Volatile
    var mCameraHeight: Int = 720

    /**
     * 当前相机角度
     */
    @Volatile
    var mCameraOrientation = mFrontCameraOrientation

    /**
     * 当前相机绑定纹理 Id
     */
    @Volatile
    var mCameraTexId = 100

    /**
     * 当前相机绑定 SurfaceTexture
     */
    @Volatile
    var mSurfaceTexture: SurfaceTexture? = null
    /**
     * 用户设置的相机绑定 SurfaceTexture
     */
    @Volatile
    var mCustomSurfaceTexture: SurfaceTexture? = null
    /**
     * 是否正在预览状态
     */
    @Volatile
    protected var mIsPreviewing = false
    /**
     * 是否只读ImageReader流
     */
    @Volatile
    var onlyReadImage = false

    /**
     * 是否需要停止预览
     */
    @Volatile
    protected var mIsNeedStopPreviewing = false

    /**
     * 事件回调
     */
    @Volatile
    protected var mCameraListener: OnFUCameraListener? = null

    /**
     * 自定义摄像头帧率范围
     * 针对camera2
     */
    var mRangeFps: Range<Int>? = null
    /**
     * 绑定数据回调
     * @param listener OnFUCameraListener
     */
    fun bindCameraListener(listener: OnFUCameraListener?) {
        this.mCameraListener = listener
    }


    /**
     * 资源释放
     */
    open fun release() {
        if (mIsPreviewing) {
            closeCamera()
        }
        mCameraListener = null
    }


    /**
     * 初始化相机
     */
    abstract fun initCameraInfo()

    /**
     * 打开相机
     */
    abstract fun openCamera()

    /**
     * 开启预览
     */
    abstract fun startPreview()

    /**
     * 对焦
     * @param viewWidth Int
     * @param viewHeight Int
     * @param rawX Float
     * @param rawY Float
     * @param areaSize Int
     */
    abstract fun handleFocus(viewWidth: Int, viewHeight: Int, rawX: Float, rawY: Float, areaSize: Int)

    /**
     * 获取亮度
     * @return Float
     */
    abstract fun getExposureCompensation(): Float

    /**
     * 设置亮度
     * @param value Float
     */
    abstract fun setExposureCompensation(value: Float)

    /**
     * 分辨率变更处理
     * @param cameraWidth Int
     * @param cameraHeight Int
     */
    abstract fun changeResolution(cameraWidth: Int, cameraHeight: Int)

    /**
     * 关闭相机
     * @param releaseSurface 是否释放SurfaceTexture资源
     */
    abstract fun closeCamera(releaseSurface:Boolean = true)

    /**
     * 切换相机前后置
     */
    fun switchCamera(surfaceTexture: SurfaceTexture?) {
        closeCamera(mCustomSurfaceTexture == null || surfaceTexture !=null)//如果使用用户自定义的surfaceTexture或者之前设置过surfaceTexture就release
        mCameraFacing = if (mCameraFacing == FUCameraFacingEnum.CAMERA_FRONT) FUCameraFacingEnum.CAMERA_BACK else FUCameraFacingEnum.CAMERA_FRONT
        mCameraOrientation = if (mCameraFacing == FUCameraFacingEnum.CAMERA_FRONT) mFrontCameraOrientation else mBackCameraOrientation
        if(surfaceTexture!= null){
            mCustomSurfaceTexture = surfaceTexture
        }
        openCamera()
    }


    /**
     * 设置相机放大等级
     */
    abstract fun setZoomRatio(zoomRatio: Float)

}

核心能力抽象出来后,剩下要做的就是camera1和camera2分别实现了。具体的实现这里就不贴代码了,给个github链接,各位自己下载直接用吧:GitHub - 279154451/Camera: Camera工具

相关推荐
jr-create(•̀⌄•́)8 小时前
静态相机中的 CCD和CMOS的区别
数码相机
中达瑞和-高光谱·多光谱9 小时前
LCTF液晶可调谐滤波器在多光谱相机捕捉无人机目标检测中的作用
数码相机·目标检测·无人机
中达瑞和-高光谱·多光谱1 天前
中达瑞和SHIS高光谱相机在黑色水彩笔墨迹鉴定中的应用
人工智能·数码相机
把玩计算机1 天前
【相机基础知识与物体检测】更新中
数码相机
lingling0092 天前
AI+3D 视觉重塑塑料袋拆垛新范式:迁移科技解锁工业自动化新高度
数码相机
猿饵块2 天前
相机--相机标定实操
数码相机
_李小白2 天前
【OSG学习笔记】Day 15: 路径动画与相机漫游
笔记·数码相机·学习
LabVIEW开发3 天前
LabVIEW杂草识别与精准喷洒
数码相机·labview开发案例
XMAIPC_Robot3 天前
基于 ZYNQ UltraScale+ OV5640的高速图像传输系统设计,支持国产替代
linux·数码相机·fpga开发·架构·边缘计算