Android Camera2拍照(一)——使用SurfaceView
原文:Android Camera2拍照(一)——使用SurfaceView
Camera2 API简介
Android 从5.0(21)开始,引入了新的Camera API Camera2,原来的android.hardware.Camera被废弃(下面称为Camera1),还有一个android.graphics.Camera,这个android.graphics.Camera不是用来照相的,是用来处理图像的,可以做出3D的图像效果之类的,之前的Camera1则由android.hardware.Camera代替。Camera2支持RAW输出,可以调节曝光,对焦模式,快门等,功能比原先Camera强大。
这里引用了管道的概念将安卓设备和摄像头之间联通起来,系统向摄像头发送 Capture 请求,而摄像头会返回 CameraMetadata。这一切建立在一个叫作 CameraCaptureSession 的会话中。
- CameraManaer 摄像头管理器,用于检测摄像头,打开系统摄像头,调用CameraManager.getCameraCharacteristics(String)可以获取指定摄像头的相关特性
- CameraCharacteristics 摄像头的特性
- CameraDevice 摄像头,类似android.hardware.Camera也就是Camera1的Camera
- CameraCaptureSession 这个类控制摄像头的预览或者拍照,setRepeatingRequest()开启预览,capture()拍照,CameraCaptureSession提供了StateCallback、CaptureCallback两个接口来监听CameraCaptureSession的创建和拍照过程。
- CameraRequest和CameraRequest.Builder,预览或者拍照时,都需要一个CameraRequest对象。CameraRequest表示一次捕获请求,用来对照片的各种参数设置,比如对焦模式、曝光模式等。CameraRequest.Builder用来生成CameraRequest对象。
Camera2的简单使用(使用SurfaceView)
主要步骤:
- 获得摄像头管理器CameraManager mCameraManager,mCameraManager.openCamera()来打开摄像头
- 指定要打开的摄像头,并创建openCamera()所需要的CameraDevice.StateCallback stateCallback
- 在CameraDevice.StateCallback stateCallback中调用takePreview(),这个方法中,使用CaptureRequest.Builder创建预览需要的CameraRequest,并初始化了CameraCaptureSession,最后调用了setRepeatingRequest(previewRequest, null, childHandler)进行了预览
- 点击拍照按钮,调用takePicture(),这个方法内,最终调用了capture(mCaptureRequest, null, childHandler)
- 在new ImageReader.OnImageAvailableListener(){}回调方法中,将拍照拿到的图片进行展示
- package org.hunter.a361camera.view;
- import android.Manifest;
- import android.content.Context;
- import android.content.pm.PackageManager;
- import android.graphics.Bitmap;
- import android.graphics.BitmapFactory;
- import android.graphics.ImageFormat;
- 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.media.Image;
- import android.media.ImageReader;
- import android.os.Build;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.HandlerThread;
- import android.support.annotation.Nullable;
- import android.support.annotation.RequiresApi;
- import android.support.v4.app.ActivityCompat;
- import android.support.v4.app.Fragment;
- import android.util.SparseIntArray;
- import android.view.LayoutInflater;
- import android.view.Surface;
- import android.view.SurfaceHolder;
- import android.view.SurfaceView;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.ImageView;
- import android.widget.Toast;
- import org.hunter.a361camera.R;
- import java.nio.ByteBuffer;
- import java.util.Arrays;
- import static android.os.Looper.getMainLooper;
- /**
- * Main UI for the statistics screen.
- */
- public class CameraFragment extends Fragment {
- public static final int REQUEST_CAMERA_CODE = 100;
- public static final String PACKAGE = "package:";
- 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);
- }
- private SurfaceView mSurfaceView;
- private SurfaceHolder mSurfaceHolder;
- private ImageView iv_show;
- private ImageView mCatture;
- private CameraManager mCameraManager;//摄像头管理器
- private Handler childHandler, mainHandler;
- private String mCameraID;//摄像头Id 0 为后 1 为前
- private ImageReader mImageReader;
- private CameraCaptureSession mCameraCaptureSession;
- private CameraDevice mCameraDevice;
- /**
- * 摄像头创建监听
- */
- 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();
- CameraFragment.this.mCameraDevice = null;
- }
- }
- @Override
- public void onError(CameraDevice camera, int error) {//发生错误
- Toast.makeText(getContext(), "摄像头开启失败", Toast.LENGTH_SHORT).show();
- }
- };
- public static CameraFragment newInstance() {
- return new CameraFragment();
- }
- @Nullable
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- View root = inflater.inflate(R.layout.camera_frag, container, false);
- initVIew(root);
- initListener();
- return root;
- }
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- }
- @Override
- public void onResume() {
- super.onResume();
- }
- /**
- * 初始化
- */
- private void initVIew(View root) {
- iv_show = (ImageView) root.findViewById(R.id.iv_show_camera2);
- //mSurfaceView
- mSurfaceView = (SurfaceView) root.findViewById(R.id.surface_view_camera2);
- mCatture = (ImageView) root.findViewById(R.id.capture);
- mSurfaceHolder = mSurfaceView.getHolder();
- mSurfaceHolder.setKeepScreenOn(true);
- // mSurfaceView添加回调
- mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
- @Override
- public void surfaceCreated(SurfaceHolder holder) { //SurfaceView创建
- // 初始化Camera
- initCamera2();
- }
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
- }
- @Override
- public void surfaceDestroyed(SurfaceHolder holder) { //SurfaceView销毁
- // 释放Camera资源
- if (null != mCameraDevice) {
- mCameraDevice.close();
- CameraFragment.this.mCameraDevice = null;
- }
- }
- });
- }
- /**
- * 初始化Camera2
- */
- @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
- private void initCamera2() {
- HandlerThread handlerThread = new HandlerThread("Camera2");
- handlerThread.start();
- childHandler = new Handler(handlerThread.getLooper());
- mainHandler = new Handler(getMainLooper());
- mCameraID = "" + CameraCharacteristics.LENS_FACING_FRONT;//后摄像头
- mImageReader = ImageReader.newInstance(1080, 1920, ImageFormat.JPEG, 1);
- mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() { //可以在这里处理拍照得到的临时照片 例如,写入本地
- @Override
- public void onImageAvailable(ImageReader reader) {
- //mCameraDevice.close();
- // 拿到拍照照片数据
- 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);
- //获取摄像头管理
- mCameraManager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);
- try {
- if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
- //申请WRITE_EXTERNAL_STORAGE权限
- requestPermissions(new String[]{Manifest.permission.CAMERA},
- REQUEST_CAMERA_CODE);
- //return;
- } else {
- //打开摄像头
- mCameraManager.openCamera(mCameraID, stateCallback, mainHandler);
- }
- } catch (CameraAccessException e) {
- e.printStackTrace();
- }
- }
- @Override
- public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults);
- if (requestCode == REQUEST_CAMERA_CODE) {
- if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
- // Permission Granted
- try {
- mCameraManager.openCamera(mCameraID, stateCallback, mainHandler);
- } catch (CameraAccessException e) {
- e.printStackTrace();
- } catch (SecurityException e) {
- e.printStackTrace();
- }
- } else {
- // Permission Denied
- }
- }
- }
- /**
- * 开始预览
- */
- private void takePreview() {
- try {
- // 创建预览需要的CaptureRequest.Builder
- final CaptureRequest.Builder previewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
- // 将SurfaceView的surface作为CaptureRequest.Builder的目标
- previewRequestBuilder.addTarget(mSurfaceHolder.getSurface());
- // 创建CameraCaptureSession,该对象负责管理处理预览请求和拍照请求
- mCameraDevice.createCaptureSession(Arrays.asList(mSurfaceHolder.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(getContext(), "配置失败", Toast.LENGTH_SHORT).show();
- }
- }, childHandler);
- } catch (CameraAccessException e) {
- e.printStackTrace();
- }
- }
- /**
- * 拍照
- */
- 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 = getActivity().getWindowManager().getDefaultDisplay().getRotation();
- // 根据设备方向计算设置照片的方向
- captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
- //拍照
- CaptureRequest mCaptureRequest = captureRequestBuilder.build();
- mCameraCaptureSession.capture(mCaptureRequest, null, childHandler);
- } catch (CameraAccessException e) {
- e.printStackTrace();
- }
- }
- private void initListener() {
- mCatture.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- takePicture();
- }
- });
- }
- }
布局文件:
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <SurfaceView
- android:id="@+id/surface_view_camera2"
- android:layout_width="match_parent"
- android:layout_height="match_parent"/>
- <org.hunter.a361camera.widget.PorterDuffViewImageView
- android:id="@+id/capture"
- android:layout_width="90dp"
- android:layout_height="90dp"
- android:layout_alignParentBottom="true"
- android:layout_centerHorizontal="true"
- android:layout_marginBottom="20dp"
- android:src="@mipmap/capture"/>
- <org.hunter.a361camera.widget.PorterDuffViewImageView
- android:id="@+id/iv_show_camera2"
- android:layout_width="80dp"
- android:layout_height="80dp"
- android:layout_alignParentBottom="true"
- android:layout_alignParentRight="true"
- android:layout_marginBottom="20dp"
- android:layout_marginRight="20dp"
- android:scaleType="centerCrop"/>
- </RelativeLayout>
源代码地址:https://github.com/gengqifu/361Camera。欢迎fork/star
Android Camera2拍照(一)——使用SurfaceView的更多相关文章
- Android Camera2 拍照(二)——使用TextureView
原文:Android Camera2 拍照(二)--使用TextureView 上一篇博文简单介绍了使用Camera2 API拍摄照片,并使用SurfaceView作为预览界面.实际上,相对于Surf ...
- Android Camera2 拍照入门学习
原文:Android Camera2 拍照入门学习 学习资料: 肾虚将军android camera2 详解说明 极客学院android.hardware.camera2 使用指南 Android 5 ...
- Android Camera2 拍照(三)——切换摄像头,延时拍摄和闪光模式
原文:Android Camera2 拍照(三)--切换摄像头,延时拍摄和闪光模式 一.切换摄像头 在前后摄像头之间切换,首先需要关闭之前打开的摄像头,关闭preview,之后重新打开新的摄像头,重新 ...
- Android Camera2 拍照(四)——对焦模式
原文:Android Camera2 拍照(四)--对焦模式 本篇将重点介绍使用Camera2 API进行手动对焦的设置,以及在手动对焦与自动对焦模式之间切换. 一.手动对焦响应事件 首先我们要实现点 ...
- Android Camera2 预览,拍照,人脸检测并实时展现
https://www.jianshu.com/p/5414ba2b5508 背景 最近需要做一个人脸检测并实时预览的功能.就是边检测人脸,边在预览界面上框出来. 当然本人并不是专门做 ...
- android Camera2 API使用详解
原文:android Camera2 API使用详解 由于最近需要使用相机拍照等功能,鉴于老旧的相机API问题多多,而且新的设备都是基于安卓5.0以上的,于是本人决定研究一下安卓5.0新引入的Came ...
- android自定义拍照
调用系统相机,然后在自己的surfaceview上预览,拍照,不废话,直接上源码 package com.example.customecamera; import java.io.File; imp ...
- Android摄像头:只拍摄SurfaceView预览界面特定区域内容(矩形框)---完整(原理:底层SurfaceView+上层绘制ImageView)
Android摄像头:只拍摄SurfaceView预览界面特定区域内容(矩形框)---完整实现(原理:底层SurfaceView+上层绘制ImageView) 分类: Android开发 Androi ...
- Android Camera2采集摄像头原始数据并手动预览
Android Camera2采集摄像头原始数据并手动预览 最近研究了一下android摄像头开发相关的技术,也看了Google提供的Camera2Basic调用示例,以及网上一部分代码,但都是在Te ...
随机推荐
- Java 学习(22):Java MySQL 连接
Java MySQL 连接 本章节我们为大家介绍 Java 如何使用 使用 JDBC 连接 MySQL 数据库. Java 连接 MySQL 需要驱动包,最新版下载地址为:http://dev.mys ...
- iOS writeTofile 和对象的序列化
前言:做了一个图片浏览的小demo,支持随意添加.删除图片,图片放大.缩小,带矩形框的截图.随后几篇博客都会详细讲解在此过程中遇到的各种问题.这篇主要讲,在做添加.删除这个功能时,遇到的存文件的问题. ...
- java 替换json字符串中间的引号保留两边的引号,避免json校验失败
一.json概要 JSON(JavaScript Object Notation, JS 对象标记)-一种轻量级的数据交换标准(相对xml),独立于编程语言.具体以逗号分隔的key:value键值对的 ...
- [Django] Creating an app, models and database
To add a new app, first cd to the project. Then run: python manage.py startapp scrumboard After that ...
- HDU 4870 Rating 高斯消元法
链接:http://acm.hdu.edu.cn/showproblem.php?pid=4870 题意:用两个账号去參加一种比赛,初始状态下两个账号都是零分,每次比赛都用分数低的账号去比赛.有P的概 ...
- PCI的imagework已由freeview软件代替
作者:朱金灿 来源:http://blog.csdn.net/clever101 在PCI 9.1中重要模块集成显示环境imagework还存在,但是到了PCI 10.0中imagework已经消失了 ...
- hadoop 3.x 启动过程中 Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).
出现这种状况是因为当前账号没有配置ssh免密登录 进入到以下目录,查看是否生成过秘钥对,如果有的话直接ssh-copy-id 主机名 没有的话执行ssh-keygen -t rsa后再重新执行ssh- ...
- 数据可视化 —— 数据流图(Data Flow Diagram)
数据流图(Data Flow Diagram):简称 DFD,它从数据传递和加工角度,以图形方式来表达系统的逻辑功能.数据在系统内部的逻辑流向和逻辑变换过程,是结构化系统分析方法的主要表达工具及用于表 ...
- 如何在华为云软件开发云上运行Python
一. 华为云软件开发云与Python 1. 华为云软件开发云简介 华为云软件开发云(DevCloud)是集华为近30年研发实践,前沿研发理念,先进研发工具为一体的一站式云端DevOps平台,面向开发者 ...
- 一个自己犯的react错误
在看<react小书>高阶组件一节的时候,看到如下代码 import React, { Component } from 'react' export default (WrappedCo ...