You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 00:37:32