2s相机 android6,Android Camera2 使用总结

最近在做自定义相机相关的项目,网上查了资料都是有关android.hardware.Camera的资料,开始使用的才发现这个类已经废弃了。Android 5.0(21)之后android.hardware.Camera就被废弃了,取而代之的是全新的android.hardware.Camera2 。Android 5.0对拍照API进行了全新的设计,新增了全新设计的Camera v2 API,这些API不仅大幅提高了Android系统拍照的功能,还能支持RAW照片输出,甚至允许程序调整相机的对焦模式、曝光模式、快门等。

Camera2主要的类说明

CameraManager:摄像头管理器。这是一个全新的系统管理器,专门用于检测系统摄像头、打开系统摄像头。除此之外,调用CameraManager的getCameraCharacteristics(String)方法即可获取指定摄像头的相关特性。

CameraCharacteristics:摄像头特性。该对象通过CameraManager来获取,用于描述特定摄像头所支持的各种特性。

CameraDevice:代表系统摄像头。该类的功能类似于早期的Camera类。

CameraCaptureSession:这是一个非常重要的API,当程序需要预览、拍照时,都需要先通过该类的实例创建Session。而且不管预览还是拍照,也都是由该对象的方法进行控制的,其中控制预览的方法为setRepeatingRequest();控制拍照的方法为capture()。

CameraRequest和CameraRequest.Builder:当程序调用setRepeatingRequest()方法进行预览时,或调用capture()方法进行拍照时,都需要传入CameraRequest参数。CameraRequest代表了一次捕获请求,用于描述捕获图片的各种参数设置,比如对焦模式、曝光模式……总之,程序需要对照片所做的各种控制,都通过CameraRequest参数进行设置。CameraRequest.Builder则负责生成CameraRequest对象。

开启相机预览

开启相机请一定添加相关的相机权限,判断6.0以后添加动态权限的获取。如果相机预览出现黑屏多半就是因为没有相机权限而导致的

首页我们要设置相机相关的参数

CameraManager manager = (CameraManager) ctx.getSystemService(Context.CAMERA_SERVICE);

try {

//获取可用摄像头列表

for (String cameraId : manager.getCameraIdList()) {

//获取相机的相关参数

CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);

// 不使用前置摄像头。

Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);

if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {

continue;

}

StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);

if (map == null) {

continue;

}

// 检查闪光灯是否支持。

Boolean available = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);

mFlashSupported = available == null ? false : available;

mCameraId = cameraId;

Log.e(TAG," 相机可用 ");

return;

}

} catch (CameraAccessException e) {

e.printStackTrace();

} catch (NullPointerException e) {

//不支持Camera2API

}

}

通过getSystemService(Context.CAMERA_SERVICE);拿到了CameraManager 返回当前可用的相机列表,在这里你可以选择使用前置还是后置摄像头。CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);可以拿到当前相机的相关参数,在这里你可以进行相关的参数检查,例如检查闪光灯是否支持等。在这里我们拿到当前相机的cameraId后面使用。

拿到cameraId我们就可以调用CameraManager的openCamera(String cameraId, CameraDevice.StateCallback callback, Handler handler)打开相机了

CameraManager manager = (CameraManager) ctx.getSystemService(Context.CAMERA_SERVICE);

try {

//打开相机预览

manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);

} catch (CameraAccessException e) {

e.printStackTrace();

} catch (InterruptedException e) {

throw new RuntimeException("Interrupted while trying to lock camera opening.", e);

}

添加 CameraDevice.StateCallback 监听

我们需要对相机状态就行监听,以便在相机状态发生改变的时候做相应的操作。openCamera(String cameraId, CameraDevice.StateCallback callback, Handler handler)中CameraDevice.StateCallback就是对相机的状态改变的Callback

private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {

@Override

public void onOpened(@NonNull CameraDevice cameraDevice) {

mCameraDevice = cameraDevice;

//创建CameraPreviewSession

createCameraPreviewSession();

}

@Override

public void onDisconnected(@NonNull CameraDevice cameraDevice) {

cameraDevice.close();

mCameraDevice = null;

}

@Override

public void onError(@NonNull CameraDevice cameraDevice, int error) {

cameraDevice.close();

mCameraDevice = null;

}

};

创建 CameraCaptureSession

在onOpened()中我们可以拿到CameraDevice对象,在相机打开后需要创建CameraCaptureSession。

CameraCaptureSession是什么呢?由于Camera2是一套全新的API,所以它引用了管道的概念将安卓设备和摄像头之间联通起来,系统向摄像头发送 Capture 请求,而摄像头会返回 CameraMetadata。这一切建立在一个叫作 CameraCaptureSession的会话中。如下图:

1488625

2086682-e68d187e1240bfc5.png

这里我们需要预览相机的内容就需要创建CameraCaptureSession向相机发送Capture请求预览相机内容

/**

* 为相机预览创建新的CameraCaptureSession

*/

private void createCameraPreviewSession() {

try {

//设置了一个具有输出Surface的CaptureRequest.Builder。

mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);

mPreviewRequestBuilder.addTarget(mSurfaceHolder.getSurface());

//创建一个CameraCaptureSession来进行相机预览。

mCameraDevice.createCaptureSession(Arrays.asList(mSurfaceHolder.getSurface()),

new CameraCaptureSession.StateCallback() {

@Override

public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {

// 相机已经关闭

if (null == mCameraDevice) {

return;

}

// 会话准备好后,我们开始显示预览

mCaptureSession = cameraCaptureSession;

try {

// 自动对焦应

mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,

CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);

// 闪光灯

setAutoFlash(mPreviewRequestBuilder);

// 开启相机预览并添加事件

mPreviewRequest = mPreviewRequestBuilder.build();

//发送请求

mCaptureSession.setRepeatingRequest(mPreviewRequest,

null, mBackgroundHandler);

Log.e(TAG," 开启相机预览并添加事件");

} catch (CameraAccessException e) {

e.printStackTrace();

}

}

@Override

public void onConfigureFailed(

@NonNull CameraCaptureSession cameraCaptureSession) {

Log.e(TAG," onConfigureFailed 开启预览失败");

}

}, null);

} catch (CameraAccessException e) {

Log.e(TAG," CameraAccessException 开启预览失败");

e.printStackTrace();

}

}

首先我们创建了一个CaptureRequest 上面说过了我们需要跟相机通信只有通过CameraCaptureSession。而要和CameraCaptureSession通信就是发送请求。这里我们相当于在创建请求的一些参数。

createCaptureRequest(int); 也有很多参数可选。这里我们发送的是CameraDevice.TEMPLATE_PREVIEW也就是告诉相机我们只需要预览。更多参数如下

详细信息可以参考官网的API文档。

调用创建方法createCaptureSession(List outputs, CameraCaptureSession.StateCallback callback, Handler handler) 第一参数就是我们需要输出到的Surface列表,这里我们可以输出到一个SurfaceView中或者TextureView中。第二参数是对创建过程的一个回调方法,当onConfigured回调的时候说明CameraCaptureSession创建成功了。现在我们可以向CameraCaptureSession发送前面创建的好的预览相机请求了。调用mCaptureSession.setRepeatingRequest(mPreviewRequest,null, mBackgroundHandler); 这样我们就开启的相机的预览,在刚才添加的输出Surface对应的控件中我们可以看到摄像头的预览内容了。

拍照

当我们需要拍照并且得到相应的照片数据的时候和开启相机预览相同的操作,我们只需要向CameraCaptureSession发送我们创建好的请求就行,就像我们请求网络数据一样,封装好参数直接告诉CameraCaptureSession需要做什么由它去和相机建立通信并执行相应的操作。

对焦

/**

* 将焦点锁定为静态图像捕获的第一步。(对焦)

*/

private void lockFocus() {

try {

// 相机对焦

mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,

CameraMetadata.CONTROL_AF_TRIGGER_START);

// 修改状态

mState = STATE_WAITING_LOCK;

mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,

mBackgroundHandler);

} catch (CameraAccessException e) {

e.printStackTrace();

}

}

向CameraCaptureSession发送对焦请求,并且对对焦是否成功进行监听,在mCaptureCallback中对回调进行处理

/**

* 处理与JPEG捕获有关的事件

*/

private CameraCaptureSession.CaptureCallback mCaptureCallback

= new CameraCaptureSession.CaptureCallback() {

//处理

private void process(CaptureResult result) {

switch (mState) {

case STATE_PREVIEW: {

//预览状态

break;

}

case STATE_WAITING_LOCK: {

//等待对焦

Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);

if (afState == null) {

captureStillPicture();

} else if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||

CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) {

// CONTROL_AE_STATE can be null on some devices

Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);

if (aeState == null || aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {

mState = STATE_PICTURE_TAKEN;

//对焦完成

captureStillPicture();

} else {

runPrecaptureSequence();

}

}

break;

}

}

}

}

拍摄图片

对焦完成后我们就可以向CameraCaptureSession发送请求可以拍照了

/**

*

* 拍摄静态图片。

*/

private void captureStillPicture() {

try {

if ( null == mCameraDevice) {

return;

}

// 这是用来拍摄照片的CaptureRequest.Builder。

final CaptureRequest.Builder captureBuilder =

mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);

captureBuilder.addTarget(mImageReader.getSurface());

// 使用相同的AE和AF模式作为预览。

captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,

CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);

setAutoFlash(captureBuilder);

// 方向

int rotation = this.getWindowManager().getDefaultDisplay().getRotation();

captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation));

CameraCaptureSession.CaptureCallback CaptureCallback

= new CameraCaptureSession.CaptureCallback() {

@Override

public void onCaptureCompleted(@NonNull CameraCaptureSession session,

@NonNull CaptureRequest request,

@NonNull TotalCaptureResult result) {

showToast("Saved: " + mFile);

Log.d(TAG, mFile.toString());

unlockFocus();

}

};

//停止连续取景

mCaptureSession.stopRepeating();

//捕获图片

mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);

} catch (CameraAccessException e) {

e.printStackTrace();

}

}

相信看到这里代码已经不复杂了,组装好我们的请求然后用CameraCaptureSession发送这个请求就可以了。这里需要注意的是我们怎么拿到图片数据呢? 这里要说回在创建CameraCaptureSession时参数不是有一个输出的Surface列表么,在列表中添加一个ImageReader的Surface用户获取图片数据

mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),null).....

在ImageReader中对图片获取就行监听

mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler);

private final ImageReader.OnImageAvailableListener mOnImageAvailableListener

= new ImageReader.OnImageAvailableListener() {

@Override

public void onImageAvailable(ImageReader reader) {

//当图片可得到的时候获取图片并保存

mBackgroundHandler.post(new ImageSaver(reader.acquireNextImage(), mFile));

}

};

调用reader.acquireNextImage()我们就可以拿到当前的图片数据了。拍完后我们需要解锁焦点让相机回到预览状态,同样的我们发送请求就可以了

/**

* 解锁焦点

*/

private void unlockFocus() {

try {

// 重置自动对焦

mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,

CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);

setAutoFlash(mPreviewRequestBuilder);

mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,

mBackgroundHandler);

// 将相机恢复正常的预览状态。

mState = STATE_PREVIEW;

// 打开连续取景模式

mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback,

mBackgroundHandler);

} catch (CameraAccessException e) {

e.printStackTrace();

}

}

效果

1488625

GIF.gif

之前看了鸿神推送的Android 仿火萤视频桌面 神奇的LiveWallPaper 一文中提到了用相机来做壁纸也就是透明屏幕,项目地址https://github.com/songixan/Wallpaper 查看源码发现还是用的旧的CameraAPI,所以我在Demo中用Camera2API做了透明屏幕,有兴趣的可以去看下。 PS:后来在同事的小米2S(5.1.1)中测试发现出错了,初步猜测是分辨率的原因,目前正在解决中。有问题大家可以私信我 谢谢~

到此Camera2的学习就结束了,同样的如果你想用相机就行拍摄视频也是如此,用CameraCaptureSession发送相应的请求了就可以了,大家有兴趣可以做一做视频的拍摄。现在做微信的小10秒小视频拍摄也很简单了,思路很简单当用户按下拍摄按钮用CameraCaptureSession发送拍摄视频的请求,松开手指的时候相机恢复到预览状态。so easy~ 大家有兴趣可以尝试下。

作者:_小河马

链接:http://www.jianshu.com/p/73fed068a795

來源:简书

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

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

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

相关文章

CentOS 7上搭建Spark3.0.1+ Hadoop3.2.1分布式集群

CentOS 7上搭建Spark3.0.1 Hadoop3.2.1分布式集群 VMWare 安装CentOS 7使用Xshell连接虚拟机集群设置安装JDK 1.8SSH 免密登陆安装hadoop 3.2安装Spark 3.0.1总结VMWare 安装CentOS 7 推荐使用VMware Workstation Pro 16,下载安装即可。下载最新的CentOS 7 Minimal…

再见安卓 你好鸿蒙,安卓,再见!你好,鸿蒙系统!

今年9月份,华为宣布鸿蒙OS操作系统将面向手机发布,今年12月份正式开放开发者Beta版本。昨天,华为鸿蒙OS迎来里程碑式的新进展,开发者Beta版本如约而至,正式开启线上公测招募,我们也可以可以一睹鸿蒙系统真容…

Kubernetes 部署 Traefik Ingress 控制器 (1.7.12)

目录[-] . 一、Ingress 介绍. 二、Traefik 介绍. 三、部署 Ingress 控制器 Traefik. 1、Traefik 两种部署方式介绍. 2、创建 Traefik 配置文件. 3、将 Traefik 配置文件挂载到 ConfigMap. 4、设置 CA 证书. 5、给节点设置 Label. 6、创建 Traefik 服务账户与角色权限. 7、创建…

Git本地缓存问题 修改密码后git无法拉取

Git本地缓存问题 修改密码后git无法拉取 问题描述:使用正确的用户名和密码可以登录到Git代码仓库,但是在本地无法使用Git bash命令行的方式拉取代码。 问题原因:第一次使用Git bash方式拉取代码时,会根据当前的用户和密码生成一串…

Ext.Net常用方法

1、js(Ext)操作 Ext.Msg.alert(系统提示, 未连接血站,该功能暂时不能使用。); Ext.getCmp("id").getValue();Ext.getCmp("id").focus();Ext.getCmp("id").selectText(); //选中修改 if (!GridPanel1.hasSelec…

Pytorch 版YOLOV5训练自己的数据集

1、环境搭建 https://github.com/ultralytics/yolov5 2、安装需要的软件 pip install -U -r requirements.txt 3、准备数据 在data文件下建立上面三个文件(Annotations、images与ImageSets,labels后续我们脚本生成)其中Annotations存放xml…

使用SQL Server作业设置定时任务

1.开启SQL Server Agent服务 使用作业需要SQL Agent服务的支持,并且需要设置为自动启动,否则你的作业不会被执行。 以下步骤开启服务:开始-->>>运行-->>>输入"services.msc"-->>>进入服务,开启SQL Server Agent服…

ListView与GridView优化

前言 ListView是Android中最常用的控件,通过适配器来进行数据适配然后显示出来,而其性能是个很值得研究的话题。本文与你一起探讨Google I/O提供的优化Adapter方案,欢迎大家交流。 声明 欢迎转载,但请保留文章原始出处:) 博客园&…

2021安徽舒城中学高考成绩查询,2021安徽省地区高考成绩排名查询,安徽省高考各高中成绩喜报榜单...

怀宁中学芜湖2017年芜湖市高考文科头名是来自于芜湖师大附中的唐逸云,高考成绩653分。2017年芜湖市高考理科头名是来自于芜湖师大附中的茅志鹏,高考成绩676分。师大附中芜湖一中淮南淮南二中文科考生最高分631(市应届生第一名),理科考生最高分…

jsonp的简单学习

前言:说到AJAX就会不可避免的面临两个问题,第一个是AJAX以何种格式来交换数据?第二个是跨域的需求如何解决?这两个问题目前都有不同的解决方案,比如数据可以用自定义字符串或者用XML来描述,跨域可以通过服务…

win7台式计算机怎么连热点,怎么用台式电脑开热点,电脑怎么开热点win7

导读:手机是每个人的随身携带之物,手机的功能让越来越多的人痴迷其中,也正是因为这个原因,手机流量的消耗也越来越多,购买流量让我们花费了很多金钱,我们该如何解决这个问题呢?下面我们就一起来看看电脑的…

WebLogic11g-创建域(Domain)及基本配置

2019独角兽企业重金招聘Python工程师标准>>> 最近看到经常有人提问weblogic相关问题,所以闲暇之际写几篇博文(基于weblogic11),仅供大家参考。 具体weblogic的介绍以及安装,这里就不赘述了。 以域的创建开篇…

计算机教室规则英语作文,班级规则初中英语作文

【导语】无规则不成方圆,班级亦是如此,也拥有属于它的规章制度。下面是无忧考网为你整理的有关班级规则初中英语作文,希望你喜欢!【篇一】班级规则初中英语作文Students should get to school for a half-hour reading before 7:30. Everyone…

高拍仪拍照SDK开发(良田影像S300L|S500L)

高拍仪拍照SDK开发下载地址:点击下载 本SDK适用于:良田影像S300L|S500L 高拍仪如图: SDN开发包安装之后找到安装目录,如图: 大家找到各自需要的版本即可,需要注意的是如果需要上传图片到服务器的话&#…

gitlab的用户使用手册

最近比较忙,没时间写博客,今天来的早所以写一篇关于gitlab的使用手册分享给大家。目录一、账户/项目申请二、登陆与修改密码三、SSH Key导入四、上传/下载代码1、上传(用户系统为linux)2、下载(用户系统为linux&#x…

学计算机多久能拿证,计算机证书多久能领取 什么时候拿

计算机证书多久能领取,什么时候能拿,小编整理了相关信息,希望会对大家有所帮助!计算机证书什么时候能领取1、一般情况下是考试结束后50个工作日左右出成绩及出证。全国计算机等级考试证书一年两次考试。每年的3月与9月考试。2、证…

MySQL_0

2019独角兽企业重金招聘Python工程师标准>>> 网址: http://www.mysqlpub.com 转载于:https://my.oschina.net/u/194743/blog/160145

TensorFlow 2.0 mnist手写数字识别(CNN卷积神经网络)

TensorFlow 2.0 (五) - mnist手写数字识别(CNN卷积神经网络) 源代码/数据集已上传到 Github - tensorflow-tutorial-samples 大白话讲解卷积神经网络工作原理,推荐一个bilibili的讲卷积神经网络的视频,up主从youtube搬运过来,用中文讲了一遍。…

职业梦想是计算机的英语作文,理想职业英语作文2篇

篇一:大学英语作文之我理想的工作my ideal jobMy Ideal JobAs college students, we will step into the society, and now we need to prepare for our future and arrange for our future career life, we need to take into consideration what to do in the fut…