原文:android Camera2 API使用详解

由于最近需要使用相机拍照等功能,鉴于老旧的相机API问题多多,而且新的设备都是基于安卓5.0以上的,于是本人决定研究一下安卓5.0新引入的Camera2 API 来实现 Camera2API地址

首先我们来熟悉一下官方给的这几个图:

这里引用了管道的概念将安卓设备和摄像头之间联通起来,系统向摄像头发送
Capture 请求,而摄像头会返回 CameraMetadata。这一切建立在一个叫作 CameraCaptureSession 的会话中。

其中 CameraManager 是那个站在高处统管所有摄像投设备(CameraDevice)的管理者,而每个 CameraDevice 自己会负责建立 CameraCaptureSession 以及建立 CaptureRequest。CameraCharacteristics 是 CameraDevice 的属性描述类,非要做个对比的话,那么它与原来的 CameraInfo 有相似性。 类图中有着三个重要的 callback,虽然这增加了阅读代码的难度,但是你必须要习惯,因为这是新包的风格。其中 CameraCaptureSession.CaptureCallback
将处理预览和拍照图片的工作,需要重点对待。这些类是如何相互配合的?下面是简单的流程图。

有了这三张图,那么接下来就好了理解了,我们按照拍照流程的指示,来吧整个过程走一遍

1首先定义一个SufaceView 用来实现预览照片用

surfaceView=(SurfaceView)
findViewById(R.id.surfaceView);

surfaceHolder.addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
initCamera();
} @Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override
public void surfaceDestroyed(SurfaceHolder holder) { }
});
其中initCamera2()方法是用来初始化相机的方法
2获取Camera ID,该ID是用来打开相机的关键,一般后置摄像头是0,前置摄像头是1,这里我们选择后置摄像头做详解

mCameraID = "" + CameraCharacteristics.LENS_FACING_BACK;//后摄像头

3通过Camera ID 来打开摄像头,这里我们需要使用CamerManager,这是类是一个管理服务类,值得注意的是,打开摄像头是一个相当复杂的过程,不能直接在主线程中直接执行,其核心代码为:

HandlerThread handlerThread=new HandlerThread("Camera2");
handlerThread.start();
childHandler=new Handler(handlerThread.getLooper());
mainHandler=new Handler(getMainLooper());

mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() { //可以在这里处理拍照得到的临时照片 例如,写入本地
@Override
public void onImageAvailable(ImageReader reader) {
mCameraDevice.close();
surfaceView.setVisibility(View.GONE);
iv_show.setVisibility(View.VISIBLE);
// 拿到拍照照片数据
Image image = reader.acquireNextImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);//由缓冲区存入字节数组
final Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
if (bitmap != null) {
iv_show.setImageBitmap(bitmap);
}
}
}, mainHandler);

cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
return;
}
//打开摄像头
cameraManager.openCamera(mCameraID, stateCallback, mainHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}

注意打开摄像头需要权限:

<uses-permission android:name="android.permission.CAMERA"></uses-permission>

4 开启相机后有一个回调,stateCallback,该回调是用来返回相机是否正常打开的状态的
private CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(CameraDevice camera) {//打开摄像头
mCameraDevice = camera;
//开启预览
takePreview();
} @Override
public void onDisconnected(CameraDevice camera) {//关闭摄像头
if (null != mCameraDevice) {
mCameraDevice.close();
MainActivity.this.mCameraDevice = null;
}
} @Override
public void onError(CameraDevice camera, int error) {//发生错误
Toast.makeText(MainActivity.this, "摄像头开启失败", Toast.LENGTH_SHORT).show();
}
};

5 相机开启成功后,执行回调中的onOpen方法,在该方法中,我们实现让图像显示在界面上
/**
* 开始预览
*/
private void takePreview() {
try {
// 创建预览需要的CaptureRequest.Builder
final CaptureRequest.Builder previewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
// 将SurfaceView的surface作为CaptureRequest.Builder的目标
previewRequestBuilder.addTarget(surfaceHolder.getSurface());
// 创建CameraCaptureSession,该对象负责管理处理预览请求和拍照请求
mCameraDevice.createCaptureSession(Arrays.asList(surfaceHolder.getSurface(), mImageReader.getSurface()), new CameraCaptureSession.StateCallback() // ③
{
@Override
public void onConfigured(CameraCaptureSession cameraCaptureSession) {
if (null == mCameraDevice) return;
// 当摄像头已经准备好时,开始显示预览
mCameraCaptureSession = cameraCaptureSession;
try {
// 自动对焦
previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
// 打开闪光灯
previewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
// 显示预览
CaptureRequest previewRequest = previewRequestBuilder.build();
mCameraCaptureSession.setRepeatingRequest(previewRequest, null, childHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
} @Override
public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
Toast.makeText(MainActivity.this, "配置失败", Toast.LENGTH_SHORT).show();
}
}, childHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
6,预览完成后,接下来就是拍照了,注意某些手机的摄像头会和正常手机的摄像头另类,成像会成180度的倒立像,比如nexus 5x,这时候只需要设置
rORIENTATIONS的值来调整角度就可以
/**
* 拍照
*/
private void takePicture() {
if (mCameraDevice == null) return;
// 创建拍照需要的CaptureRequest.Builder
final CaptureRequest.Builder captureRequestBuilder;
try {
captureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
// 将imageReader的surface作为CaptureRequest.Builder的目标
captureRequestBuilder.addTarget(mImageReader.getSurface());
// 自动对焦
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
// 自动曝光
captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
// 获取手机方向
int rotation = getWindowManager().getDefaultDisplay().getRotation();
// 根据设备方向计算设置照片的方向
captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation)+rORIENTATIONS);
//拍照
CaptureRequest mCaptureRequest = captureRequestBuilder.build();
mCameraCaptureSession.capture(mCaptureRequest, null, childHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}

android Camera2 API使用详解的更多相关文章

  1. Android API Levels 详解

    Android API Levels 当你开发你的Android应用程序时,了解该平台API变更管理的基本方法和概念是很有帮助的.同样的,知道API级别标识以及该标识如何保障你的应用与实际硬件设备相兼 ...

  2. 《Android NFC 开发实战详解 》简介+源码+样章+勘误ING

    <Android NFC 开发实战详解>简介+源码+样章+勘误ING SkySeraph Mar. 14th  2014 Email:skyseraph00@163.com 更多精彩请直接 ...

  3. 给 Android 开发者的 RxJava 详解

    我从去年开始使用 RxJava ,到现在一年多了.今年加入了 Flipboard 后,看到 Flipboard 的 Android 项目也在使用 RxJava ,并且使用的场景越来越多 .而最近这几个 ...

  4. [转]ANDROID L——Material Design详解(动画篇)

    转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 转自:http://blog.csdn.net/a396901990/article/de ...

  5. android shape的使用详解以及常用效果(渐变色、分割线、边框、半透明阴影效果等)

    shape使用.渐变色.分割线.边框.半透明.半透明阴影效果. 首先简单了解一下shape中常见的属性.(详细介绍参看  api文档 ) 转载请注明:Rflyee_大飞: http://blog.cs ...

  6. Android屏幕适配问题详解

    上篇-Android本地化资源目录详解 :http://www.cnblogs.com/steffen/p/3833048.html 单位: px(像素):屏幕上的点. in(英寸):长度单位. mm ...

  7. Android本地化资源目录详解

    我们可以设想,有两个不同分辨率的手机(320*480和480*800)要使用一些图像资源,为了使图像不失真,就需要为不同分辨率的手机指定不同的图像,为此就需要建立不同的资源目录. 在res目录中建立了 ...

  8. Android的init过程详解(一)

    Android的init过程详解(一) Android的init过程(二):初始化语言(init.rc)解析 本文使用的软件版本 Android:4.2.2 Linux内核:3.1.10 本文及后续几 ...

  9. android ------- 开发者的 RxJava 详解

    在正文开始之前的最后,放上 GitHub 链接和引入依赖的 gradle 代码: Github: https://github.com/ReactiveX/RxJava https://github. ...

随机推荐

  1. margin隐藏最后的切割线

    <style> *{margin: 0;padding: 0;} #demo li{ border-bottom: 1px solid #ccc; } #demo ul{ margin-b ...

  2. Android菜鸟的成长笔记(27)——SurfaceView的使用

    前面有关自定义View中进行了绘图,但View的绘图机制存在如下缺陷: 1.View缺乏双缓冲机制. 2.当程序需要更新View上的图像时,程序必须重绘View上显示的整张图片. 3.新线程无法直接更 ...

  3. Java 常用工具类---- 各种字符集编码判断与转换

    import java.io.UnsupportedEncodingException; /** * 判断字符编码 * * @author guyinyihun */ public class Cha ...

  4. Android组件——使用DrawerLayout仿网易新闻v4.4侧滑菜单

    摘要: 转载请注明出处:http://blog.csdn.net/allen315410/article/details/42914501 概述        今天这篇博客将记录一些关于DrawerL ...

  5. 【37.07%】【UESTC 360】Another LCIS

    Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Submit  Status F ...

  6. 阿里云centos 6.5 32位安装可视化界面的方法

    http://www.dzbfsj.com/forum.php?mod=viewthread&tid=2702 http://www.mayanpeng.cn/?p=507 http://bl ...

  7. 安全配置基线Linux系统

    Linux系统安全配置基线 一:共享账号检查 配置名称:用户账号分配检查,避免共享账号存在 配置要求:1.系统需按照实际用户分配账号: 2.避免不同用户间共享账号,避免用户账号和服务器间通信使用的账号 ...

  8. 古语云:工欲善其事必先利其器 --> 最新、最全的 IntelliJ IDEA(2018.3.3) 的介绍、安装、破解、配置与使用

    原文:古语云:工欲善其事必先利其器 --> 最新.最全的 IntelliJ IDEA(2018.3.3) 的介绍.安装.破解.配置与使用 一.IntelliJ IDEA 介绍 -> Ecl ...

  9. 创建数据库以及其属性的sql语句

    创建数据库的SQL语句: create database stuDB on primary -- 默认就属于primary文件组,可省略 ( /*--数据文件的详细描写叙述--*/ name='stu ...

  10. nil和Nil和NULL的判断

    ,nil和Nil和NULL的判断 开 发过程中,我们通过http请求,后台返回json数据,而有时数据里某一字段的值为null-,然后我们把此值赋值给 NSArray,NSdictionary,或是N ...