Android Camera2 API 后台服务

最近在搞CameraAPP需要将Camera2弄成一个后台服务,发现跟预览的Activity没多大变动只是加了Service,和一些简单的修改。之前的公司也用到Camera2,发现用到的时候还是蛮多的所以记录一下,代码在文章末尾

camera2的结构如下,主要是通过相机管理器(CameraManager)获得相机设备(CameraDevice),然后再开启一个控制相机的会话,最后发送 拍照、预览、录像等请求。

Camera流程大概如下

1.获取Camera2服务管理器,遍历摄像头,打开每一个摄像头

    public void onCreate() {super.onCreate();mActivity = this;//获取Camera管理器CameraManager manager = (CameraManager) this.getSystemService("camera");try {String[] ids = manager.getCameraIdList();mCameraNum = ids.length ;mCameraIds = ids;} catch (CameraAccessException e) {e.printStackTrace();}mBackgroundThread = new HandlerThread[mCameraNum];mBackgroundHandler = new Handler[mCameraNum];mCameraOpenCloseLock = new Semaphore[mCameraNum];mPreviewBuilder = new CaptureRequest.Builder[mCameraNum];mPreviewSession =new CameraCaptureSession[mCameraNum];mCameraDevice = new CameraDevice[mCameraNum];mStateCallback =new StateCallback[mCameraNum];mVideoSize = new Size[mCameraNum];mPreviewSize = new Size[mCameraNum];mImageReader = new RefCountedAutoCloseable[mCameraNum];mFrameListener = new FrameListener[mCameraNum];for (int i = 0; i < mCameraNum; i++) {mCameraOpenCloseLock[i]= new Semaphore(1);mStateCallback[i] = new StateCallback(i);}int width =1920;int height = 1080;mOpenCameraList.clear();//遍历摄像头,分别打开for (int i = 0; i < mCameraNum; i++) {int CameraId = Integer.valueOf(mCameraIds[i]);mFrameListener[i] = new FrameListener(CameraId,this);if(CameraId < 100 ){Log.e(TAG,"只打开USB摄像头 skip:"+mCameraIds[i]);continue;}mOpenCameraList.add(CameraId);startBackgroundThread(i);打开摄像头openCamera(i,width, height);}//设置前台服务bindNotification("Launcher 进程");}

1.获取摄像头参数,设置图像回调,打开摄像头

private void openCamera(int cameraNum, int width, int height) {if (!hasPermissionsGranted(VIDEO_PERMISSIONS)) {requestVideoPermissions();return;}CameraManager manager = (CameraManager) this.getSystemService(this.CAMERA_SERVICE);try {if (!mCameraOpenCloseLock[cameraNum].tryAcquire(2500, TimeUnit.MILLISECONDS)) {throw new RuntimeException("Time out waiting to lock camera opening.");}Log.e(TAG, String.valueOf(manager.getCameraIdList().length));String cameraId = manager.getCameraIdList()[cameraNum];mCameraIds[cameraNum] = cameraId;// Choose the sizes for camera preview and video recording获取摄像头的参数CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);if (map == null) {throw new RuntimeException("Cannot get available preview/video sizes");}mVideoSize[cameraNum] = new Size(4096,2160);mPreviewSize[cameraNum] = new Size(4096,2160);int orientation = getResources().getConfiguration().orientation;configureTransform(cameraNum,width, height);if (mImageReader[cameraNum] == null || mImageReader[cameraNum].getAndRetain() == null) {//设置摄像头的图像回调mImageReader[cameraNum] = new RefCountedAutoCloseable<>(ImageReader.newInstance(mPreviewSize[cameraNum].getWidth(),mPreviewSize[cameraNum].getHeight(), ImageFormat.YUV_420_888, /*maxImages*/5));}if (mImageReader[cameraNum] !=null){mImageReader[cameraNum].get().setOnImageAvailableListener(mFrameListener[cameraNum], mBackgroundHandler[cameraNum]);}Log.d(TAG,"openCamera:"+cameraId);//打开摄像头,打开成功会调用到 mStateCallback.onOpenedmanager.openCamera(cameraId, mStateCallback[cameraNum], null);} catch (CameraAccessException e) {} catch (NullPointerException e) {} catch (InterruptedException e) {throw new RuntimeException("Interrupted while trying to lock camera opening.");}
}
class StateCallback extends CameraDevice.StateCallback {int cameraNum;public StateCallback(int cameraNum) {super();this.cameraNum = cameraNum;}//打开成功会调用到这里@Overridepublic void onOpened(@NonNull CameraDevice cameraDevice) {mCameraDevice[cameraNum] = cameraDevice;startPreview(cameraNum);mCameraOpenCloseLock[cameraNum].release();}@Overridepublic void onDisconnected(@NonNull CameraDevice cameraDevice) {mCameraOpenCloseLock[cameraNum].release();cameraDevice.close();mCameraDevice[cameraNum] = null;}@Overridepublic void onError(@NonNull CameraDevice cameraDevice, int error) {mCameraOpenCloseLock[cameraNum].release();cameraDevice.close();mCameraDevice[cameraNum] = null;}};

1.打开成功开始重定向输出对象到ImageReader

    private void startPreview(final int cameraNum) {if (null == mCameraDevice[cameraNum]  || null == mPreviewSize[cameraNum]) {return;}try {closePreviewSession(cameraNum);//设置Camera为预览输出mPreviewBuilder[cameraNum] = mCameraDevice[cameraNum].createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);List<Surface> surfaces;//获取mImageReader的SureFace ,就能通过ImageReader的图像回调获取数据mPreviewBuilder[cameraNum].addTarget(mImageReader[cameraNum].get().getSurface());surfaces = Arrays.asList(mImageReader[cameraNum].get().getSurface());mCameraDevice[cameraNum].createCaptureSession(surfaces,new CameraCaptureSession.StateCallback() {@Overridepublic void onConfigured(@NonNull CameraCaptureSession session) {mPreviewSession[cameraNum] = session;updatePreview(cameraNum);}@Overridepublic void onConfigureFailed(@NonNull CameraCaptureSession session) {}}, mBackgroundHandler[cameraNum]);} catch (CameraAccessException e) {e.printStackTrace();}}

图像数据回调

class FrameListener implements   ImageReader.OnImageAvailableListener{int cameraNum;Context context;public FrameListener(int cameraNum, Context context) {this.cameraNum = cameraNum;this.context = context;}long frameID = 0;@Overridepublic void onImageAvailable(ImageReader reader) {Image image = reader.acquireNextImage();if (image !=null) {frameID++;int width = image.getWidth();//1920int height = image.getHeight();//1080//摄像头1920*1080 y长度2073600,uv1036800//获取y数据地址ByteBuffer ybuffer = image.getPlanes()[0].getBuffer();//u数据地址,一般uv数据都是交替存放,所以这里包含有uv的数据ByteBuffer ubuffer = image.getPlanes()[1].getBuffer();//ByteBuffer vbuffer = image.getPlanes()[2].getBuffer();int yLen = ybuffer.remaining();int uLen = ubuffer.remaining();int vLen = vbuffer.remaining();byte[] yBytes = new byte[yLen];byte[] uBytes = new byte[uLen];//byte[] vBytes = new byte[vLen];byte[] yuvBytes = new byte[3110400];ybuffer.get(yBytes);ubuffer.get(uBytes);//vbuffer.get(vBytes);System.arraycopy(yBytes,0,yuvBytes,0,2073600);System.arraycopy(uBytes,0,yuvBytes,2073600,1036800);nativeReadImageBuf(width,height,image.getFormat(),yuvBytes, 3110400, mOpenCameraList.size(), mOpenCameraList.indexOf(cameraNum));image.close();}}}

当服务起来后会直接打开摄像头,获取回调数据

运行一段时间后服务自动停止,原因是没有和APP活动在同一个生命周期

使用

        /*** 设置为前台服务* @param title*/
protected void bindNotification(String title){String CHANNEL_ONE_ID = "com.example.android.camera2videopushnew";String CHANNEL_ONE_NAME = "com.example.android.camera2videopushnew.name";Notification notification = null;NotificationChannel notificationChannel = new NotificationChannel(CHANNEL_ONE_ID,CHANNEL_ONE_NAME, NotificationManager.IMPORTANCE_LOW);notificationChannel.enableLights(false);notificationChannel.setLightColor(Color.RED);notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);manager.createNotificationChannel(notificationChannel);notification = new Notification.Builder(this,CHANNEL_ONE_ID).setContentTitle(title).setContentText(title).build();notification.flags |= Notification.FLAG_NO_CLEAR;startForeground(1, notification);}

结束

APP代码链接:【免费】AndroidCamera2后台服务APP资源-CSDN文库

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

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

相关文章

Peter算法小课堂—Dijkstra最短路算法

大家好&#xff0c;我们人见人爱、花见花开、车见车爆胎的Peter Pan来啦&#xff0c;hia~hia~hia。今天&#xff0c;我们今天来学习毒瘤的最短路算法啦。啊这……什么是Dijkstra算法&#xff1f;长文警告⚠ 正经点啊 手算样例 大家思考一下&#xff0c;你在手算样例的时候&am…

企业申请sectigo ip https证书

Sectigo&#xff08;原名Comodo&#xff0c;在整合https证书业务后改名为Sectigo&#xff09;是一家知名的数字证书提供商&#xff0c;拥有多种类型的数字证书&#xff0c;例如单域名https证书、多域名https证书、通配符https证书、IP https证书和代码签名证书等满足各类用户的…

2024022期传足14场胜负前瞻

2024022期赛事由英超4场&#xff0c;德甲2场、意甲4场、西甲4场组成。售止时间为2月4日&#xff08;周日&#xff09;19点00分&#xff0c;敬请留意&#xff1a; 本期中深盘较多&#xff0c;1.5以下赔率3场&#xff0c;1.5-2.0赔率7场&#xff0c;其他场次是平半盘、平盘。本期…

TCP 协议的相关特性

1. TCP格式 TCP特性&#xff1a;有连接&#xff0c;全双关&#xff0c;面向字节流&#xff0c;可靠传输。&#xff08;TCP安身立命的本钱&#xff0c;初心就是解决“可靠传输”问题&#xff09; 其实TCP的特征有很多这里我就简单的介绍几个。 2. 确认应答 其实用来确保可靠性&…

Java并发基础:CountDownLatch全面解析!

内容概要 CountDownLatch的优点在于能够简洁高效地协调多个线程的执行顺序&#xff0c;确保一组线程都完成后才触发其他线程的执行&#xff0c;适用于资源加载、任务初始化等场景。它提供了清晰的等待/通知机制&#xff0c;易于理解和使用&#xff0c;是提升多线程程序性能和可…

面试数据结构与算法总结分类+leetcode题目目录【基础版】

&#x1f9e1;&#x1f9e1;&#x1f9e1;算法题目总结&#xff1a; 这里为大家总结数据结构与算法的题库目录&#xff0c;如果已经解释过的题目会标注链接更新&#xff0c;方便查看。 数据结构概览 Array & String 大家对这两类肯定比较清楚的&#xff0c;同时这也是面试…

Java基础—反射

Java基础-反射 前置知识动态语言JVM堆Java引用变量类型编译时类型运行时类型举栗特殊情况 RRTI概念为什么需要RTTI例子 Class类对象前置知识类加载器概念作用 Class类对象的概念Class类对象的总结 总结一下前置知识 反射基础概念为什么要学反射我需要学到什么程度 反射的基础内…

GMT绘图笔记

(1)图框设置。在利用GMT绘制图件时&#xff0c;需要设置边框的类型&#xff0c;字体的大小&#xff0c;标记距离边框的距离。主要涉及的参数有&#xff1a; gmt set MAP_FRAME_TYPE plain/fancy 可以调整边框为火车轨道或者线段。 (2)调整图框的粗细&#xff1a;主要是包含有…

解决vue3+ts打包,ts类型检查报错导致打包失败,goview打包报错options

最近拉的开源大屏项目goview&#xff0c;在打包的过程中一直报Ts类型报错导致打包失败&#xff0c;项目的打包命令为&#xff1a; “build”: “vue-tsc --noEmit && vite build” 是因为 vue-tsc --noEmit 是 TypeScript 编译器&#xff08;tsc&#xff09;的命令&…

Mov转MP4怎么转换?如何播放mov视频?

MOV文件格式的使用场景 MOV文件格式以其支持多种媒体数据类型的特性而闻名&#xff0c;包括视频、音频、文本、动画等。它常用于存储包含视频剪辑、电影、音频轨道等多媒体元素的文件。由于其在质量和编辑方面的优越性&#xff0c;MOV文件在电影制作、广告宣传、多媒体演示等领…

MySQL篇----第三篇

系列文章目录 文章目录 系列文章目录前言一、InnoDB与MyISAM的区别二、索引三、常见索引原则有前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 一、InnoDB与MyISAM…

【华为】GRE VPN 实验配置

【华为】GRE VPN 实验配置 前言报文格式 实验需求配置思路配置拓扑GRE配置步骤R1基础配置GRE 配置 ISP_R2基础配置 R3基础配置GRE 配置 PCPC1PC2 抓包检查OSPF建立GRE隧道建立 配置文档 前言 VPN &#xff1a;&#xff08;Virtual Private Network&#xff09;&#xff0c;即“…

【京东云新品发布月刊】2024年1月产品动态来啦

1&#xff09;【莫奈可视化平台】新品上线 京东莫奈可视化平台通过自由拖拽、图形化编辑、所见即所得的方式&#xff0c;快速实现极致酷炫、直观清晰的视觉场景&#xff0c;将海量繁杂数据背后所蕴含的价值更直观、深层、全面的展现出来&#xff0c;辅助决策者合理决策。 2&a…

Redis集群环境搭建

Redis集群环境搭建 Redis主从复制 概念 主从复制是指将一台Redis服务器的数据&#xff0c;复制到其他的Redis服务器&#xff0c;前者称为主节点(master/leader)&#xff0c;后者称为从节点(slave/followe)&#xff1b;数据的复制是单向的&#xff0c;只能从主节点到从节点&a…

学成在线: 新增/修改课程计划

新增/修改课程计划(同接口) 界面原型 第一步: 在课程计划界面,点击添加章新增第一级课程计划,点击添加小节可以向某个第一级课程计划下添加小节 新增章/节成功后会自动发起请求刷新课程计划列表并且把新增的课程计划信息添加到数据库当中,新增的课程计划自动排序到最后 第二…

CentOS 8 下载

https://mirrors.bfsu.edu.cn/centos/8-stream/isos/x86_64/ 下载地址&#xff1a; https://mirrors.bfsu.edu.cn/centos/8-stream/isos/x86_64/CentOS-Stream-8-x86_64-latest-dvd1.iso

喜报|博睿数据算力调度可观测平台荣获信通院“算力服务领航者计划”优秀案例

近日&#xff0c;中国通信标准化协会云计算标准和开源推进委员会2023年度工作总结会暨算力服务工作组成果发布会在京举行。会上&#xff0c;“2023年算力服务领航者计划优秀案例名单”正式公布&#xff0c;博睿数据的核心产品算力调度可观测平台 Bonree ONE成功入选&#xff0c…

数据结构----队列(Queue)的概念、队列的使用、模拟实现队列、循环队列、模拟实现循环队列、双端队列、模拟实现双端队列

文章目录 1 概念2 队列的使用3 队列模拟实现4 循环队列4.1 循环队列 概念4.1 循环队列模拟实现 5. 双端队列 (Deque)6 用队列实现栈7 用栈实现队列 1 概念 队列&#xff1a;只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表&#xff0c;队列具有…

LeetCode:283. 移动零

283. 移动零 1&#xff09;题目2&#xff09;代码方法一&#xff1a;两层for循环方法二&#xff1a;使用双指针 3&#xff09;结果方法一结果方法二结果 1&#xff09;题目 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的…

QT研究笔记(一)windows 开发环境安装部署

一、Qt 是什么&#xff1f; Qt 是一个跨平台的应用程序开发框架&#xff0c;最初由挪威的 Trolltech 公司开发&#xff0c;并于2008年被诺基亚收购。后来&#xff0c;Qt 框架由 Digia 公司接手&#xff0c;并在2012年成立了 The Qt Company。Qt 提供了一套丰富的工具和类库&am…