我需要一种在录制视频时控制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-hacking,但这是我所知道的:
所以,我仍然可以访问相机,但它不会听我说的任何东西。 (这是Camera.unlock()的目的)
修改
在检查本机代码后,我可以看到在CameraService.cpp中我对Camera.setParameters(Parameters)的调用被拒绝,因为我的进程ID与摄像头服务记录的进程ID不匹配。所以这似乎是我的障碍。
EDIT2:
MediaPlayerService似乎是录制视频时控制摄像头的主要服务。我不知道是否可能,但如果我能以某种方式在我自己的进程中启动该服务,我应该可以跳过Camera.unlock()调用。
EDIT3:
最后一个选项是,如果我能以某种方式获得指向CameraHardwareInterface的指针。从它的外观来看,这是一个特定于设备的接口,可能不包括PID检查。这个问题的主要问题是我能找到指向它的唯一地方是在CameraService中,CameraService没有说话。
编辑4 :(几个月后)
此时,我认为不可能做我原本想要的事情。我不想删除有人确实回答的问题,但我并没有积极寻求答案。 (虽然,收到有效的答案会很棒。)
答案 0 :(得分:12)
我遇到了类似的问题。用户应该能够在录制期间更改闪光模式,以根据光线情况满足他们的需求。经过一些调查研究后,我得出了以下解决方案:
我假设您已经设置了适当的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()。这也说明了每个set属性的正确顺序,否则在调用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-Version 4.1.2的三星Galaxy S3上测试的。希望这种方法有所帮助。
答案 1 :(得分:1)
准备好录像机后,使用camera.lock(),然后设置要设置为摄像机的任何参数。 但在开始录制之前,你需要调用camera.unlock(),停止媒体录制后,你需要调用camera.lock()来开始预览。 享受!!!
答案 2 :(得分:0)
试试这个..希望它能起作用.. :)
private static Torch torch;
public Torch() {
super();
torch = this;
}
public static Torch getTorch() {
return torch;
}
private void getCamera() {
if (mCamera == null) {
try {
mCamera = Camera.open();
} catch (RuntimeException e) {
Log.e(TAG, "Camera.open() failed: " + e.getMessage());
}
}
}
public void toggleLight(View view) {
toggleLight();
}
private void toggleLight() {
if (lightOn) {
turnLightOff();
} else {
turnLightOn();
}
}
private void turnLightOn() {
if (!eulaAgreed) {
return;
}
if (mCamera == null) {
Toast.makeText(this, "Camera not found", Toast.LENGTH_LONG);
button.setBackgroundColor(COLOR_WHITE);
return;
}
lightOn = true;
Parameters parameters = mCamera.getParameters();
if (parameters == null) {
button.setBackgroundColor(COLOR_WHITE);
return;
}
List<String> flashModes = parameters.getSupportedFlashModes();
if (flashModes == null) {
button.setBackgroundColor(COLOR_WHITE);
return;
}
String flashMode = parameters.getFlashMode();
Log.i(TAG, "Flash mode: " + flashMode);
Log.i(TAG, "Flash modes: " + flashModes);
if (!Parameters.FLASH_MODE_TORCH.equals(flashMode)) {
if (flashModes.contains(Parameters.FLASH_MODE_TORCH)) {
parameters.setFlashMode(Parameters.FLASH_MODE_TORCH);
mCamera.setParameters(parameters);
button.setBackgroundColor(COLOR_LIGHT);
startWakeLock();
} else {
Toast.makeText(this, "Flash mode (torch) not supported",
Toast.LENGTH_LONG);
button.setBackgroundColor(COLOR_WHITE);
Log.e(TAG, "FLASH_MODE_TORCH not supported");
}
}
}
private void turnLightOff() {
if (lightOn) {
button.setBackgroundColor(COLOR_DARK);
lightOn = false;
if (mCamera == null) {
return;
}
Parameters parameters = mCamera.getParameters();
if (parameters == null) {
return;
}
List<String> flashModes = parameters.getSupportedFlashModes();
String flashMode = parameters.getFlashMode();
if (flashModes == null) {
return;
}
Log.i(TAG, "Flash mode: " + flashMode);
Log.i(TAG, "Flash modes: " + flashModes);
if (!Parameters.FLASH_MODE_OFF.equals(flashMode)) {
if (flashModes.contains(Parameters.FLASH_MODE_OFF)) {
parameters.setFlashMode(Parameters.FLASH_MODE_OFF);
mCamera.setParameters(parameters);
stopWakeLock();
} else {
Log.e(TAG, "FLASH_MODE_OFF not supported");
}
}
}
}
private void startPreview() {
if (!previewOn && mCamera != null) {
mCamera.startPreview();
previewOn = true;
}
}
private void stopPreview() {
if (previewOn && mCamera != null) {
mCamera.stopPreview();
previewOn = false;
}
}
private void startWakeLock() {
if (wakeLock == null) {
Log.d(TAG, "wakeLock is null, getting a new WakeLock");
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
Log.d(TAG, "PowerManager acquired");
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKE_LOCK_TAG);
Log.d(TAG, "WakeLock set");
}
wakeLock.acquire();
Log.d(TAG, "WakeLock acquired");
}
private void stopWakeLock() {
if (wakeLock != null) {
wakeLock.release();
Log.d(TAG, "WakeLock released");
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Eula.show(this)) {
eulaAgreed = true;
}
setContentView(R.layout.main);
button = findViewById(R.id.button);
surfaceView = (SurfaceView) this.findViewById(R.id.surfaceview);
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
disablePhoneSleep();
Log.i(TAG, "onCreate");
}
答案 3 :(得分:-2)
要访问设备相机,您必须在Android Manifest中声明CAMERA权限。另外,请确保包含<uses-feature>
清单元素,以声明应用程序使用的相机功能。例如,如果您使用相机和自动对焦功能,您的清单应包括以下内容:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
检查火炬支持的示例可能如下所示:
//Create camera and parameter objects
private Camera mCamera;
private Camera.Parameters mParameters;
private boolean mbTorchEnabled = false;
//... later in a click handler or other location, assuming that the mCamera object has already been instantiated with Camera.open()
mParameters = mCamera.getParameters();
//Get supported flash modes
List flashModes = mParameters.getSupportedFlashModes ();
//Make sure that torch mode is supported
//EDIT - wrong and dangerous to check for torch support this way
//if(flashModes != null && flashModes.contains("torch")){
if(flashModes != null && flashModes.contains(Camera.Parameters.FLASH_MODE_TORCH)){
if(mbTorchEnabled){
//Set the flash parameter to off
mParameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
}
else{
//Set the flash parameter to use the torch
mParameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
}
//Commit the camera parameters
mCamera.setParameters(mParameters);
mbTorchEnabled = !mbTorchEnabled;
}
要打开手电筒,只需设置相机参数Camera.Parameters.FLASH_MODE_TORCH
Camera mCamera;
Camera.Parameters mParameters;
//Get a reference to the camera/parameters
mCamera = Camera.open();
mParameters = mCamera.getParameters();
//Set the torch parameter
mParameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
//Comit camera parameters
mCamera.setParameters(mParameters);
要关闭手电筒,请设置Camera.Parameters.FLASH_MODE_OFF