JavaCamera2View开启闪光灯问题求助:替代已废弃Camera1 API方案
解决JavaCamera2View的闪光灯控制问题
我明白你遇到的痛点——Camera2 API的设计和老旧的Camera1完全不一样,没有直接给你一个Camera对象来直接调参数。不过别慌,我们可以利用Camera2的核心组件CaptureRequest和CameraCaptureSession来实现闪光灯控制,下面是适配JavaCamera2View的完整解决方案,替换你原来基于Camera1的代码:
完整的CustomCamera2实现
import android.content.Context; import android.hardware.camera2.CameraCaptureSession; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CaptureRequest; import android.util.AttributeSet; import android.util.Log; import org.opencv.android.JavaCamera2View; import org.opencv.android.PictureCallback; import java.io.FileOutputStream; import java.io.IOException; import java.util.List; public class CustomCamera2 extends JavaCamera2View implements PictureCallback { private String mPictureFileName; // Camera2的核心操作对象 private CameraDevice mCameraDevice; private CameraCaptureSession mCaptureSession; private CaptureRequest.Builder mPreviewRequestBuilder; public CustomCamera2(Context context, AttributeSet attrs) { super(context, attrs); } // 重写JavaCamera2View的回调,拿到初始化后的相机设备 @Override protected void onCameraOpened(CameraDevice cameraDevice, CameraCharacteristics cameraCharacteristics) { super.onCameraOpened(cameraDevice, cameraCharacteristics); this.mCameraDevice = cameraDevice; // 创建预览请求的Builder,后续用来修改闪光灯等参数 try { mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); } catch (Exception e) { Log.e("CustomCamera2", "创建预览请求Builder失败", e); } } // 拿到配置好的预览会话 @Override protected void onPreviewSessionConfigured(CameraCaptureSession cameraCaptureSession) { super.onPreviewSessionConfigured(cameraCaptureSession); this.mCaptureSession = cameraCaptureSession; } // 获取支持的闪光灯模式列表 public List<Integer> getFlashModeList() { if (mCameraDevice == null) return null; CameraCharacteristics characteristics = getCameraCharacteristics(); return characteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES); } // 检查设备是否支持闪光灯 public boolean isFlashSupported() { if (mCameraDevice == null) return false; CameraCharacteristics characteristics = getCameraCharacteristics(); Boolean isAvailable = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE); return isAvailable != null && isAvailable; } // 设置闪光灯模式 public void setFlashMode(int flashMode) { // 先判断核心对象是否初始化完成,避免空指针 if (mPreviewRequestBuilder == null || mCaptureSession == null) { Log.w("CustomCamera2", "相机还未初始化完成,无法设置闪光灯"); return; } // 常用闪光灯模式说明: // CONTROL_AE_MODE_ON_ALWAYS_FLASH:强制开启闪光灯 // CONTROL_AE_MODE_ON_AUTO_FLASH:自动闪光(光线暗时自动触发) // CONTROL_AE_MODE_ON:自动曝光但不自动闪光 // CONTROL_AE_MODE_OFF:关闭闪光灯(需手动处理曝光,一般不推荐) mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, flashMode); try { // 更新预览会话,让新的闪光灯设置生效 mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), null, null); } catch (Exception e) { Log.e("CustomCamera2", "设置闪光灯模式失败", e); } } // 获取当前的闪光灯模式 public Integer getCurrentFlashMode() { if (mPreviewRequestBuilder == null) return null; return mPreviewRequestBuilder.get(CaptureRequest.CONTROL_AE_MODE); } // 适配Camera2的拍照功能 public void takePicture(final String fileName) { this.mPictureFileName = fileName; if (mCameraDevice == null || mCaptureSession == null) { Log.w("CustomCamera2", "相机未初始化完成,无法拍照"); return; } try { // 创建拍照专用的请求Builder CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); captureBuilder.addTarget(getImageReader().getSurface()); // 继承当前预览的闪光灯设置,保证拍照时闪光灯状态和预览一致 Integer currentFlashMode = getCurrentFlashMode(); if (currentFlashMode != null) { captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, currentFlashMode); } // 触发拍照,并在完成后处理回调 mCaptureSession.capture(captureBuilder.build(), new CameraCaptureSession.CaptureCallback() { @Override public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, android.hardware.camera2.TotalCaptureResult result) { super.onCaptureCompleted(session, request, result); // 拍照完成后重启预览 startPreview(); // 保存图片到指定文件 saveCapturedPicture(); } }, null); } catch (Exception e) { Log.e("CustomCamera2", "拍照失败", e); } } // 保存拍照数据到文件 private void saveCapturedPicture() { if (mPictureFileName == null) return; try { // 从JavaCamera2View的ImageReader中获取拍照的字节数据 byte[] pictureData = getPictureData(); if (pictureData != null) { FileOutputStream fos = new FileOutputStream(mPictureFileName); fos.write(pictureData); fos.close(); } } catch (IOException e) { Log.e("CustomCamera2", "保存图片时出错", e); } } @Override public void onPictureTaken(byte[] data, org.opencv.android.CameraBridgeViewBase.CvCameraViewFrame frame) { // 注意:这个回调在JavaCamera2View中已经不再直接触发,我们改用上面的CaptureCallback来处理拍照完成逻辑 } // 释放相机资源 public void releaseCamera() { if (mCaptureSession != null) { mCaptureSession.close(); mCaptureSession = null; } if (mCameraDevice != null) { mCameraDevice.close(); mCameraDevice = null; } super.disconnectCamera(); } }
关键要点说明
- 核心对象获取:通过重写
onCameraOpened和onPreviewSessionConfigured这两个JavaCamera2View的回调方法,我们能拿到Camera2操作必须的CameraDevice和CameraCaptureSession对象,这是所有相机参数设置的基础。 - 闪光灯控制逻辑:Camera2不再像Camera1那样直接修改相机参数,而是通过
CaptureRequest.Builder来配置参数(比如闪光灯模式),然后把这个配置更新到CameraCaptureSession中,让预览实时生效。 - 拍照适配:拍照时需要创建专门的
TEMPLATE_STILL_CAPTURE请求,并且要继承预览的闪光灯设置,这样拍照时的闪光灯状态才会和预览时保持一致。 - 兼容性检查:在所有操作前都先判断核心对象是否初始化完成,避免空指针异常;同时通过
CameraCharacteristics检查设备是否支持闪光灯,提升代码鲁棒性。
使用示例
// 强制开启闪光灯 customCamera2.setFlashMode(CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH); // 切换到自动闪光模式 customCamera2.setFlashMode(CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); // 关闭闪光灯(仅自动曝光,不触发闪光) customCamera2.setFlashMode(CaptureRequest.CONTROL_AE_MODE_ON);
内容的提问来源于stack exchange,提问作者Raf
相关产品推荐
相关产品推荐

