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

news2024/12/19 23:15:21

在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同学需要买相关插件的可以留言联系

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

R语言学习笔记-1

1. 基础操作和函数 清空环境&#xff1a;rm(list ls()) 用于清空当前的R环境。 打印输出&#xff1a;print("Hello, world") 用于输出文本到控制台。 查看已安装包和加载包&#xff1a; search()&#xff1a;查看当前加载的包。install.packages("package_na…

Windows如何安装go环境,离线安装beego

一、安装go 1、下载go All releases - The Go Programming Language 通过网盘分享的文件&#xff1a;分享的文件 链接: https://pan.baidu.com/s/1MCbo3k3otSoVdmIR4mpPiQ 提取码: hxgf 下载amd64.zip文件&#xff0c;然后解压到指定的路径 2、配置环境变量 需要新建两个环境…

Mac上使用ln指令创建软链接、硬链接

在Mac、Linux和Unix系统中&#xff0c;软连接&#xff08;Symbolic Link&#xff09;和硬连接&#xff08;Hard Link&#xff09;是两种不同的文件链接方式。它们的主要区别如下&#xff1a; 区别&#xff1a; 硬连接&#xff1a; 不能跨文件系统。不能链接目录&#xff08;为…

Unity A*算法实现+演示

注意&#xff1a; 本文是对基于下方文章链接的理论&#xff0c;并最终代码实现&#xff0c;感谢作者大大的描述&#xff0c;非常详细&#xff0c;流程稍微做了些改动&#xff0c;文末有工程网盘链接&#xff0c;感兴趣的可以下载。 A*算法详解(个人认为最详细,最通俗易懂的一…

博弈论3:图游戏SG函数(Graph Games)

目录 一、图游戏是什么 1.游戏特征 2.游戏实例 二、图游戏的必胜策略 1.SG 函数&#xff08;Sprague-Grundy Function&#xff09; 2.必胜策略&#xff08;利用SG函数&#xff09; 3.拿走游戏转化成图游戏&#xff08;Take-away Game -> Graph Game&#xff09; 一、图…

0101多级nginx代理websocket配置-nginx-web服务器

1. 前言 项目一些信息需要通过站内信主动推动给用户&#xff0c;使用websocket。web服务器选用nginx&#xff0c;但是域名是以前通过阿里云申请的&#xff0c;解析ip也是阿里云的服务器&#xff0c;甲方不希望更换域名。新的系统需要部署在内网服务器&#xff0c;简单拓扑图如…

qt-C++笔记之自定义类继承自 `QObject` 与 `QWidget` 及开发方式详解

qt-C笔记之自定义类继承自 QObject 与 QWidget 及开发方式详解 code review! 参考笔记 1.qt-C笔记之父类窗口、父类控件、对象树的关系 2.qt-C笔记之继承自 QWidget和继承自QObject 并通过 getWidget() 显示窗口或控件时的区别和原理 3.qt-C笔记之自定义类继承自 QObject 与 QW…

Elastic 8.17:Elasticsearch logsdb 索引模式、Elastic Rerank 等

作者&#xff1a;来自 Elastic Brian Bergholm 今天&#xff0c;我们很高兴地宣布 Elastic 8.17 正式发布&#xff01; 紧随一个月前发布的 Elastic 8.16 之后&#xff0c;我们将 Elastic 8.17 的重点放在快速跟踪关键功能上&#xff0c;这些功能将带来存储节省和搜索性能优势…

[C++]类的继承

一、什么是继承 1.定义&#xff1a; 在 C 中&#xff0c;继承是一种机制&#xff0c;允许一个类&#xff08;派生类&#xff09;继承另一个类&#xff08;基类&#xff09;的成员&#xff08;数据和函数&#xff09;。继承使得派生类能够直接访问基类的公有和保护成员&#xf…

Docker 用法详解

文章目录 一、Docker 快速入门1.1 部署 MYSQL1.2 命令解读&#xff1a; 二、Docker 基础2.1 常见命令&#xff1a;2.1.1 命令介绍&#xff1a;2.1.2 演示&#xff1a;2.1.3 命令别名&#xff1a; 2.2 数据卷&#xff1a;2.2.1 数据卷简介&#xff1a;2.2.2 数据卷命令&#xff…

【自动化】Python SeleniumUtil 油猴 工具 自动安装用户脚本

【自动化】Python SeleniumUtil 油猴 工具 【自动化】Python SeleniumUtil 工具-CSDN博客【自动化】Python SeleniumUtil 工具。https://blog.csdn.net/G971005287W/article/details/144565691 油猴工具 import timefrom selenium.webdriver.support.wait import WebDriverW…

盛元广通畜牧与水产品检验技术研究所LIMS系统

一、系统概述 盛元广通畜牧与水产品检验技术研究所LIMS系统集成了检测流程管理、样品管理、仪器设备管理、质量控制、数据记录与分析、合规性管理等功能于一体&#xff0c;能够帮助实验室实现全流程的数字化管理。在水产、畜牧产品的质检实验室中&#xff0c;LIMS系统通过引入…

clickhouse-数据库引擎

1、数据库引擎和表引擎 数据库引擎默认是Ordinary&#xff0c;在这种数据库下面的表可以是任意类型引擎。 生产环境中常用的表引擎是MergeTree系列&#xff0c;也是官方主推的引擎。 MergeTree是基础引擎&#xff0c;有主键索引、数据分区、数据副本、数据采样、删除和修改等功…

GEE+本地XGboot分类

GEE本地XGboot分类 我想做提取耕地提取&#xff0c;想到了一篇董金玮老师的一篇论文&#xff0c;这个论文是先提取的耕地&#xff0c;再做作物分类&#xff0c;耕地的提取代码是开源的。 但这个代码直接在云端上进行分类&#xff0c;GEE会爆内存&#xff0c;因此我准备把数据下…

Docker搭建kafka环境

系统&#xff1a;MacOS Sonoma 14.1 Docker版本&#xff1a;Docker version 27.3.1, build ce12230 Docker desktop版本&#xff1a;Docker Desktop 4.36.0 (175267) 1.拉取镜像 先打开Docker Desktop&#xff0c;然后在终端执行命令 docker pull lensesio/fast-data-dev …

校园点餐订餐外卖跑腿Java源码

简介&#xff1a; 一个非常实用的校园外卖系统&#xff0c;基于 SpringBoot 和 Vue 的开发。这一系统源于黑马的外卖案例项目 经过站长的进一步改进和优化&#xff0c;提供了更丰富的功能和更高的可用性。 这个项目的架构设计非常有趣。虽然它采用了SpringBoot和Vue的组合&am…

Linux文件属性 --- 硬链接、所有者、所属组

三、硬链接数 1.目录 使用“ll”命令查看&#xff0c;在文件权限的后面有一列数字&#xff0c;这是文件的硬链接数。 对于目录&#xff0c;硬链接的数量是它具有的直接子目录的数量加上其父目录和自身。 下图的“qwe”目录就是“abc”目录的直接子目录。 2.文件 对于文件可…

Centos7 部署ZLMediakit

1、拉取代码 #国内用户推荐从同步镜像网站gitee下载 git clone --depth 1 https://gitee.com/xia-chu/ZLMediaKit cd ZLMediaKit #千万不要忘记执行这句命令 git submodule update --init 2、安装编译器 sudo yum -y install gcc 3、安装cmake sudo yum -y install cmake 4…

无管理员权限 LCU auth-token、port 获取(全网首发 go)

一&#xff1a; 提要&#xff1a; 参考项目&#xff1a; https://github.com/Zzaphkiel/Seraphine 想做一个 lol 查战绩的软件&#xff0c;并且满足自己的需求&#xff08;把混子和大爹都表示出来&#xff09;&#xff0c;做的第一步就是获取 lcu token &#xff0c;网上清一色…

《云原生安全攻防》-- K8s安全框架:认证、鉴权与准入控制

从本节课程开始&#xff0c;我们将来介绍K8s安全框架&#xff0c;这是保障K8s集群安全比较关键的安全机制。接下来&#xff0c;让我们一起来探索K8s安全框架的运行机制。 在这个课程中&#xff0c;我们将学习以下内容&#xff1a; K8s安全框架&#xff1a;由认证、鉴权和准入控…