录制视频时启用相机闪光灯

2022-09-01 13:26:52

我需要一种方法来控制Android设备上录制视频时的相机闪光灯。我正在制作一个闪光灯应用程序,使用闪烁的频闪灯拍摄视频将能够记录高速移动的物体,例如风扇叶片。

闪光灯只能通过启动视频预览并在相机参数中设置FLASH_MODE_TORCH来启用。这看起来像这样:

Camera c = Camera.open();
Camera.Parameters p = c.getParameters();
p.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
c.setParameters(p);
c.startPreview();

预览开始后,我可以来回翻转该参数以打开和关闭灯光。在我尝试录制视频之前,这很有效。麻烦的是,为了将相机交给MediaRecorder,我首先必须将其解锁。

MediaRecorder m = new MediaRecorder();
c.unlock();     // the killer
m.setCamera(c);

解锁后,我无法再更改相机参数,因此无法更改闪光灯状态。

我不知道是否真的有可能做到这一点,因为我不是Java黑客的最佳人选,但以下是我所知道的:

  • Camera.unlock()是一种原生方法,所以我无法真正看到它锁定我的方式背后的机制。
  • Camera.Parameter 有一个包含其所有参数的 HashMap
  • Camera.setParameters(Parameters) 获取 HashMap,将其转换为字符串,然后将其传递给本机方法
  • 我可以消除所有参数,但从HashMap和相机中消除TORCH模式仍然会接受它

因此,我仍然可以访问相机,但它不会听我告诉它的任何内容。(这就是Camera.unlock()的目的)

编辑:

检查本机代码后,我可以看到在 CameraService 中.cpp我对 Camera.setParameters(Parameters) 的调用被拒绝,因为我的进程 ID 与相机服务记录的进程 ID 不匹配。所以看起来这是我的障碍。

编辑2:

MediaPlayerService似乎是在录制视频时控制摄像机的主要服务。我不知道这是否可能,但是如果我可以在自己的进程中以某种方式启动该服务,我应该能够跳过Camera.unlock()调用。

编辑3:

最后一个选择是,如果我能以某种方式获得指向CameraHardwareInterface的指针。从外观上看,这是一个特定于设备的接口,可能不包括PID检查。不过,这样做的主要问题是,我唯一能找到指向它的指针的地方是在CameraService中,而CameraService并没有说话。

编辑4:(几个月后)

在这一点上,我认为不可能做我最初想要的事情。我不想在有人回答问题的情况下删除这个问题,但我没有积极寻求答案。(不过,收到一个有效的答案会很棒。


答案 1

我遇到了类似的问题。用户应该能够在录制期间根据光线情况更改闪光灯模式以满足他们的需求。经过一些调查研究,我得出了以下解决方案:

我假设,您已经设置了一个正确的SurfaceView和一个SurfaceHolder及其必要的回调。我做的第一件事是提供这段代码(未声明的变量是全局变量):

public void surfaceCreated(SurfaceHolder holder) {
    try {
        camera = Camera.open();

        parameters = camera.getParameters();
        parameters.setFlashMode(Parameters.FLASH_MODE_OFF);

        camera.setParameters(parameters);
        camera.setPreviewDisplay(holder);
        camera.startPreview();

        recorder = new MediaRecorder();
    } catch (IOException e) {
        e.printStackTrace();
    }       
}

我的下一步是初始化和准备记录器:

private void initialize() {
    camera.unlock();

    recorder.setCamera(camera);
    recorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
    recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
    recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
    recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
    recorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
    recorder.setVideoFrameRate(20);
    recorder.setOutputFile(filePath);

    try {
        recorder.prepare();
    } catch (IllegalStateException e) {
        e.printStackTrace();
        finish();
    } catch (IOException e) {
        e.printStackTrace();
        finish();
    }
}

重要的是要注意,camera.unlock() 必须在媒体录制器的整个初始化过程之前调用。也就是说,还要注意每个集合属性的正确顺序,否则在调用 prepare() 或 start() 时,你会得到一个 IllegalStateException。在录音方面,我这样做。这通常由视图元素触发:

public void record(View view) {
    if (recording) {
        recorder.stop();

        //TODO: do stuff....

        recording = false;
    } else {
        recording = true;

        initialize();
        recorder.start();
    }
}

所以现在,我终于可以正确录制了。但是那个闪光灯有什么用呢?最后但并非最不重要的一点是,幕后的魔力来了:

public void flash(View view) {
    if(!recording) {
        camera.lock();
    }

    parameters.setFlashMode(parameters.getFlashMode().equals(Parameters.FLASH_MODE_TORCH) ? Parameters.FLASH_MODE_OFF : Parameters.FLASH_MODE_TORCH);
    camera.setParameters(parameters);

    if(!recording) {
        camera.unlock();
    }
}

每次我通过onClick操作调用该方法时,我都可以更改闪光灯模式,即使在录制期间也是如此。只需注意正确锁定相机即可。在录制过程中媒体录像机获得锁定后,您不必再次锁定/解锁相机。它甚至不起作用。这是在带有Android版本4.1.2的三星Galaxy S3上测试的。希望这种方法有所帮助。


答案 2

准备媒体录制器后,使用 camera.lock(),然后将要设置为 camera 的任何参数设置为 camera。但是在开始录制之前,您需要调用camera.unlock(),并且在停止媒体录制器后,您需要调用camera.lock()以开始预览。享受!!!


推荐