Android Camera2使用

简介: 1. 相机使用流程图1.jpg2. SurfaceView/** * Android 5.0 使用Camera2 照相 * 使用SurfaceView显示 * 主要步骤: * 1.

1. 相机使用流程

img_fe9897bef6d4544f03b6f23a64f60009.jpe
图1.jpg

2. SurfaceView

/**
 * Android 5.0 使用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(){}回调方法中,将拍照拿到的图片进行展示
 */
public class CameraSurfaceFragment extends Fragment {
  /**照相机设备请求码*/
  private static final int REQUEST_CAMERA_CODE = 0x100;
  /**拍照*/
  private Button mBtnTake;
  /**显示拍照好的图片*/
  private ImageView mIvShow;
  /**预览窗口*/
  private SurfaceView mSurfaceView;
  /**预览窗口Holder*/
  private SurfaceHolder mSurfaceHolder;
  /**子线程Handler*/
  private Handler mChildHandler;
  /**主线程Handler*/
  private Handler mMainHandler;
  /**照相机ID,标识前置,后置*/
  private String mCameraId;
  /**图片读取器*/
  private ImageReader mImageReader;
  /**摄像头管理者*/
  private CameraManager mCameraManager;
  /**照相机设备*/
  private CameraDevice mCameraDevice;
  /**照相会话*/
  private CameraCaptureSession mCameraCaptureSession;
  /**方向列表*/
  private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
  
  /**
   * 摄像头状态监听
   */
  private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
    @Override
    public void onOpened(@NonNull CameraDevice camera) {
      // 打开摄像头
      mCameraDevice = camera;
      // 开启预览
      takePreview();
    }
  
    @Override
    public void onDisconnected(@NonNull CameraDevice camera) {
      // 关闭摄像头
      if (null != mCameraDevice) {
        // 关闭摄像头
        mCameraDevice.close();
        mCameraDevice = null;
      }
    }
  
    @Override
    public void onError(@NonNull CameraDevice camera, int error) {
      // 摄像头异常
      Toast.makeText(getContext(), "摄像头开启失败", Toast.LENGTH_SHORT).show();
    }
  };
  
  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);
  }
  
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
                           Bundle savedInstanceState) {
    View root = inflater.inflate(R.layout.fragment_camera_surface, container, false);
    initView(root);
    initListener();
    return root;
  }
  
  /**
   * 初始化View
   */
  private void initView(View view) {
    // 绑定View
    mIvShow = view.findViewById(R.id.iv_show);
    mBtnTake = view.findViewById(R.id.btn_take);
    mSurfaceView = view.findViewById(R.id.sv_camera);
    // 获取Holder
    mSurfaceHolder = mSurfaceView.getHolder();
    // 设置屏幕常量
    mSurfaceHolder.setKeepScreenOn(true);
    // 设置SurfaceView回调
    mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
      @Override
      public void surfaceCreated(SurfaceHolder holder) {
        // SurfaceView 创建
        initCamera();
      }
  
      @Override
      public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        // SurfaceView 改变
      }
  
      @Override
      public void surfaceDestroyed(SurfaceHolder holder) {
        // SurfaceView 销毁
        // 销毁照相机设备
        if (null != mCameraDevice) {
          mCameraDevice.close();
          mCameraDevice = null;
        }
      }
    });
  }
  
  /**
   * 初始化监听器
   */
  private void initListener() {
    mBtnTake.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        takePicture();
      }
      
    });
  }
  
  /**
   * 初始化照相机
   */
  private void initCamera() {
    // 创建Handler线程并启动
    HandlerThread handlerThread = new HandlerThread("Camera");
    handlerThread.start();
    // 创建子线程Handler
    mChildHandler = new Handler(handlerThread.getLooper());
    // 创建主线程Handler
    mMainHandler = new Handler(Looper.getMainLooper());
    // 设置后置摄像头ID
    mCameraId = String.valueOf(CameraCharacteristics.LENS_FACING_FRONT);
    // 创建图片读取器
    mImageReader = ImageReader.newInstance(1080, 1920, ImageFormat.JPEG, 1);
    // 图片读取器设置图片可用监听
    mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
      @Override
      public void onImageAvailable(ImageReader reader) {
        showImage(reader);
      }
    }, mMainHandler);
    // 获取摄像头管理
    mCameraManager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);
    // 打开摄像头
    try {
      if (ActivityCompat.checkSelfPermission
              (getContext(), Manifest.permission.CAMERA)
              != PackageManager.PERMISSION_GRANTED) {
        // 申请权限
        requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_CODE);
      } else {
        // 打开摄像头
        mCameraManager.openCamera(mCameraId, mStateCallback, mMainHandler);
      }
    } catch (CameraAccessException e) {
      e.printStackTrace();
    }
  }
  
  @Override
  public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (REQUEST_CAMERA_CODE == requestCode) {
      // 权限允许
      if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        try {
          if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            return;
          }
          mCameraManager.openCamera(mCameraId, mStateCallback, mMainHandler);
        } catch (CameraAccessException e) {
          e.printStackTrace();
        }
      } else {
        // 权限拒绝
        Toast.makeText(getContext(), "无权限", Toast.LENGTH_SHORT).show();
      }
    }
  }
  
  /**
   * 图片可用后,读取并显示图片
   * @param reader 图片读取器
   */
  private void showImage(ImageReader reader) {
    // 拿到图片数据
    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 (null != bitmap) {
      mIvShow.setImageBitmap(bitmap);
    }
  }
  
  /**
   * 预览
   */
  private void takePreview() {
    try {
      // 创建预览需要的CaptureRequest.Builder
      final CaptureRequest.Builder builder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
      // 将SurfaceView的surface作为Builder的目标
      builder.addTarget(mSurfaceHolder.getSurface());
      // 创建CameraCaptureSession,该对象负责管理处理预览请求和拍照请求
      mCameraDevice.createCaptureSession(Arrays.asList(mSurfaceHolder.getSurface(), mImageReader.getSurface()), new CameraCaptureSession.StateCallback() {
        @Override
        public void onConfigured(@NonNull CameraCaptureSession session) {
          // 检测设备是否为空
          if (null == mCameraDevice) return;
          // 配置
          // 当摄像头已经准备好时,开始显示预览
          mCameraCaptureSession = session;
          try {
            // 自动对焦
            builder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
            // 打开闪光灯
            builder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
            // 显示预览
            CaptureRequest request = builder.build();
            // 会话设置重复请求
            mCameraCaptureSession.setRepeatingRequest(request, null, mChildHandler);
          } catch (CameraAccessException e) {
            e.printStackTrace();
          }
        }
  
        @Override
        public void onConfigureFailed(@NonNull CameraCaptureSession session) {
          Toast.makeText(getContext(), "配置失败", Toast.LENGTH_SHORT).show();
        }
      }, mChildHandler);
    } catch (CameraAccessException e) {
      e.printStackTrace();
    }
  }
  
  /**
   * 拍照
   */
  private void takePicture() {
    // 判断设备是否为空
    if (null == mCameraDevice) return;
    // 创建拍照需要的CaptureRequest.Builder
    final CaptureRequest.Builder builder;
    try {
      // 创建拍照请求
      builder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
      // 将imageReader的surface作为CaptureRequest.Builder的木白哦
      builder.addTarget(mImageReader.getSurface());
      // 自动对焦
      builder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
      // 自动曝光
      builder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
      // 获取手机方向
      int rotation = getActivity().getWindowManager().getDefaultDisplay().getRotation();
      // 根据设备方向计算设置照片的方向
      builder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
      // 拍照
      CaptureRequest request = builder.build();
      // 拍照会话执行拍照
      mCameraCaptureSession.capture(request, null, mChildHandler);
    } catch (CameraAccessException e) {
      e.printStackTrace();
    }
  }
}

3. TextureView

/**
 * Camera2 与 Texture使用
 */
public class CameraTextureFragment extends Fragment {
  /**相机权限请求标识*/
  private static final int REQUEST_CAMERA_CODE = 0x100;
  /**预览*/
  private TextureView mTextureView;
  /**拍照按钮*/
  private Button mBtnTake;
  /**图片*/
  private ImageView mImageView;
  /**照相机ID,标识前置后置*/
  private String mCameraId;
  /**相机尺寸*/
  private Size mCaptureSize;
  /**图像读取者*/
  private ImageReader mImageReader;
  /**图像主线程Handler*/
  private Handler mCameraHandler;
  /**相机设备*/
  private CameraDevice mCameraDevice;
  /**预览大小*/
  private Size mPreviewSize;
  /**相机请求*/
  private CaptureRequest.Builder mCameraCaptureBuilder;
  /**相机拍照捕获会话*/
  private CameraCaptureSession mCameraCaptureSession;
  /**相机管理者*/
  private CameraManager mCameraManager;
  /**相机设备状态回调*/
  private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
    @Override
    public void onOpened(@NonNull CameraDevice camera) {
      // 打开
      mCameraDevice = camera;
      // 开始预览
      takePreview();
    }
  
    @Override
    public void onDisconnected(@NonNull CameraDevice camera) {
      // 断开连接
      camera.close();
      mCameraDevice = null;
    }
  
    @Override
    public void onError(@NonNull CameraDevice camera, int error) {
      // 异常
      camera.close();
      mCameraDevice = null;
    }
  };
  
  
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
                           Bundle savedInstanceState) {
    View root = inflater.inflate(R.layout.fragment_camera_texture, container, false);
    initView(root);
    initListener();
    return root;
  }
  
  /**
   * 初始化View
   */
  private void initView(View view) {
    // 初始化View
    mImageView = view.findViewById(R.id.iv_show);
    mTextureView = view.findViewById(R.id.tv_camera);
    mBtnTake = view.findViewById(R.id.btn_take);
  }
  
  @Override
  public void onResume() {
    super.onResume();
    mTextureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
      @Override
      public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
        // SurfaceTexture可用
        // 设置相机参数并打开相机
        setUpCamera(width, height);
        openCamera();
      }
  
      @Override
      public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
        // SurfaceTexture大小改变
      }
  
      @Override
      public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
        // SurfaceTexture 销毁
        return false;
      }
  
      @Override
      public void onSurfaceTextureUpdated(SurfaceTexture surface) {
        // SurfaceTexture 更新
      }
    });
  }
  
  /**
   * 打开相机
   */
  private void openCamera() {
    // 获取照相机管理者
    mCameraManager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);
    try {
      if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
        requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_CODE);
        return;
      }
      // 打开相机
      mCameraManager.openCamera(mCameraId, mStateCallback, mCameraHandler);
    } catch (CameraAccessException e) {
      e.printStackTrace();
    }
  }
  
  @Override
  public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (REQUEST_CAMERA_CODE == requestCode) {
      // 权限允许
      if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        try {
          if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            return;
          }
          mCameraManager.openCamera(mCameraId, mStateCallback, mCameraHandler);
        } catch (CameraAccessException e) {
          e.printStackTrace();
        }
      } else {
        // 权限拒绝
        Toast.makeText(getContext(), "无权限", Toast.LENGTH_SHORT).show();
      }
    }
  }
  
  /**
   * 设置相机参数
   * @param width 宽度
   * @param height 高度
   */
  private void setUpCamera(int width, int height) {
    // 创建Handler
    mCameraHandler = new Handler(Looper.getMainLooper());
    // 获取摄像头的管理者
    CameraManager cameraManager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);
    try {
      // 遍历所有摄像头
      for (String cameraId : cameraManager.getCameraIdList()) {
        // 相机特性
        CameraCharacteristics cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId);
        // 获取摄像头是前置还是后置
        Integer facing = cameraCharacteristics.get(CameraCharacteristics.LENS_FACING);
        // 此处默认打开后置摄像头
        if (null != facing && CameraCharacteristics.LENS_FACING_FRONT == facing)  continue;
        // 获取StreamConfigurationMap,管理摄像头支持的所有输出格式和尺寸
        StreamConfigurationMap map = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
        assert map != null;
        // 根据TextureView的尺寸设置预览尺寸
        mPreviewSize = getOptimalSize(map.getOutputSizes(SurfaceTexture.class), width, height);
        // 获取相机支持的最大拍照尺寸
        mCaptureSize = Collections.max(
                Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)), new Comparator<Size>() {
                  @Override
                  public int compare(Size lhs, Size rhs) {
                    return Long.signum(lhs.getWidth() * lhs.getHeight() - rhs.getHeight() * rhs.getWidth());
                  }
                });
        // 此处ImageReader用于拍照所需
        setupImageReader();
        // 为摄像头赋值
        mCameraId = cameraId;
        break;
      }
    } catch (CameraAccessException e) {
      e.printStackTrace();
    }
  }
  
  /**
   * 设置ImageReader
   */
  private void setupImageReader() {
    // 2代表ImageReader中最多可以获取两帧图像流
    mImageReader = ImageReader.newInstance(mCaptureSize.getWidth(), mCaptureSize.getHeight(), ImageFormat.JPEG, 1);
    // 设置图像可用监听
    mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
      @Override
      public void onImageAvailable(ImageReader reader) {
        // 获取图片
        final Image image = reader.acquireNextImage();
        // 提交任务,保存图片
        mCameraHandler.post(new ImageSaver(image));
        // 更新UI
        getActivity().runOnUiThread(new Runnable() {
          @Override
          public void run() {
            // 获取字节缓冲区
            ByteBuffer buffer = image.getPlanes()[0].getBuffer();
            // 创建数组之前调用此方法,恢复默认设置
            buffer.rewind();
            // 创建与缓冲区内容大小相同的数组
            byte[] bytes = new byte[buffer.remaining()];
            // 从缓冲区存入字节数组,读取完成之后position在末尾
            buffer.get(bytes);
            // 获取Bitmap图像
            final Bitmap bitmap =  BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
            // 显示
            if (null != bitmap) {
              mImageView.setImageBitmap(bitmap);
            }
            
          }
        });
      }
    }, mCameraHandler);
  }
  
  /**
   * 选择SizeMap中大于并且最接近width和height的size
   * @param sizeMap 可选的尺寸
   * @param width 宽
   * @param height 高
   * @return 最接近width和height的size
   */
  private Size getOptimalSize(Size[] sizeMap, int width, int height) {
    // 创建列表
    List<Size> sizeList = new ArrayList<>();
    // 遍历
    for (Size option : sizeMap) {
      // 判断宽度是否大于高度
      if (width > height) {
        if (option.getWidth() > width && option.getHeight() > height) {
          sizeList.add(option);
        }
      } else {
        if (option.getWidth() > height && option.getHeight() > width) {
          sizeList.add(option);
        }
      }
    }
    // 判断存储Size的列表是否有数据
    if (sizeList.size() > 0) {
      return Collections.min(sizeList, new Comparator<Size>() {
        @Override
        public int compare(Size lhs, Size rhs) {
          return Long.signum(lhs.getWidth() * lhs.getHeight() - rhs.getWidth() * rhs.getHeight());
        }
      });
    }
    return sizeMap[0];
  }
  
  /**
   * 设置监听
   */
  private void initListener() {
    mBtnTake.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        takePicture();
      }
    });
  }
  
  /**
   * 预览
   */
  private void takePreview(){
    // 获取SurfaceTexture
    SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
    // 设置默认的缓冲大小
    surfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
    // 创建Surface
    Surface previewSurface = new Surface(surfaceTexture);
    try {
      // 创建预览请求
      mCameraCaptureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
      // 将previewSurface添加到预览请求中
      mCameraCaptureBuilder.addTarget(previewSurface);
      // 创建会话
      mCameraDevice.createCaptureSession(Arrays.asList(previewSurface, mImageReader.getSurface()), new CameraCaptureSession.StateCallback() {
        @Override
        public void onConfigured(@NonNull CameraCaptureSession session) {
          try {
            // 配置
            CaptureRequest captureRequest = mCameraCaptureBuilder.build();
            // 設置session
            mCameraCaptureSession = session;
            // 设置重复预览请求
            mCameraCaptureSession.setRepeatingRequest(captureRequest, null, mCameraHandler);
          } catch (CameraAccessException e) {
            e.printStackTrace();
          }
        }
  
        @Override
        public void onConfigureFailed(@NonNull CameraCaptureSession session) {
          // 配置失败
        }
      }, mCameraHandler);
    } catch (CameraAccessException e) {
      e.printStackTrace();
    }
  }
  
  /**
   * 拍照
   */
  private void takePicture() {
    try {
      // 设置触发
      mCameraCaptureBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);
      mCameraCaptureBuilder.addTarget(mImageReader.getSurface());
      // 拍照
      mCameraCaptureSession.capture(mCameraCaptureBuilder.build(), null, mCameraHandler);
    } catch (CameraAccessException e) {
      Toast.makeText(getActivity(), "异常", Toast.LENGTH_SHORT).show();
      e.printStackTrace();
    }
  }
  
  /**
   * 保存图片任务
   */
  private class ImageSaver implements Runnable {
    /**图像*/
    private Image mImage;
    ImageSaver(Image image) {
      this.mImage = image;
    }
  
    @Override
    public void run() {
      // 获取字节缓冲区
      ByteBuffer buffer = mImage.getPlanes()[0].getBuffer();
      // 创建数组之前调用此方法,恢复默认设置--重要
      buffer.rewind();
      // 创建与字节缓冲区大小相同的字节数组
      byte[] data = new byte[buffer.remaining()];
      // 将数据读取字节数组
      buffer.get(data);
      // 获取缓存路径
      String path = getActivity().getExternalCacheDir().getPath();
      // 获取时间戳
      String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(new Date());
      // 文件名
      String fileName = path + "/IMG_" + timeStamp + ".jpg";
      // 创建文件输出流
      FileOutputStream fos = null;
      try {
        // 初始化文件输出流
        fos = new FileOutputStream(fileName);
        // 将数据写入文件
        fos.write(data, 0, data.length);
        // 刷新缓冲区
        fos.flush();
      } catch (IOException e) {
        e.printStackTrace();
      } finally {
        if (null != fos) {
          try {
            fos.close();
          } catch (IOException e) {
            e.printStackTrace();
          }
        }
      }
    }
  }
}

4. 多功能相机

  • 切换摄像头
  /**
   * 后置摄像头
   */
  private static final int CAMERA_FRONT = CameraCharacteristics.LENS_FACING_FRONT;
  /**
   * 前置摄像头
   */
  private static final int CAMERA_BACK = CameraCharacteristics.LENS_FACING_BACK;
  /**
   * 照相机ID,标识前置后置
   */
  private String mCameraId;

  /**
   * 切换前后摄像头
   */
  private void switchCamera() {
    if (String.valueOf(CAMERA_FRONT).equals(mCameraId)) {
      // 后置
      mCameraId = String.valueOf(CAMERA_BACK);
    } else if (String.valueOf(CAMERA_BACK).equals(mCameraId)) {
      // 前置
      mCameraId = String.valueOf(CAMERA_FRONT);
    }
    closeCamera();
    reOpenCamera();
  }
  
  /**
   * 重新打开摄像头
   */
  private void reOpenCamera() {
    if (mTextureView.isAvailable()) {
      openCamera();
    } else {
      setTextureListener();
    }
  }
  
  /**
   * 关闭摄像头
   */
  private void closeCamera() {
    if (null != mCameraCaptureSession) {
      mCameraCaptureSession.close();
      mCameraCaptureSession = null;
    }
    if (null != mCameraDevice) {
      mCameraDevice.close();
      mCameraDevice = null;
    }
    if (null != mImageReader) {
      mImageReader.close();
      mImageReader = null;
    }
  }
  • 延时拍摄
  /**
   * 无延时
   */
  private static final int DELAY_ZERO = 0;
  /**
   * 延时3秒
   */
  private static final int DELAY_THREE = 3;
  /**
   * 延时10秒
   */
  private static final int DELAY_TEN = 10;
  
  /**
   * 延时拍摄
   */
  private void delayTake() {
    switch (mDelayTime) {
      case DELAY_ZERO:
        mDelayTime = DELAY_THREE;
        break;
      case DELAY_THREE:
        mDelayTime = DELAY_TEN;
        break;
      case DELAY_TEN:
        mDelayTime = DELAY_ZERO;
        break;
    }
    mBtnDelay.setText("延时" + mDelayTime + "秒");
    if (mDelayTime == DELAY_ZERO) {
      takePicture();
    } else {
      // 定时器
      new CountDownTimer(mDelayTime * 1000, 1000) {
        
        @Override
        public void onTick(long millisUntilFinished) {
          mBtnDelay.setText(String.valueOf(millisUntilFinished/1000) + "秒");
        }
        
        @Override
        public void onFinish() {
          mBtnDelay.setText("延时" + mDelayTime + "秒");
          takePicture();
        }
      }.start();
    }
  }

  • 切换闪光
  /**
   * 闪光标识--自动开启
   */
  private static final int FLASH_ZERO = 0;
  /**
   * 闪光标识--总是开启
   */
  private static final int FLASH_ONE = 1;
  /**
   * 闪光标识--关闭
   */
  private static final int FLASH_TWO = 2;
  /**
   * 切换闪光模式
   */
  private void switchFlash() {
    switch(mFlashMode) {
      case FLASH_ZERO:
        mFlashMode = FLASH_ONE;
        mCameraCaptureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
        break;
      case FLASH_ONE:
        mFlashMode = FLASH_TWO;
        mCameraCaptureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
        break;
      case FLASH_TWO:
        mFlashMode = FLASH_ZERO;
        mCameraCaptureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
        // 必须设置
        mCameraCaptureBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
        break;
    }
    try {
      mCameraCaptureSession.setRepeatingRequest(mCameraCaptureBuilder.build(), null, mCameraHandler);
    } catch (CameraAccessException e) {
      e.printStackTrace();
    }
  }
  

代码下载

目录
相关文章
|
数据采集 编解码 API
如何实现Android平台GB28181设备对接Camera2数据
在写如何实现Android平台GB28181设备对接Camera2数据说明之前,我在前两年的blog就有针对camera2的RTMP直播推送模块做过技术分享:
如何实现Android平台GB28181设备对接Camera2数据
|
算法 API 开发工具
Android平台Camera2数据如何对接RTMP推流到服务器
在Google 推出Android 5.0的时候, Android Camera API 版本升级到了API2(android.hardware.camera2), 之前使用的API1(android.hardware.camera)就被标为 Deprecated 了。
308 0
|
API 开发工具 Android开发
如何实现RTMP推送Android Camera2数据
在Google 推出Android 5.0的时候, Android Camera API 版本升级到了API2(android.hardware.camera2), 之前使用的API1(android.hardware.camera)就被标为 Deprecated 了。
140 0
|
传感器 前端开发 Java
Android流媒体开发之路一:Camera2采集摄像头原始数据并手动预览
Android流媒体开发之路一:Camera2采集摄像头原始数据并手动预览
665 0
|
Android开发
android10.0(Q) Camera2 保存图片角度不对和镜像问题
android10.0(Q) Camera2 保存图片角度不对和镜像问题
255 0
|
传感器 算法 API
Android9.0 Camera2 横屏问题修改记录
Android9.0 Camera2 横屏问题修改记录
140 0
|
Android开发 API
Android Camera2 拍照(四)——对焦模式
原文:Android Camera2 拍照(四)——对焦模式 本篇将重点介绍使用Camera2 API进行手动对焦的设置,以及在手动对焦与自动对焦模式之间切换。
3688 0
|
API Android开发
Android中的拍照camera和camera2
在android我们可以调用系统的相机来进行照相,当然也可以设计自己的照相页面,通过surface进行预览,通过camera api来进行拍照即可。 在Android 5.0之后google推荐使用的Camera2 Api,但是由于兼容问题我们大部分还在使用Camera Api。这里我们一起简单介绍一下,仅仅是预览拍照,至于细节的设置,比如图像大小比例、对焦、图像旋转等就不一一细说了。 首先我们需要在布局中加入一个SurfaceView
721 0
|
API Android开发
android Camera2 API使用详解
原文:android Camera2 API使用详解 由于最近需要使用相机拍照等功能,鉴于老旧的相机API问题多多,而且新的设备都是基于安卓5.0以上的,于是本人决定研究一下安卓5.0新引入的Camera2 API 来实现 Camera2API地址 首先我们来熟悉一下官方给的这几个图: 这里引用了管道的概念将安卓设备和摄像头之间联通起来,系统向摄像头发送 Capture 请求,而摄像头会返回 CameraMetadata。
3790 0
|
Android开发
Android Camera2 拍照(三)——切换摄像头,延时拍摄和闪光模式
原文:Android Camera2 拍照(三)——切换摄像头,延时拍摄和闪光模式 一、切换摄像头 在前后摄像头之间切换,首先需要关闭之前打开的摄像头,关闭preview,之后重新打开新的摄像头,重新打开preview。
4227 1