说来惭愧,为了打开摄像头参考了好多博客,搞了一晚上才搞完,主要参考一篇文章学会Android Camera2 Api,实现自定义相机入门。 - 简书。

只使用了其中的camera2的内容,作了一些裁剪,保留了必要的东西。

废话不多说,上代码。

布局文件:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".FaceCaptureActivity"><com.fmm.face2.views.AutoFitTextureViewandroid:id="@+id/texture"android:layout_width="match_parent"android:layout_height="match_parent" /></android.support.constraint.ConstraintLayout>

activity:

package com.fmm.face2;import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.ImageReader;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.annotation.RequiresApi;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.util.Size;
import android.util.SparseIntArray;
import android.view.Surface;
import android.view.TextureView;
import android.widget.Toast;import com.fmm.face2.views.AutoFitTextureView;import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.jar.Manifest;import butterknife.BindView;
import butterknife.ButterKnife;@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class FaceCaptureActivity extends AppCompatActivity {@BindView(R.id.texture)AutoFitTextureView texture;/*** 相机管理类*/CameraManager mCameraManager;/*** 指定摄像头ID对应的Camera实体对象*/CameraDevice mCameraDevice;/*** 预览尺寸*/private Size mPreviewSize;private int mSurfaceWidth;private int mSurfaceHeight;/*** 打开摄像头的ID{@link CameraDevice}.*/private int mCameraId = CameraCharacteristics.LENS_FACING_FRONT;/*** 处理静态图像捕获的ImageReader。{@link ImageReader}*/private ImageReader mImageReader;/*** 用于相机预览的{@Link CameraCaptureSession}。*/private CameraCaptureSession mCaptureSession;/*** {@link CaptureRequest.Builder}用于相机预览请求的构造器*/private CaptureRequest.Builder mPreviewRequestBuilder;/***预览请求, 由上面的构建器构建出来*/private CaptureRequest mPreviewRequest;/*** 从屏幕旋转图片转换方向。*/private static final SparseIntArray ORIENTATIONS = new SparseIntArray();static {ORIENTATIONS.append(Surface.ROTATION_0, 90);ORIENTATIONS.append(Surface.ROTATION_90, 0);ORIENTATIONS.append(Surface.ROTATION_180, 270);ORIENTATIONS.append(Surface.ROTATION_270, 180);}/*** 预览请求构建器, 用来构建"预览请求"(下面定义的)通过pipeline发送到Camera device* 这是{@link ImageReader}的回调对象。 当静止图像准备保存时,将会调用“onImageAvailable”。*/private final ImageReader.OnImageAvailableListener mOnImageAvailableListener= new ImageReader.OnImageAvailableListener() {@Overridepublic void onImageAvailable(ImageReader reader) {// 对reader进行处理}};/*** 用于在后台运行任务的{@link Handler}。*/private Handler mBackgroundHandler;/*** {@link CameraDevice.StateCallback}打开指定摄像头回调{@link CameraDevice}*/private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {@Overridepublic void onOpened(@NonNull CameraDevice cameraDevice) {mCameraDevice = cameraDevice;createCameraPreview();}@Overridepublic void onDisconnected(@NonNull CameraDevice cameraDevice) {cameraDevice.close();cameraDevice = null;}@Overridepublic void onError(@NonNull CameraDevice cameraDevice, int error) {cameraDevice.close();cameraDevice = null;}};/***判断是否支持闪关灯*/private boolean mFlashSupported;private int CONTROL_AE_MODE;/*** 设置相机闪关灯模式** @param AE_MODE 闪关灯的模式* @throws CameraAccessException*/private void setFlashMode(int AE_MODE) {if (mFlashSupported) {this.CONTROL_AE_MODE = AE_MODE;mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, AE_MODE);if (AE_MODE == CaptureRequest.CONTROL_AE_MODE_OFF) {mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);}}// 构建上述的请求mPreviewRequest = mPreviewRequestBuilder.build();// 重复进行上面构建的请求, 用于显示预览try {mCaptureSession.setRepeatingRequest(mPreviewRequest, null, mBackgroundHandler);} catch (CameraAccessException e) {e.printStackTrace();}}private void createCameraPreview() {try {// 获取Texture实例SurfaceTexture surfaceTexture = texture.getSurfaceTexture();assert surfaceTexture != null;// 将默认缓冲区的大小配置为我们想要的相机预览的大小surfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());// new一个用来开始预览的输出surfaceSurface surface = new Surface(surfaceTexture);// 创建预览请求构造器mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);// 将TextureView的Surface作为相机的预览显示输出mPreviewRequestBuilder.addTarget(surface);// 为相机创建一个CameraCaptureSessionmCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()), new CameraCaptureSession.StateCallback(){@Overridepublic void onConfigured(CameraCaptureSession cameraCaptureSession) {// 相机关闭时,直接返回if (mCameraDevice==null){return;}// 会话准备就绪后,我们就开始显示预览// 会话可行时,将构建的会话赋给fieldmCaptureSession = cameraCaptureSession;// 相机预览应该连续自动对焦mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);//设置闪关灯模式setFlashMode(CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);}@Overridepublic void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {// 预览失败showToast("预览失败");}}, null);} catch (CameraAccessException e) {e.printStackTrace();}}private void showToast(final String text){Toast.makeText(FaceCaptureActivity.this, text, Toast.LENGTH_SHORT).show();//runOnUiThread(() -> Toast.makeText(FaceCaptureActivity.this, text, Toast.LENGTH_SHORT).show());}/*** TextureView 生命周期响应*/private final TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {@Overridepublic void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {// 当TextureView创建完成,打开指定摄像头openCamera(width, height, mCameraId);}@Override // 尺寸改变public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width, int height) {}@Override // 销毁public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {return false;}@Override // 更新public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_face_capture);ButterKnife.bind(this);initView();}@Overrideprotected void onResume() {super.onResume();if (texture.isAvailable()){openCamera(texture.getWidth(), texture.getHeight(), mCameraId);}else{texture.setSurfaceTextureListener(textureListener);}}@Overrideprotected void onPause() {closeCamera();super.onPause();}private void showLogD(String text){Log.d("faceCap", "showLogD: " + text);}private void initView() {closeCamera();// 前置摄像头mCameraId = CameraCharacteristics.LENS_FACING_BACK;if (texture.isAvailable()){openCamera(texture.getWidth(), texture.getHeight(), mCameraId);}else{texture.setSurfaceTextureListener(textureListener);}// 获取相机设备管理器mCameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);}private void openCamera(int width, int height, int cameraId) {if (ActivityCompat.checkSelfPermission(FaceCaptureActivity.this, android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED){// 权限不允许return;}try {mSurfaceWidth = width;mSurfaceHeight = height;CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(mCameraId + "");StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);// 获取设备方向int rotation = getWindowManager().getDefaultDisplay().getRotation();int totalRotation = sensorToDeviceRotation(characteristics, rotation);boolean swapRotation = totalRotation == 90 || totalRotation == 270;int rotatedWidth = mSurfaceWidth;int rotatedHeight = mSurfaceHeight;if (swapRotation){rotatedWidth = mSurfaceWidth;rotatedHeight = mSurfaceHeight;}// 获取最佳的预览尺寸mPreviewSize = getPreferredPreviewSize(map.getOutputSizes(SurfaceTexture.class), rotatedWidth, rotatedHeight);if (swapRotation){texture.setAspectRatio(mPreviewSize.getWidth(), mPreviewSize.getHeight());}else{texture.setAspectRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth());}if (mImageReader == null){// 创建一个ImageReader的对象,用于获取摄像头的图像数据,maxImages是ImageReader一次可以访问的最大图片数量mImageReader = ImageReader.newInstance(mPreviewSize.getWidth(), mPreviewSize.getHeight(),ImageFormat.JPEG, 2);mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler);}showLogD("马上打开摄像头");// 打开摄像头mCameraManager.openCamera(mCameraId + "", mStateCallback, null);showLogD("已经打开摄像头");} catch (CameraAccessException e) {e.printStackTrace();}}private Size getPreferredPreviewSize(Size[] outputSizes, int rotatedWidth, int rotatedHeight) {List<Size> collectorSizes = new ArrayList<>();for (Size option : outputSizes){if (rotatedWidth > rotatedHeight){if (option.getWidth()>rotatedWidth&&option.getHeight()>rotatedHeight){collectorSizes.add(option);}}else{if (option.getHeight()>rotatedWidth&&option.getWidth()>rotatedHeight){collectorSizes.add(option);}}}if (collectorSizes.size() > 0){return Collections.min(collectorSizes, new Comparator<Size>() {@Overridepublic int compare(Size size, Size t1) {return Long.signum(size.getWidth()*size.getHeight() - t1.getWidth() * t1.getHeight());}});}return outputSizes[0];}private static int sensorToDeviceRotation(CameraCharacteristics characteristics, int deviceOrientation){int sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);deviceOrientation = ORIENTATIONS.get(deviceOrientation);return (sensorOrientation + deviceOrientation + 360) % 360;}private void closeCamera() {// 关闭捕获会话if(null != mCaptureSession){mCaptureSession.close();mCaptureSession = null;}// 关闭当前相机if (null != mCameraDevice){mCameraDevice.close();mCameraDevice = null;}// 关闭拍照处理器if (null != mImageReader){mImageReader.close();mImageReader = null;}}
}

安卓开发(简单打开前置摄像头并显示)相关推荐

  1. android打开前置摄像头和后置摄像头

    android打开前置摄像头和后置摄像头 前言: 我的android设备是原道N70双擎pad.这个平板电脑没有后置摄像头,只有前置摄像头,当我安装一些程序的时候,会出现"xxxx.apk已 ...

  2. android打开前置摄像头和后置摄像头 .

    android打开前置摄像头和后置摄像头 前言: 我的android设备是原道N70双擎pad.这个平板电脑没有后置摄像头,只有前置摄像头,当我安装一些程序的时候,会出现"xxxx.apk已 ...

  3. 使用ESP32-CAM开发板链接OV2640摄像头网页显示

    ESP32-CAM OV2640摄像头 模块简介 下载接线及配置 下载接线 例程说明 输出图像 总结 原文链接:https://www.yourcee.com/newsinfo/2925714.htm ...

  4. 安卓开发-自定义照相机界面

    安卓开发-自定义照相机界面 此项目是总结了其他三位大佬的代码后写出来的,在此首先感谢三位大佬: 自定义照相机编写方法:https://blog.csdn.net/shan286/article/det ...

  5. android html 打开摄像头,在android上,用WEB页面打开手机摄像头

    今天看到一个人提问,怎么在android上用web页面打开手机摄像头.刚好我们之前也做过类似的工程,刚好把想法写一下: 1.基本原理: 页面上做一个按钮,如打开摄像头,它做的事情就是将页面链接到一个特 ...

  6. android 9.0 Camera2 去掉后置摄像头仅支持前置摄像头功能

    1.概述 在9.0的系统产品rom定制化开发中,在一些产品中只有前置摄像头一个摄像头的产品中,这时在打开摄像头的时候,只需要打开前置摄像头的就可以了,所以这需要 在Camera2的app中找到关于调用 ...

  7. android intent开启前置摄像头

    网上大部分的文章是这样写的: Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra("ca ...

  8. android 12.0Camera2 去掉后置摄像头 仅支持前置摄像头功能

    1.概述 在定制化12.0的产品时,只有一个前置摄像头单摄像头,这时调用相机时就需要默认打开前置摄像头就需要来看调用摄像头这块的代码,屏蔽掉后置摄像头的调用api就可以了 2.Camera2 去掉后置 ...

  9. 如何用openvr api打开vive前置摄像头

    随着越来越多的开发者开始他们的VR开发工作,他们看到了这项技术的巨大潜力,像是Valve这样的公司正在想办法保证他们的软件开发包(SDK)能够提供尽量多的功能.今天这家公司发布了其针对SteamVR的 ...

  10. Android使用百度地图定位并显示手机位置后使用前置摄像头“偷拍”

    今天老板让我验证一下技术可行性,记录下来. 需求 :定位手机的位置并在百度地图上显示,得到位置后使用前置摄像头进行抓拍 拿到这个需求后,对于摄像头的使用不太熟悉,于是我先做了定位手机并在百度地图上显示 ...

最新文章

  1. android oom 检测工具,Android中UI检测、内存泄露、OOM、等优化处理
  2. MYSQL 与 Oracle 之间的数据类型转换
  3. Hibernate注解使用以及Spring整合
  4. centos 升级curl版本
  5. If 的替代词汇:unless、in case..._60
  6. git 命令总结(转)
  7. easyicon-----一个非常好用的找图标的网站
  8. 父与子的编程python_父与子的编程之旅:与小卡特一起学Python 完整版
  9. window如何安装head插件
  10. Ali-tomcat之HSF框架Demo启动报错HSFServiceAddressNotFoundException
  11. linux 配置思科路由器,思科路由器配置帧中继基本命令
  12. 我对onselect和onchange事件的误解
  13. AD7705-模数转换器-工作原理介绍
  14. 车牌识别技术应用场景
  15. java广度优先爬虫示例_广度优先搜索与网络爬虫
  16. 2048小游戏(原生js基础代码篇)
  17. Fisher线性判别
  18. java自行车为什么被黑_谷歌自行车没有「愚人」,我来告诉你为什么
  19. java des ecb_【转】 java DES ECB模式对称加密解密
  20. Python学习(13)--Lambda表达式和switch语句的实现

热门文章

  1. Orcad Capture CIS出BOM表
  2. python自动下载小说
  3. 为什么程序员从来不炫富?
  4. 变换元素transform和过渡元素transition混合使用
  5. 阿里双十一数据库技术
  6. ps抠图教程:各类章子专用方法
  7. Android View绘制6 Draw过程(下)
  8. Unity:骨骼动画
  9. Pyechart绘制疫情发文可视化动态地图
  10. 程序员必读职场15大定律和7大原则