新的相机API也就是Camera2是在Android 5.0引进的。通常情况下,我们都是使用Android旧的相机API,纵然在Android Studio里老是提示已经废弃,但是只要都能用,也就没必要单独为了使用新的API而写两套代码。那为什么要介绍Camera2的使用呢?一切问题的根源都是多样化的需求引起的,特别是在Android领域,兼容性问题更是层出不穷。经常会碰到,其他手机都可以,怎么就这个不行……

  我也是跟大家一样,碰到了一个跟相机有关的兼容性问题。我们APP在进行活体识别的时候,除了要进行每个frame的检测同时也要进行当前活体检测的视频录制,使用的都是旧的相机API。在多样化机型测试下,我们发现在红米Note2和魅族MX5下,无法正常的同时进行活体检测和视频录制,换得更技术一点的说法就是,在旧的API下,Camera.PreviewCallback和MediaRecorder不能同时进行。怎么办?google 来波search,你会发现,然并卵……刚开始,我们还专门联系了魅族的相机开发人员,以为会有什么比较“魅族化”的方案,结果他们直接回了一句:平台相关,MX5不支持录像输出的同时提供预览数据。怎么办?砍需求?这种关键流程,都是经过法务部门专门审核过的,那能说砍就砍。我们一边申请是否可以砍掉这个需求,同时也依然继续研究怎么解决这个问题~

  我们发现这两款不能同时进行的手机都是5.0以上的,于是我就想,也许新的Camera2有可能解决的~下面开始进行专业技术干货解说模式……

  当我们要学着使用某个新的API时,最好是直接到官网去找reference,然后尽量科学上网。Android的大部分API示例,都在https://github.com/googlesamples里面,这次提到的关于Camera2的使用,当然也是从那里下载下来的,源码地址如下:

https://github.com/googlesamples/android-Camera2Basic以及https://github.com/googlesamples/android-Camera2Video。但是googlesamples里面的代码都是比较原始的代码。

  我们需要静下心来分析相机使用的过程:

  1、首先一定得判断权限,是否有权利使用相机;

  2、通过什么方式连上相机设备;

  3、拿到相机设备后怎么进行录像;

  4、如何在录像的过程中监听到每一帧的数据;

  

  一、关于检查权限就不说了,这里补充一句有一个类叫ActivityCompat,大家如果以前没用过可以看一下,是v4包下的类。

  二、Camera2打开相机设备的方式跟老的不一样,以前直接就new一个就open了,比较直接。现在把camera当做一种服务去对待,要申请,而申请的方式如下,

private void openCamera() {
if (isOpened) {
return;
}
isOpened = true;
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
String cameraId = manager.getCameraIdList()[0];//这个可能会有很多个,但是通常都是两个,第一个是后置,第二个是前置;
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
assert map != null;
imageDimension = map.getOutputSizes(SurfaceTexture.class)[0];
manager.openCamera(cameraId, new CameraDevice.StateCallback() {
@Override
public void onOpened(CameraDevice camera) {
G.i("onOpened");
createCameraPreview(camera);
} @Override
public void onDisconnected(CameraDevice camera) {
G.i("onDisconnected");
camera.close();
} @Override
public void onError(CameraDevice camera, int error) {
G.e("onError -> " + error);
camera.close();
}
}, handlerHelper.getBackgroundHandler());//这个指定其后台运行,如果直接UI线程也可以,直接填null;
G.i("open Camera " + cameraId);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}

  三、拿到相机设备的回调就是如上代码的 public void onOpened(CameraDevice camera) 方法,此时的cameraDevice就是我们可以完全使用的Camera。拿到相机以后,就开始创建预览即preview。

protected void createCameraPreview(final CameraDevice cameraDevice) {
try {
if (null == cameraDevice) {
G.i("updatePreview error, return");
return;
}
setUpImageReader();
setUpMediaRecorder();
final CaptureRequest.Builder captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
SurfaceTexture texture = textureView.getSurfaceTexture();
texture.setDefaultBufferSize(imageDimension.getWidth(), imageDimension.getHeight());
Surface textureSurface = new Surface(texture);
Surface recorderSurface = mMediaRecorder.getSurface();
Surface imageSurface = imageReader.getSurface();
captureRequestBuilder.addTarget(textureSurface);
captureRequestBuilder.addTarget(recorderSurface);
captureRequestBuilder.addTarget(imageSurface);
List<Surface> surfaceList = Arrays.asList(textureSurface, recorderSurface, imageSurface);
cameraDevice.createCaptureSession(surfaceList, new CameraCaptureSession.StateCallback() {//配置要接受图像的surface
@Override
public void onConfigured(CameraCaptureSession cameraCaptureSession) {
captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
try {
cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, handlerHelper.getBackgroundHandler());//成功配置后,便开始进行相机图像的监听
} catch (CameraAccessException e) {
e.printStackTrace();
}
mMediaRecorder.start();
} @Override
public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
ToastUtils.show("Configuration change");
}
}, handlerHelper.getBackgroundHandler());
} catch (CameraAccessException e) {
e.printStackTrace();
}
} private void setUpMediaRecorder() {
mMediaRecorder = new MediaRecorder();
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
mMediaRecorder.setProfile(getCamcorderProfile());
mMediaRecorder.setOutputFile(new File(getExternalCacheDir(), System.currentTimeMillis() + ".mp4").getAbsolutePath());
try {
mMediaRecorder.prepare();
} catch (IOException e) {
e.printStackTrace();
}
} private void setUpImageReader() {
imageReader = ImageReader.newInstance(imageDimension.getWidth(), imageDimension.getHeight(), ImageFormat.YUV_420_888, 10);
imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
Image image = reader.acquireLatestImage();
if (image != null) {
image.close();
}
G.i("onImageAvailable");
}
}, handlerHelper.getBackgroundHandler());
}

由于camera2的api使用的方式是,相机设备可以向意多个surface进行图像的输出。如上代码,通过cameraDevice.createCaptureSession(....)方法去配置要输出的surface,任意一个没有被配置过的surface在使用的时候都会报错。同时有回调通知,是否配置成功,成功以后便可以开始启动图像的输出监听,即cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, handlerHelper.getBackgroundHandler());其中captureRequestBuilder就是配置相机属性以及添加那些已经成功配置过了surface,至于怎么接收相机的图像,便有各个surface的所有者自己去定义。这里使用到的是MediaRecorder和ImageReader,一个是为了录像,一个是为了所谓的监听PreviewCallback。

  注意:使用ImageReader的时候会比较卡,特别是如果使用JPEG的格式的话,因为使用JPEG,ImageReader需要进行额外的处理。我为了使回调与旧的PreviewCallback一样使用了ImageFormat.YUV_420_888格式。这个格式,输出非常流畅。

  

关于使用Android新版Camera即Camera2的使用介绍 暨解决Camera.PreviewCallback和MediaRecorder无法同时进行的更多相关文章

  1. Android Camera API/Camera2 API 相机预览及滤镜、贴纸等处理

    Android Lollipop 添加了Camera2 API,并将原来的Camera API标记为废弃了.相对原来的Camera API来说.Camera2是又一次定义的相机 API,也重构了相机 ...

  2. 使用Kotlin开发Android应用(I):简单介绍

    使用Kotlin开发Android应用(I):简单介绍 @author ASCE1885的 Github 简书 微博 CSDN 原文链接 Kotlin是一门基于JVM的编程语言.它正成长为Androi ...

  3. 高通camera结构(摄像头基础介绍)

    摄像头基础介绍 一.摄像头结构和工作原理. 拍摄景物通过镜头,将生成的光学图像投射到传感器上,然后光学图像被转换成电信号,电信号再经过模数转换变为数字信号,数字信号经过DSP加工处理,再被送到电脑中进 ...

  4. [Android]使用Dagger 2依赖注入 - DI介绍(翻译)

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5092083.html 使用Dagger 2依赖注入 - DI介 ...

  5. Android使用Fragment来实现ViewPager的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信

    以下内容为原创,转载请注明:http://www.cnblogs.com/tiantianbyconan/p/3364728.html 我前两天写过一篇博客<Android使用Fragment来 ...

  6. 【Java/Android性能优3】Android性能调优工具TraceView使用介绍

    本文转自:http://blog.csdn.net/innost/article/details/9008691 在软件开发过程中,想必很多读者都遇到过系统性能问题.而解决系统性能问题的几个主要步骤是 ...

  7. 转:Android 2.3 代码混淆proguard技术介绍

    ProGuard简介 ProGuard是一个SourceForge上非常知名的开源项目.官网网址是:http://proguard.sourceforge.net/. Java的字节码一般是非常容易反 ...

  8. 启动android程序和虚拟机时候出现如下错误的解决方法

    启动android程序和虚拟机时候出现如下错误的解决方法. 错误重现: [2011-07-13 16:22:48 - Emulator] invalid command-line parameter: ...

  9. IDEA插件(Android Studio插件)开发示例代码及bug解决

    IDEA插件(Android Studio插件)开发示例代码及bug解决 代码在actionPerformed方法中,有个AnActionEvent e 插件开发就是要求我们复写上述的这个方法即可,在 ...

随机推荐

  1. 如何在本地用vs调试微信接口

    这段时间在研究微信,看了网上很多都是把项目发布之后在服务器上调试,可以我想可以直接在vs上面设置断点调试 刚开始才用 http://www.cnblogs.com/hanzhaoxin/p/45186 ...

  2. [New learn]讲解Objective-c的block知识-实践

    1.简介 在之前的文章[New learn]讲解Objective-c的block知识中介绍了block的相关知识.本章中我们将以一个实际例子来简单介绍一下block如何代替代理. 2.原有通过代理实 ...

  3. linux命令--head

    head 与 tail 就像它的名字一样的浅显易懂,它是用来显示开头或结尾某个数量的文字区块,head 用来显示档案的开头至标准输出中,而 tail 想当然尔就是看档案的结尾. 具体使用参考链接: h ...

  4. 去掉a标签的虚线框,避免出现奇怪的选中区域

    a{blr:expression(this.onFocus=this.blur())}/*去掉a标签的虚线框,避免出现奇怪的选中区域*/

  5. 使用 Visual Studio 部署 .NET Core 应用

    可将 .NET Core 应用程序部署为依赖框架的部署或独立部署,前者包含应用程序二进制文件,但依赖目标系统上存在的 .NET Core,而后者同时包含应用程序和 .NET Core 二进制文件. 有 ...

  6. Struts2学习笔记03 之 Result组件

    二.Result原理 1.stream 2.redirectAction 3.Json

  7. 用指定jdk执行jar包

    在运行jar包前执行以下命令,作用是在当前命令行窗口作用域内修改环境变量: export JAVA_HOME=/root/jiabao.gao/Hbase2Redis-1.0.0-SNAPSHOT/j ...

  8. hihocoder 1177 : 顺子

    #1177 : 顺子 时间限制:6000ms 单点时限:1000ms 内存限制:256MB 描述 你在赌场里玩梭哈,已经被发了4张牌,现在你想要知道发下一张牌后你得到顺子的概率是多少? 假定赌场使用的 ...

  9. LeetCode解题报告—— Permutations & Permutations II & Rotate Image

    1. Permutations Given a collection of distinct numbers, return all possible permutations. For exampl ...

  10. hdu 2881(LIS变形)

    Jack's struggle Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others) ...