据我自己的搜索所见(我还想为不同的应用程序控制相机 LED 的亮度),只能使用相机界面使用手电筒模式关闭或打开 LED。
现在,还可以在 Java 级别编写模拟 PWM(脉冲宽度调制)以在 TORCH_MODE 和 OFF 之间切换。但是我这样做的测试产生了太多的闪烁。
然后,我还尝试使用 NDK 在 Native 级别查看类似的方法,但似乎与相机(和 LED)的唯一接口是通过 Java 层。
2013-10-05 更新
下面是用于相机 LED 的 PWM 控制的 Java 代码。它可以工作,但闪烁使其通常无法使用。可能还有更多可以添加的优化,但不确定它们是否会对闪烁产生重大影响。
2013-12-15 更新
根据 Class Stacker 的反馈,我已经删除了无法实现的线程优先级,并且还改进了 PWM 延迟以单独使用 Thread.sleep 函数。测试显示略有改善,但闪烁仍然存在。请注意,可以减少睡眠值,但相机 API 调用需要相当长的时间才能返回,因此减少 PWM 睡眠不会对闪烁产生任何影响。
package com.whimsicalotter.ledpwmexample;
import java.util.List;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.util.Log;
public class LedPwmController {
private static String TAG = "LedPwmController";
private Camera m_camera = null;
private boolean m_torchSupported = false;
private LedPwmThread m_ledPwmThread = null;
private final int m_pwmMax = 10;
private int m_pwmValue = m_pwmMax;
public void init() {
initCamera();
// Start the thread
m_ledPwmThread = new LedPwmThread();
m_ledPwmThread.setRunning(true);
m_ledPwmThread.start();
}
public void shutdown() {
// Join the thread
boolean retry = true;
if (m_ledPwmThread != null) {
m_ledPwmThread.setRunning(false);
while (retry) {
try {
m_ledPwmThread.join();
retry = false;
} catch (InterruptedException e) {
// we will try it again and again...
}
}
}
destroyCamera();
}
/**
* Set the LED brightness 0.0f to 1.0f.
* @param brightness
*/
public void setLedBrightness(float brightness) {
if( brightness < 0.0f ) brightness = 0.0f;
if( brightness > 1.0f ) brightness = 1.0f;
// Now convert to integer
m_pwmValue = (int) Math.floor((brightness * (float)m_pwmMax));
Log.i(TAG, "LED Brightness set:" + brightness + " == " + m_pwmValue);
}
private void initCamera() {
if( m_camera == null ) {
Log.i(TAG, "Opening Camera...");
m_camera = Camera.open();
m_torchSupported = isTorchSupported();
Log.i(TAG, "Camera is open. Torch Supported = " + m_torchSupported);
}
}
private void destroyCamera() {
// switch off led
ledOff();
if( m_camera != null ) {
Log.i(TAG, "Releasing Camera...");
m_camera.release();
m_camera = null;
}
}
private boolean isTorchSupported() {
if( m_camera != null ) {
Parameters params = m_camera.getParameters();
List<String> flashmodes = params.getSupportedFlashModes();
if( flashmodes == null ) {
return false;
}
return flashmodes.contains( Parameters.FLASH_MODE_TORCH );
}
return false;
}
private void ledOn() {
if( !m_torchSupported ) {
return;
}
if( m_camera != null ) {
Parameters params = m_camera.getParameters();
params.setFlashMode( Parameters.FLASH_MODE_TORCH );
m_camera.setParameters(params);
}
}
private void ledOff() {
if( !m_torchSupported ) {
return;
}
if( m_camera != null ) {
Parameters params = m_camera.getParameters();
params.setFlashMode( Parameters.FLASH_MODE_OFF );
m_camera.setParameters(params);
}
}
private class LedPwmThread extends Thread {
private boolean m_running = false;
public void setRunning(boolean running) {
m_running = running;
}
@Override
public void run() {
if( m_camera != null && m_torchSupported ) {
Parameters params = m_camera.getParameters();
while( m_running ) {
//ledOn();
if( m_pwmValue > 0 ) {
params.setFlashMode( Parameters.FLASH_MODE_TORCH);
m_camera.setParameters(params);
try {
Thread.sleep(10*m_pwmValue,0);
} catch (InterruptedException e) {
}
}
//ledOff();
if( m_pwmValue < m_pwmMax ) {
params.setFlashMode( Parameters.FLASH_MODE_OFF );
m_camera.setParameters(params);
try {
Thread.sleep(10*(m_pwmMax-m_pwmValue),0);
} catch (InterruptedException e) {
}
}
}
}
}
}
}