安卓获取所有可用摄像头并指定预览

在Android设备中,做预览拍照的需求的时候,我们会指定

CameraSelector DEFAULT_FRONT_CAMERA前置
或者后置CameraSelector DEFAULT_BACK_CAMERA

如果你使用的是平板或者工业平板,那么就会遇到多摄像头以及外置摄像头问题,简单的指定前后置是不行的,哪怕是USB 外置也有挂载两个的情况 ,本文就是写于两个外置的特殊情况作为验证,所以我们必须能获取所有可用的摄像头,我们以最新的预览拍照控件为例(
单摄像头推荐PreviewView+CameraSelector 与挂载的位置相关 且绑定了activity lifecycle
多摄像头推荐Surfaceview+CameraId 与id相关 surfaceview方式获取id在下面

PreviewView

为例初始化的时候需要使用

CameraSelector去绑定拍照的UseCase
    @MainThread
    @NonNull
    public Camera bindToLifecycle(@NonNull LifecycleOwner lifecycleOwner,
            @NonNull CameraSelector cameraSelector,
            @NonNull UseCase... useCases) {
        if (getCameraOperatingMode() == CAMERA_OPERATING_MODE_CONCURRENT) {
            throw new UnsupportedOperationException("bindToLifecycle for single camera is not "
                    + "supported in concurrent camera mode, call unbindAll() first");
        }
        setCameraOperatingMode(CAMERA_OPERATING_MODE_SINGLE);
        Camera camera = bindToLifecycle(lifecycleOwner, cameraSelector, null, emptyList(),
                useCases);
        return camera;
    }

因为我们需要获取所有可用的摄像头类似旧版的CameraId

将下面代码放入activity获取

   val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
        cameraProviderFuture.addListener({
            LogUtils.log("摄像头结果返回")
            val cameraProvider = cameraProviderFuture.get()
            var textC = ""
            val cameraInfos = cameraProvider.availableCameraInfos
            var isSupportBack = false
            var isSupportFront = false
            var isExternal = false
            var isUnknow = false
            for (cameraInfo in cameraInfos) {
                when (cameraInfo.lensFacing) {
                    CameraSelector.LENS_FACING_FRONT -> {
                        isSupportFront = true
                        textC += "\n前置 lensFacing:[${cameraInfo.lensFacing},${cameraInfo.cameraSelector}]"

                    }

                    CameraSelector.LENS_FACING_BACK -> {
                        isSupportBack = true
                        textC += "\n后置 lensFacing:[${cameraInfo.lensFacing},${cameraInfo.cameraSelector}]"

                    }

                    CameraSelector.LENS_FACING_EXTERNAL -> {
                        isExternal = true
                        textC += "\n外置 lensFacing:[${cameraInfo.lensFacing},${cameraInfo.cameraSelector}]"
                    }

                    CameraSelector.LENS_FACING_UNKNOWN -> {
                        isUnknow = true
                        textC += "\n未知 lensFacing:[${cameraInfo.lensFacing},${cameraInfo.cameraSelector}]"

                    }
                }

            }


            LogUtils.logI(
                "init",
                "设备支持情况:后置:${isSupportBack},前置:${isSupportFront},外置:${isExternal},未知:${isUnknow}"
            )

            binding.tvCheckResult.text = "len:$textC\n" +
                    "设备支持情况:后置:${isSupportBack},前置:${isSupportFront},外置:${isExternal},未知:${isUnknow}"

        }, ContextCompat.getMainExecutor(this))

工业平板做的产品摄像头一般固定获取之后指定即可,也可以自己编辑优先级逻辑,下面是插两个摄像头的例子

可以使用上述打印的具体摄像头(推荐) 也可以自己bulid,自己build有局限性比如两个外置,你使用2去build就不行了

        val selector: CameraSelector = if (isSupportBack) {
            CameraSelector.DEFAULT_BACK_CAMERA
        } else if (isSupportFront) {
            CameraSelector.DEFAULT_FRONT_CAMERA
        } else if (isExternal) {
            CameraSelector.Builder().requireLensFacing(2)
                .build()
        } else if (isUnknow) {
            CameraSelector.Builder().requireLensFacing(1)
                .build()
        } else {
            CameraSelector.DEFAULT_BACK_CAMERA
        }

// 如果你使用的是surfaceview+cameraId 而且是多预览 

   val cameraManager =
            activity.getSystemService(AppCompatActivity.CAMERA_SERVICE) as CameraManager
      val cameraIds = cameraManager.cameraIdList
        for (cameraId in cameraIds) {
            val characteristics = cameraManager.getCameraCharacteristics(cameraId)
            val facing = characteristics.get(CameraCharacteristics.LENS_FACING)

        }

明确了cameraId 其他通过预览的示例代码 我也传一下吧,由于每个摄像头是独立 有多少个预览就new多少个出来 

class CameraUtils {

    val TAG = "CameraUtils"
    private var mCameraDevice: CameraDevice? = null
    private var mCaptureSession: CameraCaptureSession? = null
    private var mPreviewBuilder: CaptureRequest.Builder? = null

    fun bindSurfaceView(
        activity: Activity,
        surfaceView: SurfaceView,
        len: Int,
        cId: String?
    ): String {
        val cameraManager =
            activity.getSystemService(AppCompatActivity.CAMERA_SERVICE) as CameraManager
        surfaceView.holder.setFixedSize(9999, 9999)
        LogUtils.logI(TAG, "bindSurfaceView")
        val cameraId = cId ?: getCameraId(cameraManager, len)

        try {
            LogUtils.log("len:$len cameraId:$cameraId")
            if (TextUtils.isEmpty(cameraId)) {
                LogUtils.logE(TAG, "cameraId  null")
                return "cameraId  null"
            }
            if (ActivityCompat.checkSelfPermission(
                    activity,
                    Manifest.permission.CAMERA
                ) != PackageManager.PERMISSION_GRANTED
            ) {

                LogUtils.logE(TAG, "没有权限")
                return "没有权限"
            }
            cameraManager.openCamera(cameraId!!, object : CameraDevice.StateCallback() {
                override fun onOpened(camera: CameraDevice) {
                    LogUtils.logE(TAG, "onOpened cameraId:$cameraId")

                    mCameraDevice = camera
                    createCaptureSession(camera, surfaceView)
                }

                override fun onDisconnected(camera: CameraDevice) {
                    LogUtils.logE(TAG, "onDisconnected cameraId:$cameraId")
                }

                override fun onError(camera: CameraDevice, error: Int) {
                    LogUtils.logE(TAG, "onError:$error cameraId:$cameraId")
                }
            }, null)
        } catch (e: CameraAccessException) {
            e.printStackTrace()
            LogUtils.logE(TAG, "onError:$e")
            return "onError:$e"


        }
        return "cameraId:$cameraId"

    }


    /**
     * 创建CaptureSession
     */
    private fun createCaptureSession(camera: CameraDevice, surfaceView: SurfaceView) {
        try {
            surfaceView.run {

                val surfaceHolder: SurfaceHolder = getHolder()
                surfaceHolder.setFixedSize(getWidth(), getHeight())
                val surfaces: MutableList<Surface> = ArrayList()
                surfaces.add(surfaceHolder.surface)
                mPreviewBuilder = camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
                mPreviewBuilder?.addTarget(surfaceHolder.surface)
                camera.createCaptureSession(
                    surfaces,
                    object : CameraCaptureSession.StateCallback() {
                        override fun onConfigured(session: CameraCaptureSession) {
                            mCaptureSession = session
                            updatePreview()
                        }

                        override fun onConfigureFailed(session: CameraCaptureSession) {
                            // 配置会话失败
                        }
                    },
                    null
                )

            }

        } catch (e: CameraAccessException) {
            e.printStackTrace()
        }
    }

    private fun updatePreview() {
        if (mCameraDevice == null) {
            LogUtils.logE(TAG, "mCameraDevice null")
            return
        }
        if (mCaptureSession == null) {
            LogUtils.logE(TAG, "mCaptureSession null")
            return
        }

        if (mPreviewBuilder == null) {
            LogUtils.logE(TAG, "mPreviewBuilder null")
            return
        }
        LogUtils.logI(TAG, "updatePreview.")

        try {
            mCaptureSession?.setRepeatingRequest(mPreviewBuilder!!.build(), null, null)
        } catch (e: Exception) {
            e.printStackTrace()
            LogUtils.logE(TAG, "updatePreview: $e")
        }
    }


    @Throws(CameraAccessException::class)
    private fun getCameraId(cameraManager: CameraManager, len: Int): String? {
        val cameraIds = cameraManager.cameraIdList
        for (cameraId in cameraIds) {
            val characteristics = cameraManager.getCameraCharacteristics(cameraId)
            val facing = characteristics.get(CameraCharacteristics.LENS_FACING)
            //            CameraCharacteristics.LENS_FACING_BACK CameraCharacteristics.LENS_FACING_FRONT
            if (facing != null && facing == len) {
                return cameraId
            }
        }
        return null
    }

}

比如用RecyclerView 多个item预览  可以这样初始化

    fun getOneUtils(index: Int): CameraUtils {
        var cache = mCameraUnitsMap[index]
        if (cache == null) {
            cache = CameraUtils()
            mCameraUnitsMap[index] = cache
        }
        return cache
    }

使用

   val text = getOneUtils(position).bindSurfaceView(
                    this@CameraInfoActivity,
                    holder.getView(R.id.surfaceView),
                    len, cameraId
                )

如果是uniapp同学需要买相关插件的可以留言联系

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/937700.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

回归任务与分类任务应用及评价指标

能源系统中的回归任务与分类任务应用及评价指标 一、回归任务应用1.1 能源系统中的回归任务应用1.1.1 能源消耗预测1.1.2 负荷预测1.1.3 电池健康状态估计&#xff08;SOH预测&#xff09;1.1.4 太阳能发电量预测1.1.5 风能发电量预测 1.2 回归任务中的评价指标1.2.1 RMSE&…

shilei定标算法,测试的时候为什么有多解

设定P&#xff0c;找C12和C13时&#xff0c;如果找的是实数&#xff0c;则求解的P只需要保证是实数就能满足螺旋度 0方程

【echarts】数据过多时可以左右滑动查看(可鼠标可滚动条)

1. 鼠标左右拖动 在和 series 同级的地方配置 dataZoom&#xff1a; dataZoom: [{type: inside, // inside 鼠标左右拖图表&#xff0c;滚轮缩放&#xff1b; slider 使用滑动条start: 0, // 左边的滑块位置&#xff0c;表示从 0 开始显示end: 60, // 右边的滑块位置&#xf…

redis集群 服务器更换ip,怎么办,怎么更换redis集群的ip

redis集群 服务器更换ip&#xff0c;怎么办&#xff0c;怎么更换redis集群的ip 1、安装redis三主三从集群2、正常状态的redis集群3、更改redis集群服务器的ip 重启服务器 集群会down4、更改redis集群服务器的ip 重启服务器 集群down的原因5、更改redis集群服务器的ip后&#xf…

计算机网络知识点全梳理(一.TCP/IP网络模型)

目录 TCP/IP网络模型概述 应用层 什么是应用层 应用层功能 应用层协议 传输层 什么是传输层 传输层功能 传输层协议 网络层 什么是网络层 网络层功能 网络层协议 数据链路层 什么是数据链路层 数据链路层功能 物理层 物理层的概念和功能 写在前面 本系列文…

【Python爬虫实战】深入解析 Scrapy 管道:数据清洗、验证与存储的实战指南

&#x1f308;个人主页&#xff1a;易辰君-CSDN博客 &#x1f525; 系列专栏&#xff1a;https://blog.csdn.net/2401_86688088/category_12797772.html ​ 目录 前言 一、了解 Scrapy Shell 二、配置文件 settings.py &#xff08;一&#xff09;为什么需要配置文件 &…

PHPstudy中的数据库启动不了

法一 netstat -ano |findstr "3306" 查看占用该端口的进程号 taskkill /f /pid 6720 杀死进程 法二 sc delete mysql

Hu矩原理 | cv2中基于Hu矩计算图像轮廓相似度差异的函数cv2.matchShapes【小白记笔记】

Hu 矩&#xff08;Hu Moments&#xff09; 是一种用于描述轮廓形状的 不变特征。它基于图像的矩提取&#xff0c;经过数学变换得到 7 个不变矩&#xff0c;这些不变矩在图像 平移、旋转和缩放等几何变换下保持不变&#xff0c;适合用来衡量轮廓或形状的相似度差异。 1、图像矩…

Ilya Sutskever发表了对AI未来发展的颠覆性看法

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

网络层IP协议(TCP)

IP协议&#xff1a; 在了解IP协议之前&#xff0c;我们市面上看到的"路由器"其实就是工作在网络层。如下图&#xff1a; 那么网络层中的IP协议究竟是如何发送数据包的呢&#xff1f; IP报头&#xff1a; IP协议的报头是比较复杂的&#xff0c;作为程序猿只需要我们重…

【MySQL】InnoDB引擎中的Compact行格式

目录 1、背景2、数据示例3、Compact解释【1】组成【2】头部信息【3】隐藏列【4】数据列 4、总结 1、背景 mysql中数据存储是存储引擎干的事&#xff0c;InnoDB存储引擎以页为单位存储数据&#xff0c;每个页的大小为16KB&#xff0c;平时我们操作数据库都是以行为单位进行增删…

Visual Studio 玩转 IntelliCode AI辅助开发

&#x1f380;&#x1f380;&#x1f380;【AI辅助编程系列】&#x1f380;&#x1f380;&#x1f380; Visual Studio 使用 GitHub Copilot 与 IntelliCode 辅助编码Visual Studio 安装和管理 GitHub CopilotVisual Studio 使用 GitHub Copilot 扩展Visual Studio 使用 GitHu…

【LDAP】LDAP概念和原理介绍

目录 一、前言 二、什么是LDAP&#xff1f; 2.1 什么是目录服务&#xff1f; 2.2 LDAP的介绍 2.3 为什么要使用LDAP 三、LDAP的主要产品线 四、LDAP的基本模型 4.1 目录树概念 4.2 LDAP常用关键字列表 4.3 objectClass介绍 五、JXplorer工具使用 一、前言 对于许多的…

用ue5打开网址链接

需要用到 Launch URL 这个函数 字面意思就是打开填写的链接网页 这里填写的是百度&#xff0c;按下Tab键后就会打开百度的网页

在ESP32使用AT指令集与服务器进行TCP/IP通信时,<link ID> 解释

在ESP32使用AT指令集与服务器进行TCP/IP通信时&#xff0c;<link ID> 是一个非常重要的参数。它用于标识不同的连接实例&#xff0c;特别是在多连接场景下&#xff08;如同时建立多个TCP或UDP连接&#xff09;。每个连接都有唯一的<link ID>&#xff0c;通过这个ID…

前后端跨域问题(CROS)

前端 在src中创建util文件&#xff0c;写request.js文件&#xff1a; request.js代码如下&#xff1a; import axios from axios import { ElMessage } from element-plus;const request axios.create({// baseURL: /api, // 注意&#xff01;&#xff01; 这里是全局统一加…

学习笔记071——Java中的【线程】

文章目录 1、基础2、进程和线程3、什么是多线程4、Java 中线程的使用5、Java 中创建线程的方式5.1、继承 Thread 类5.2、实现 Runnable 接口5.3、继承 Thread 和实现 Runnable 接口的区别5.4、实现 Runnable 接口的优化 6、线程的状态7、线程调度7.1、线程休眠7.2、线程合并7.3…

devops-部署Harbor实现私有Docker镜像仓库

文章目录 概述下载配置安装安装后生成的文件使用和维护Harbor参考资料 概述 Harbor是一个开源注册中心&#xff0c;它使用策略和基于角色的访问控制来保护工件&#xff0c;确保镜像被扫描并且没有漏洞&#xff0c;并将镜像签名为可信的。Harbor是CNCF的一个毕业项目&#xff0…

快速上手Neo4j图关系数据库

参考视频&#xff1a; 【IT老齐589】快速上手Neo4j网状关系图库 1 Neo4j简介 Neo4j是一个图数据库&#xff0c;是知识图谱的基础 在Neo4j中&#xff0c;数据的基本构建块包括&#xff1a; 节点(Nodes)关系(Relationships)属性(Properties)标签(Labels) 1.1 节点(Nodes) 节点…

Polkadot 11 月生态月报:3900万交易量、69%增长率,技术与社区齐头并进

原文&#xff1a;https://x.com/Polkadot/status/1865118662069490074 编译&#xff1a;OneBlock 上个月对 Polkadot 生态来说可谓是跌宕起伏&#xff0c;从创下交易记录到开创性合作&#xff0c;Polkadot 热度不断。展现出强大的技术实力和蓬勃发展的社区活力。在回顾本月亮点…