使用Samsung S5的Camera2 API自动对焦

时间:2015-11-25 17:18:51

标签: android android-camera

我在Samsung S5上使用新的Camera2 API。此设备报告的受支持硬件级别为LEGACY,这很好。

但是,我似乎无法自动对焦于此设备。触发自动对焦的请求如下所示:

previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);
previewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START);
state = STATE_PREVIEW;
try {
  captureSession.setRepeatingRequest(previewRequestBuilder.build(), captureCallback, backgroundHandler);
} catch (CameraAccessException e) {
  e.printStackTrace();
}

发送请求后,请求的结果始终为CONTROL_AF_STATE_ACTIVE_SCAN,偶尔会CONTROL_AF_STATE_NOT_FOCUSED_LOCKED

奇怪的是,当状态为CONTROL_AF_STATE_NOT_FOCUSED_LOCKED时,自动对焦会回到CONTROL_AF_STATE_ACTIVE_SCAN状态一段时间,然后再回到CONTROL_AF_STATE_NOT_FOCUSED_LOCKED,从而产生无限的状态焦点循环。根据文档,当状态是CONTROL_AF_STATE_NOT_FOCUSED_LOCKED ...

  

镜头将保持静止,直到AF模式(android.control.afMode)发生变化或新的AF触发器被发送到相机设备(android.control.afTrigger)。

我想知道这种差异是否是因为硬件级别为LEGACY并且我应该回到使用已弃用的Camera API,但这对于如此流行的功能而言似乎很疯狂作为自动对焦。

是否有任何建议如何处理报告LEGACY的设备?

4 个答案:

答案 0 :(得分:12)

我将google's Camera2Basic example分支并将其更改为使用CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE而不是Camera2BasicFragment

您可以从git中获取项目并对其进行测试 - https://github.com/pinhassi/android-Camera2Basic

或者只是将其添加到private static final long LOCK_FOCUS_DELAY_ON_FOCUSED = 5000; private static final long LOCK_FOCUS_DELAY_ON_UNFOCUSED = 1000; private Integer mLastAfState = null; private Handler mUiHandler = new Handler(); // UI handler private Runnable mLockAutoFocusRunnable = new Runnable() { @Override public void run() { lockAutoFocus(); } }; public void lockAutoFocus() { try { // This is how to tell the camera to lock focus. mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START); CaptureRequest captureRequest = mPreviewRequestBuilder.build(); mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, null); // prevent CONTROL_AF_TRIGGER_START from calling over and over again mCaptureSession.capture(captureRequest, mCaptureCallback, mBackgroundHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } /** * * @return */ private float getMinimumFocusDistance() { if (mCameraId == null) return 0; Float minimumLens = null; try { CameraManager manager = (CameraManager) getActivity().getSystemService(Context.CAMERA_SERVICE); CameraCharacteristics c = manager.getCameraCharacteristics(mCameraId); minimumLens = c.get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE); } catch (Exception e) { Log.e(TAG, "isHardwareLevelSupported Error", e); } if (minimumLens != null) return minimumLens; return 0; } /** * * @return */ private boolean isAutoFocusSupported() { return isHardwareLevelSupported(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) || getMinimumFocusDistance() > 0; } // Returns true if the device supports the required hardware level, or better. @TargetApi(Build.VERSION_CODES.LOLLIPOP) private boolean isHardwareLevelSupported(int requiredLevel) { boolean res = false; if (mCameraId == null) return res; try { CameraManager manager = (CameraManager) getActivity().getSystemService(Context.CAMERA_SERVICE); CameraCharacteristics cameraCharacteristics = manager.getCameraCharacteristics(mCameraId); int deviceLevel = cameraCharacteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); switch (deviceLevel) { case CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3: Log.d(TAG, "Camera support level: INFO_SUPPORTED_HARDWARE_LEVEL_3"); break; case CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL: Log.d(TAG, "Camera support level: INFO_SUPPORTED_HARDWARE_LEVEL_FULL"); break; case CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY: Log.d(TAG, "Camera support level: INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY"); break; case CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED: Log.d(TAG, "Camera support level: INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED"); break; default: Log.d(TAG, "Unknown INFO_SUPPORTED_HARDWARE_LEVEL: " + deviceLevel); break; } if (deviceLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) { res = requiredLevel == deviceLevel; } else { // deviceLevel is not LEGACY, can use numerical sort res = requiredLevel <= deviceLevel; } } catch (Exception e) { Log.e(TAG, "isHardwareLevelSupported Error", e); } return res; }

STATE_PREVIEW

然后,添加到 case STATE_PREVIEW: { // We have nothing to do when the camera preview is working normally. // TODO: handle auto focus Integer afState = result.get(CaptureResult.CONTROL_AF_STATE); if (afState != null && !afState.equals(mLastAfState)) { switch (afState) { case CaptureResult.CONTROL_AF_STATE_INACTIVE: Log.d(TAG, "CaptureResult.CONTROL_AF_STATE_INACTIVE"); lockAutoFocus(); break; case CaptureResult.CONTROL_AF_STATE_ACTIVE_SCAN: Log.d(TAG, "CaptureResult.CONTROL_AF_STATE_ACTIVE_SCAN"); break; case CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED: Log.d(TAG, "CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED"); mUiHandler.removeCallbacks(mLockAutoFocusRunnable); mUiHandler.postDelayed(mLockAutoFocusRunnable, LOCK_FOCUS_DELAY_ON_FOCUSED); break; case CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED: mUiHandler.removeCallbacks(mLockAutoFocusRunnable); mUiHandler.postDelayed(mLockAutoFocusRunnable, LOCK_FOCUS_DELAY_ON_UNFOCUSED); Log.d(TAG, "CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED"); break; case CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED: mUiHandler.removeCallbacks(mLockAutoFocusRunnable); //mUiHandler.postDelayed(mLockAutoFocusRunnable, LOCK_FOCUS_DELAY_ON_UNFOCUSED); Log.d(TAG, "CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED"); break; case CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN: Log.d(TAG, "CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN"); break; case CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED: mUiHandler.removeCallbacks(mLockAutoFocusRunnable); //mUiHandler.postDelayed(mLockAutoFocusRunnable, LOCK_FOCUS_DELAY_ON_FOCUSED); Log.d(TAG, "CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED"); break; } } mLastAfState = afState; break; } 块:

mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                                            CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);

并替换所有出现的:

if (isAutoFocusSupported())
                                mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                                        CaptureRequest.CONTROL_AF_MODE_AUTO);
                            else
                                mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                                        CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);

使用:

public class NoLongClickMovementMethod extends LinkMovementMethod {

long longClickDelay = ViewConfiguration.getLongPressTimeout();
long startTime;

private static NoLongClickMovementMethod linkMovementMethod = new NoLongClickMovementMethod();

@Override
public boolean onTouchEvent(android.widget.TextView widget, android.text.Spannable buffer, MotionEvent event) {
    int action = event.getAction();

    if (action == MotionEvent.ACTION_DOWN) {
        startTime = System.currentTimeMillis();
    }

    if (action == MotionEvent.ACTION_UP) {
        long currentTime = System.currentTimeMillis();
        if (currentTime - startTime >= longClickDelay)
            return true;
    }
    return super.onTouchEvent(widget, buffer, event);
}

public static android.text.method.MovementMethod getInstance() {
    return linkMovementMethod;
}

答案 1 :(得分:1)

我认为问题出在你的setRepeatingRequest上。据我所知,CaptureRequest.CONTROL_AF_MODE_AUTO应该只导致自动对焦发生一次,但setRepeatingRequest将发送连续请求。请尝试使用捕获:

previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);
previewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START);

state = STATE_PREVIEW;

try {
mCaptureSession.capture(mPreviewRequestBuilder.build(), mPreCaptureCallback, mBackgroundHandler);
} catch (Exception e) {e.printStackTrace();}

答案 2 :(得分:0)

我在运行Android 5.1.1的Galaxy Note 4上遇到了同样的问题 - 而相同的代码在各种其他Android设备上运行良好。有报道称Galaxy-S4 / S5 / S6存在类似问题。

http://developer.samsung.com/forum/board/thread/view.do?boardName=SDK&messageId=289824&startId=zzzzz~ https://www.youtube.com/watch?v=lnMoYZwVaFM

所以要问你一个问题:这很可能是三星实施Camera-2实施的一个错误 - 这似乎是非常低质量的,不幸的是。

答案 3 :(得分:-2)

带有自动对焦功能的Samsung S5返回INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY,这意味着它不支持Camera2 api。

我在我的应用程序中使用了以下过滤器来使用相机。

if (Build.VERSION.SDK_INT >= 21 &amp;&amp; isDeviceCompatibleOfCamera2()) {
 // Use camera2
} else {
 // Use old camera
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
 public boolean isDeviceCompatibleOfCamera2() {
 try {
    CameraManager manager = (CameraManager) getActivity().getSystemService(Context.CAMERA_SERVICE);
    String backCameraId = manager.getCameraIdList()[0];
    CameraCharacteristics backCameraInfo = manager.getCameraCharacteristics(backCameraId);

    int level = backCameraInfo.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
    return level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL;

    } catch (CameraAccessException e) {
     ETLog.d(TAG, &quot;Device not compatible of camera2 api&quot; + e);
    }
    return false;
 }