Android Camera2拍照——使用SurfaceView

博观而约取,厚积而薄发。这篇文章主要讲述Android Camera2拍照——使用SurfaceView相关的知识,希望能为你提供帮助。
原文:Android Camera2拍照(一)——使用SurfaceViewCamera2 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强大。

Android Camera2拍照——使用SurfaceView

文章图片

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

文章图片

  • 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)主要步骤:
  1. 获得摄像头管理器CameraManager mCameraManager,mCameraManager.openCamera()来打开摄像头
  2. 指定要打开的摄像头,并创建openCamera()所需要的CameraDevice.StateCallback stateCallback
  3. 在CameraDevice.StateCallback stateCallback中调用takePreview(),这个方法中,使用CaptureRequest.Builder创建预览需要的CameraRequest,并初始化了CameraCaptureSession,最后调用了setRepeatingRequest(previewRequest, null, childHandler)进行了预览
  4. 点击拍照按钮,调用takePicture(),这个方法内,最终调用了capture(mCaptureRequest, null, childHandler)
  5. 在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="https://www.songbingjia.com/android/@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】












    推荐阅读