参考:
Camera v2文档1:https://www.jianshu.com/p/73fed068a795

github参考代码:https://github.com/googlesamples/android-Camera2Basic
参数调节关键字翻译集合,常用关键字解析文档:


一、前言:
    Android 5.0(21)之后android.hardware.Camera就被废弃了,取而代之的是全新的android.hardware.Camera2。
    Android 5.0对拍照API进行了全新的设计,新增了全新设计的Camera v2 API,这些API不仅大幅提高了Android系统拍照的功能,还能支持RAW照片输出,甚至允许程序调整相机的对焦模式、曝光模式、快门等。

常识:
------------相机参数:快门
快门就是相当于是一个门,在拍照的时候光通过这个门时间。快门速度越快,进光越少,那么拍照的速度就会越快。在运动中我们的快门速度通常会设置的快一点的,快门快的可以将运动的人拍的清晰,而且可以拍到运动中我们人眼看不到的动作

------------相机参数:光圈
光圈值越小,光圈越大,相当于相机的门较大,进入的光较多。在光弱的时候我通常是加大光圈的,加大光圈就是在手机上把光圈值调小就可了。光圈越大,焦点之外的清晰范围越小,焦点之外的模糊程度就越大。这里所说的模糊是虚焦模糊,也就是没对上焦的模糊。

------------相机参数 :感光度
感光度大部分都是自动的,相机的感光度顾名思义就是相片的亮度。在亮度低的地方我们通常要调高感光度的,同时也要减少曝光时间的,感光度高的时候需要更长的时间来提高相片的亮度的,一般在黑暗中提高感光度的同时一般都要提高曝光时间,曝光时间是通过快门调的,这时候就需要将快门时间调大点就可以。
感光度达到一定数值后(根据相机性能不同而不同),其值越高,画面中的噪点就越多,物体细节就越粗糙,画面的颗粒感就越重。进而会直接影响到画面细节表现,并且产生色彩偏差的可能性就越大。

 

二、Camera v2主要类说明
1、CameraManager:摄像头管理器。这是一个全新的系统管理器,专门用于检测系统摄像头、打开系统摄像头。
2、CameraCharacteristics:硬件摄像头特性。该对象通过CameraManager来获取,用于描述特定摄像头硬件所支持的各种特性。调用CameraManager的getCameraCharacteristics(cameraID)方法即可获取指定摄像头的相关特性。
3、CameraDevice:当前打开的摄像头类。该类的功能类似于早期的Camera类
4、CameraCaptureSession:这是一个非常重要的API,当程序需要预览、拍照时,都需要先通过该类的实例创建Session。而且不管预览还是拍照,也都是由该对象的方法进行控制的,其中控制预览的方法为setRepeatingRequest();控制拍照的方法为capture()。
5、CameraMetadata:控制相机和带有相机参数的基础类,它的子类是: CameraCharacteristics,CaptureRequest,CaptureResult。

三、使用

1、权限,6.0以后添加动态权限的获取:
 <uses-permission android:name="android.permission.CAMERA" />
 <uses-feature android:name="android.hardware.camera" />
 <uses-feature android:name="android.hardware.camera.autofocus" /> 
2、获取相机硬件属性
 CameraManager manager = (CameraManager) ctx.getSystemService(Context.CAMERA_SERVICE);
         try {
             //获取可用摄像头列表
             for (String cameraId : manager.getCameraIdList()) {
                 //获取相机的相关参数
                 CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
                 // 不使用前置摄像头。
                 Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
                 if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
                     continue;
                 }
                 StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
                 if (map == null) {
                     continue;
                 }
                 // 检查闪光灯是否支持。
                 Boolean available = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
                 mFlashSupported = available == null ? false : available;        //CameraID
                 mCameraId = cameraId;
                 Log.e(TAG," 相机可用 ");
                 return;
             }
         } catch (CameraAccessException e) {
             e.printStackTrace();
         } catch (NullPointerException e) {
             //不支持Camera2API
         }
     } 
3、打开指定相机(mCameraId)
 1)打开相机
     CameraManager manager = (CameraManager) ctx.getSystemService(Context.CAMERA_SERVICE);
         try {
             //打开相机预览
             manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);
         } catch (CameraAccessException e) {
             e.printStackTrace();
         } catch (InterruptedException e) {
             throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
         } 2)回调,获取当前相机设备的java对象mCameraDevice。
 private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {        @Override
         public void onOpened(@NonNull CameraDevice cameraDevice) {
             mCameraDevice = cameraDevice;
             //创建CameraPreviewSession
             createCameraPreviewSession();
         }        @Override
         public void onDisconnected(@NonNull CameraDevice cameraDevice) {
             cameraDevice.close();
             mCameraDevice = null;
         }        @Override
         public void onError(@NonNull CameraDevice cameraDevice, int error) {
             cameraDevice.close();
             mCameraDevice = null;
         }    };
 3)mBackgroundHandler定义: onResume中调用startBackgroundThread;onPause中调用stopBackgroundThread
     /**
      * Starts a background thread and its {@link Handler}.
      */
     private void startBackgroundThread() {
         mBackgroundThread = new HandlerThread("CameraBackground");
         mBackgroundThread.start();
         mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
     }    /**
      * Stops the background thread and its {@link Handler}.
      */
     private void stopBackgroundThread() {
         mBackgroundThread.quitSafely();
         try {
             mBackgroundThread.join();
             mBackgroundThread = null;
             mBackgroundHandler = null;
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
     } 
 4、关联surface和相机mCameraDevice:创建预览;设置当前相机预览时的参数;发送请求,无限次获取图像
    /**
      * 为相机预览创建新的CameraCaptureSession
      */
     private void createCameraPreviewSession() {         try {
             //CaptureRequest用的是builder模式,创建一个针对预览的CaptureRequest,设置其预览的surface
             mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
             mPreviewRequestBuilder.addTarget(mSurfaceHolder.getSurface());
             //创建一个CameraCaptureSession来进行相机预览。在安卓端和相机硬件端建立通道,进行信息的交换
             mCameraDevice.createCaptureSession(Arrays.asList(mSurfaceHolder.getSurface()),
                     new CameraCaptureSession.StateCallback() {                        @Override
                         public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
                             // 相机已经关闭
                             if (null == mCameraDevice) {
                                 return;
                             }
                             // 会话准备好后,我们开始显示预览
                             mCaptureSession = cameraCaptureSession;
                             try {
                                 // 自动对焦应
                                 mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                                         CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
                                 // 闪光灯
                                 setAutoFlash(mPreviewRequestBuilder);
                                 // 开启相机预览并添加事件
                                 mPreviewRequest = mPreviewRequestBuilder.build();
                                 //发送请求,无限次的重复获取图像
                                 mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback, mBackgroundHandler);
                                 Log.e(TAG," 开启相机预览并添加事件");
                             } catch (CameraAccessException e) {
                                 e.printStackTrace();
                             }
                         }                        @Override
                         public void onConfigureFailed(
                                 @NonNull CameraCaptureSession cameraCaptureSession) {
                             Log.e(TAG," onConfigureFailed 开启预览失败");
                         }
                     }, null);
         } catch (CameraAccessException e) {
             Log.e(TAG," CameraAccessException 开启预览失败");
             e.printStackTrace();
         }
     } private CameraCaptureSession.CaptureCallback mCaptureCallback = new CameraCaptureSession.CaptureCallback() {
        private void process(CaptureResult result) {
             //拍摄完全完成并且成功,拍摄图像数据可用时回调
         }        @Override
         public void onCaptureProgressed(@NonNull CameraCaptureSession session,
                                         @NonNull CaptureRequest request,
                                         @NonNull CaptureResult partialResult) {
       //拍摄进行中,但拍摄图像数据部分可用时回调
             process(partialResult);
         }        @Override
         public void onCaptureCompleted(@NonNull CameraCaptureSession session,
                                        @NonNull CaptureRequest request,
                                        @NonNull TotalCaptureResult result) {
         //拍摄失败时回调
             process(result);
         }    };

如上,分三部:
1)创建CameraCaptureSession会话对象:全新的API引用了管道的概念将安卓设备和摄像头之间联通起来,系统向摄像头发送 Capture 请求,而摄像头会返回 CameraMetadata。
    createCaptureSession(List<Surface> outputs, CameraCaptureSession.StateCallback callback, Handler handler) :
    第一参数就是我们需要输出到的Surface列表,这里我们可以输出到一个SurfaceView中或者TextureView中。
    第二参数是对创建过程的一个回调方法,当onConfigured回调的时候说明CameraCaptureSession创建成功了。

2)创建CaptureRequest请求,并设置当前相机预览时的参数:
    createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 这里我们发送的TEMPLATE_PREVIEW也就是告诉相机我们只需要预览。其他参数:
    TEMPLATE_RECORD 创建适合录像的请求。
    TEMPLATE_PREVIEW 创建一个适合于相机预览窗口的请求。
    TEMPLATE_STILL_CAPTURE 创建适用于静态图像捕获的请求
    TEMPLATE_VIDEO_SNAPSHOT 在录制视频时创建适合静态图像捕获的请求。

3)上面两个创建完毕后,调用mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback, mBackgroundHandler);  发情求开启预览,并无限次的重复请求获取图像。mCaptureCallback作为回调不断输出数据

 

5、拍照
 1)对焦
    /**
      * 将焦点锁定为静态图像捕获的第一步。(对焦)
      */
     private void lockFocus() {
         try {
             // 相机对焦
             mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
                     CameraMetadata.CONTROL_AF_TRIGGER_START);
             // 修改状态
             mState = STATE_WAITING_LOCK;
         //CameraCaptureSession发送对焦请求
             mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
                     mBackgroundHandler);
         } catch (CameraAccessException e) {
             e.printStackTrace();
         }
     } 2)对对焦是否成功进行监听,在mCaptureCallback中对回调进行处理
     /**
      * 处理与JPEG捕获有关的事件
      */
     private CameraCaptureSession.CaptureCallback mCaptureCallback
             = new CameraCaptureSession.CaptureCallback() {        //处理
         private void process(CaptureResult result) {
             switch (mState) {
                 case STATE_PREVIEW: {
                     //预览状态
                     break;
                 }                case STATE_WAITING_LOCK: {
                     //等待对焦
                     Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
                     if (afState == null) {
                         captureStillPicture();
                     } else if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||
                             CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) {
                         // CONTROL_AE_STATE can be null on some devices
                         Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
                         if (aeState == null || aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
                             mState = STATE_PICTURE_TAKEN;
                             //对焦完成
                             captureStillPicture();  
                         } else {
                             runPrecaptureSequence();
                         }
                     }
                     break;
                 }
                 
                 
                 }
             }
         } 3)向CameraCaptureSession发送请求拍照:
创建拍照请求mCaptureRequest对象;设置参数;发请求拍照:
     /**
      *
      * 拍摄静态图片。
      */
     private void captureStillPicture() {
         try {
             if ( null == mCameraDevice) {
                 return;
             }
             // 这是用来拍摄照片的CaptureRequest.Builder。
             final CaptureRequest.Builder captureBuilder =
                     mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
             captureBuilder.addTarget(mImageReader.getSurface());            // 使用相同的AE和AF模式作为预览。
             captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                     CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
             setAutoFlash(captureBuilder);
             // 方向
             int rotation = this.getWindowManager().getDefaultDisplay().getRotation();
             captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation));            CameraCaptureSession.CaptureCallback CaptureCallback
                     = new CameraCaptureSession.CaptureCallback() {
                 @Override
                 public void onCaptureCompleted(@NonNull CameraCaptureSession session,
                                                @NonNull CaptureRequest request,
                                                @NonNull TotalCaptureResult result) {
                     showToast("Saved: " + mFile);
                     Log.d(TAG, mFile.toString());
                     unlockFocus();
                 }
             };
             //停止连续取景
             mCaptureSession.stopRepeating();
             //捕获图片
             mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);
         } catch (CameraAccessException e) {
             e.printStackTrace();
         }
     } 4)拍照后,拿到数据进行保存:
 ------------这里要说回在创建CameraCaptureSession时参数不是有一个输出的Surface列表么,在列表中添加一个ImageReader的Surface用户获取图片数据(ImageReader是一个可以让我们对绘制到surface的图像进行直接操作的类),
 即:
 mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()), new CameraCaptureSession.StateCallback()...)------------在ImageReader中对图片获取就行监听:
 mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler);private final ImageReader.OnImageAvailableListener mOnImageAvailableListener
             = new ImageReader.OnImageAvailableListener() {        @Override
         public void onImageAvailable(ImageReader reader) {
             //当图片可得到的时候获取图片并保存,reader.acquireNextImage()我们就可以拿到当前的图片数据了
             mBackgroundHandler.post(new ImageSaver(reader.acquireNextImage(), mFile));
         reader.acquireNextImage().close();
         }    };
注意:一定要调用reader.acquireLatestImage()和close()方法,否则画面就会卡住
 
5)拍完后我们需要解锁焦点让相机回到预览状态
/**
      * 解锁焦点
      */
     private void unlockFocus() {
         try {
             // 重置自动对焦
             mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
                     CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
             setAutoFlash(mPreviewRequestBuilder);
             mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
                     mBackgroundHandler);
             // 将相机恢复正常的预览状态。
             mState = STATE_PREVIEW;
             // 打开连续取景模式
             mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback,
                     mBackgroundHandler);
         } catch (CameraAccessException e) {
             e.printStackTrace();
         }
     }

 

6、预览图片实时输出
mPreviewRequestBuilder.addTarget(mSurfaceHolder.getSurface());
mPreviewRequestBuilder.addTarget(mImageReader.getSurface());//添加mImageReader.getSurface(),这样会在mOnImageAvailableListener监听中会实时收到预览数据
mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()), new CameraCaptureSession.StateCallback()...)

 

7、注意点
Camera2 API配合SurfaceView暂时没有找到设置输出分辨率的接口。导致mOnImageAvailableListener监听中获取的Image对象,data数据的分辨率和image的宽高(mImageReader对象创建时设置)不一样。
Camera2 API根据google官方API配合TextureView进行预览

 

 

四、其他
1、通过设置ANDROID_CONTROL_MODE控制3A。可以选择没有3A(ANDROID_CONTROL_MODE_OFF),自动模式(ANDROID_CONTROL_MODE_AUTO)和场景模式(ANDROID_CONTROL_USE_SCENE_MODE)。
·        在OFF模式下,自动聚焦(AF),自动曝光(AE)和自动白平衡(AEB)模式都被关闭。3A事例不会重置捕获控制中的任何设置。
·        在AUTO模式下,AF,AE和AWB模式运行各自的独立算法,它们有自己的模式,状态和触发器元数据实体,如下段描述。
·        在USE_SCENE_MODE模式下,ANDROID_CONTROL_SCENE_MODE的值决定3A事例的行为。在除了FACE_PRIORITY的SCENE_MODE中,HAL层必须将ANDROID_CONTROL_AE/AWB/AF_MODE的值重置为更适合被选择的SCENE_MODE的模式。例如,HAL层喜欢在SCENE_MODE_NIGHT场景中使用AF的CONTINUOUS_FOCUS模式。当这些场景模式被忽略时,将使用用户对AE/AWB/AF_MODE的选择。
·        对SCENE_MODE_FACE_PRIORITY的场景,AE/AWB/AFMODE工作在ANDROID_CONTROL_MODE_AUTO模式下。但是3A算法需要侧重对场景中检测出来的脸进行测光和聚焦。

2、自动曝光模式下:

requestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
                     CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
 requestBuilder.set(CaptureRequest.CONTROL_MODE,
                 CaptureRequest.CONTROL_MODE_AUTO);

mCaptureCallback中回调的的数据对象CaptureResult:
通过CaptureResult.get(CaptureResult.SENSOR_SENSITIVITY) 可以实时获取每一帧的实时感光度。