Camera2 API 自动对焦与三星 S5

Posted

技术标签:

【中文标题】Camera2 API 自动对焦与三星 S5【英文标题】:Camera2 API AutoFocus with Samsung S5 【发布时间】:2016-02-28 14:33:45 【问题描述】:

我正在三星 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 并且我应该重新使用已弃用的相机 API,但这对于自动对焦等如此普遍的功能来说似乎很疯狂。

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

【问题讨论】:

你解决了这个问题吗? 【参考方案1】:

我对@9​​87654321@ 进行了分支并将其更改为使用CaptureRequest.CONTROL_AF_MODE_AUTO 而不是CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE

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

或者直接添加到Camera2BasicFragment:

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);

【讨论】:

@AlexShcherbyna 对我来说确实工作得很好。你做了哪些进一步的调整? @Entertain,下一步是这样的if(supportsContinuousAutoFocus(activity, mCameraId)) builder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); else builder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO); builder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START); 【参考方案2】:

我认为问题在于您的 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();

【讨论】:

我也是这样做的,但是,我发现自从第二次尝试拍照后,afState 始终为 0(不活跃)而不是 4 或 5(锁定)【参考方案3】:

我在运行 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 实施中的一个错误 - 不幸的是,它的质量似乎非常低。

【讨论】:

【参考方案4】:

三星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;
 

【讨论】:

这个答案不正确。 LEGACY 硬件支持与自动对焦、曝光或白平衡无关,它基本上与手动传感器控制有关。如果您正确使用它们,旧设备可以(并且确实)仍然具有自动控制功能。见developer.android.com/reference/android/hardware/camera2/… 如何判断是否支持 CONTROL_AF_MODE_AUTO?通过获取 LENS_INFO_MINIMUM_FOCUS_DISTANCE 值,该值仅适用于硬件支持 > LEGACY

以上是关于Camera2 API 自动对焦与三星 S5的主要内容,如果未能解决你的问题,请参考以下文章

Android 相机 2 对焦区域

Android SDK - camera2 - 在 TextureView 上绘制矩形

Android camera2 API在AF模式下获取焦距

Camera2 API 和 java.lang.IllegalStateException

对焦fullscan啥意思

问题支持Android相机的API和camera2 API问题,怎么解决