自己总结的camera2的简单使用
一、使用步骤及介绍 使用步骤1.申请相机权限和存储读写权限 2.创建CameraManager对象,获取里面的摄像头信息 2.创建surfaceHolder并为其添加状态监听器,重写里面的surfaceCreated方法 3.在surfaceCreated方法中,创建一个UI线程HandlerThread,也可以不创建 4.调用CameraManager的openCamera()方法打开相机 openCamera()方法有三个参数: 1.相机id 2.摄像头状态监听器:CameraDevice.StateCallback 3.用于相机运行的Ui线程,没有创建UI线程的话也可以为null,为null时默认在主线程运行 5.上一步需要一个摄象头状态监听器,所以这里创建一个CameraDevice.StateCallback 在这个监听器中有一个onOpened方法,这个方法是摄像头打开成功后会调用的
代码步骤1.创建图像捕获状态监听器:CameraCaptureSession.CaptureCallback 2.创建相机捕获会话状态监听器:CameraCaptureSession.StateCallback,在onConfigured方法里面设置摄像头参数 3.创建相机状态监听器:CameraDevice.StateCallback,在onOpened方法中创建相机捕获会话 4.创建CameraManager对象,获取设备的摄像头信息 5.创建预览组件状态监听器:android.view.SurfaceHolder.Callback,在surfaceCreated方法中创建相机线程并打开相机,线程也可以不创建 6.申请权限,权限申请成功后创建预览组件管理器并添加状态监听器:SurfaceHolder
实际步骤先申请权限,权限到手后先创建SurfaceHolder,然后在SurfaceHolder中添加SurfaceHolder.Callback, SurfaceHolder.Callback中需要用到CameraManager和CameraDevice.StateCallback, CameraDevice.StateCallback中又需要用到CameraCaptureSession.StateCallback, CameraCaptureSession.StateCallback中又需要用到CameraCaptureSession.CaptureCallback, 所以写代码的时候先创建最后一个,看起来有点绕
二、实例代码 使用SurfaceView实现预览 package com.eyetracking.camera2preview;import androidx.annotation.NonNull;import androidx.appcompat.app.AppCompatActivity;import androidx.core.app.ActivityCompat;import androidx.core.content.ContextCompat;import android.Manifest;import android.content.Context;import android.content.pm.PackageManager;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.os.Bundle;import android.os.Handler;import android.os.HandlerThread;import android.util.Log;import android.view.SurfaceHolder;import android.view.SurfaceView;import android.widget.Toast;import java.util.Arrays;public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback { private SurfaceView surfaceView; private SurfaceHolder holder; private CameraDevice cameraDevice; private HandlerThread handlerThread; private Handler myHandler; private CameraManager manager; private CameraCaptureSession previeSession; private CaptureRequest.Builder previeBuilder; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); surfaceView = (SurfaceView) findViewById(R.id.surfaceView); holder = surfaceView.getHolder(); checkCameraPermission(); }/*SurfaceHolder.Callback *********************************************************************************************** */ @Override public void surfaceCreated(SurfaceHolder holder) { Log.d("SurfaceHolders", "SurfaceHolder创建成功!"); String cameraId = getCameras(); //创建一个UI线程 handlerThread = new HandlerThread("camera"); handlerThread.start(); myHandler = new Handler(handlerThread.getLooper()); try { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { return; } manager.openCamera(cameraId, new CameraDevice.StateCallback() { @Override public void onOpened(@NonNull CameraDevice camera) { Log.d("DeviceCallback", "摄像头打开成功!"); cameraDevice = camera; try { cameraDevice.createCaptureSession(Arrays.asList(holder.getSurface()), new CameraCaptureSession.StateCallback() { //摄像机设备完成自身配置后会调用此方法,并且会话可以开始处理捕获请求。 @Override public void onConfigured(@NonNull CameraCaptureSession session) { Log.d("CaptureSessionCallback", "摄像机设备已完成自身配置,并且会话可以开始处理捕获请求!"); previeSession = session; try { previeBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); //设置预览画面显示的surface previeBuilder.addTarget(holder.getSurface()); // previeBuilder.set()方法参数解析:第一个参数表示设置的是什么东西,比如闪光灯,第二个参数表示把要设置的东西设置成什么样,比如关闭闪光灯,打开闪光灯 //可以设置的内容参考https://www.apiref.com/android-zh/android/hardware/camera2/CaptureRequest.html // 设置对焦模式-自动对焦 previeBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); // 设置闪光灯模式-自动打开闪光灯 previeBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); //setRepeatingRequest()方法参数说明: // 第二个参数为CameraCaptureSession.StateCallback(),没什么作用,可以写null // 第三个参数为预览的hndler线程,为null的时候表示在主线程预览 previeSession.setRepeatingRequest(previeBuilder.build(), null, myHandler); } catch (CameraAccessException e) { Log.d("CaptureSessionCallback", "cameraCaptureSession访问摄像头失败"); } } //如果会话无法按请求进行配置,则调用此方法。 @Override public void onConfigureFailed(@NonNull CameraCaptureSession session) { Log.d("CaptureSessionCallback", "会话无法按请求进行配置!"); } }, myHandler); } catch (CameraAccessException e) { e.printStackTrace(); Log.d("DeviceCallback", "CaptureRequest.Builder访问摄像头失败"); } } @Override public void onDisconnected(@NonNull CameraDevice camera) { } @Override public void onError(@NonNull CameraDevice camera, int error) { closeCamera(); Toast.makeText(MainActivity.this, "摄像头打开错误", Toast.LENGTH_SHORT).show(); } }, myHandler); } catch (CameraAccessException e) { Log.d("SurfaceHolders", "cameraManager访问摄像头失败"); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { } public String getCameras() { String[] cameras = new String[0]; String cameid = "1"; try { manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); cameras = manager.getCameraIdList(); for (int i = 0; i 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { holder.addCallback(this); } else { Toast.makeText(this, "拒绝权限,请去设置里面手动开启权限", Toast.LENGTH_SHORT).show(); } break; } }} 使用TextureView实现预览这里说明以下TextureView和可以在view层对图片显示优化,镜像翻转等操作,SurfaceView不行
package com.eyetracking.camera2preview2;import androidx.annotation.NonNull;import androidx.appcompat.app.AppCompatActivity;import androidx.core.app.ActivityCompat;import androidx.core.content.ContextCompat;import android.Manifest;import android.content.Context;import android.content.pm.PackageManager;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.os.Bundle;import android.os.Handler;import android.os.HandlerThread;import android.util.Log;import android.view.Surface;import android.view.TextureView;import android.widget.Toast;import java.util.Arrays;public class MainActivity extends AppCompatActivity implements TextureView.SurfaceTextureListener { private TextureView textureView; private CameraDevice cameraDevice; private HandlerThread handlerThread; private Handler myHandler; private CameraManager manager; private CameraCaptureSession previeSession; private CaptureRequest.Builder previeBuilder; private Surface mSurface; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textureView = (TextureView) findViewById(R.id.textureView); checkCameraPermission(); } @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { Log.d("SurfaceHolders", "SurfaceHolder创建成功!"); //设置预览分辨率 surface.setDefaultBufferSize(1920, 1080); mSurface = new Surface(surface); String cameraId = getCameras(); //创建一个UI线程 handlerThread = new HandlerThread("camera"); handlerThread.start(); myHandler = new Handler(handlerThread.getLooper()); try { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { return; } manager.openCamera(cameraId, new CameraDevice.StateCallback() { @Override public void onOpened(@NonNull CameraDevice camera) { Log.d("DeviceCallback", "摄像头打开成功!"); cameraDevice = camera; try { cameraDevice.createCaptureSession(Arrays.asList(mSurface), new CameraCaptureSession.StateCallback() { //摄像机设备完成自身配置后会调用此方法,并且会话可以开始处理捕获请求。 @Override public void onConfigured(@NonNull CameraCaptureSession session) { Log.d("CaptureSessionCallback", "摄像机设备已完成自身配置,并且会话可以开始处理捕获请求!"); previeSession = session; try { previeBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); //设置预览画面显示的surface previeBuilder.addTarget(mSurface); // previeBuilder.set()方法参数解析:第一个参数表示设置的是什么东西,比如闪光灯,第二个参数表示把要设置的东西设置成什么样,比如关闭闪光灯,打开闪光灯 //可以设置的内容参考https://www.apiref.com/android-zh/android/hardware/camera2/CaptureRequest.html // 设置对焦模式-自动对焦 previeBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); // 设置闪光灯模式-自动打开闪光灯 previeBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); //setRepeatingRequest()方法参数说明: // 第二个参数为CameraCaptureSession.StateCallback(),没什么作用,可以写null // 第三个参数为预览的hndler线程,为null的时候表示在主线程预览 previeSession.setRepeatingRequest(previeBuilder.build(), null, myHandler); } catch (CameraAccessException e) { Log.d("CaptureSessionCallback", "cameraCaptureSession访问摄像头失败"); } } //如果会话无法按请求进行配置,则调用此方法。 @Override public void onConfigureFailed(@NonNull CameraCaptureSession session) { Log.d("CaptureSessionCallback", "会话无法按请求进行配置!"); } }, myHandler); } catch (CameraAccessException e) { e.printStackTrace(); Log.d("DeviceCallback", "CaptureRequest.Builder访问摄像头失败"); } } @Override public void onDisconnected(@NonNull CameraDevice camera) { } @Override public void onError(@NonNull CameraDevice camera, int error) { closeCamera(); Toast.makeText(MainActivity.this, "摄像头打开错误", Toast.LENGTH_SHORT).show(); } }, myHandler); } catch (CameraAccessException e) { Log.d("SurfaceHolders", "cameraManager访问摄像头失败"); } } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { return false; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surface) { } public String getCameras() { String[] cameras = new String[0]; String cameid = "1"; try { manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); cameras = manager.getCameraIdList(); for (int i = 0; i 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { textureView.setSurfaceTextureListener(this); } else { Toast.makeText(this, "拒绝权限,请去设置里面手动开启权限", Toast.LENGTH_SHORT).show(); } break; } }} 实现预览和拍照功能 package com.eyetracking.camera2picture;import androidx.annotation.NonNull;import androidx.appcompat.app.AppCompatActivity;import androidx.core.app.ActivityCompat;import androidx.core.content.ContextCompat;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.hardware.camera2.TotalCaptureResult;import android.media.Image;import android.media.ImageReader;import android.os.Build;import android.os.Bundle;import android.os.Environment;import android.os.Handler;import android.os.HandlerThread;import android.util.Log;import android.view.SurfaceHolder;import android.view.SurfaceView;import android.view.View;import android.widget.ImageButton;import android.widget.Toast;import java.io.FileOutputStream;import java.io.IOException;import java.nio.ByteBuffer;import java.util.Arrays;public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback { private ImageButton btPicture; private SurfaceView surfaceView; private SurfaceHolder holder; private CameraDevice cameraDevice; private HandlerThread handlerThread; private Handler myHandler; private CameraManager manager; private CameraCaptureSession previeSession; private CaptureRequest.Builder previeBuilder; private CaptureRequest.Builder captureBuilder; private ImageReader imageReader; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); surfaceView = (SurfaceView) findViewById(R.id.surfaceView); btPicture = (ImageButton) findViewById(R.id.picture); holder = surfaceView.getHolder(); checkCameraPermission(); } public void btPicture(View v) { Toast.makeText(getApplicationContext(), "点击拍照", Toast.LENGTH_SHORT).show(); openCapture(); } @Override public void surfaceCreated(SurfaceHolder holder) { setImageReader(); Log.d("SurfaceHolders", "SurfaceHolder创建成功!"); String cameraId = getCameras(); //创建一个UI线程 handlerThread = new HandlerThread("camera"); handlerThread.start(); myHandler = new Handler(handlerThread.getLooper()); try { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { return; } manager.openCamera(cameraId, new CameraDevice.StateCallback() { @Override public void onOpened(@NonNull CameraDevice camera) { Log.d("DeviceCallback", "摄像头打开成功!"); cameraDevice = camera; try { cameraDevice.createCaptureSession(Arrays.asList(holder.getSurface(), imageReader.getSurface()), new CameraCaptureSession.StateCallback() { @Override public void onConfigured(@NonNull CameraCaptureSession session) { Log.d("CaptureSessionCallback", "摄像机设备已完成自身配置,并且会话可以开始处理捕获请求!"); previeSession = session; openPreview(); } //如果会话无法按请求进行配置,则调用此方法。 @Override public void onConfigureFailed(@NonNull CameraCaptureSession session) { Log.d("CaptureSessionCallback", "会话无法按请求进行配置!"); } }, myHandler); } catch (CameraAccessException e) { e.printStackTrace(); Log.d("DeviceCallback", "CaptureRequest.Builder访问摄像头失败"); } } @Override public void onDisconnected(@NonNull CameraDevice camera) { previeSession.close(); closeCamera(); } @Override public void onError(@NonNull CameraDevice camera, int error) { previeSession.close(); closeCamera(); Toast.makeText(MainActivity.this, "摄像头打开错误", Toast.LENGTH_SHORT).show(); } }, myHandler); } catch (CameraAccessException e) { Log.d("SurfaceHolders", "cameraManager访问摄像头失败"); } } public void openCapture() { if (previeSession != null) { try { //设置拍照参数 captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); captureBuilder.addTarget(imageReader.getSurface()); captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); //停止预览状态 previeSession.stopRepeating(); previeSession.abortCaptures(); //执行拍照 previeSession.capture(captureBuilder.build(), new CameraCaptureSession.CaptureCallback() { //当图像捕捉已完全完成并且所有结果元数据可用时调用此方法。 @Override public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) { super.onCaptureCompleted(session, request, result); Log.d("CaptureCallbacks", "拍摄完成,重新打开预览"); openPreview(); } }, myHandler); } catch (CameraAccessException e) { Log.d("CaptureSessionCallback", "cameraCaptureSession访问摄像头失败"); } } } public void openPreview() { try { previeBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); previeBuilder.addTarget(holder.getSurface()); previeBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); previeBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); previeSession.setRepeatingRequest(previeBuilder.build(), null, myHandler); } catch (CameraAccessException e) { Log.d("CaptureSessionCallback", "cameraCaptureSession访问摄像头失败"); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { closeCamera(); destoryHandler(); } private void setImageReader() { imageReader = ImageReader.newInstance(1920, 1080, ImageFormat.JPEG, 1); imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() { @Override public void onImageAvailable(ImageReader reader) { Log.d("pictureListener", "取出图片数据"); Image image = reader.acquireNextImage(); ByteBuffer buffer = image.getPlanes()[0].getBuffer(); byte[] bytes = new byte[buffer.remaining()]; buffer.get(bytes);//由缓冲区存入字节数组 Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); try { String filePath = null; if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { if (Build.VERSION.SDK_INT 使用ImageReader实现不显示预览画面,仅获取预览数据(AI人脸识别可用) package com.eyetracking.camera2preview3;import androidx.annotation.NonNull;import androidx.appcompat.app.AppCompatActivity;import androidx.core.app.ActivityCompat;import androidx.core.content.ContextCompat;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.Environment;import android.os.Handler;import android.os.HandlerThread;import android.util.Log;import android.widget.Toast;import java.io.FileOutputStream;import java.io.IOException;import java.nio.ByteBuffer;import java.util.Arrays;public class MainActivity extends AppCompatActivity { private CameraDevice cameraDevice; private HandlerThread handlerThread; private Handler myHandler; private CameraManager manager; private CameraCaptureSession previeSession; private CaptureRequest.Builder previeBuilder; private ImageReader imageReader; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); checkCameraPermission(); } private void setImageReader() { imageReader = ImageReader.newInstance(1920, 1080, ImageFormat.JPEG, 2); imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() { @Override public void onImageAvailable(ImageReader reader) { Log.d("pictureListener", "取出图片数据"); Image image = reader.acquireNextImage(); ByteBuffer buffer = image.getPlanes()[0].getBuffer(); byte[] bytes = new byte[buffer.remaining()]; buffer.get(bytes);//由缓冲区存入字节数组 Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); try { String filePath = null; if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { if (Build.VERSION.SDK_INT